Merge branch 'tmaster' into future
[fw/stlink] / example / stm32f4 / STM32_USB_HOST_Library / Class / MSC / src / usbh_msc_core.c
diff --git a/example/stm32f4/STM32_USB_HOST_Library/Class/MSC/src/usbh_msc_core.c b/example/stm32f4/STM32_USB_HOST_Library/Class/MSC/src/usbh_msc_core.c
new file mode 100644 (file)
index 0000000..466399e
--- /dev/null
@@ -0,0 +1,559 @@
+/**
+  ******************************************************************************
+  * @file    usbh_msc_core.c
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    22-July-2011
+  * @brief   This file implements the MSC class driver functions
+  *          ===================================================================      
+  *                                MSC Class  Description
+  *          =================================================================== 
+  *           This module manages the MSC class V1.0 following the "Universal 
+  *           Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+  *           Sep. 31, 1999".
+  *           This driver implements the following aspects of the specification:
+  *             - Bulk-Only Transport protocol
+  *             - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+  *      
+  *  @endverbatim
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+  *
+  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
+*/ 
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "usbh_msc_core.h"
+#include "usbh_msc_scsi.h"
+#include "usbh_msc_bot.h"
+#include "usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+  * @{
+  */
+
+/** @addtogroup USBH_CLASS
+  * @{
+  */
+
+/** @addtogroup USBH_MSC_CLASS
+  * @{
+  */
+  
+/** @defgroup USBH_MSC_CORE 
+  * @brief    This file includes the mass storage related functions
+  * @{
+  */ 
+
+
+/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
+  * @{
+  */ 
+/**
+  * @}
+  */ 
+
+/** @defgroup USBH_MSC_CORE_Private_Defines
+  * @{
+  */ 
+#define USBH_MSC_ERROR_RETRY_LIMIT 10
+/**
+  * @}
+  */ 
+
+/** @defgroup USBH_MSC_CORE_Private_Macros
+  * @{
+  */ 
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBH_MSC_CORE_Private_Variables
+  * @{
+  */ 
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+    #pragma data_alignment=4   
+  #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN MSC_Machine_TypeDef         MSC_Machine __ALIGN_END ;
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+    #pragma data_alignment=4   
+  #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN USB_Setup_TypeDef           MSC_Setup __ALIGN_END ;
+uint8_t MSCErrorCount = 0;
+
+
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
+  * @{
+  */ 
+
+static USBH_Status USBH_MSC_InterfaceInit  (USB_OTG_CORE_HANDLE *pdev , 
+                                            void *phost);
+
+static void USBH_MSC_InterfaceDeInit  (USB_OTG_CORE_HANDLE *pdev , 
+                                       void *phost);
+
+static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev , 
+                            void *phost);
+
+static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
+                                         void *phost);
+
+static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
+                              USBH_HOST *phost);
+static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev,
+                               USBH_HOST *phost);
+
+
+USBH_Class_cb_TypeDef  USBH_MSC_cb = 
+{
+  USBH_MSC_InterfaceInit,
+  USBH_MSC_InterfaceDeInit,
+  USBH_MSC_ClassRequest,
+  USBH_MSC_Handle,
+};
+
+void USBH_MSC_ErrorHandle(uint8_t status);
+
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBH_MSC_CORE_Private_Functions
+  * @{
+  */ 
+
+
+/**
+  * @brief  USBH_MSC_InterfaceInit 
+  *         Interface initialization for MSC class.
+  * @param  pdev: Selected device
+  * @param  hdev: Selected device property
+  * @retval USBH_Status : Status of class request handled.
+  */
+static USBH_Status USBH_MSC_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev, 
+                                        void *phost)
+{       
+  USBH_HOST *pphost = phost;
+  
+  if((pphost->device_prop.Itf_Desc[0].bInterfaceClass == MSC_CLASS) && \
+     (pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == MSC_PROTOCOL))
+  {
+    if(pphost->device_prop.Ep_Desc[0][0].bEndpointAddress & 0x80)
+    {
+      MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
+      MSC_Machine.MSBulkInEpSize  = pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize;
+    }
+    else
+    {
+      MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
+      MSC_Machine.MSBulkOutEpSize  = pphost->device_prop.Ep_Desc[0] [0].wMaxPacketSize;      
+    }
+    
+    if(pphost->device_prop.Ep_Desc[0][1].bEndpointAddress & 0x80)
+    {
+      MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
+      MSC_Machine.MSBulkInEpSize  = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;      
+    }
+    else
+    {
+      MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
+      MSC_Machine.MSBulkOutEpSize  = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;      
+    }
+    
+    MSC_Machine.hc_num_out = USBH_Alloc_Channel(pdev, 
+                                                MSC_Machine.MSBulkOutEp);
+    MSC_Machine.hc_num_in = USBH_Alloc_Channel(pdev,
+                                                MSC_Machine.MSBulkInEp);  
+    
+    /* Open the new channels */
+    USBH_Open_Channel  (pdev,
+                        MSC_Machine.hc_num_out,
+                        pphost->device_prop.address,
+                        pphost->device_prop.speed,
+                        EP_TYPE_BULK,
+                        MSC_Machine.MSBulkOutEpSize);  
+    
+    USBH_Open_Channel  (pdev,
+                        MSC_Machine.hc_num_in,
+                        pphost->device_prop.address,
+                        pphost->device_prop.speed,
+                        EP_TYPE_BULK,
+                        MSC_Machine.MSBulkInEpSize);    
+    
+  }
+  
+  else
+  {
+    pphost->usr_cb->USBH_USR_DeviceNotSupported(); 
+  }
+  
+  return USBH_OK ;
+}
+
+
+/**
+  * @brief  USBH_MSC_InterfaceDeInit 
+  *         De-Initialize interface by freeing host channels allocated to interface
+  * @param  pdev: Selected device
+  * @param  hdev: Selected device property
+  * @retval None
+  */
+void USBH_MSC_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
+                                void *phost)
+{      
+  if ( MSC_Machine.hc_num_out)
+  {
+    USB_OTG_HC_Halt(pdev, MSC_Machine.hc_num_out);
+    USBH_Free_Channel  (pdev, MSC_Machine.hc_num_out);
+    MSC_Machine.hc_num_out = 0;     /* Reset the Channel as Free */
+  }
+   
+  if ( MSC_Machine.hc_num_in)
+  {
+    USB_OTG_HC_Halt(pdev, MSC_Machine.hc_num_in);
+    USBH_Free_Channel  (pdev, MSC_Machine.hc_num_in);
+    MSC_Machine.hc_num_in = 0;     /* Reset the Channel as Free */
+  } 
+}
+
+/**
+  * @brief  USBH_MSC_ClassRequest 
+  *         This function will only initialize the MSC state machine
+  * @param  pdev: Selected device
+  * @param  hdev: Selected device property
+  * @retval USBH_Status : Status of class request handled.
+  */
+
+static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
+                                        void *phost)
+{   
+  
+  USBH_Status status = USBH_OK ;
+  USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_INIT_STATE;
+  
+  return status; 
+}
+
+
+/**
+  * @brief  USBH_MSC_Handle 
+  *         MSC state machine handler 
+  * @param  pdev: Selected device
+  * @param  hdev: Selected device property
+  * @retval USBH_Status
+  */
+
+static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev , 
+                                   void   *phost)
+{
+  USBH_HOST *pphost = phost;
+    
+  USBH_Status status = USBH_BUSY;
+  uint8_t mscStatus = USBH_MSC_BUSY;
+  uint8_t appliStatus = 0;
+  
+  static uint8_t maxLunExceed = FALSE;
+  
+    
+  if(HCD_IsDeviceConnected(pdev))
+  {   
+    switch(USBH_MSC_BOTXferParam.MSCState)
+    {
+    case USBH_MSC_BOT_INIT_STATE:
+      USBH_MSC_Init(pdev);
+      USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;  
+      break;
+      
+    case USBH_MSC_BOT_RESET:   
+      /* Issue BOT RESET request */
+      status = USBH_MSC_BOTReset(pdev, phost);
+      if(status == USBH_OK )
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;
+      }
+      
+      if(status == USBH_NOT_SUPPORTED )
+      {
+       /* If the Command has failed, then we need to move to Next State, after
+        STALL condition is cleared by Control-Transfer */
+        USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_GET_MAX_LUN; 
+
+        /* a Clear Feature should be issued here */
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
+      }  
+      break;
+      
+    case USBH_MSC_GET_MAX_LUN:
+      /* Issue GetMaxLUN request */
+      status = USBH_MSC_GETMaxLUN(pdev, phost);
+      
+      if(status == USBH_OK )
+      {
+        MSC_Machine.maxLun = *(MSC_Machine.buff) ;
+        
+        /* If device has more that one logical unit then it is not supported */
+        if((MSC_Machine.maxLun > 0) && (maxLunExceed == FALSE))
+        {
+          maxLunExceed = TRUE;
+          pphost->usr_cb->USBH_USR_DeviceNotSupported();
+          
+          break;
+        }
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;
+      }
+      
+      if(status == USBH_NOT_SUPPORTED )
+      {
+               /* If the Command has failed, then we need to move to Next State, after
+        STALL condition is cleared by Control-Transfer */
+        USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_TEST_UNIT_READY; 
+        
+        /* a Clear Feature should be issued here */
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
+      }    
+      break;
+      
+    case USBH_MSC_CTRL_ERROR_STATE:
+      /* Issue Clearfeature request */
+      status = USBH_ClrFeature(pdev,
+                               phost,
+                               0x00,
+                               pphost->Control.hc_num_out);
+      if(status == USBH_OK )
+      {
+        /* If GetMaxLun Request not support, assume Single LUN configuration */
+        MSC_Machine.maxLun = 0;  
+        
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;     
+      }
+      break;  
+      
+    case USBH_MSC_TEST_UNIT_READY:
+      /* Issue SCSI command TestUnitReady */ 
+      mscStatus = USBH_MSC_TestUnitReady(pdev);
+      
+      if(mscStatus == USBH_MSC_OK )
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_READ_CAPACITY10;
+        MSCErrorCount = 0;
+        status = USBH_OK;
+      }
+      else
+      {
+        USBH_MSC_ErrorHandle(mscStatus);
+      } 
+      break;
+      
+    case USBH_MSC_READ_CAPACITY10:
+      /* Issue READ_CAPACITY10 SCSI command */
+      mscStatus = USBH_MSC_ReadCapacity10(pdev);
+      if(mscStatus == USBH_MSC_OK )
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_MODE_SENSE6;
+        MSCErrorCount = 0;
+        status = USBH_OK;
+      }
+      else
+      {
+        USBH_MSC_ErrorHandle(mscStatus);
+      }
+      break;
+
+    case USBH_MSC_MODE_SENSE6:
+      /* Issue ModeSense6 SCSI command for detecting if device is write-protected */
+      mscStatus = USBH_MSC_ModeSense6(pdev);
+      if(mscStatus == USBH_MSC_OK )
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
+        MSCErrorCount = 0;
+        status = USBH_OK;
+      }
+      else
+      {
+        USBH_MSC_ErrorHandle(mscStatus);
+      }
+      break;
+      
+    case USBH_MSC_REQUEST_SENSE:
+      /* Issue RequestSense SCSI command for retreiving error code */
+      mscStatus = USBH_MSC_RequestSense(pdev);
+      if(mscStatus == USBH_MSC_OK )
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
+        status = USBH_OK;
+      }
+      else
+      {
+        USBH_MSC_ErrorHandle(mscStatus);
+      }  
+      break;
+      
+    case USBH_MSC_BOT_USB_TRANSFERS:
+      /* Process the BOT state machine */
+      USBH_MSC_HandleBOTXfer(pdev , phost);
+      break;
+    
+    case USBH_MSC_DEFAULT_APPLI_STATE:
+      /* Process Application callback for MSC */
+      appliStatus = pphost->usr_cb->USBH_USR_MSC_Application();
+      if(appliStatus == 0)
+      {
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
+      }
+      else if (appliStatus == 1) 
+      {
+        /* De-init requested from application layer */
+        status =  USBH_APPLY_DEINIT;
+      }
+      break;
+      
+    case USBH_MSC_UNRECOVERED_STATE:
+      
+      status = USBH_UNRECOVERED_ERROR;
+      
+      break;
+      
+    default:
+      break; 
+      
+    }
+  }
+   return status;
+}
+
+
+
+/**
+  * @brief  USBH_MSC_BOTReset
+  *         This request is used to reset the mass storage device and its 
+  *         associated interface. This class-specific request shall ready the 
+  *         device for the next CBW from the host.
+  * @param  pdev: Selected device
+  * @retval USBH_Status : Status of class request handled.
+  */
+static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
+                              USBH_HOST *phost)
+{
+  
+  phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
+                              USB_REQ_RECIPIENT_INTERFACE;
+  
+  phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
+  phost->Control.setup.b.wValue.w = 0;
+  phost->Control.setup.b.wIndex.w = 0;
+  phost->Control.setup.b.wLength.w = 0;           
+  
+  return USBH_CtlReq(pdev, phost, 0 , 0 ); 
+}
+
+
+/**
+  * @brief  USBH_MSC_GETMaxLUN
+  *         This request is used to reset the mass storage device and its 
+  *         associated interface. This class-specific request shall ready the 
+  *         device for the next CBW from the host.
+  * @param  pdev: Selected device
+  * @retval USBH_Status : USB ctl xfer status
+  */
+static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
+{
+  phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
+                              USB_REQ_RECIPIENT_INTERFACE;
+  
+  phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
+  phost->Control.setup.b.wValue.w = 0;
+  phost->Control.setup.b.wIndex.w = 0;
+  phost->Control.setup.b.wLength.w = 1;           
+  
+  return USBH_CtlReq(pdev, phost, MSC_Machine.buff , 1 ); 
+}
+
+/**
+  * @brief  USBH_MSC_ErrorHandle 
+  *         The function is for handling errors occuring during the MSC
+  *         state machine   
+  * @param  status
+  * @retval None
+  */
+
+void USBH_MSC_ErrorHandle(uint8_t status)
+{  
+    if(status == USBH_MSC_FAIL)
+    { 
+      MSCErrorCount++;
+      if(MSCErrorCount < USBH_MSC_ERROR_RETRY_LIMIT)
+      { /* Try MSC level error recovery, Issue the request Sense to get 
+        Drive error reason  */
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_REQUEST_SENSE;
+        USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
+      }
+      else
+      {
+        /* Error trials exceeded the limit, go to unrecovered state */
+        USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
+      }
+    } 
+    else if(status == USBH_MSC_PHASE_ERROR)
+    {
+      /* Phase error, Go to Unrecoovered state */
+      USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
+    }
+    else if(status == USBH_MSC_BUSY)
+    {
+      /*No change in state*/
+    }
+}
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/