eeb10755b8f8625185cec05b49e700252c9568c7
[fw/stlink] / example / stm32f4 / STM32_USB_HOST_Library / Class / MSC / src / usbh_msc_bot.c
1 /**
2   ******************************************************************************
3   * @file    usbh_msc_bot.c 
4   * @author  MCD Application Team
5   * @version V2.0.0
6   * @date    22-July-2011
7   * @brief   This file includes the mass storage related functions
8   ******************************************************************************
9   * @attention
10   *
11   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
14   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
17   *
18   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
19   ******************************************************************************
20   */ 
21
22 /* Includes ------------------------------------------------------------------*/
23 #include "usbh_msc_core.h"
24 #include "usbh_msc_scsi.h"
25 #include "usbh_msc_bot.h"
26 #include "usbh_ioreq.h"
27 #include "usbh_def.h"
28 #include "usb_hcd_int.h"
29
30
31 /** @addtogroup USBH_LIB
32 * @{
33 */
34
35 /** @addtogroup USBH_CLASS
36 * @{
37 */
38
39 /** @addtogroup USBH_MSC_CLASS
40 * @{
41 */
42
43 /** @defgroup USBH_MSC_BOT 
44 * @brief    This file includes the mass storage related functions
45 * @{
46 */ 
47
48
49 /** @defgroup USBH_MSC_BOT_Private_TypesDefinitions
50 * @{
51 */ 
52 /**
53 * @}
54 */ 
55
56 /** @defgroup USBH_MSC_BOT_Private_Defines
57 * @{
58 */ 
59 /**
60 * @}
61 */ 
62
63 /** @defgroup USBH_MSC_BOT_Private_Macros
64 * @{
65 */ 
66 /**
67 * @}
68 */ 
69
70
71 /** @defgroup USBH_MSC_BOT_Private_Variables
72 * @{
73 */ 
74
75 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
76   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
77     #pragma data_alignment=4   
78   #endif
79 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ 
80 __ALIGN_BEGIN HostCBWPkt_TypeDef USBH_MSC_CBWData __ALIGN_END ;
81
82 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
83   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
84     #pragma data_alignment=4   
85   #endif
86 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
87 __ALIGN_BEGIN HostCSWPkt_TypeDef USBH_MSC_CSWData __ALIGN_END ;
88
89
90 static uint32_t BOTStallErrorCount;   /* Keeps count of STALL Error Cases*/
91
92 /**
93 * @}
94 */ 
95
96
97 /** @defgroup USBH_MSC_BOT_Private_FunctionPrototypes
98 * @{
99 */ 
100 /**
101 * @}
102 */ 
103
104
105 /** @defgroup USBH_MSC_BOT_Exported_Variables
106 * @{
107 */ 
108 USBH_BOTXfer_TypeDef USBH_MSC_BOTXferParam; 
109 /**
110 * @}
111 */ 
112
113
114 /** @defgroup USBH_MSC_BOT_Private_Functions
115 * @{
116 */ 
117
118
119 /**
120 * @brief  USBH_MSC_Init 
121 *         Initializes the mass storage parameters
122 * @param  None
123 * @retval None
124 */
125 void USBH_MSC_Init(USB_OTG_CORE_HANDLE *pdev )
126 {
127   if(HCD_IsDeviceConnected(pdev))
128   {      
129     USBH_MSC_CBWData.field.CBWSignature = USBH_MSC_BOT_CBW_SIGNATURE;
130     USBH_MSC_CBWData.field.CBWTag = USBH_MSC_BOT_CBW_TAG;
131     USBH_MSC_CBWData.field.CBWLUN = 0;  /*Only one LUN is supported*/
132     USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;  
133   }
134   
135   BOTStallErrorCount = 0;
136   MSCErrorCount = 0;
137 }
138
139 /**
140 * @brief  USBH_MSC_HandleBOTXfer 
141 *         This function manages the different states of BOT transfer and 
142 *         updates the status to upper layer.
143 * @param  None
144 * @retval None
145
146 */
147 void USBH_MSC_HandleBOTXfer (USB_OTG_CORE_HANDLE *pdev ,USBH_HOST *phost)
148 {
149   uint8_t xferDirection, index;
150   static uint32_t remainingDataLength;
151   static uint8_t *datapointer;
152   static uint8_t error_direction;
153   USBH_Status status;
154   
155   URB_STATE URB_Status = URB_IDLE;
156   
157   if(HCD_IsDeviceConnected(pdev))
158   {  
159     
160     switch (USBH_MSC_BOTXferParam.BOTState)
161     {
162     case USBH_MSC_SEND_CBW:
163       /* send CBW */    
164       USBH_BulkSendData (pdev,
165                          &USBH_MSC_CBWData.CBWArray[0], 
166                          USBH_MSC_BOT_CBW_PACKET_LENGTH , 
167                          MSC_Machine.hc_num_out);
168       
169       USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SEND_CBW;
170       USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SENT_CBW;
171       
172       break;
173       
174     case USBH_MSC_SENT_CBW:
175       URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_out);
176       
177       if(URB_Status == URB_DONE)
178       { 
179         BOTStallErrorCount = 0;
180         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SENT_CBW; 
181         
182         /* If the CBW Pkt is sent successful, then change the state */
183         xferDirection = (USBH_MSC_CBWData.field.CBWFlags & USB_REQ_DIR_MASK);
184         
185         if ( USBH_MSC_CBWData.field.CBWTransferLength != 0 )
186         {
187           remainingDataLength = USBH_MSC_CBWData.field.CBWTransferLength ;
188           datapointer = USBH_MSC_BOTXferParam.pRxTxBuff;
189           
190           /* If there is Data Transfer Stage */
191           if (xferDirection == USB_D2H)
192           {
193             /* Data Direction is IN */
194             USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAIN_STATE;
195           }
196           else
197           {
198             /* Data Direction is OUT */
199             USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAOUT_STATE;
200           } 
201         }
202         
203         else
204         {/* If there is NO Data Transfer Stage */
205           USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE;
206         }
207         
208       }   
209       else if(URB_Status == URB_NOTREADY)
210       {
211         USBH_MSC_BOTXferParam.BOTState  = USBH_MSC_BOTXferParam.BOTStateBkp;    
212       }     
213       else if(URB_Status == URB_STALL)
214       {
215         error_direction = USBH_MSC_DIR_OUT;
216         USBH_MSC_BOTXferParam.BOTState  = USBH_MSC_BOT_ERROR_OUT;
217       }
218       break;
219       
220     case USBH_MSC_BOT_DATAIN_STATE:
221       
222       URB_Status =   HCD_GetURB_State(pdev , MSC_Machine.hc_num_in);
223       /* BOT DATA IN stage */
224       if((URB_Status == URB_DONE) ||(USBH_MSC_BOTXferParam.BOTStateBkp != USBH_MSC_BOT_DATAIN_STATE))
225       {
226         BOTStallErrorCount = 0;
227         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAIN_STATE;    
228         
229         if(remainingDataLength > USBH_MSC_MPS_SIZE)
230         {
231           USBH_BulkReceiveData (pdev,
232                                 datapointer, 
233                                 USBH_MSC_MPS_SIZE , 
234                                 MSC_Machine.hc_num_in);
235           
236           remainingDataLength -= USBH_MSC_MPS_SIZE;
237           datapointer = datapointer + USBH_MSC_MPS_SIZE;
238         }
239         else if ( remainingDataLength == 0)
240         {
241           /* If value was 0, and successful transfer, then change the state */
242           USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE;
243         }
244         else
245         {       
246           USBH_BulkReceiveData (pdev,
247                                 datapointer, 
248                                 remainingDataLength , 
249                                 MSC_Machine.hc_num_in);
250           
251           remainingDataLength = 0; /* Reset this value and keep in same state */
252         }
253       }
254       else if(URB_Status == URB_STALL)
255       {
256         /* This is Data Stage STALL Condition */
257         
258         error_direction = USBH_MSC_DIR_IN;
259         USBH_MSC_BOTXferParam.BOTState  = USBH_MSC_BOT_ERROR_IN;
260         
261         /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 
262         6.7.2 Host expects to receive data from the device
263         3. On a STALL condition receiving data, then:
264         The host shall accept the data received.
265         The host shall clear the Bulk-In pipe.
266         4. The host shall attempt to receive a CSW.
267         
268         USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original 
269         state after the ClearFeature Command is issued.
270         */
271         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE;
272         
273       }     
274       break;   
275       
276       
277     case USBH_MSC_BOT_DATAOUT_STATE:
278       /* BOT DATA OUT stage */
279       URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_out);       
280       if(URB_Status == URB_DONE)
281       {
282         BOTStallErrorCount = 0;
283         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAOUT_STATE;    
284         if(remainingDataLength > USBH_MSC_MPS_SIZE)
285         {
286           USBH_BulkSendData (pdev,
287                              datapointer, 
288                              USBH_MSC_MPS_SIZE , 
289                              MSC_Machine.hc_num_out);
290           datapointer = datapointer + USBH_MSC_MPS_SIZE;
291           remainingDataLength = remainingDataLength - USBH_MSC_MPS_SIZE;
292         }
293         else if ( remainingDataLength == 0)
294         {
295           /* If value was 0, and successful transfer, then change the state */
296           USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE;
297         }
298         else
299         {
300           USBH_BulkSendData (pdev,
301                              datapointer, 
302                              remainingDataLength , 
303                              MSC_Machine.hc_num_out);
304           
305           remainingDataLength = 0; /* Reset this value and keep in same state */   
306         }      
307       }
308       
309       else if(URB_Status == URB_NOTREADY)
310       {
311         USBH_BulkSendData (pdev,
312                            (datapointer - USBH_MSC_MPS_SIZE), 
313                            USBH_MSC_MPS_SIZE , 
314                            MSC_Machine.hc_num_out);
315       }
316       
317       else if(URB_Status == URB_STALL)
318       {
319         error_direction = USBH_MSC_DIR_OUT;
320         USBH_MSC_BOTXferParam.BOTState  = USBH_MSC_BOT_ERROR_OUT;
321         
322         /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 
323         6.7.3 Ho - Host expects to send data to the device
324         3. On a STALL condition sending data, then:
325         " The host shall clear the Bulk-Out pipe.
326         4. The host shall attempt to receive a CSW.
327         
328         The Above statement will do the clear the Bulk-Out pipe.
329         The Below statement will help in Getting the CSW.  
330         
331         USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original 
332         state after the ClearFeature Command is issued.
333         */
334         
335         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE;
336         
337       }
338       break;
339       
340     case USBH_MSC_RECEIVE_CSW_STATE:
341       /* BOT CSW stage */     
342         /* NOTE: We cannot reset the BOTStallErrorCount here as it may come from 
343         the clearFeature from previous command */
344         
345         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE;
346         
347         USBH_MSC_BOTXferParam.pRxTxBuff = USBH_MSC_CSWData.CSWArray;
348         USBH_MSC_BOTXferParam.DataLength = USBH_MSC_CSW_MAX_LENGTH;
349         
350         for(index = USBH_MSC_CSW_LENGTH; index != 0; index--)
351         {
352           USBH_MSC_CSWData.CSWArray[index] = 0;
353         }
354         
355         USBH_MSC_CSWData.CSWArray[0] = 0;
356         
357         USBH_BulkReceiveData (pdev,
358                               USBH_MSC_BOTXferParam.pRxTxBuff, 
359                               USBH_MSC_CSW_MAX_LENGTH , 
360                               MSC_Machine.hc_num_in);
361         USBH_MSC_BOTXferParam.BOTState = USBH_MSC_DECODE_CSW;    
362
363       break;
364       
365     case USBH_MSC_DECODE_CSW:
366       URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_in);
367       /* Decode CSW */
368       if(URB_Status == URB_DONE)
369       {
370         BOTStallErrorCount = 0;
371         USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE;
372         
373         USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateCurrent ;
374         
375         USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_DecodeCSW(pdev , phost);
376       }
377       else if(URB_Status == URB_STALL)     
378       {
379         error_direction = USBH_MSC_DIR_IN;
380         USBH_MSC_BOTXferParam.BOTState  = USBH_MSC_BOT_ERROR_IN;
381       }
382       break;
383       
384     case USBH_MSC_BOT_ERROR_IN: 
385       status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_IN);
386       if (status == USBH_OK)
387       {
388         /* Check if the error was due in Both the directions */
389         if (error_direction == USBH_MSC_BOTH_DIR)
390         {/* If Both directions are Needed, Switch to OUT Direction */
391           USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT;
392         }
393         else
394         {
395           /* Switch Back to the Original State, In many cases this will be 
396           USBH_MSC_RECEIVE_CSW_STATE state */
397           USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp;
398         }
399       }
400       else if (status == USBH_UNRECOVERED_ERROR)
401       {
402         /* This means that there is a STALL Error limit, Do Reset Recovery */
403         USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR;
404       }
405       break;
406       
407     case USBH_MSC_BOT_ERROR_OUT: 
408       status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_OUT);
409       if ( status == USBH_OK)
410       { /* Switch Back to the Original State */
411         USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp;        
412       }
413       else if (status == USBH_UNRECOVERED_ERROR)
414       {
415         /* This means that there is a STALL Error limit, Do Reset Recovery */
416         USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR;
417       }
418       break;
419       
420     default:      
421       break;
422     }
423   }
424 }
425
426 /**
427 * @brief  USBH_MSC_BOT_Abort 
428 *         This function manages the different Error handling for STALL
429 * @param  direction : IN / OUT 
430 * @retval None
431 */
432 USBH_Status USBH_MSC_BOT_Abort(USB_OTG_CORE_HANDLE *pdev, 
433                                USBH_HOST *phost,
434                                uint8_t direction)
435 {
436   USBH_Status status;
437   
438   status = USBH_BUSY;
439   
440   switch (direction)
441   {
442   case USBH_MSC_DIR_IN :
443     /* send ClrFeture on Bulk IN endpoint */
444     status = USBH_ClrFeature(pdev,
445                              phost,
446                              MSC_Machine.MSBulkInEp,
447                              MSC_Machine.hc_num_in);
448     
449     break;
450     
451   case USBH_MSC_DIR_OUT :
452     /*send ClrFeature on Bulk OUT endpoint */
453     status = USBH_ClrFeature(pdev, 
454                              phost,
455                              MSC_Machine.MSBulkOutEp,
456                              MSC_Machine.hc_num_out);
457     break;
458     
459   default:
460     break;
461   }
462   
463   BOTStallErrorCount++; /* Check Continous Number of times, STALL has Occured */ 
464   if (BOTStallErrorCount > MAX_BULK_STALL_COUNT_LIMIT )
465   {
466     status = USBH_UNRECOVERED_ERROR;
467   }
468   
469   return status;
470 }
471
472 /**
473 * @brief  USBH_MSC_DecodeCSW
474 *         This function decodes the CSW received by the device and updates the
475 *         same to upper layer.
476 * @param  None
477 * @retval On success USBH_MSC_OK, on failure USBH_MSC_FAIL
478 * @notes
479 *     Refer to USB Mass-Storage Class : BOT (www.usb.org)
480 *    6.3.1 Valid CSW Conditions :
481 *     The host shall consider the CSW valid when:
482 *     1. dCSWSignature is equal to 53425355h
483 *     2. the CSW is 13 (Dh) bytes in length,
484 *     3. dCSWTag matches the dCBWTag from the corresponding CBW.
485 */
486
487 uint8_t USBH_MSC_DecodeCSW(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
488 {
489   uint8_t status;
490   uint32_t dataXferCount = 0;
491   status = USBH_MSC_FAIL;
492   
493   if(HCD_IsDeviceConnected(pdev))
494   {
495     /*Checking if the transfer length is diffrent than 13*/
496     dataXferCount = HCD_GetXferCnt(pdev, MSC_Machine.hc_num_in); 
497     
498     if(dataXferCount != USBH_MSC_CSW_LENGTH)
499     {
500       /*(4) Hi > Dn (Host expects to receive data from the device,
501       Device intends to transfer no data)
502       (5) Hi > Di (Host expects to receive data from the device,
503       Device intends to send data to the host)
504       (9) Ho > Dn (Host expects to send data to the device,
505       Device intends to transfer no data)
506       (11) Ho > Do  (Host expects to send data to the device,
507       Device intends to receive data from the host)*/
508       
509       
510       status = USBH_MSC_PHASE_ERROR;
511     }
512     else
513     { /* CSW length is Correct */
514       
515       /* Check validity of the CSW Signature and CSWStatus */
516       if(USBH_MSC_CSWData.field.CSWSignature == USBH_MSC_BOT_CSW_SIGNATURE)
517       {/* Check Condition 1. dCSWSignature is equal to 53425355h */
518         
519         if(USBH_MSC_CSWData.field.CSWTag == USBH_MSC_CBWData.field.CBWTag)
520         {
521           /* Check Condition 3. dCSWTag matches the dCBWTag from the 
522           corresponding CBW */
523           
524           if(USBH_MSC_CSWData.field.CSWStatus == USBH_MSC_OK) 
525           {
526             /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 
527             
528             Hn Host expects no data transfers
529             Hi Host expects to receive data from the device
530             Ho Host expects to send data to the device
531             
532             Dn Device intends to transfer no data
533             Di Device intends to send data to the host
534             Do Device intends to receive data from the host
535             
536             Section 6.7 
537             (1) Hn = Dn (Host expects no data transfers,
538             Device intends to transfer no data)
539             (6) Hi = Di (Host expects to receive data from the device,
540             Device intends to send data to the host)
541             (12) Ho = Do (Host expects to send data to the device, 
542             Device intends to receive data from the host)
543             
544             */
545             
546             status = USBH_MSC_OK;
547           }
548           else if(USBH_MSC_CSWData.field.CSWStatus == USBH_MSC_FAIL)
549           {
550             status = USBH_MSC_FAIL;
551           }
552           
553           else if(USBH_MSC_CSWData.field.CSWStatus == USBH_MSC_PHASE_ERROR)
554           { 
555             /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 
556             Section 6.7 
557             (2) Hn < Di ( Host expects no data transfers, 
558             Device intends to send data to the host)
559             (3) Hn < Do ( Host expects no data transfers, 
560             Device intends to receive data from the host)
561             (7) Hi < Di ( Host expects to receive data from the device, 
562             Device intends to send data to the host)
563             (8) Hi <> Do ( Host expects to receive data from the device, 
564             Device intends to receive data from the host)
565             (10) Ho <> Di (Host expects to send data to the device,
566             Di Device intends to send data to the host)
567             (13) Ho < Do (Host expects to send data to the device, 
568             Device intends to receive data from the host)
569             */
570             
571             status = USBH_MSC_PHASE_ERROR;
572           }
573         } /* CSW Tag Matching is Checked  */
574       } /* CSW Signature Correct Checking */
575       else
576       {
577         /* If the CSW Signature is not valid, We sall return the Phase Error to
578         Upper Layers for Reset Recovery */
579         
580         status = USBH_MSC_PHASE_ERROR;
581       }
582     } /* CSW Length Check*/
583   }
584   
585   USBH_MSC_BOTXferParam.BOTXferStatus  = status;
586   return status;
587 }
588
589
590 /**
591 * @}
592 */ 
593
594 /**
595 * @}
596 */ 
597
598 /**
599 * @}
600 */
601
602 /**
603 * @}
604 */ 
605
606 /**
607 * @}
608 */
609
610 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
611
612
613