2 ******************************************************************************
3 * @file usbh_msc_core.c
4 * @author MCD Application Team
7 * @brief This file implements the MSC class driver functions
8 * ===================================================================
9 * MSC Class Description
10 * ===================================================================
11 * This module manages the MSC class V1.0 following the "Universal
12 * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
14 * This driver implements the following aspects of the specification:
15 * - Bulk-Only Transport protocol
16 * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
20 ******************************************************************************
23 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
24 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
25 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
26 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
27 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
28 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
30 * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
33 /* Includes ------------------------------------------------------------------*/
35 #include "usbh_msc_core.h"
36 #include "usbh_msc_scsi.h"
37 #include "usbh_msc_bot.h"
38 #include "usbh_core.h"
41 /** @addtogroup USBH_LIB
45 /** @addtogroup USBH_CLASS
49 /** @addtogroup USBH_MSC_CLASS
53 /** @defgroup USBH_MSC_CORE
54 * @brief This file includes the mass storage related functions
59 /** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
66 /** @defgroup USBH_MSC_CORE_Private_Defines
69 #define USBH_MSC_ERROR_RETRY_LIMIT 10
74 /** @defgroup USBH_MSC_CORE_Private_Macros
82 /** @defgroup USBH_MSC_CORE_Private_Variables
85 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
86 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
87 #pragma data_alignment=4
89 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
90 __ALIGN_BEGIN MSC_Machine_TypeDef MSC_Machine __ALIGN_END ;
92 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
93 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
94 #pragma data_alignment=4
96 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
97 __ALIGN_BEGIN USB_Setup_TypeDef MSC_Setup __ALIGN_END ;
98 uint8_t MSCErrorCount = 0;
106 /** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
110 static USBH_Status USBH_MSC_InterfaceInit (USB_OTG_CORE_HANDLE *pdev ,
113 static void USBH_MSC_InterfaceDeInit (USB_OTG_CORE_HANDLE *pdev ,
116 static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev ,
119 static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
122 static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
124 static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev,
128 USBH_Class_cb_TypeDef USBH_MSC_cb =
130 USBH_MSC_InterfaceInit,
131 USBH_MSC_InterfaceDeInit,
132 USBH_MSC_ClassRequest,
136 void USBH_MSC_ErrorHandle(uint8_t status);
143 /** @defgroup USBH_MSC_CORE_Exported_Variables
152 /** @defgroup USBH_MSC_CORE_Private_Functions
158 * @brief USBH_MSC_InterfaceInit
159 * Interface initialization for MSC class.
160 * @param pdev: Selected device
161 * @param hdev: Selected device property
162 * @retval USBH_Status : Status of class request handled.
164 static USBH_Status USBH_MSC_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev,
167 USBH_HOST *pphost = phost;
169 if((pphost->device_prop.Itf_Desc[0].bInterfaceClass == MSC_CLASS) && \
170 (pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == MSC_PROTOCOL))
172 if(pphost->device_prop.Ep_Desc[0][0].bEndpointAddress & 0x80)
174 MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
175 MSC_Machine.MSBulkInEpSize = pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize;
179 MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
180 MSC_Machine.MSBulkOutEpSize = pphost->device_prop.Ep_Desc[0] [0].wMaxPacketSize;
183 if(pphost->device_prop.Ep_Desc[0][1].bEndpointAddress & 0x80)
185 MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
186 MSC_Machine.MSBulkInEpSize = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;
190 MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
191 MSC_Machine.MSBulkOutEpSize = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;
194 MSC_Machine.hc_num_out = USBH_Alloc_Channel(pdev,
195 MSC_Machine.MSBulkOutEp);
196 MSC_Machine.hc_num_in = USBH_Alloc_Channel(pdev,
197 MSC_Machine.MSBulkInEp);
199 /* Open the new channels */
200 USBH_Open_Channel (pdev,
201 MSC_Machine.hc_num_out,
202 pphost->device_prop.address,
203 pphost->device_prop.speed,
205 MSC_Machine.MSBulkOutEpSize);
207 USBH_Open_Channel (pdev,
208 MSC_Machine.hc_num_in,
209 pphost->device_prop.address,
210 pphost->device_prop.speed,
212 MSC_Machine.MSBulkInEpSize);
218 pphost->usr_cb->USBH_USR_DeviceNotSupported();
227 * @brief USBH_MSC_InterfaceDeInit
228 * De-Initialize interface by freeing host channels allocated to interface
229 * @param pdev: Selected device
230 * @param hdev: Selected device property
233 void USBH_MSC_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
236 if ( MSC_Machine.hc_num_out)
238 USB_OTG_HC_Halt(pdev, MSC_Machine.hc_num_out);
239 USBH_Free_Channel (pdev, MSC_Machine.hc_num_out);
240 MSC_Machine.hc_num_out = 0; /* Reset the Channel as Free */
243 if ( MSC_Machine.hc_num_in)
245 USB_OTG_HC_Halt(pdev, MSC_Machine.hc_num_in);
246 USBH_Free_Channel (pdev, MSC_Machine.hc_num_in);
247 MSC_Machine.hc_num_in = 0; /* Reset the Channel as Free */
252 * @brief USBH_MSC_ClassRequest
253 * This function will only initialize the MSC state machine
254 * @param pdev: Selected device
255 * @param hdev: Selected device property
256 * @retval USBH_Status : Status of class request handled.
259 static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
263 USBH_Status status = USBH_OK ;
264 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_INIT_STATE;
271 * @brief USBH_MSC_Handle
272 * MSC state machine handler
273 * @param pdev: Selected device
274 * @param hdev: Selected device property
275 * @retval USBH_Status
278 static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev ,
281 USBH_HOST *pphost = phost;
283 USBH_Status status = USBH_BUSY;
284 uint8_t mscStatus = USBH_MSC_BUSY;
285 uint8_t appliStatus = 0;
287 static uint8_t maxLunExceed = FALSE;
290 if(HCD_IsDeviceConnected(pdev))
292 switch(USBH_MSC_BOTXferParam.MSCState)
294 case USBH_MSC_BOT_INIT_STATE:
296 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;
299 case USBH_MSC_BOT_RESET:
300 /* Issue BOT RESET request */
301 status = USBH_MSC_BOTReset(pdev, phost);
302 if(status == USBH_OK )
304 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;
307 if(status == USBH_NOT_SUPPORTED )
309 /* If the Command has failed, then we need to move to Next State, after
310 STALL condition is cleared by Control-Transfer */
311 USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_GET_MAX_LUN;
313 /* a Clear Feature should be issued here */
314 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
318 case USBH_MSC_GET_MAX_LUN:
319 /* Issue GetMaxLUN request */
320 status = USBH_MSC_GETMaxLUN(pdev, phost);
322 if(status == USBH_OK )
324 MSC_Machine.maxLun = *(MSC_Machine.buff) ;
326 /* If device has more that one logical unit then it is not supported */
327 if((MSC_Machine.maxLun > 0) && (maxLunExceed == FALSE))
330 pphost->usr_cb->USBH_USR_DeviceNotSupported();
334 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;
337 if(status == USBH_NOT_SUPPORTED )
339 /* If the Command has failed, then we need to move to Next State, after
340 STALL condition is cleared by Control-Transfer */
341 USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_TEST_UNIT_READY;
343 /* a Clear Feature should be issued here */
344 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
348 case USBH_MSC_CTRL_ERROR_STATE:
349 /* Issue Clearfeature request */
350 status = USBH_ClrFeature(pdev,
353 pphost->Control.hc_num_out);
354 if(status == USBH_OK )
356 /* If GetMaxLun Request not support, assume Single LUN configuration */
357 MSC_Machine.maxLun = 0;
359 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
363 case USBH_MSC_TEST_UNIT_READY:
364 /* Issue SCSI command TestUnitReady */
365 mscStatus = USBH_MSC_TestUnitReady(pdev);
367 if(mscStatus == USBH_MSC_OK )
369 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_READ_CAPACITY10;
375 USBH_MSC_ErrorHandle(mscStatus);
379 case USBH_MSC_READ_CAPACITY10:
380 /* Issue READ_CAPACITY10 SCSI command */
381 mscStatus = USBH_MSC_ReadCapacity10(pdev);
382 if(mscStatus == USBH_MSC_OK )
384 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_MODE_SENSE6;
390 USBH_MSC_ErrorHandle(mscStatus);
394 case USBH_MSC_MODE_SENSE6:
395 /* Issue ModeSense6 SCSI command for detecting if device is write-protected */
396 mscStatus = USBH_MSC_ModeSense6(pdev);
397 if(mscStatus == USBH_MSC_OK )
399 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
405 USBH_MSC_ErrorHandle(mscStatus);
409 case USBH_MSC_REQUEST_SENSE:
410 /* Issue RequestSense SCSI command for retreiving error code */
411 mscStatus = USBH_MSC_RequestSense(pdev);
412 if(mscStatus == USBH_MSC_OK )
414 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
419 USBH_MSC_ErrorHandle(mscStatus);
423 case USBH_MSC_BOT_USB_TRANSFERS:
424 /* Process the BOT state machine */
425 USBH_MSC_HandleBOTXfer(pdev , phost);
428 case USBH_MSC_DEFAULT_APPLI_STATE:
429 /* Process Application callback for MSC */
430 appliStatus = pphost->usr_cb->USBH_USR_MSC_Application();
433 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
435 else if (appliStatus == 1)
437 /* De-init requested from application layer */
438 status = USBH_APPLY_DEINIT;
442 case USBH_MSC_UNRECOVERED_STATE:
444 status = USBH_UNRECOVERED_ERROR;
459 * @brief USBH_MSC_BOTReset
460 * This request is used to reset the mass storage device and its
461 * associated interface. This class-specific request shall ready the
462 * device for the next CBW from the host.
463 * @param pdev: Selected device
464 * @retval USBH_Status : Status of class request handled.
466 static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
470 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
471 USB_REQ_RECIPIENT_INTERFACE;
473 phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
474 phost->Control.setup.b.wValue.w = 0;
475 phost->Control.setup.b.wIndex.w = 0;
476 phost->Control.setup.b.wLength.w = 0;
478 return USBH_CtlReq(pdev, phost, 0 , 0 );
483 * @brief USBH_MSC_GETMaxLUN
484 * This request is used to reset the mass storage device and its
485 * associated interface. This class-specific request shall ready the
486 * device for the next CBW from the host.
487 * @param pdev: Selected device
488 * @retval USBH_Status : USB ctl xfer status
490 static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
492 phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
493 USB_REQ_RECIPIENT_INTERFACE;
495 phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
496 phost->Control.setup.b.wValue.w = 0;
497 phost->Control.setup.b.wIndex.w = 0;
498 phost->Control.setup.b.wLength.w = 1;
500 return USBH_CtlReq(pdev, phost, MSC_Machine.buff , 1 );
504 * @brief USBH_MSC_ErrorHandle
505 * The function is for handling errors occuring during the MSC
511 void USBH_MSC_ErrorHandle(uint8_t status)
513 if(status == USBH_MSC_FAIL)
516 if(MSCErrorCount < USBH_MSC_ERROR_RETRY_LIMIT)
517 { /* Try MSC level error recovery, Issue the request Sense to get
518 Drive error reason */
519 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_REQUEST_SENSE;
520 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
524 /* Error trials exceeded the limit, go to unrecovered state */
525 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
528 else if(status == USBH_MSC_PHASE_ERROR)
530 /* Phase error, Go to Unrecoovered state */
531 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
533 else if(status == USBH_MSC_BUSY)
535 /*No change in state*/
559 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/