21 #include "msddmedia.h"
59 #define MSD_DIR_DATA_OUT 0
60 #define MSD_DIR_DATA_IN 1
61 #define MSD_MAX_BURST 32768U
70 MSDD_WAITFOR_RECOVERY = 2,
72 MSDD_WAIT_FOR_INUNSTALLED = 4,
74 MSDD_ACCESS_INDIRECT = 6,
75 MSDD_WRITE_INDIRECT = 7,
81 static int CbwCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
82 __STATIC_INLINE
bool CswMeaningful(
void);
83 __STATIC_INLINE
bool CswValid(
void);
84 __STATIC_INLINE
void EnableNextCbw(
void);
85 static void ProcessScsiCdb(
void);
86 __STATIC_INLINE
void SendCsw(
void);
87 static void UsbXferBotData(uint8_t *data, uint32_t len, USB_XferCompleteCb_TypeDef cb);
88 static void XferBotData(uint32_t length);
89 static int XferBotDataCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
90 static int XferBotDataIndirectCallback(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining);
95 STATIC_UBUF(cbw, USB_FS_BULK_EP_MAXSIZE);
107 static msdState_TypeDef savedState;
109 static
unsigned int ledPin;
110 static
bool turResponse = true;
119 { .Reserved1 = 0, .Removable = 1 },
123 { .ResponseDataFormat = 2,
124 .HiSup = 0, .NormACA = 0, .Obsolete1 = 0 },
126 .AdditionalLength = 31,
128 { .Protect = 0, .Reserved2 = 0, .ThirdPartyCode = 0,
129 .Tpgs = 0, .Acc = 0, .Sccs = 0 },
131 { .Addr16 = 0, .Obsolete2 = 0, .MChngr = 0, .MultiP = 0,
132 .Vs1 = 0, .EncServ = 0, .BQue = 0 },
134 { .Vs2 = 0, .CmdQue = 0, .Obsolete3 = 0, .Linked = 0,
135 .Sync = 0, .Wbus16 = 0, .Obsolete4 = 0 },
137 .T10VendorId = {
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ' },
138 .ProductId = {
'E',
'F',
'M',
'3',
'2',
' ',
'M',
'S',
'D',
' ',
'D',
'e',
'v',
'i',
'c',
'e' },
139 .ProductRevisionLevel ={
'1',
'.',
'0',
'0' }
150 { .ResponseCode = 0x70, .Valid = 0 },
152 { .SenseKey = 0, .Reserved =0, .Ili = 0, .Eom = 0, .FileMark = 0 },
154 .AdditionalLength = 10,
155 .CmdSpecificInfo = 0,
159 { .SenseKeySpecific1 = 0, .Sksv = 0 },
160 .SenseKeySpecific2 = 0,
161 .SenseKeySpecific3 = 0
173 { .ResponseCode = 0x70, .Valid = 0 },
176 .Reserved = 0, .Ili = 0, .Eom = 0, .FileMark = 0 },
178 .AdditionalLength = 10,
179 .CmdSpecificInfo = 0,
183 { .SenseKeySpecific1 = 0, .Sksv = 0 },
184 .SenseKeySpecific2 = 0,
185 .SenseKeySpecific3 = 0
188 static volatile msdState_TypeDef msdState;
203 void MSDD_Init(
int activityLedPort, uint32_t activityLedPin)
216 DEBUG_USB_API_PUTS(
"\nMSDD_Init(), typedef size error");
221 if ( ( activityLedPort >= gpioPortA ) && ( activityLedPort <= gpioPortF ) )
222 ledPort = activityLedPort;
226 ledPin = activityLedPin;
227 msdState = MSDD_IDLE;
252 case MSDD_ACCESS_INDIRECT:
253 if (pCmdStatus->xferLen)
255 len =
SL_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst);
257 msdState = MSDD_IDLE;
258 if (pCmdStatus->direction)
260 MSDDMEDIA_Read(pCmdStatus, mediaBuffer, len / 512);
262 UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback);
267 msdState = savedState;
269 if (msdState == MSDD_SEND_CSW)
273 msdState = MSDD_WAITFOR_CBW;
276 else if (msdState == MSDD_STALL_IN)
278 USBD_StallEp(MSD_BULK_IN);
279 msdState = MSDD_WAIT_FOR_INUNSTALLED;
284 case MSDD_WRITE_INDIRECT:
285 MSDDMEDIA_Write(pCmdStatus, mediaBuffer, len / 512);
286 pCmdStatus->lba += len / 512;
287 msdState = MSDD_ACCESS_INDIRECT;
290 case MSDD_DO_CMD_TASK:
298 msdState = MSDD_WAITFOR_CBW;
304 return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE);
324 retVal = USB_STATUS_REQ_UNHANDLED;
328 if ( ( setup->Type == USB_SETUP_TYPE_CLASS ) &&
329 ( setup->Direction == USB_SETUP_DIR_OUT ) &&
330 ( setup->Recipient == USB_SETUP_RECIPIENT_INTERFACE ) &&
331 ( setup->bRequest == USB_MSD_BOTRESET ) &&
332 ( setup->wValue == 0 ) &&
333 ( setup->wIndex == MSD_INTERFACE_NO ) &&
334 ( setup->wLength == 0 ) )
336 if (msdState == MSDD_WAITFOR_RECOVERY)
338 msdState = MSDD_IDLE;
340 retVal = USB_STATUS_OK;
346 else if ( ( setup->Type == USB_SETUP_TYPE_CLASS ) &&
347 ( setup->Direction == USB_SETUP_DIR_IN ) &&
348 ( setup->Recipient == USB_SETUP_RECIPIENT_INTERFACE ) &&
349 ( setup->bRequest == USB_MSD_GETMAXLUN ) &&
350 ( setup->wValue == 0 ) &&
351 ( setup->wIndex == MSD_INTERFACE_NO ) &&
352 ( setup->wLength == 1 ) )
356 retVal = USBD_Write(0, (
void*) &tmp, 1, NULL);
362 else if ( ( setup->Type == USB_SETUP_TYPE_STANDARD ) &&
363 ( setup->Direction == USB_SETUP_DIR_OUT ) &&
364 ( setup->Recipient == USB_SETUP_RECIPIENT_ENDPOINT ) &&
365 ( setup->bRequest == CLEAR_FEATURE ) &&
366 ( setup->wValue == USB_FEATURE_ENDPOINT_HALT ) &&
367 ( setup->wLength == 0 ) )
369 if ( ( ( setup->wIndex & 0xFF) == MSD_BULK_OUT ) ||
370 ( ( setup->wIndex & 0xFF) == MSD_BULK_IN ) )
372 retVal = USB_STATUS_OK;
375 if (msdState != MSDD_WAITFOR_RECOVERY)
377 retVal = USBD_UnStallEp(setup->wIndex & 0xFF);
379 if ((setup->wIndex & 0xFF) == MSD_BULK_IN)
381 if (msdState == MSDD_WAIT_FOR_INUNSTALLED)
385 msdState = MSDD_WAITFOR_CBW;
391 msdState = MSDD_WAITFOR_CBW;
411 USBD_State_TypeDef newState )
413 if (newState == USBD_STATE_CONFIGURED)
417 msdState = MSDD_WAITFOR_CBW;
421 else if ((oldState == USBD_STATE_CONFIGURED) &&
422 (newState != USBD_STATE_SUSPENDED))
425 msdState = MSDD_IDLE;
428 else if (newState == USBD_STATE_SUSPENDED)
431 msdState = MSDD_IDLE;
456 static int CbwCallback(USB_Status_TypeDef status,
457 uint32_t xferred, uint32_t remaining)
461 if ( ( msdState == MSDD_WAITFOR_CBW ) &&
462 ( status == USB_STATUS_OK ) &&
463 ( xferred == CBW_LEN ) &&
465 ( CswMeaningful() ) )
473 if (pCmdStatus->valid)
474 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDPASSED;
476 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
478 pCsw->dCSWSignature = CSW_SIGNATURE;
485 (pCbw->
Direction != pCmdStatus->direction))
488 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
493 USBD_StallEp(MSD_BULK_IN);
494 msdState = MSDD_WAIT_FOR_INUNSTALLED;
499 USBD_StallEp(MSD_BULK_OUT);
501 msdState = MSDD_IDLE;
513 if (pCmdStatus->xferLen)
516 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
519 if ((pCmdStatus->xferLen == 0) &&
520 (pCmdStatus->xferType == XFER_INDIRECT))
524 msdState = MSDD_DO_CMD_TASK;
530 msdState = MSDD_WAITFOR_CBW;
537 msdState = MSDD_SEND_CSW;
538 XferBotData(pCmdStatus->xferLen);
544 if (pCmdStatus->xferLen > 0)
548 msdState = MSDD_STALL_IN;
549 XferBotData(pCmdStatus->xferLen);
554 USBD_StallEp(MSD_BULK_IN);
555 msdState = MSDD_WAIT_FOR_INUNSTALLED;
561 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
563 msdState = MSDD_SEND_CSW;
578 msdState = MSDD_SEND_CSW;
579 XferBotData(pCmdStatus->xferLen);
584 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
585 USBD_StallEp(MSD_BULK_OUT);
587 msdState = MSDD_IDLE;
592 pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
593 USBD_StallEp(MSD_BULK_OUT);
595 msdState = MSDD_IDLE;
598 return USB_STATUS_OK;
601 if ((status == USB_STATUS_OK) &&
602 (USBD_GetUsbState() == USBD_STATE_CONFIGURED))
605 USBD_StallEp(MSD_BULK_OUT);
606 USBD_StallEp(MSD_BULK_IN);
607 msdState = MSDD_WAITFOR_RECOVERY;
610 return USB_STATUS_OK;
618 __STATIC_INLINE
bool CswMeaningful(
void)
623 ( pCbw->
Lun == 0 ) &&
637 __STATIC_INLINE
bool CswValid(
void)
646 __STATIC_INLINE
void EnableNextCbw(
void)
648 USBD_Read(MSD_BULK_OUT, (
void*) &cbw, USB_FS_BULK_EP_MAXSIZE, CbwCallback);
656 static void ProcessScsiCdb(
void)
669 pCmdStatus->valid = false;
670 pCmdStatus->xferType = XFER_MEMORYMAPPED;
671 pCmdStatus->maxBurst = MSD_MAX_BURST;
673 switch (pCbw->CBWCB[ 0 ])
681 pCmdStatus->valid =
true;
682 pCmdStatus->direction = MSD_DIR_DATA_IN;
683 pCmdStatus->pData = (uint8_t*) &InquiryData;
695 pCmdStatus->valid =
true;
696 pCmdStatus->direction = MSD_DIR_DATA_IN;
697 pCmdStatus->pData = (uint8_t*) pSenseData;
707 if ((cbRC->
Pmi == 0) && (cbRC->
Lba == 0))
709 ReadCapData.LogicalBlockAddress = __REV(MSDDMEDIA_GetSectorCount() - 1);
710 ReadCapData.LogicalBlockLength = __REV(512);
712 pCmdStatus->valid =
true;
713 pCmdStatus->direction = MSD_DIR_DATA_IN;
714 pCmdStatus->pData = (uint8_t*) &ReadCapData;
722 pCmdStatus->direction = MSD_DIR_DATA_IN;
723 pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
731 pCmdStatus->direction = MSD_DIR_DATA_OUT;
732 pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
745 pCmdStatus->valid =
true;
747 pCmdStatus->xferLen = 0;
752 pCmdStatus->valid = turResponse;
754 pCmdStatus->xferLen = 0;
767 pCmdStatus->valid =
true;
769 pCmdStatus->xferLen = 0;
770 pCmdStatus->xferType = XFER_INDIRECT;
774 if (!pCmdStatus->valid)
776 pCmdStatus->xferLen = 0;
786 __STATIC_INLINE
void SendCsw(
void)
791 USBD_Write(MSD_BULK_IN, (
void*) &csw, CSW_LEN, NULL);
808 static void UsbXferBotData(uint8_t *data, uint32_t len,
809 USB_XferCompleteCb_TypeDef cb)
811 if (pCmdStatus->direction)
813 USBD_Write(MSD_BULK_IN, data, len, cb);
817 USBD_Read(MSD_BULK_OUT, data, len, cb);
829 static void XferBotData(uint32_t length)
831 pCmdStatus->xferLen = length;
834 if (pCmdStatus->xferType == XFER_INDIRECT)
837 savedState = msdState;
838 msdState = MSDD_ACCESS_INDIRECT;
842 UsbXferBotData(pCmdStatus->pData,
843 SL_MIN(length, pCmdStatus->maxBurst),
844 XferBotDataCallback);
867 static int XferBotDataCallback(USB_Status_TypeDef status,
868 uint32_t xferred, uint32_t remaining)
873 pCmdStatus->xferLen -= xferred;
874 pCsw->dCSWDataResidue -= xferred;
876 if (pCmdStatus->xferLen)
878 pCmdStatus->pData += xferred;
879 UsbXferBotData(pCmdStatus->pData,
880 SL_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst),
881 XferBotDataCallback);
885 if (msdState == MSDD_SEND_CSW)
889 msdState = MSDD_WAITFOR_CBW;
892 else if (msdState == MSDD_STALL_IN)
894 USBD_StallEp(MSD_BULK_IN);
895 msdState = MSDD_WAIT_FOR_INUNSTALLED;
899 return USB_STATUS_OK;
919 static int XferBotDataIndirectCallback(USB_Status_TypeDef status,
920 uint32_t xferred, uint32_t remaining)
925 pCmdStatus->xferLen -= xferred;
926 pCsw->dCSWDataResidue -= xferred;
928 if (pCmdStatus->direction)
930 pCmdStatus->lba += xferred / 512;
931 msdState = MSDD_ACCESS_INDIRECT;
935 msdState = MSDD_WRITE_INDIRECT;
938 return USB_STATUS_OK;
Clock management unit (CMU) API.
#define SCSI_TESTUNIT_READY
SCSI Inquiry response data typedef.
#define SCSI_STARTSTOPUNIT_LEN
Status info for one BOT CBW -> Data I/O -> CSW cycle.
#define SCSI_REQUESTSENSEDATA_LEN
__STATIC_INLINE void GPIO_PinOutToggle(GPIO_Port_TypeDef port, unsigned int pin)
Toggle a single pin in GPIO port data out register.
SCSI Request Sense response data typedef.
uint32_t dCBWDataTransferLength
SCSI Read Capacity Command Descriptor Block (CDB) typedef.
#define SL_ALIGN(X)
Macro for aligning a variable. Use this macro before the variable definition. X denotes the stora...
SCSI Read Capacity response data typedef.
SCSI Inquiry Command Descriptor Block (CDB) typedef.
void MSDD_StateChangeEvent(USBD_State_TypeDef oldState, USBD_State_TypeDef newState)
Called whenever the USB device has changed its device state.
SCSI interface for Mass Storage Devices (MSD).
SCSI Verify 10 Command Descriptor Block (CDB) typedef.
#define SCSI_READCAPACITY
Mass Storage class Device (MSD) driver.
void GPIO_PinModeSet(GPIO_Port_TypeDef port, unsigned int pin, GPIO_Mode_TypeDef mode, unsigned int out)
Set the mode for a GPIO pin.
int MSDD_SetupCmd(const USB_Setup_TypeDef *setup)
Called whenever a USB setup command is received. This function overrides standard CLEAR_FEATURE comma...
General Purpose IO (GPIO) peripheral API.
SCSI Start Stop Unit Command Descriptor Block (CDB) typedef.
#define SCSI_STARTSTOP_UNIT
#define SL_ATTRIBUTE_ALIGN(X)
GCC style macro for aligning a variable.
Definitions for the Bulk Only Transport protocol of USB Mass Storage devices.
SCSI Read 10 Command Descriptor Block (CDB) typedef.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
#define SCSI_READCAPACITY_LEN
#define SCSI_REQUESTSENSE_LEN
bool MSDD_Handler(void)
Serve the MSD state machine. This function should be called on a regular basis from your main loop...
SCSI Request Sense Command Descriptor Block (CDB) typedef.
#define SCSI_READCAPACITYDATA_LEN
Bulk Only Transport (BOT) Command Block Wrapper (CBW) typedef.
#define SCSI_INQUIRYDATA_LEN
SCSI Write 10 Command Descriptor Block (CDB) typedef.
Bulk Only Transport (BOT) Command Status Wrapper (CSW) typedef.
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
Initialize MSD device.
#define SCSI_REQUESTSENSE
#define SCSI_VERIFY10_LEN
uint16_t AllocationLength
uint8_t PeripheralDeviceType