msdbot.c

Go to the documentation of this file.
00001 /***************************************************************************/
00036 #include "em_usb.h"
00037 #include "msdbot.h"
00038 
00041 #define TIMEOUT_1SEC       1000
00042 #define TIMEOUT_2SEC       2000
00043 #define DEFAULT_TIMEOUT    TIMEOUT_2SEC
00044 
00045 /* Bulk endpoint "handles". */
00046 static USBH_Ep_TypeDef *epOut = NULL;
00047 static USBH_Ep_TypeDef *epIn  = NULL;
00048 
00049 /* Bulk transfer timeout scale factor. */
00050 static int timeoutFactor;
00051 
00052 /* CSW buffer. */
00053 STATIC_UBUF(csw, CSW_LEN);
00054 static MSDBOT_CSW_TypeDef *pCsw = (MSDBOT_CSW_TypeDef*) csw;
00055 
00056 /* Function prototypes. */
00057 static bool CswMeaningful(MSDBOT_CBW_TypeDef *pCbw);
00058 static bool CswValid(MSDBOT_CBW_TypeDef *pCbw);
00059 static void ResetRecovery(void);
00060 
00063 /***************************************************************************/
00076 int MSDBOT_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
00077 {
00078   /* Check if typedef's are properly packed. */
00079 
00080   if ((sizeof(MSDBOT_CBW_TypeDef) != CBW_LEN) ||
00081       (sizeof(MSDBOT_CSW_TypeDef) != CSW_LEN))
00082   {
00083     DEBUG_USB_API_PUTS("\nMSDBOT_Init(), typedef size error");
00084     EFM_ASSERT(false);
00085     return MSDBOT_INIT_ERROR;
00086   }
00087 
00088   /* Keep a local copy of bulk IN/OUT endpoint handles. */
00089   epOut = out;
00090   epIn  = in;
00091 
00092   /* Transfer timeouts are scaled according to device bus speed. */
00093   if (epIn->parentDevice->speed == PORT_FULL_SPEED)
00094     timeoutFactor = 512;
00095   else
00096     timeoutFactor = 64;
00097 
00098   return MSDBOT_STATUS_OK;
00099 }
00100 
00101 /***************************************************************************/
00116 int MSDBOT_Xfer(void* cbw, void* data)
00117 {
00118   uint32_t           len;
00119   int                timeout, result, direction, retVal;
00120   MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) cbw;
00121 
00122   /* Send CBW. */
00123   result = USBH_WriteB(epOut, cbw, CBW_LEN, DEFAULT_TIMEOUT);
00124 
00125   if (result != CBW_LEN)
00126   {
00127     ResetRecovery();
00128     return MSDBOT_XFER_ERROR;
00129   }
00130 
00131   retVal    = 0;
00132   direction = pCbw->Direction;
00133   len       = pCbw->dCBWDataTransferLength;
00134 
00135   /* Send/receive data (optional phase). */
00136   if (len)
00137   {
00138     timeout = DEFAULT_TIMEOUT + (len / timeoutFactor);
00139 
00140     if (direction)
00141       result = USBH_ReadB(epIn, data, len, timeout);
00142     else
00143       result = USBH_WriteB(epOut, data, len, timeout);
00144 
00145     retVal = result;
00146 
00147     if (result == USB_STATUS_EP_STALLED)
00148     {
00149       if (direction)
00150         USBH_UnStallEpB(epIn);
00151       else
00152         USBH_UnStallEpB(epOut);
00153     }
00154 
00155     else if (result <= 0)
00156     {
00157       ResetRecovery();
00158       return MSDBOT_XFER_ERROR;
00159     }
00160   }
00161 
00162   /* Retrieve CSW. */
00163   result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
00164 
00165   if (result != CSW_LEN)
00166   {
00167     if (result == USB_STATUS_EP_STALLED)
00168     {
00169       if (direction)
00170         USBH_UnStallEpB(epIn);
00171       else
00172         USBH_UnStallEpB(epOut);
00173 
00174       result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
00175 
00176       if (result != CSW_LEN)
00177       {
00178         ResetRecovery();
00179         return MSDBOT_XFER_ERROR;
00180       }
00181     }
00182     else
00183     {
00184       ResetRecovery();
00185       return MSDBOT_XFER_ERROR;
00186     }
00187   }
00188 
00189   if (CswValid(pCbw) && CswMeaningful(pCbw))
00190   {
00191     if (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED)
00192     {
00193       return retVal;
00194     }
00195     return MSDBOT_CMD_FAILED;
00196   }
00197 
00198   ResetRecovery();
00199   return MSDBOT_XFER_ERROR;
00200 }
00201 
00204 /***************************************************************************/
00215 static bool CswMeaningful(MSDBOT_CBW_TypeDef *cbw)
00216 {
00217   if (((pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED) ||
00218        (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDFAILED)) &&
00219       (pCsw->dCSWDataResidue <= cbw->dCBWDataTransferLength))
00220     return true;
00221 
00222   return false;
00223 }
00224 
00225 /***************************************************************************/
00236 static bool CswValid(MSDBOT_CBW_TypeDef *cbw)
00237 {
00238   if ((pCsw->dCSWSignature == CSW_SIGNATURE) &&
00239       (pCsw->dCSWTag == cbw->dCBWTag))
00240     return true;
00241 
00242   return false;
00243 }
00244 
00245 /***************************************************************************/
00249 static void ResetRecovery(void)
00250 {
00251   USBH_ControlMsgB(&epIn->parentDevice->ep0,
00252                    USB_SETUP_DIR_H2D | USB_SETUP_RECIPIENT_INTERFACE |
00253                    USB_SETUP_TYPE_CLASS_MASK,             /* bmRequestType */
00254                    USB_MSD_BOTRESET,                      /* bRequest      */
00255                    0,                                     /* wValue        */
00256                    0,                                     /* wIndex        */
00257                    0,                                     /* wLength       */
00258                    NULL,                                  /* void* data    */
00259                    TIMEOUT_1SEC);                         /* int timeout   */
00260 
00261   USBH_UnStallEpB(epIn);
00262   USBH_UnStallEpB(epOut);
00263 }
00264