466399e90b0c257e2a3588ff9f5a09cacc7ee6f8
[fw/stlink] / example / stm32f4 / STM32_USB_HOST_Library / Class / MSC / src / usbh_msc_core.c
1 /**
2   ******************************************************************************
3   * @file    usbh_msc_core.c
4   * @author  MCD Application Team
5   * @version V2.0.0
6   * @date    22-July-2011
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
13   *           Sep. 31, 1999".
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))
17   *      
18   *  @endverbatim
19   *
20   ******************************************************************************
21   * @attention
22   *
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.
29   *
30   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
31 */ 
32
33 /* Includes ------------------------------------------------------------------*/
34
35 #include "usbh_msc_core.h"
36 #include "usbh_msc_scsi.h"
37 #include "usbh_msc_bot.h"
38 #include "usbh_core.h"
39
40
41 /** @addtogroup USBH_LIB
42   * @{
43   */
44
45 /** @addtogroup USBH_CLASS
46   * @{
47   */
48
49 /** @addtogroup USBH_MSC_CLASS
50   * @{
51   */
52   
53 /** @defgroup USBH_MSC_CORE 
54   * @brief    This file includes the mass storage related functions
55   * @{
56   */ 
57
58
59 /** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
60   * @{
61   */ 
62 /**
63   * @}
64   */ 
65
66 /** @defgroup USBH_MSC_CORE_Private_Defines
67   * @{
68   */ 
69 #define USBH_MSC_ERROR_RETRY_LIMIT 10
70 /**
71   * @}
72   */ 
73
74 /** @defgroup USBH_MSC_CORE_Private_Macros
75   * @{
76   */ 
77 /**
78   * @}
79   */ 
80
81
82 /** @defgroup USBH_MSC_CORE_Private_Variables
83   * @{
84   */ 
85 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
86   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
87     #pragma data_alignment=4   
88   #endif
89 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
90 __ALIGN_BEGIN MSC_Machine_TypeDef         MSC_Machine __ALIGN_END ;
91
92 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
93   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
94     #pragma data_alignment=4   
95   #endif
96 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
97 __ALIGN_BEGIN USB_Setup_TypeDef           MSC_Setup __ALIGN_END ;
98 uint8_t MSCErrorCount = 0;
99
100
101 /**
102   * @}
103   */ 
104
105
106 /** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
107   * @{
108   */ 
109
110 static USBH_Status USBH_MSC_InterfaceInit  (USB_OTG_CORE_HANDLE *pdev , 
111                                             void *phost);
112
113 static void USBH_MSC_InterfaceDeInit  (USB_OTG_CORE_HANDLE *pdev , 
114                                        void *phost);
115
116 static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev , 
117                             void *phost);
118
119 static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
120                                          void *phost);
121
122 static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
123                               USBH_HOST *phost);
124 static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev,
125                                USBH_HOST *phost);
126
127
128 USBH_Class_cb_TypeDef  USBH_MSC_cb = 
129 {
130   USBH_MSC_InterfaceInit,
131   USBH_MSC_InterfaceDeInit,
132   USBH_MSC_ClassRequest,
133   USBH_MSC_Handle,
134 };
135
136 void USBH_MSC_ErrorHandle(uint8_t status);
137
138 /**
139   * @}
140   */ 
141
142
143 /** @defgroup USBH_MSC_CORE_Exported_Variables
144   * @{
145   */ 
146
147 /**
148   * @}
149   */ 
150
151
152 /** @defgroup USBH_MSC_CORE_Private_Functions
153   * @{
154   */ 
155
156
157 /**
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.
163   */
164 static USBH_Status USBH_MSC_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev, 
165                                         void *phost)
166 {        
167   USBH_HOST *pphost = phost;
168   
169   if((pphost->device_prop.Itf_Desc[0].bInterfaceClass == MSC_CLASS) && \
170      (pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == MSC_PROTOCOL))
171   {
172     if(pphost->device_prop.Ep_Desc[0][0].bEndpointAddress & 0x80)
173     {
174       MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
175       MSC_Machine.MSBulkInEpSize  = pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize;
176     }
177     else
178     {
179       MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][0].bEndpointAddress);
180       MSC_Machine.MSBulkOutEpSize  = pphost->device_prop.Ep_Desc[0] [0].wMaxPacketSize;      
181     }
182     
183     if(pphost->device_prop.Ep_Desc[0][1].bEndpointAddress & 0x80)
184     {
185       MSC_Machine.MSBulkInEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
186       MSC_Machine.MSBulkInEpSize  = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;      
187     }
188     else
189     {
190       MSC_Machine.MSBulkOutEp = (pphost->device_prop.Ep_Desc[0][1].bEndpointAddress);
191       MSC_Machine.MSBulkOutEpSize  = pphost->device_prop.Ep_Desc[0][1].wMaxPacketSize;      
192     }
193     
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);  
198     
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,
204                         EP_TYPE_BULK,
205                         MSC_Machine.MSBulkOutEpSize);  
206     
207     USBH_Open_Channel  (pdev,
208                         MSC_Machine.hc_num_in,
209                         pphost->device_prop.address,
210                         pphost->device_prop.speed,
211                         EP_TYPE_BULK,
212                         MSC_Machine.MSBulkInEpSize);    
213     
214   }
215   
216   else
217   {
218     pphost->usr_cb->USBH_USR_DeviceNotSupported(); 
219   }
220   
221   return USBH_OK ;
222  
223 }
224
225
226 /**
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
231   * @retval None
232   */
233 void USBH_MSC_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
234                                 void *phost)
235 {       
236   if ( MSC_Machine.hc_num_out)
237   {
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 */
241   }
242    
243   if ( MSC_Machine.hc_num_in)
244   {
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 */
248   } 
249 }
250
251 /**
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.
257   */
258
259 static USBH_Status USBH_MSC_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
260                                         void *phost)
261 {   
262   
263   USBH_Status status = USBH_OK ;
264   USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_INIT_STATE;
265   
266   return status; 
267 }
268
269
270 /**
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
276   */
277
278 static USBH_Status USBH_MSC_Handle(USB_OTG_CORE_HANDLE *pdev , 
279                                    void   *phost)
280 {
281   USBH_HOST *pphost = phost;
282     
283   USBH_Status status = USBH_BUSY;
284   uint8_t mscStatus = USBH_MSC_BUSY;
285   uint8_t appliStatus = 0;
286   
287   static uint8_t maxLunExceed = FALSE;
288   
289     
290   if(HCD_IsDeviceConnected(pdev))
291   {   
292     switch(USBH_MSC_BOTXferParam.MSCState)
293     {
294     case USBH_MSC_BOT_INIT_STATE:
295       USBH_MSC_Init(pdev);
296       USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_RESET;  
297       break;
298       
299     case USBH_MSC_BOT_RESET:   
300       /* Issue BOT RESET request */
301       status = USBH_MSC_BOTReset(pdev, phost);
302       if(status == USBH_OK )
303       {
304         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_GET_MAX_LUN;
305       }
306       
307       if(status == USBH_NOT_SUPPORTED )
308       {
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; 
312
313         /* a Clear Feature should be issued here */
314         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
315       }  
316       break;
317       
318     case USBH_MSC_GET_MAX_LUN:
319       /* Issue GetMaxLUN request */
320       status = USBH_MSC_GETMaxLUN(pdev, phost);
321       
322       if(status == USBH_OK )
323       {
324         MSC_Machine.maxLun = *(MSC_Machine.buff) ;
325         
326         /* If device has more that one logical unit then it is not supported */
327         if((MSC_Machine.maxLun > 0) && (maxLunExceed == FALSE))
328         {
329           maxLunExceed = TRUE;
330           pphost->usr_cb->USBH_USR_DeviceNotSupported();
331           
332           break;
333         }
334         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_TEST_UNIT_READY;
335       }
336       
337       if(status == USBH_NOT_SUPPORTED )
338       {
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; 
342         
343         /* a Clear Feature should be issued here */
344         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_CTRL_ERROR_STATE;
345       }    
346       break;
347       
348     case USBH_MSC_CTRL_ERROR_STATE:
349       /* Issue Clearfeature request */
350       status = USBH_ClrFeature(pdev,
351                                phost,
352                                0x00,
353                                pphost->Control.hc_num_out);
354       if(status == USBH_OK )
355       {
356         /* If GetMaxLun Request not support, assume Single LUN configuration */
357         MSC_Machine.maxLun = 0;  
358         
359         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;     
360       }
361       break;  
362       
363     case USBH_MSC_TEST_UNIT_READY:
364       /* Issue SCSI command TestUnitReady */ 
365       mscStatus = USBH_MSC_TestUnitReady(pdev);
366       
367       if(mscStatus == USBH_MSC_OK )
368       {
369         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_READ_CAPACITY10;
370         MSCErrorCount = 0;
371         status = USBH_OK;
372       }
373       else
374       {
375         USBH_MSC_ErrorHandle(mscStatus);
376       } 
377       break;
378       
379     case USBH_MSC_READ_CAPACITY10:
380       /* Issue READ_CAPACITY10 SCSI command */
381       mscStatus = USBH_MSC_ReadCapacity10(pdev);
382       if(mscStatus == USBH_MSC_OK )
383       {
384         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_MODE_SENSE6;
385         MSCErrorCount = 0;
386         status = USBH_OK;
387       }
388       else
389       {
390         USBH_MSC_ErrorHandle(mscStatus);
391       }
392       break;
393
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 )
398       {
399         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
400         MSCErrorCount = 0;
401         status = USBH_OK;
402       }
403       else
404       {
405         USBH_MSC_ErrorHandle(mscStatus);
406       }
407       break;
408       
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 )
413       {
414         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
415         status = USBH_OK;
416       }
417       else
418       {
419         USBH_MSC_ErrorHandle(mscStatus);
420       }  
421       break;
422       
423     case USBH_MSC_BOT_USB_TRANSFERS:
424       /* Process the BOT state machine */
425       USBH_MSC_HandleBOTXfer(pdev , phost);
426       break;
427     
428     case USBH_MSC_DEFAULT_APPLI_STATE:
429       /* Process Application callback for MSC */
430       appliStatus = pphost->usr_cb->USBH_USR_MSC_Application();
431       if(appliStatus == 0)
432       {
433         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_DEFAULT_APPLI_STATE;
434       }
435       else if (appliStatus == 1) 
436       {
437         /* De-init requested from application layer */
438         status =  USBH_APPLY_DEINIT;
439       }
440       break;
441       
442     case USBH_MSC_UNRECOVERED_STATE:
443       
444       status = USBH_UNRECOVERED_ERROR;
445       
446       break;
447       
448     default:
449       break; 
450       
451     }
452   }
453    return status;
454 }
455
456
457
458 /**
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.
465   */
466 static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev,
467                               USBH_HOST *phost)
468 {
469   
470   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
471                               USB_REQ_RECIPIENT_INTERFACE;
472   
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;           
477   
478   return USBH_CtlReq(pdev, phost, 0 , 0 ); 
479 }
480
481
482 /**
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
489   */
490 static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
491 {
492   phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
493                               USB_REQ_RECIPIENT_INTERFACE;
494   
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;           
499   
500   return USBH_CtlReq(pdev, phost, MSC_Machine.buff , 1 ); 
501 }
502
503 /**
504   * @brief  USBH_MSC_ErrorHandle 
505   *         The function is for handling errors occuring during the MSC
506   *         state machine   
507   * @param  status
508   * @retval None
509   */
510
511 void USBH_MSC_ErrorHandle(uint8_t status)
512 {  
513     if(status == USBH_MSC_FAIL)
514     { 
515       MSCErrorCount++;
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;
521       }
522       else
523       {
524         /* Error trials exceeded the limit, go to unrecovered state */
525         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
526       }
527     } 
528     else if(status == USBH_MSC_PHASE_ERROR)
529     {
530       /* Phase error, Go to Unrecoovered state */
531       USBH_MSC_BOTXferParam.MSCState = USBH_MSC_UNRECOVERED_STATE;
532     }
533     else if(status == USBH_MSC_BUSY)
534     {
535       /*No change in state*/
536     }
537 }
538
539 /**
540   * @}
541   */ 
542
543 /**
544   * @}
545   */ 
546
547 /**
548   * @}
549   */
550
551 /**
552   * @}
553   */ 
554
555 /**
556   * @}
557   */
558
559 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/