msdbot.c

Go to the documentation of this file.
00001 /***************************************************************************/
00018 #include "em_usb.h"
00019 #include "msdbot.h"
00020 
00023 #define TIMEOUT_1SEC       1000
00024 #define TIMEOUT_2SEC       2000
00025 #define DEFAULT_TIMEOUT    TIMEOUT_2SEC
00026 
00027 /* Bulk endpoint "handles". */
00028 static USBH_Ep_TypeDef *epOut = NULL;
00029 static USBH_Ep_TypeDef *epIn  = NULL;
00030 
00031 /* Bulk transfer timeout scale factor. */
00032 static int timeoutFactor;
00033 
00034 /* CSW buffer. */
00035 STATIC_UBUF(csw, CSW_LEN);
00036 static MSDBOT_CSW_TypeDef *pCsw = (MSDBOT_CSW_TypeDef*) csw;
00037 
00038 /* Function prototypes. */
00039 static bool CswMeaningful(MSDBOT_CBW_TypeDef *pCbw);
00040 static bool CswValid(MSDBOT_CBW_TypeDef *pCbw);
00041 static void ResetRecovery(void);
00042 
00045 /***************************************************************************/
00058 int MSDBOT_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
00059 {
00060   /* Check if typedef's are properly packed. */
00061 
00062   if ((sizeof(MSDBOT_CBW_TypeDef) != CBW_LEN) ||
00063       (sizeof(MSDBOT_CSW_TypeDef) != CSW_LEN))
00064   {
00065     DEBUG_USB_API_PUTS("\nMSDBOT_Init(), typedef size error");
00066     EFM_ASSERT(false);
00067     return MSDBOT_INIT_ERROR;
00068   }
00069 
00070   /* Keep a local copy of bulk IN/OUT endpoint handles. */
00071   epOut = out;
00072   epIn  = in;
00073 
00074   /* Transfer timeouts are scaled according to device bus speed. */
00075   if (epIn->parentDevice->speed == PORT_FULL_SPEED)
00076     timeoutFactor = 512;
00077   else
00078     timeoutFactor = 64;
00079 
00080   return MSDBOT_STATUS_OK;
00081 }
00082 
00083 /***************************************************************************/
00098 int MSDBOT_Xfer(void* cbw, void* data)
00099 {
00100   uint32_t           len;
00101   int                timeout, result, direction, retVal;
00102   MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) cbw;
00103 
00104   /* Send CBW. */
00105   result = USBH_WriteB(epOut, cbw, CBW_LEN, DEFAULT_TIMEOUT);
00106 
00107   if (result != CBW_LEN)
00108   {
00109     ResetRecovery();
00110     return MSDBOT_XFER_ERROR;
00111   }
00112 
00113   retVal    = 0;
00114   direction = pCbw->Direction;
00115   len       = pCbw->dCBWDataTransferLength;
00116 
00117   /* Send/receive data (optional phase). */
00118   if (len)
00119   {
00120     timeout = DEFAULT_TIMEOUT + (len / timeoutFactor);
00121 
00122     if (direction)
00123       result = USBH_ReadB(epIn, data, len, timeout);
00124     else
00125       result = USBH_WriteB(epOut, data, len, timeout);
00126 
00127     retVal = result;
00128 
00129     if (result == USB_STATUS_EP_STALLED)
00130     {
00131       if (direction)
00132         USBH_UnStallEpB(epIn);
00133       else
00134         USBH_UnStallEpB(epOut);
00135     }
00136 
00137     else if (result <= 0)
00138     {
00139       ResetRecovery();
00140       return MSDBOT_XFER_ERROR;
00141     }
00142   }
00143 
00144   /* Retrieve CSW. */
00145   result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
00146 
00147   if (result != CSW_LEN)
00148   {
00149     if (result == USB_STATUS_EP_STALLED)
00150     {
00151       if (direction)
00152         USBH_UnStallEpB(epIn);
00153       else
00154         USBH_UnStallEpB(epOut);
00155 
00156       result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT);
00157 
00158       if (result != CSW_LEN)
00159       {
00160         ResetRecovery();
00161         return MSDBOT_XFER_ERROR;
00162       }
00163     }
00164     else
00165     {
00166       ResetRecovery();
00167       return MSDBOT_XFER_ERROR;
00168     }
00169   }
00170 
00171   if (CswValid(pCbw) && CswMeaningful(pCbw))
00172   {
00173     if (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED)
00174     {
00175       return retVal;
00176     }
00177     return MSDBOT_CMD_FAILED;
00178   }
00179 
00180   ResetRecovery();
00181   return MSDBOT_XFER_ERROR;
00182 }
00183 
00186 /***************************************************************************/
00197 static bool CswMeaningful(MSDBOT_CBW_TypeDef *cbw)
00198 {
00199   if (((pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED) ||
00200        (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDFAILED)) &&
00201       (pCsw->dCSWDataResidue <= cbw->dCBWDataTransferLength))
00202     return true;
00203 
00204   return false;
00205 }
00206 
00207 /***************************************************************************/
00218 static bool CswValid(MSDBOT_CBW_TypeDef *cbw)
00219 {
00220   if ((pCsw->dCSWSignature == CSW_SIGNATURE) &&
00221       (pCsw->dCSWTag == cbw->dCBWTag))
00222     return true;
00223 
00224   return false;
00225 }
00226 
00227 /***************************************************************************/
00231 static void ResetRecovery(void)
00232 {
00233   USBH_ControlMsgB(&epIn->parentDevice->ep0,
00234                    USB_SETUP_DIR_H2D | USB_SETUP_RECIPIENT_INTERFACE |
00235                    USB_SETUP_TYPE_CLASS_MASK,             /* bmRequestType */
00236                    USB_MSD_BOTRESET,                      /* bRequest      */
00237                    0,                                     /* wValue        */
00238                    0,                                     /* wIndex        */
00239                    0,                                     /* wLength       */
00240                    NULL,                                  /* void* data    */
00241                    TIMEOUT_1SEC);                         /* int timeout   */
00242 
00243   USBH_UnStallEpB(epIn);
00244   USBH_UnStallEpB(epOut);
00245 }
00246