EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
msdbot.c
Go to the documentation of this file.
1 /***************************************************************************/
18 #include "em_usb.h"
19 #include "msdbot.h"
20 
23 #define TIMEOUT_1SEC 1000
24 #define TIMEOUT_2SEC 2000
25 #define DEFAULT_TIMEOUT TIMEOUT_2SEC
26 
27 /* Bulk endpoint "handles". */
28 static USBH_Ep_TypeDef *epOut = NULL;
29 static USBH_Ep_TypeDef *epIn = NULL;
30 
31 /* Bulk transfer timeout scale factor. */
32 static int timeoutFactor;
33 
34 /* CSW buffer. */
35 STATIC_UBUF(csw, CSW_LEN);
36 static MSDBOT_CSW_TypeDef *pCsw = (MSDBOT_CSW_TypeDef*) csw;
37 
38 /* Function prototypes. */
39 static bool CswMeaningful(MSDBOT_CBW_TypeDef *pCbw);
40 static bool CswValid(MSDBOT_CBW_TypeDef *pCbw);
41 static void ResetRecovery(void);
42 
45 /***************************************************************************/
58 int MSDBOT_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
59 {
60  /* Check if typedef's are properly packed. */
61 
62  if ((sizeof(MSDBOT_CBW_TypeDef) != CBW_LEN) ||
63  (sizeof(MSDBOT_CSW_TypeDef) != CSW_LEN))
64  {
65  DEBUG_USB_API_PUTS("\nMSDBOT_Init(), typedef size error");
66  EFM_ASSERT(false);
67  return MSDBOT_INIT_ERROR;
68  }
69 
70  /* Keep a local copy of bulk IN/OUT endpoint handles. */
71  epOut = out;
72  epIn = in;
73 
74  /* Transfer timeouts are scaled according to device bus speed. */
75  if (epIn->parentDevice->speed == PORT_FULL_SPEED)
76  timeoutFactor = 512;
77  else
78  timeoutFactor = 64;
79 
80  return MSDBOT_STATUS_OK;
81 }
82 
83 /***************************************************************************/
98 int MSDBOT_Xfer(void* cbw, void* data)
99 {
100  uint32_t len;
101  int timeout, result, direction, retVal;
102  MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) cbw;
103 
104  /* Send CBW. */
105  result = USBH_WriteB(epOut, cbw, CBW_LEN, DEFAULT_TIMEOUT);
106 
107  if (result != CBW_LEN)
108  {
109  ResetRecovery();
110  return MSDBOT_XFER_ERROR;
111  }
112 
113  retVal = 0;
114  direction = pCbw->Direction;
115  len = pCbw->dCBWDataTransferLength;
116 
117  /* Send/receive data (optional phase). */
118  if (len)
119  {
120  timeout = DEFAULT_TIMEOUT + (len / timeoutFactor);
121 
122  if (direction)
123  result = USBH_ReadB(epIn, data, len, timeout);
124  else
125  result = USBH_WriteB(epOut, data, len, timeout);
126 
127  retVal = result;
128 
129  if (result == USB_STATUS_EP_STALLED)
130  {
131  if (direction)
132  USBH_UnStallEpB(epIn);
133  else
134  USBH_UnStallEpB(epOut);
135  }
136 
137  else if (result <= 0)
138  {
139  ResetRecovery();
140  return MSDBOT_XFER_ERROR;
141  }
142  }
143 
144  /* Retrieve CSW. */
145  result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
146 
147  if (result != CSW_LEN)
148  {
149  if (result == USB_STATUS_EP_STALLED)
150  {
151  if (direction)
152  USBH_UnStallEpB(epIn);
153  else
154  USBH_UnStallEpB(epOut);
155 
156  result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
157 
158  if (result != CSW_LEN)
159  {
160  ResetRecovery();
161  return MSDBOT_XFER_ERROR;
162  }
163  }
164  else
165  {
166  ResetRecovery();
167  return MSDBOT_XFER_ERROR;
168  }
169  }
170 
171  if (CswValid(pCbw) && CswMeaningful(pCbw))
172  {
173  if (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED)
174  {
175  return retVal;
176  }
177  return MSDBOT_CMD_FAILED;
178  }
179 
180  ResetRecovery();
181  return MSDBOT_XFER_ERROR;
182 }
183 
186 /***************************************************************************/
197 static bool CswMeaningful(MSDBOT_CBW_TypeDef *cbw)
198 {
199  if (((pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED) ||
200  (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDFAILED)) &&
201  (pCsw->dCSWDataResidue <= cbw->dCBWDataTransferLength))
202  return true;
203 
204  return false;
205 }
206 
207 /***************************************************************************/
218 static bool CswValid(MSDBOT_CBW_TypeDef *cbw)
219 {
220  if ((pCsw->dCSWSignature == CSW_SIGNATURE) &&
221  (pCsw->dCSWTag == cbw->dCBWTag))
222  return true;
223 
224  return false;
225 }
226 
227 /***************************************************************************/
231 static void ResetRecovery(void)
232 {
233  USBH_ControlMsgB(&epIn->parentDevice->ep0,
234  USB_SETUP_DIR_H2D | USB_SETUP_RECIPIENT_INTERFACE |
235  USB_SETUP_TYPE_CLASS_MASK, /* bmRequestType */
236  USB_MSD_BOTRESET, /* bRequest */
237  0, /* wValue */
238  0, /* wIndex */
239  0, /* wLength */
240  NULL, /* void* data */
241  TIMEOUT_1SEC); /* int timeout */
242 
243  USBH_UnStallEpB(epIn);
244  USBH_UnStallEpB(epOut);
245 }
246 
uint32_t dCBWTag
Definition: msdbot.h:55
uint32_t dCBWDataTransferLength
Definition: msdbot.h:56
int MSDBOT_Xfer(void *cbw, void *data)
Perform an MSD Bulk Only Transfer (BOT).
Definition: msdbot.c:98
int MSDBOT_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
MSDBOT module initialization.
Definition: msdbot.c:58
Definitions for the Bulk Only Transport protocol of USB Mass Storage devices.
uint32_t dCSWDataResidue
Definition: msdbot.h:97
Bulk Only Transport (BOT) Command Block Wrapper (CBW) typedef.
Definition: msdbot.h:52
uint8_t Direction
Definition: msdbot.h:63
Bulk Only Transport (BOT) Command Status Wrapper (CSW) typedef.
Definition: msdbot.h:93
uint32_t dCSWSignature
Definition: msdbot.h:95
uint8_t bCSWStatus
Definition: msdbot.h:98
uint32_t dCSWTag
Definition: msdbot.h:96