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);
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);
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)
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);
333 ( setup->
wIndex == MSD_INTERFACE_NO ) &&
336 if (msdState == MSDD_WAITFOR_RECOVERY)
338 msdState = MSDD_IDLE;
351 ( setup->
wIndex == MSD_INTERFACE_NO ) &&
356 retVal =
USBD_Write(0, (
void*) &tmp, 1, NULL);
369 if ( ( ( setup->
wIndex & 0xFF) == MSD_BULK_OUT ) ||
370 ( ( setup->
wIndex & 0xFF) == MSD_BULK_IN ) )
375 if (msdState != MSDD_WAITFOR_RECOVERY)
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;
417 msdState = MSDD_WAITFOR_CBW;
425 msdState = MSDD_IDLE;
431 msdState = MSDD_IDLE;
457 uint32_t xferred, uint32_t remaining)
461 if ( ( msdState == MSDD_WAITFOR_CBW ) &&
463 ( xferred == CBW_LEN ) &&
465 ( CswMeaningful() ) )
473 if (pCmdStatus->valid)
478 pCsw->dCSWSignature = CSW_SIGNATURE;
485 (pCbw->
Direction != pCmdStatus->direction))
494 msdState = MSDD_WAIT_FOR_INUNSTALLED;
501 msdState = MSDD_IDLE;
513 if (pCmdStatus->xferLen)
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);
555 msdState = MSDD_WAIT_FOR_INUNSTALLED;
563 msdState = MSDD_SEND_CSW;
578 msdState = MSDD_SEND_CSW;
579 XferBotData(pCmdStatus->xferLen);
587 msdState = MSDD_IDLE;
595 msdState = MSDD_IDLE;
607 msdState = MSDD_WAITFOR_RECOVERY;
618 __STATIC_INLINE
bool CswMeaningful(
void)
623 ( pCbw->
Lun == 0 ) &&
637 __STATIC_INLINE
bool CswValid(
void)
646 __STATIC_INLINE
void EnableNextCbw(
void)
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,
811 if (pCmdStatus->direction)
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);
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)
895 msdState = MSDD_WAIT_FOR_INUNSTALLED;
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;
Clock management unit (CMU) API.
#define SCSI_TESTUNIT_READY
SCSI Inquiry response data typedef.
#define USB_MSD_GETMAXLUN
#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.
#define USB_SETUP_RECIPIENT_ENDPOINT
SCSI Request Sense response data typedef.
uint32_t dCBWDataTransferLength
#define USB_FS_BULK_EP_MAXSIZE
#define USB_CLASS_MSD_CSW_CMDFAILED
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.
#define USB_CLASS_MSD_CSW_CMDPASSED
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).
USB Setup request package.
USBD_State_TypeDef
USB device state enumerator.
SCSI Verify 10 Command Descriptor Block (CDB) typedef.
int(* USB_XferCompleteCb_TypeDef)(USB_Status_TypeDef status, uint32_t xferred, uint32_t remaining)
USB transfer callback function.
#define SCSI_READCAPACITY
USB_Status_TypeDef
USB transfer status enumerator.
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.
#define USB_SETUP_DIR_OUT
SCSI Read 10 Command Descriptor Block (CDB) typedef.
USB protocol stack library API for EFM32/EZR32.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
#define USB_SETUP_RECIPIENT_INTERFACE
#define USB_SETUP_TYPE_STANDARD
#define SCSI_READCAPACITY_LEN
int USBD_StallEp(int epAddr)
Set an endpoint in the stalled (halted) state.
#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.
USBD_State_TypeDef USBD_GetUsbState(void)
Get current USB device state.
#define SCSI_READCAPACITYDATA_LEN
int USBD_UnStallEp(int epAddr)
Reset stall state on a stalled (halted) endpoint.
int USBD_Write(int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback)
Start a write (IN) transfer on an endpoint.
Bulk Only Transport (BOT) Command Block Wrapper (CBW) typedef.
#define SCSI_INQUIRYDATA_LEN
SCSI Write 10 Command Descriptor Block (CDB) typedef.
#define USB_FEATURE_ENDPOINT_HALT
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 USB_SETUP_TYPE_CLASS
#define SCSI_VERIFY10_LEN
uint16_t AllocationLength
#define USB_CLASS_MSD_CSW_PHASEERROR
uint8_t PeripheralDeviceType
int USBD_Read(int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback)
Start a read (OUT) transfer on an endpoint.
#define STATIC_UBUF(x, y)