00001
00017 #include "em_usb.h"
00018 #include "em_cmu.h"
00019 #include "em_gpio.h"
00020 #include "msdbot.h"
00021 #include "msdscsi.h"
00022 #include "msdd.h"
00023 #include "msddmedia.h"
00024
00027
00028
00029 #define BULK_OUT 0x01
00030 #define BULK_IN 0x81
00031 #define DIR_DATA_OUT 0
00032 #define DIR_DATA_IN 1
00033 #define MAX_BURST 32768U
00034
00035
00038 typedef enum
00039 {
00040 MSDD_IDLE = 0,
00041 MSDD_WAITFOR_CBW = 1,
00042 MSDD_WAITFOR_RECOVERY = 2,
00043 MSDD_SEND_CSW = 3,
00044 MSDD_WAIT_FOR_INUNSTALLED = 4,
00045 MSDD_STALL_IN = 5,
00046 MSDD_ACCESS_INDIRECT = 6,
00047 MSDD_WRITE_INDIRECT = 7,
00048 MSDD_DO_CMD_TASK = 8,
00049 } msdState_TypeDef;
00050
00051
00052
00053 static int CbwCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
00054 __STATIC_INLINE bool CswMeaningful(void);
00055 __STATIC_INLINE bool CswValid(void);
00056 __STATIC_INLINE void EnableNextCbw(void);
00057 static void ProcessScsiCdb(void);
00058 __STATIC_INLINE void SendCsw(void);
00059 static int UsbSetupCmd(const USB_Setup_TypeDef *setup);
00060 static void UsbStateChangeEvent(USBD_State_TypeDef oldState, USBD_State_TypeDef newState);
00061 static void UsbXferBotData(uint8_t *data, uint32_t len, USB_XferCompleteCb_TypeDef cb);
00062 static void XferBotData(uint32_t length);
00063 static int XferBotDataCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
00064 static int XferBotDataIndirectCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
00065
00066
00067
00068 #include "descriptors.h"
00069
00070
00071
00072
00073 STATIC_UBUF(cbw, USB_MAX_EP_SIZE);
00074 static MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) &cbw;
00075
00076 EFM32_ALIGN(4)
00077
00078 static MSDBOT_CSW_TypeDef csw __attribute__ ((aligned(4)));
00079 static MSDBOT_CSW_TypeDef *pCsw = &csw;
00080
00081 STATIC_UBUF(mediaBuffer, MEDIA_BUFSIZ);
00082
00083 static MSDD_CmdStatus_TypeDef CmdStatus;
00084 static MSDD_CmdStatus_TypeDef *pCmdStatus = &CmdStatus;
00085 static msdState_TypeDef savedState;
00086 static int ledPort;
00087 static unsigned int ledPin;
00088
00089
00092 EFM32_ALIGN(4)
00093 static const MSDSCSI_InquiryData_TypeDef InquiryData __attribute__ ((aligned(4))) =
00094 {
00095 { .PeripheralDeviceType = 0, .PeripheralQualifier = 0 },
00096 { .Reserved1 = 0, .Removable = 1 },
00097
00098 .Version = 5,
00099
00100 { .ResponseDataFormat = 2,
00101 .HiSup = 0, .NormACA = 0, .Obsolete1 = 0 },
00102
00103 .AdditionalLength = 31,
00104
00105 { .Protect = 0, .Reserved2 = 0, .ThirdPartyCode = 0,
00106 .Tpgs = 0, .Acc = 0, .Sccs = 0 },
00107
00108 { .Addr16 = 0, .Obsolete2 = 0, .MChngr = 0, .MultiP = 0,
00109 .Vs1 = 0, .EncServ = 0, .BQue = 0 },
00110
00111 { .Vs2 = 0, .CmdQue = 0, .Obsolete3 = 0, .Linked = 0,
00112 .Sync = 0, .Wbus16 = 0, .Obsolete4 = 0 },
00113
00114 .T10VendorId = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
00115 .ProductId = { 'E', 'F', 'M', '3', '2', ' ', 'M', 'S', 'D', ' ', 'D', 'e', 'v', 'i', 'c', 'e' },
00116 .ProductRevisionLevel ={ '1', '.', '0', '0' }
00117 };
00118
00119
00124 EFM32_ALIGN(4)
00125 static const MSDSCSI_RequestSenseData_TypeDef NoSenseData __attribute__ ((aligned(4))) =
00126 {
00127 { .ResponseCode = 0x70, .Valid = 0 },
00128 .Obsolete = 0,
00129 { .SenseKey = 0, .Reserved =0, .Ili = 0, .Eom = 0, .FileMark = 0 },
00130 .Information = 0,
00131 .AdditionalLength = 10,
00132 .CmdSpecificInfo = 0,
00133 .Asc = 0,
00134 .Ascq = 0,
00135 .Fruc = 0,
00136 { .SenseKeySpecific1 = 0, .Sksv = 0 },
00137 .SenseKeySpecific2 = 0,
00138 .SenseKeySpecific3 = 0
00139 };
00140
00141
00147 EFM32_ALIGN(4)
00148 static const MSDSCSI_RequestSenseData_TypeDef IllegalSenseData __attribute__ ((aligned(4))) =
00149 {
00150 { .ResponseCode = 0x70, .Valid = 0 },
00151 .Obsolete = 0,
00152 { .SenseKey = 5,
00153 .Reserved = 0, .Ili = 0, .Eom = 0, .FileMark = 0 },
00154 .Information = 0,
00155 .AdditionalLength = 10,
00156 .CmdSpecificInfo = 0,
00157 .Asc = 0x24,
00158 .Ascq = 0,
00159 .Fruc = 0,
00160 { .SenseKeySpecific1 = 0, .Sksv = 0 },
00161 .SenseKeySpecific2 = 0,
00162 .SenseKeySpecific3 = 0
00163 };
00164
00165 static volatile msdState_TypeDef msdState;
00166 static MSDSCSI_RequestSenseData_TypeDef *pSenseData;
00170
00180 void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
00181 {
00182 if ( ( sizeof(MSDSCSI_Read10_TypeDef) != SCSI_READ10_LEN ) ||
00183 ( sizeof(MSDSCSI_Write10_TypeDef) != SCSI_WRITE10_LEN ) ||
00184 ( sizeof(MSDSCSI_RequestSense_TypeDef) != SCSI_REQUESTSENSE_LEN ) ||
00185 ( sizeof(InquiryData) != SCSI_INQUIRYDATA_LEN ) ||
00186 ( sizeof(NoSenseData) != SCSI_REQUESTSENSEDATA_LEN ) ||
00187 ( sizeof(IllegalSenseData) != SCSI_REQUESTSENSEDATA_LEN ) ||
00188 ( sizeof(MSDSCSI_ReadCapacity_TypeDef) != SCSI_READCAPACITY_LEN ) ||
00189 ( sizeof(MSDSCSI_ReadCapacityData_TypeDef) != SCSI_READCAPACITYDATA_LEN ) )
00190 {
00191 DEBUG_USB_API_PUTS("\nMSDD_Init(), typedef size error");
00192 EFM_ASSERT(false);
00193 return;
00194 }
00195
00196 if ( ( activityLedPort >= gpioPortA ) && ( activityLedPort <= gpioPortF ) )
00197 ledPort = activityLedPort;
00198 else
00199 ledPort = -1;
00200
00201 ledPin = activityLedPin;
00202 msdState = MSDD_IDLE;
00203 pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
00204 USBD_Init(&initstruct);
00205
00206 if ( ledPort != -1 )
00207 {
00208 CMU_ClockEnable(cmuClock_GPIO, true);
00209 GPIO_PinModeSet((GPIO_Port_TypeDef)ledPort, ledPin, gpioModePushPull, 0);
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219 }
00220
00221
00230 bool MSDD_Handler(void)
00231 {
00232 static uint32_t len;
00233
00234 switch (msdState)
00235 {
00236 case MSDD_ACCESS_INDIRECT:
00237 if (pCmdStatus->xferLen)
00238 {
00239 len = EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst);
00240
00241 msdState = MSDD_IDLE;
00242 if (pCmdStatus->direction)
00243 {
00244 MSDDMEDIA_Read(pCmdStatus, mediaBuffer, len / 512);
00245 }
00246 UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback);
00247 }
00248 else
00249 {
00250
00251 msdState = savedState;
00252
00253 if (msdState == MSDD_SEND_CSW)
00254 {
00255 SendCsw();
00256 EnableNextCbw();
00257 msdState = MSDD_WAITFOR_CBW;
00258 }
00259
00260 else if (msdState == MSDD_STALL_IN)
00261 {
00262 USBD_StallEp(BULK_IN);
00263 msdState = MSDD_WAIT_FOR_INUNSTALLED;
00264 }
00265 }
00266 break;
00267
00268 case MSDD_WRITE_INDIRECT:
00269 MSDDMEDIA_Write(pCmdStatus, mediaBuffer, len / 512);
00270 pCmdStatus->lba += len / 512;
00271 msdState = MSDD_ACCESS_INDIRECT;
00272 break;
00273
00274 case MSDD_DO_CMD_TASK:
00275 if (pCbw->CBWCB[ 0 ] == SCSI_STARTSTOP_UNIT)
00276 {
00277 MSDDMEDIA_Flush();
00278 }
00279
00280 SendCsw();
00281 EnableNextCbw();
00282 msdState = MSDD_WAITFOR_CBW;
00283 break;
00284
00285 default:
00286 break;
00287 }
00288 return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE);
00289 }
00290
00293
00310 static int CbwCallback(USB_Status_TypeDef status,
00311 uint32_t xferred, uint32_t remaining)
00312 {
00313 (void) remaining;
00314
00315 if ((msdState == MSDD_WAITFOR_CBW) &&
00316 (status == USB_STATUS_OK) &&
00317 (xferred == CBW_LEN) &&
00318 (CswValid()) &&
00319 (CswMeaningful()))
00320 {
00321 if ( ledPort != -1 )
00322 GPIO_PinOutToggle((GPIO_Port_TypeDef)ledPort, ledPin);
00323
00324
00325 ProcessScsiCdb();
00326
00327 if (pCmdStatus->valid)
00328 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDPASSED;
00329 else
00330 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
00331
00332 pCsw->dCSWSignature = CSW_SIGNATURE;
00333 pCsw->dCSWTag = pCbw->dCBWTag;
00334 pCsw->dCSWDataResidue = pCbw->dCBWDataTransferLength;
00335
00336
00337
00338 if ((pCbw->dCBWDataTransferLength != 0) &&
00339 (pCbw->Direction != pCmdStatus->direction))
00340 {
00341
00342 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
00343
00344 if (pCbw->Direction)
00345 {
00346
00347 USBD_StallEp(BULK_IN);
00348 msdState = MSDD_WAIT_FOR_INUNSTALLED;
00349 }
00350 else
00351 {
00352
00353 USBD_StallEp(BULK_OUT);
00354 SendCsw();
00355 msdState = MSDD_IDLE;
00356 }
00357 }
00358
00359 else if (pCbw->Direction || (pCbw->dCBWDataTransferLength == 0))
00360 {
00361
00362
00363
00364 if (pCbw->dCBWDataTransferLength == 0)
00365 {
00366
00367 if (pCmdStatus->xferLen)
00368 {
00369
00370 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
00371 }
00372
00373 if ((pCmdStatus->xferLen == 0) &&
00374 (pCmdStatus->xferType == XFER_INDIRECT))
00375 {
00376
00377
00378 msdState = MSDD_DO_CMD_TASK;
00379 }
00380 else
00381 {
00382 SendCsw();
00383 EnableNextCbw();
00384 msdState = MSDD_WAITFOR_CBW;
00385 }
00386 }
00387 else if (pCbw->dCBWDataTransferLength == pCmdStatus->xferLen)
00388 {
00389
00390
00391 msdState = MSDD_SEND_CSW;
00392 XferBotData(pCmdStatus->xferLen);
00393 }
00394 else if (pCbw->dCBWDataTransferLength > pCmdStatus->xferLen)
00395 {
00396
00397
00398 if (pCmdStatus->xferLen > 0)
00399 {
00400
00401
00402 msdState = MSDD_STALL_IN;
00403 XferBotData(pCmdStatus->xferLen);
00404 }
00405 else
00406 {
00407
00408 USBD_StallEp(BULK_IN);
00409 msdState = MSDD_WAIT_FOR_INUNSTALLED;
00410 }
00411 }
00412 else
00413 {
00414
00415 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
00416
00417 msdState = MSDD_SEND_CSW;
00418 XferBotData(pCbw->dCBWDataTransferLength);
00419 }
00420 }
00421
00422 else
00423 {
00424
00425
00426
00427 if (pCbw->dCBWDataTransferLength == pCmdStatus->xferLen)
00428 {
00429
00430
00431
00432 msdState = MSDD_SEND_CSW;
00433 XferBotData(pCmdStatus->xferLen);
00434 }
00435 else if (pCbw->dCBWDataTransferLength > pCmdStatus->xferLen)
00436 {
00437
00438 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
00439 USBD_StallEp(BULK_OUT);
00440 SendCsw();
00441 msdState = MSDD_IDLE;
00442 }
00443 else
00444 {
00445
00446 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
00447 USBD_StallEp(BULK_OUT);
00448 SendCsw();
00449 msdState = MSDD_IDLE;
00450 }
00451 }
00452 return USB_STATUS_OK;
00453 }
00454
00455 if ((status == USB_STATUS_OK) &&
00456 (USBD_GetUsbState() == USBD_STATE_CONFIGURED))
00457 {
00458
00459 USBD_StallEp(BULK_OUT);
00460 USBD_StallEp(BULK_IN);
00461 msdState = MSDD_WAITFOR_RECOVERY;
00462 }
00463
00464 return USB_STATUS_OK;
00465 }
00466
00467
00472 __STATIC_INLINE bool CswMeaningful(void)
00473 {
00474 if ( ( pCbw->Reserved1 == 0 ) &&
00475 ( pCbw->Obsolete == 0 ) &&
00476 ( pCbw->Reserved2 == 0 ) &&
00477 ( pCbw->Lun == 0 ) &&
00478 ( pCbw->Reserved3 == 0 ) )
00479 {
00480 return true;
00481 }
00482
00483 return false;
00484 }
00485
00486
00491 __STATIC_INLINE bool CswValid(void)
00492 {
00493 return pCbw->dCBWSignature == CBW_SIGNATURE ? true : false;
00494 }
00495
00496
00500 __STATIC_INLINE void EnableNextCbw(void)
00501 {
00502 USBD_Read(BULK_OUT, (void*) &cbw, USB_MAX_EP_SIZE, CbwCallback);
00503 }
00504
00505
00510 static void ProcessScsiCdb(void)
00511 {
00512 MSDSCSI_Inquiry_TypeDef *cbI;
00513 MSDSCSI_RequestSense_TypeDef *cbRS;
00514 MSDSCSI_ReadCapacity_TypeDef *cbRC;
00515 MSDSCSI_Read10_TypeDef *cbR10;
00516 MSDSCSI_Write10_TypeDef *cbW10;
00517
00518 EFM32_ALIGN(4)
00519 static MSDSCSI_ReadCapacityData_TypeDef ReadCapData __attribute__ ((aligned(4)));
00520
00521 pCmdStatus->valid = false;
00522 pCmdStatus->xferType = XFER_MEMORYMAPPED;
00523 pCmdStatus->maxBurst = MAX_BURST;
00524
00525 switch (pCbw->CBWCB[ 0 ])
00526 {
00527 case SCSI_INQUIRY:
00528 cbI = (MSDSCSI_Inquiry_TypeDef*) &pCbw->CBWCB;
00529
00530 if ((cbI->Evpd == 0) && (cbI->PageCode == 0))
00531 {
00532
00533 pCmdStatus->valid = true;
00534 pCmdStatus->direction = DIR_DATA_IN;
00535 pCmdStatus->pData = (uint8_t*) &InquiryData;
00536 pCmdStatus->xferLen = EFM32_MIN(SCSI_INQUIRYDATA_LEN,
00537 __REV16(cbI->AllocationLength));
00538 }
00539 break;
00540
00541 case SCSI_REQUESTSENSE:
00542 cbRS = (MSDSCSI_RequestSense_TypeDef*) &pCbw->CBWCB;
00543
00544 if ((cbRS->Desc == 0) && (cbRS->Reserved1 == 0) &&
00545 (cbRS->Reserved2 == 0) && (cbRS->Reserved3 == 0))
00546 {
00547 pCmdStatus->valid = true;
00548 pCmdStatus->direction = DIR_DATA_IN;
00549 pCmdStatus->pData = (uint8_t*) pSenseData;
00550 pCmdStatus->xferLen = EFM32_MIN(SCSI_REQUESTSENSEDATA_LEN,
00551 cbRS->AllocationLength);
00552 pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
00553 }
00554 break;
00555
00556 case SCSI_READCAPACITY:
00557 cbRC = (MSDSCSI_ReadCapacity_TypeDef*) &pCbw->CBWCB;
00558
00559 if ((cbRC->Pmi == 0) && (cbRC->Lba == 0))
00560 {
00561 ReadCapData.LogicalBlockAddress = __REV(MSDDMEDIA_GetSectorCount() - 1);
00562 ReadCapData.LogicalBlockLength = __REV(512);
00563
00564 pCmdStatus->valid = true;
00565 pCmdStatus->direction = DIR_DATA_IN;
00566 pCmdStatus->pData = (uint8_t*) &ReadCapData;
00567 pCmdStatus->xferLen = SCSI_READCAPACITYDATA_LEN;
00568 }
00569 break;
00570
00571 case SCSI_READ10:
00572 cbR10 = (MSDSCSI_Read10_TypeDef*) &pCbw->CBWCB;
00573
00574 pCmdStatus->direction = DIR_DATA_IN;
00575 pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
00576 __REV(cbR10->Lba),
00577 __REV16(cbR10->TransferLength));
00578 break;
00579
00580 case SCSI_WRITE10:
00581 cbW10 = (MSDSCSI_Write10_TypeDef*) &pCbw->CBWCB;
00582
00583 pCmdStatus->direction = DIR_DATA_OUT;
00584 pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
00585 __REV(cbW10->Lba),
00586 __REV16(cbW10->TransferLength));
00587 break;
00588
00589 case SCSI_TESTUNIT_READY:
00590 pCmdStatus->valid = true;
00591 pCmdStatus->direction = pCbw->Direction;
00592 pCmdStatus->xferLen = 0;
00593 break;
00594
00595 case SCSI_STARTSTOP_UNIT:
00596 pCmdStatus->valid = true;
00597 pCmdStatus->direction = pCbw->Direction;
00598 pCmdStatus->xferLen = 0;
00599 pCmdStatus->xferType = XFER_INDIRECT;
00600 break;
00601 }
00602
00603 if (!pCmdStatus->valid)
00604 {
00605 pCmdStatus->xferLen = 0;
00606 pCmdStatus->direction = pCbw->Direction;
00607 pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &IllegalSenseData;
00608 }
00609 }
00610
00611
00615 __STATIC_INLINE void SendCsw(void)
00616 {
00617 if ( ledPort != -1 )
00618 GPIO_PinOutToggle((GPIO_Port_TypeDef)ledPort, ledPin);
00619
00620 USBD_Write(BULK_IN, (void*) &csw, CSW_LEN, NULL);
00621 }
00622
00623
00635 static int UsbSetupCmd(const USB_Setup_TypeDef *setup)
00636 {
00637 int retVal;
00638 static uint32_t tmp;
00639
00640 retVal = USB_STATUS_REQ_UNHANDLED;
00641
00642
00643
00644 if ( ( setup->Type == USB_SETUP_TYPE_CLASS ) &&
00645 ( setup->Direction == USB_SETUP_DIR_OUT ) &&
00646 ( setup->Recipient == USB_SETUP_RECIPIENT_INTERFACE ) &&
00647 ( setup->bRequest == USB_MSD_BOTRESET ) &&
00648 ( setup->wValue == 0 ) &&
00649 ( setup->wIndex == 0 ) &&
00650 ( setup->wLength == 0 ) )
00651 {
00652 if (msdState == MSDD_WAITFOR_RECOVERY)
00653 {
00654 msdState = MSDD_IDLE;
00655 }
00656 retVal = USB_STATUS_OK;
00657 }
00658
00659
00660
00661
00662 else if ( ( setup->Type == USB_SETUP_TYPE_CLASS ) &&
00663 ( setup->Direction == USB_SETUP_DIR_IN ) &&
00664 ( setup->Recipient == USB_SETUP_RECIPIENT_INTERFACE ) &&
00665 ( setup->bRequest == USB_MSD_GETMAXLUN ) &&
00666 ( setup->wValue == 0 ) &&
00667 ( setup->wIndex == 0 ) &&
00668 ( setup->wLength == 1 ) )
00669 {
00670
00671 tmp = 0;
00672 retVal = USBD_Write(0, (void*) &tmp, 1, NULL);
00673 }
00674
00675
00676
00677
00678 else if ( ( setup->Type == USB_SETUP_TYPE_STANDARD ) &&
00679 ( setup->Direction == USB_SETUP_DIR_OUT ) &&
00680 ( setup->Recipient == USB_SETUP_RECIPIENT_ENDPOINT ) &&
00681 ( setup->bRequest == CLEAR_FEATURE ) &&
00682 ( setup->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
00683 ( setup->wLength == 0 ) )
00684 {
00685 if ( ( ( setup->wIndex & 0xFF) == BULK_OUT ) ||
00686 ( ( setup->wIndex & 0xFF) == BULK_IN ) )
00687 {
00688 retVal = USB_STATUS_OK;
00689
00690
00691 if (msdState != MSDD_WAITFOR_RECOVERY)
00692 {
00693 retVal = USBD_UnStallEp(setup->wIndex & 0xFF);
00694
00695 if ((setup->wIndex & 0xFF) == BULK_IN)
00696 {
00697 if (msdState == MSDD_WAIT_FOR_INUNSTALLED)
00698 {
00699 SendCsw();
00700 EnableNextCbw();
00701 msdState = MSDD_WAITFOR_CBW;
00702 }
00703 }
00704 else
00705 {
00706 EnableNextCbw();
00707 msdState = MSDD_WAITFOR_CBW;
00708 }
00709 }
00710 }
00711 }
00712
00713 return retVal;
00714 }
00715
00716
00726 static void UsbStateChangeEvent(USBD_State_TypeDef oldState,
00727 USBD_State_TypeDef newState)
00728 {
00729 if (newState == USBD_STATE_CONFIGURED)
00730 {
00731
00732 EnableNextCbw();
00733 msdState = MSDD_WAITFOR_CBW;
00734 }
00735
00736 else if ((oldState == USBD_STATE_CONFIGURED) &&
00737 (newState != USBD_STATE_SUSPENDED))
00738 {
00739
00740 msdState = MSDD_IDLE;
00741 }
00742
00743 else if (newState == USBD_STATE_SUSPENDED)
00744 {
00745
00746 msdState = MSDD_IDLE;
00747
00748
00749 }
00750 }
00751
00752
00766 static void UsbXferBotData(uint8_t *data, uint32_t len,
00767 USB_XferCompleteCb_TypeDef cb)
00768 {
00769 if (pCmdStatus->direction)
00770 {
00771 USBD_Write(BULK_IN, data, len, cb);
00772 }
00773 else
00774 {
00775 USBD_Read(BULK_OUT, data, len, cb);
00776 }
00777 }
00778
00779
00787 static void XferBotData(uint32_t length)
00788 {
00789 pCmdStatus->xferLen = length;
00790 pCsw->dCSWDataResidue = pCbw->dCBWDataTransferLength;
00791
00792 if (pCmdStatus->xferType == XFER_INDIRECT)
00793 {
00794
00795 savedState = msdState;
00796 msdState = MSDD_ACCESS_INDIRECT;
00797 }
00798 else
00799 {
00800 UsbXferBotData(pCmdStatus->pData,
00801 EFM32_MIN(length, pCmdStatus->maxBurst),
00802 XferBotDataCallback);
00803 }
00804 }
00805
00806
00825 static int XferBotDataCallback(USB_Status_TypeDef status,
00826 uint32_t xferred, uint32_t remaining)
00827 {
00828 (void) status;
00829 (void) remaining;
00830
00831 pCmdStatus->xferLen -= xferred;
00832 pCsw->dCSWDataResidue -= xferred;
00833
00834 if (pCmdStatus->xferLen)
00835 {
00836 pCmdStatus->pData += xferred;
00837 UsbXferBotData(pCmdStatus->pData,
00838 EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst),
00839 XferBotDataCallback);
00840 }
00841 else
00842 {
00843 if (msdState == MSDD_SEND_CSW)
00844 {
00845 SendCsw();
00846 EnableNextCbw();
00847 msdState = MSDD_WAITFOR_CBW;
00848 }
00849
00850 else if (msdState == MSDD_STALL_IN)
00851 {
00852 USBD_StallEp(BULK_IN);
00853 msdState = MSDD_WAIT_FOR_INUNSTALLED;
00854 }
00855 }
00856
00857 return USB_STATUS_OK;
00858 }
00859
00860
00877 static int XferBotDataIndirectCallback(USB_Status_TypeDef status,
00878 uint32_t xferred, uint32_t remaining)
00879 {
00880 (void) status;
00881 (void) remaining;
00882
00883 pCmdStatus->xferLen -= xferred;
00884 pCsw->dCSWDataResidue -= xferred;
00885
00886 if (pCmdStatus->direction)
00887 {
00888 pCmdStatus->lba += xferred / 512;
00889 msdState = MSDD_ACCESS_INDIRECT;
00890 }
00891 else
00892 {
00893 msdState = MSDD_WRITE_INDIRECT;
00894 }
00895
00896 return USB_STATUS_OK;
00897 }
00898