Improve generic & stm32f4 demos
[lwext4.git] / demos / stm32f429_disco / stm / usb_host / Class / MSC / src / usbh_msc_scsi.c
1 /**\r
2   ******************************************************************************\r
3   * @file    usbh_msc_scsi.c \r
4   * @author  MCD Application Team\r
5   * @version V3.0.0\r
6   * @date    18-February-2014\r
7   * @brief   This file implements the SCSI commands\r
8   ******************************************************************************\r
9   * @attention\r
10   *\r
11   * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>\r
12   *\r
13   * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");\r
14   * You may not use this file except in compliance with the License.\r
15   * You may obtain a copy of the License at:\r
16   *\r
17   *        http://www.st.com/software_license_agreement_liberty_v2\r
18   *\r
19   * Unless required by applicable law or agreed to in writing, software \r
20   * distributed under the License is distributed on an "AS IS" BASIS, \r
21   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
22   * See the License for the specific language governing permissions and\r
23   * limitations under the License.\r
24   *\r
25   ******************************************************************************\r
26   */ \r
27 \r
28 /* Includes ------------------------------------------------------------------*/\r
29 #include "usbh_msc.h"\r
30 #include "usbh_msc_scsi.h"\r
31 #include "usbh_msc_bot.h"\r
32 \r
33 \r
34 /** @addtogroup USBH_LIB\r
35   * @{\r
36   */\r
37 \r
38 /** @addtogroup USBH_CLASS\r
39   * @{\r
40   */\r
41 \r
42 /** @addtogroup USBH_MSC_CLASS\r
43   * @{\r
44   */\r
45   \r
46 /** @defgroup USBH_MSC_SCSI \r
47   * @brief    This file includes the mass storage related functions\r
48   * @{\r
49   */ \r
50 \r
51 \r
52 /** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions\r
53   * @{\r
54   */ \r
55 \r
56 /**\r
57   * @}\r
58   */ \r
59 \r
60 /** @defgroup USBH_MSC_SCSI_Private_Defines\r
61   * @{\r
62   */ \r
63 /**\r
64   * @}\r
65   */ \r
66 \r
67 /** @defgroup USBH_MSC_SCSI_Private_Macros\r
68   * @{\r
69   */ \r
70 /**\r
71   * @}\r
72   */ \r
73 \r
74 \r
75 /** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes\r
76   * @{\r
77   */ \r
78 /**\r
79   * @}\r
80   */ \r
81 \r
82 \r
83 /** @defgroup USBH_MSC_SCSI_Exported_Variables\r
84   * @{\r
85   */ \r
86 \r
87 /**\r
88   * @}\r
89   */ \r
90 \r
91 \r
92 /** @defgroup USBH_MSC_SCSI_Private_Functions\r
93   * @{\r
94   */ \r
95 \r
96 \r
97 /**\r
98   * @brief  USBH_MSC_SCSI_TestUnitReady \r
99   *         Issue TestUnitReady command.\r
100   * @param  phost: Host handle\r
101   * @param  lun: Logical Unit Number\r
102   * @retval USBH Status\r
103   */\r
104 USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost, \r
105                                                 uint8_t lun)\r
106 {\r
107   USBH_StatusTypeDef    error = USBH_FAIL ;\r
108   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
109   \r
110   switch(MSC_Handle->hbot.cmd_state)\r
111   {\r
112   case BOT_CMD_SEND:  \r
113     \r
114     /*Prepare the CBW and relevent field*/\r
115     MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY;     \r
116     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;\r
117     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
118     \r
119     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);\r
120     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_TEST_UNIT_READY; \r
121     \r
122     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
123     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
124     error = USBH_BUSY; \r
125     break;\r
126     \r
127   case BOT_CMD_WAIT: \r
128     error = USBH_MSC_BOT_Process(phost, lun);\r
129     break;\r
130     \r
131   default:\r
132     break;\r
133   }\r
134   \r
135   return error;\r
136 }\r
137 \r
138 /**\r
139   * @brief  USBH_MSC_SCSI_ReadCapacity \r
140   *         Issue Read Capacity command.\r
141   * @param  phost: Host handle\r
142   * @param  lun: Logical Unit Number\r
143   * @param  capacity: pointer to the capacity structure\r
144   * @retval USBH Status\r
145   */\r
146 USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost, \r
147                                                uint8_t lun,\r
148                                                SCSI_CapacityTypeDef *capacity)\r
149 {\r
150   USBH_StatusTypeDef    error = USBH_BUSY ;\r
151   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
152   \r
153   switch(MSC_Handle->hbot.cmd_state)\r
154   {\r
155   case BOT_CMD_SEND:  \r
156     \r
157     /*Prepare the CBW and relevent field*/\r
158     MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10;\r
159     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;\r
160     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
161     \r
162     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);\r
163     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_READ_CAPACITY10; \r
164     \r
165     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
166     \r
167     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
168     MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;\r
169     error = USBH_BUSY; \r
170     break;\r
171     \r
172   case BOT_CMD_WAIT: \r
173     \r
174     error = USBH_MSC_BOT_Process(phost, lun);\r
175     \r
176     if(error == USBH_OK)\r
177     {\r
178       /*assign the capacity*/\r
179       capacity->block_nbr = MSC_Handle->hbot.pbuf[3] | (MSC_Handle->hbot.pbuf[2] << 8) |\\r
180                            (MSC_Handle->hbot.pbuf[1] << 16) | (MSC_Handle->hbot.pbuf[0] << 24);\r
181 \r
182       /*assign the page length*/\r
183       capacity->block_size = MSC_Handle->hbot.pbuf[7] | (MSC_Handle->hbot.pbuf[6] << 8); \r
184     }\r
185     break;\r
186     \r
187   default:\r
188     break;\r
189   }\r
190   \r
191   return error;\r
192 }\r
193 \r
194 /**\r
195   * @brief  USBH_MSC_SCSI_Inquiry \r
196   *         Issue Inquiry command.\r
197   * @param  phost: Host handle\r
198   * @param  lun: Logical Unit Number\r
199   * @param  capacity: pointer to the inquiry structure\r
200   * @retval USBH Status\r
201   */\r
202 USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost, \r
203                                                uint8_t lun, \r
204                                                SCSI_StdInquiryDataTypeDef *inquiry)\r
205 {\r
206   USBH_StatusTypeDef    error = USBH_FAIL ;\r
207   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
208   switch(MSC_Handle->hbot.cmd_state)\r
209   {\r
210   case BOT_CMD_SEND:  \r
211     \r
212     /*Prepare the CBW and relevent field*/\r
213     MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY;\r
214     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;\r
215     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
216     \r
217     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH);\r
218     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_INQUIRY; \r
219     MSC_Handle->hbot.cbw.field.CB[1]  = (lun << 5);    \r
220     MSC_Handle->hbot.cbw.field.CB[2]  = 0;    \r
221     MSC_Handle->hbot.cbw.field.CB[3]  = 0;    \r
222     MSC_Handle->hbot.cbw.field.CB[4]  = 0x24;    \r
223     MSC_Handle->hbot.cbw.field.CB[5]  = 0;    \r
224         \r
225     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
226 \r
227     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
228     MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;\r
229     error = USBH_BUSY; \r
230     break;\r
231     \r
232   case BOT_CMD_WAIT: \r
233     \r
234     error = USBH_MSC_BOT_Process(phost, lun);\r
235     \r
236     if(error == USBH_OK)\r
237     {\r
238       USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef));\r
239       /*assign Inquiry Data */\r
240       inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1F;\r
241       inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5;  \r
242       inquiry->RemovableMedia = (MSC_Handle->hbot.pbuf[1] & 0x80)== 0x80;\r
243       USBH_memcpy (inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8);\r
244       USBH_memcpy (inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16);\r
245       USBH_memcpy (inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4);    \r
246     }\r
247     break;\r
248     \r
249   default:\r
250     break;\r
251   }\r
252   \r
253   return error;\r
254 }\r
255 \r
256 /**\r
257   * @brief  USBH_MSC_SCSI_RequestSense \r
258   *         Issue RequestSense command.\r
259   * @param  phost: Host handle\r
260   * @param  lun: Logical Unit Number\r
261   * @param  capacity: pointer to the sense data structure\r
262   * @retval USBH Status\r
263   */\r
264 USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost, \r
265                                                uint8_t lun, \r
266                                                SCSI_SenseTypeDef *sense_data)\r
267 {\r
268   USBH_StatusTypeDef    error = USBH_FAIL ;\r
269   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
270   \r
271   switch(MSC_Handle->hbot.cmd_state)\r
272   {\r
273   case BOT_CMD_SEND:  \r
274     \r
275     /*Prepare the CBW and relevent field*/\r
276     MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE;\r
277     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;\r
278     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
279     \r
280     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);\r
281     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_REQUEST_SENSE; \r
282     MSC_Handle->hbot.cbw.field.CB[1]  = (lun << 5); \r
283     MSC_Handle->hbot.cbw.field.CB[2]  = 0; \r
284     MSC_Handle->hbot.cbw.field.CB[3]  = 0; \r
285     MSC_Handle->hbot.cbw.field.CB[4]  = DATA_LEN_REQUEST_SENSE;\r
286     MSC_Handle->hbot.cbw.field.CB[5]  = 0;       \r
287     \r
288     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
289     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
290     MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data;\r
291     error = USBH_BUSY; \r
292     break;\r
293     \r
294   case BOT_CMD_WAIT: \r
295     \r
296     error = USBH_MSC_BOT_Process(phost, lun);\r
297     \r
298     if(error == USBH_OK)\r
299     {\r
300       sense_data->key  = MSC_Handle->hbot.pbuf[2] & 0x0F;  \r
301       sense_data->asc  = MSC_Handle->hbot.pbuf[12];\r
302       sense_data->ascq = MSC_Handle->hbot.pbuf[13];\r
303     }\r
304     break;\r
305     \r
306   default:\r
307     break;\r
308   }\r
309   \r
310   return error;\r
311 }\r
312 \r
313 /**\r
314   * @brief  USBH_MSC_SCSI_Write \r
315   *         Issue write10 command.\r
316   * @param  phost: Host handle\r
317   * @param  lun: Logical Unit Number\r
318   * @param  address: sector address\r
319   * @param  pbuf: pointer to data\r
320   * @param  length: number of sector to write\r
321   * @retval USBH Status\r
322   */\r
323 USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,\r
324                                      uint8_t lun,\r
325                                      uint32_t address,\r
326                                      uint8_t *pbuf,\r
327                                      uint32_t length)\r
328 {\r
329   USBH_StatusTypeDef    error = USBH_FAIL ;\r
330 \r
331   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
332   \r
333   switch(MSC_Handle->hbot.cmd_state)\r
334   {\r
335   case BOT_CMD_SEND:  \r
336     \r
337     /*Prepare the CBW and relevent field*/\r
338     MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;\r
339     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;\r
340     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
341     \r
342     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);\r
343     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_WRITE10; \r
344     \r
345     /*logical block address*/\r
346     MSC_Handle->hbot.cbw.field.CB[2]  = (((uint8_t*)&address)[3]);\r
347     MSC_Handle->hbot.cbw.field.CB[3]  = (((uint8_t*)&address)[2]);\r
348     MSC_Handle->hbot.cbw.field.CB[4]  = (((uint8_t*)&address)[1]);\r
349     MSC_Handle->hbot.cbw.field.CB[5]  = (((uint8_t*)&address)[0]);\r
350     \r
351     \r
352     /*Tranfer length */\r
353     MSC_Handle->hbot.cbw.field.CB[7]  = (((uint8_t *)&length)[1]) ; \r
354     MSC_Handle->hbot.cbw.field.CB[8]  = (((uint8_t *)&length)[0]) ; \r
355 \r
356     \r
357     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
358     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
359     MSC_Handle->hbot.pbuf = pbuf;\r
360     error = USBH_BUSY; \r
361     break;\r
362     \r
363   case BOT_CMD_WAIT: \r
364     error = USBH_MSC_BOT_Process(phost, lun);\r
365     break;\r
366     \r
367   default:\r
368     break;\r
369   }\r
370   \r
371   return error;\r
372 }\r
373 \r
374 /**\r
375   * @brief  USBH_MSC_SCSI_Read \r
376   *         Issue Read10 command.\r
377   * @param  phost: Host handle\r
378   * @param  lun: Logical Unit Number\r
379   * @param  address: sector address\r
380   * @param  pbuf: pointer to data\r
381   * @param  length: number of sector to read\r
382   * @retval USBH Status\r
383   */\r
384 USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,\r
385                                      uint8_t lun,\r
386                                      uint32_t address,\r
387                                      uint8_t *pbuf,\r
388                                      uint32_t length)\r
389 {\r
390   USBH_StatusTypeDef    error = USBH_FAIL ;\r
391   MSC_HandleTypeDef *MSC_Handle =  phost->pActiveClass->pData;\r
392   \r
393   switch(MSC_Handle->hbot.cmd_state)\r
394   {\r
395   case BOT_CMD_SEND:  \r
396     \r
397     /*Prepare the CBW and relevent field*/\r
398     MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512;\r
399     MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;\r
400     MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;\r
401     \r
402     USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);\r
403     MSC_Handle->hbot.cbw.field.CB[0]  = OPCODE_READ10; \r
404     \r
405     /*logical block address*/\r
406     MSC_Handle->hbot.cbw.field.CB[2]  = (((uint8_t*)&address)[3]);\r
407     MSC_Handle->hbot.cbw.field.CB[3]  = (((uint8_t*)&address)[2]);\r
408     MSC_Handle->hbot.cbw.field.CB[4]  = (((uint8_t*)&address)[1]);\r
409     MSC_Handle->hbot.cbw.field.CB[5]  = (((uint8_t*)&address)[0]);\r
410     \r
411     \r
412     /*Tranfer length */\r
413     MSC_Handle->hbot.cbw.field.CB[7]  = (((uint8_t *)&length)[1]) ; \r
414     MSC_Handle->hbot.cbw.field.CB[8]  = (((uint8_t *)&length)[0]) ; \r
415 \r
416     \r
417     MSC_Handle->hbot.state = BOT_SEND_CBW;\r
418     MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;\r
419     MSC_Handle->hbot.pbuf = pbuf;\r
420     error = USBH_BUSY; \r
421     break;\r
422     \r
423   case BOT_CMD_WAIT: \r
424     error = USBH_MSC_BOT_Process(phost, lun);\r
425     break;\r
426     \r
427   default:\r
428     break;\r
429   }\r
430   \r
431   return error;\r
432 }\r
433 \r
434 \r
435 /**\r
436   * @}\r
437   */ \r
438 \r
439 /**\r
440   * @}\r
441   */ \r
442 \r
443 /**\r
444   * @}\r
445   */\r
446 \r
447 /**\r
448   * @}\r
449   */ \r
450 \r
451 /**\r
452   * @}\r
453   */\r
454 \r
455 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/\r
456 \r
457 \r
458 \r