EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
msdd.c
Go to the documentation of this file.
1 /**************************************************************************/
15 #include "em_usb.h"
16 #include "em_cmu.h"
17 #include "em_gpio.h"
18 #include "msdbot.h"
19 #include "msdscsi.h"
20 #include "msdd.h"
21 #include "msddmedia.h"
22 
23 /**************************************************************************/
58 /*** Typedef's and defines. ***/
59 #define MSD_DIR_DATA_OUT 0
60 #define MSD_DIR_DATA_IN 1
61 #define MSD_MAX_BURST 32768U /* 32 * 1024 */
62 
63 /**************************************************************************/
66 typedef enum
67 {
68  MSDD_IDLE = 0,
69  MSDD_WAITFOR_CBW = 1,
70  MSDD_WAITFOR_RECOVERY = 2,
71  MSDD_SEND_CSW = 3,
72  MSDD_WAIT_FOR_INUNSTALLED = 4,
73  MSDD_STALL_IN = 5,
74  MSDD_ACCESS_INDIRECT = 6,
75  MSDD_WRITE_INDIRECT = 7,
76  MSDD_DO_CMD_TASK = 8,
77 } msdState_TypeDef;
78 
79 /*** Function prototypes. ***/
80 
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);
91 
92 /*** Variables ***/
93 
94 /* Storage for one CBW */
95 STATIC_UBUF(cbw, USB_FS_BULK_EP_MAXSIZE);
96 static MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) &cbw;
97 
98 SL_ALIGN(4)
99 /* Storage for one CSW */
101 static MSDBOT_CSW_TypeDef *pCsw = &csw;
102 
103 STATIC_UBUF(mediaBuffer, MEDIA_BUFSIZ); /* Intermediate media storage buffer */
104 
105 static MSDD_CmdStatus_TypeDef CmdStatus;
106 static MSDD_CmdStatus_TypeDef *pCmdStatus = &CmdStatus;
107 static msdState_TypeDef savedState; /* MSD state machine state. */
108 static int ledPort;
109 static unsigned int ledPin;
110 static bool turResponse = true; // Response on TEST UNIT READY command.
111 
112 /**************************************************************************/
115 SL_ALIGN(4)
116 static const MSDSCSI_InquiryData_TypeDef InquiryData SL_ATTRIBUTE_ALIGN(4) =
117 {
118  { .PeripheralDeviceType = 0, .PeripheralQualifier = 0 }, /* Block device */
119  { .Reserved1 = 0, .Removable = 1 },
120 
121  .Version = 5, /* T10 SPC-3 compliant */
122 
123  { .ResponseDataFormat = 2, /* T10 SPC-3 compliant reponse data */
124  .HiSup = 0, .NormACA = 0, .Obsolete1 = 0 },
125 
126  .AdditionalLength = 31,
127 
128  { .Protect = 0, .Reserved2 = 0, .ThirdPartyCode = 0,
129  .Tpgs = 0, .Acc = 0, .Sccs = 0 },
130 
131  { .Addr16 = 0, .Obsolete2 = 0, .MChngr = 0, .MultiP = 0,
132  .Vs1 = 0, .EncServ = 0, .BQue = 0 },
133 
134  { .Vs2 = 0, .CmdQue = 0, .Obsolete3 = 0, .Linked = 0,
135  .Sync = 0, .Wbus16 = 0, .Obsolete4 = 0 },
136 
137  .T10VendorId = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
138  .ProductId = { 'E', 'F', 'M', '3', '2', ' ', 'M', 'S', 'D', ' ', 'D', 'e', 'v', 'i', 'c', 'e' },
139  .ProductRevisionLevel ={ '1', '.', '0', '0' }
140 };
141 
142 /**************************************************************************/
147 SL_ALIGN(4)
148 static const MSDSCSI_RequestSenseData_TypeDef NoSenseData SL_ATTRIBUTE_ALIGN(4) =
149 {
150  { .ResponseCode = 0x70, .Valid = 0 },
151  .Obsolete = 0,
152  { .SenseKey = 0, .Reserved =0, .Ili = 0, .Eom = 0, .FileMark = 0 },
153  .Information = 0,
154  .AdditionalLength = 10,
155  .CmdSpecificInfo = 0,
156  .Asc = 0,
157  .Ascq = 0,
158  .Fruc = 0,
159  { .SenseKeySpecific1 = 0, .Sksv = 0 },
160  .SenseKeySpecific2 = 0,
161  .SenseKeySpecific3 = 0
162 };
163 
164 /**************************************************************************/
170 SL_ALIGN(4)
171 static const MSDSCSI_RequestSenseData_TypeDef IllegalSenseData SL_ATTRIBUTE_ALIGN(4) =
172 {
173  { .ResponseCode = 0x70, .Valid = 0 },
174  .Obsolete = 0,
175  { .SenseKey = 5, /* SensKey = 5 => ILLEGAL REQUEST */
176  .Reserved = 0, .Ili = 0, .Eom = 0, .FileMark = 0 },
177  .Information = 0,
178  .AdditionalLength = 10,
179  .CmdSpecificInfo = 0,
180  .Asc = 0x24, /* Asc/Ascq = 0x24/0x00 => INVALID FIELD IN CDB*/
181  .Ascq = 0,
182  .Fruc = 0,
183  { .SenseKeySpecific1 = 0, .Sksv = 0 },
184  .SenseKeySpecific2 = 0,
185  .SenseKeySpecific3 = 0
186 };
187 
188 static volatile msdState_TypeDef msdState;
189 static MSDSCSI_RequestSenseData_TypeDef *pSenseData;
193 /**************************************************************************/
203 void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
204 {
205  if ( ( sizeof(MSDSCSI_Read10_TypeDef) != SCSI_READ10_LEN ) ||
206  ( sizeof(MSDSCSI_Write10_TypeDef) != SCSI_WRITE10_LEN ) ||
209  ( sizeof(InquiryData) != SCSI_INQUIRYDATA_LEN ) ||
210  ( sizeof(NoSenseData) != SCSI_REQUESTSENSEDATA_LEN ) ||
211  ( sizeof(IllegalSenseData) != SCSI_REQUESTSENSEDATA_LEN ) ||
215  {
216  DEBUG_USB_API_PUTS("\nMSDD_Init(), typedef size error");
217  EFM_ASSERT(false);
218  return;
219  }
220 
221  if ( ( activityLedPort >= gpioPortA ) && ( activityLedPort <= gpioPortF ) )
222  ledPort = activityLedPort;
223  else
224  ledPort = -1;
225 
226  ledPin = activityLedPin;
227  msdState = MSDD_IDLE;
228  pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
229 
230  if ( ledPort != -1 )
231  {
233  GPIO_PinModeSet((GPIO_Port_TypeDef)ledPort, ledPin, gpioModePushPull, 0);
234  }
235 }
236 
237 /**************************************************************************/
246 bool MSDD_Handler(void)
247 {
248  static uint32_t len; /* Note: len is static ! */
249 
250  switch (msdState)
251  {
252  case MSDD_ACCESS_INDIRECT:
253  if (pCmdStatus->xferLen)
254  {
255  len = SL_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst);
256 
257  msdState = MSDD_IDLE;
258  if (pCmdStatus->direction)
259  {
260  MSDDMEDIA_Read(pCmdStatus, mediaBuffer, len / 512);
261  }
262  UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback);
263  }
264  else
265  {
266  /* We are done ! */
267  msdState = savedState;
268 
269  if (msdState == MSDD_SEND_CSW)
270  {
271  SendCsw();
272  EnableNextCbw();
273  msdState = MSDD_WAITFOR_CBW;
274  }
275 
276  else if (msdState == MSDD_STALL_IN)
277  {
278  USBD_StallEp(MSD_BULK_IN);
279  msdState = MSDD_WAIT_FOR_INUNSTALLED;
280  }
281  }
282  break;
283 
284  case MSDD_WRITE_INDIRECT:
285  MSDDMEDIA_Write(pCmdStatus, mediaBuffer, len / 512);
286  pCmdStatus->lba += len / 512;
287  msdState = MSDD_ACCESS_INDIRECT;
288  break;
289 
290  case MSDD_DO_CMD_TASK:
291  if (pCbw->CBWCB[ 0 ] == SCSI_STARTSTOP_UNIT)
292  {
293  MSDDMEDIA_Flush();
294  }
295  /* else if ( .... ) Add more when needed. */
296  SendCsw();
297  EnableNextCbw();
298  msdState = MSDD_WAITFOR_CBW;
299  break;
300 
301  default:
302  break;
303  }
304  return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE);
305 }
306 
307 /**************************************************************************/
319 int MSDD_SetupCmd(const USB_Setup_TypeDef *setup)
320 {
321  int retVal;
322  static uint32_t tmp;
323 
324  retVal = USB_STATUS_REQ_UNHANDLED;
325 
326  /* Check if it is MSD class command: "Bulk-Only Mass Storage Reset" */
327 
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 ) )
335  {
336  if (msdState == MSDD_WAITFOR_RECOVERY)
337  {
338  msdState = MSDD_IDLE;
339  }
340  retVal = USB_STATUS_OK;
341  }
342 
343 
344  /* Check if it is MSD class command: "Get Max LUN" */
345 
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 ) )
353  {
354  /* Only one LUN (i.e. no support for multiple LUN's). Reply "0". */
355  tmp = 0;
356  retVal = USBD_Write(0, (void*) &tmp, 1, NULL);
357  }
358 
359 
360  /* Check if it is a standard CLEAR_FEATURE endpoint command */
361 
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 ) )
368  {
369  if ( ( ( setup->wIndex & 0xFF) == MSD_BULK_OUT ) ||
370  ( ( setup->wIndex & 0xFF) == MSD_BULK_IN ) )
371  {
372  retVal = USB_STATUS_OK;
373 
374  /* Dont unstall ep's when waiting for reset recovery */
375  if (msdState != MSDD_WAITFOR_RECOVERY)
376  {
377  retVal = USBD_UnStallEp(setup->wIndex & 0xFF);
378 
379  if ((setup->wIndex & 0xFF) == MSD_BULK_IN)
380  {
381  if (msdState == MSDD_WAIT_FOR_INUNSTALLED)
382  {
383  SendCsw();
384  EnableNextCbw();
385  msdState = MSDD_WAITFOR_CBW;
386  }
387  }
388  else
389  {
390  EnableNextCbw();
391  msdState = MSDD_WAITFOR_CBW;
392  }
393  }
394  }
395  }
396 
397  return retVal;
398 }
399 
400 /**************************************************************************/
410 void MSDD_StateChangeEvent( USBD_State_TypeDef oldState,
411  USBD_State_TypeDef newState )
412 {
413  if (newState == USBD_STATE_CONFIGURED)
414  {
415  /* We have been configured, start MSD functionality ! */
416  EnableNextCbw();
417  msdState = MSDD_WAITFOR_CBW;
418  turResponse = true; // Set TEST UNIT READY response value.
419  }
420 
421  else if ((oldState == USBD_STATE_CONFIGURED) &&
422  (newState != USBD_STATE_SUSPENDED))
423  {
424  /* We have been de-configured */
425  msdState = MSDD_IDLE;
426  }
427 
428  else if (newState == USBD_STATE_SUSPENDED)
429  {
430  /* We have been suspended. */
431  msdState = MSDD_IDLE;
432 
433  /* Reduce current consumption to below 2.5 mA. */
434  }
435 }
436 
439 /**************************************************************************/
456 static int CbwCallback(USB_Status_TypeDef status,
457  uint32_t xferred, uint32_t remaining)
458 {
459  (void) remaining;
460 
461  if ( ( msdState == MSDD_WAITFOR_CBW ) &&
462  ( status == USB_STATUS_OK ) &&
463  ( xferred == CBW_LEN ) &&
464  ( CswValid() ) &&
465  ( CswMeaningful() ) )
466  {
467  if ( ledPort != -1 )
468  GPIO_PinOutToggle((GPIO_Port_TypeDef)ledPort, ledPin);
469 
470  /* Check the SCSI command descriptor block (CDB) */
471  ProcessScsiCdb();
472 
473  if (pCmdStatus->valid)
474  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDPASSED;
475  else
476  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
477 
478  pCsw->dCSWSignature = CSW_SIGNATURE;
479  pCsw->dCSWTag = pCbw->dCBWTag;
480  pCsw->dCSWDataResidue = pCbw->dCBWDataTransferLength;
481 
482  /* Check the "thirteen cases" */
483 
484  if ((pCbw->dCBWDataTransferLength != 0) &&
485  (pCbw->Direction != pCmdStatus->direction))
486  {
487  /* Handle cases 8 and 10 */
488  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
489 
490  if (pCbw->Direction)
491  {
492  /* Host expects to receive data, case 8 */
493  USBD_StallEp(MSD_BULK_IN);
494  msdState = MSDD_WAIT_FOR_INUNSTALLED;
495  }
496  else
497  {
498  /* Host expects to send data, case 10 */
499  USBD_StallEp(MSD_BULK_OUT);
500  SendCsw();
501  msdState = MSDD_IDLE;
502  }
503  }
504 
505  else if (pCbw->Direction || (pCbw->dCBWDataTransferLength == 0))
506  {
507  /* SCSI IN commands or commands without data phase */
508  /* Handle cases 1-7 */
509 
510  if (pCbw->dCBWDataTransferLength == 0)
511  {
512  /* Host expects no data, case 1, 2 or 3 */
513  if (pCmdStatus->xferLen)
514  {
515  /* Device has data to transmit, case 2 & 3 */
516  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
517  }
518 
519  if ((pCmdStatus->xferLen == 0) &&
520  (pCmdStatus->xferType == XFER_INDIRECT))
521  {
522  /* Commands with no data phase which require timeconsuming */
523  /* processing are executed in MSDD_Handler() */
524  msdState = MSDD_DO_CMD_TASK;
525  }
526  else
527  {
528  SendCsw();
529  EnableNextCbw();
530  msdState = MSDD_WAITFOR_CBW;
531  }
532  }
533  else if (pCbw->dCBWDataTransferLength == pCmdStatus->xferLen)
534  {
535  /* Host and device agree on transferlength, case 6 */
536  /* Send data to host */
537  msdState = MSDD_SEND_CSW;
538  XferBotData(pCmdStatus->xferLen);
539  }
540  else if (pCbw->dCBWDataTransferLength > pCmdStatus->xferLen)
541  {
542  /* Host expects more data than device can provide, case 4 and 5 */
543 
544  if (pCmdStatus->xferLen > 0)
545  {
546  /* Device has data, case 5 */
547  /* Send data to host */
548  msdState = MSDD_STALL_IN;
549  XferBotData(pCmdStatus->xferLen);
550  }
551  else
552  {
553  /* Device has no data, case 4 */
554  USBD_StallEp(MSD_BULK_IN);
555  msdState = MSDD_WAIT_FOR_INUNSTALLED;
556  }
557  }
558  else
559  {
560  /* Host expects less data than device will provide, case 7 */
561  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
562  /* Send data to host */
563  msdState = MSDD_SEND_CSW;
564  XferBotData(pCbw->dCBWDataTransferLength);
565  }
566  }
567 
568  else /* Host Direction is OUT and Host transferlength > 0 */
569  {
570  /* SCSI OUT commands */
571  /* Handle cases 9, 11, 12 and 13 */
572 
573  if (pCbw->dCBWDataTransferLength == pCmdStatus->xferLen)
574  {
575  /* Host and device agree on transferlength, case 12 */
576 
577  /* Read data from host */
578  msdState = MSDD_SEND_CSW;
579  XferBotData(pCmdStatus->xferLen);
580  }
581  else if (pCbw->dCBWDataTransferLength > pCmdStatus->xferLen)
582  {
583  /* Host intend to send more data than device expects, case 9 & 11 */
584  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_CMDFAILED;
585  USBD_StallEp(MSD_BULK_OUT);
586  SendCsw();
587  msdState = MSDD_IDLE;
588  }
589  else
590  {
591  /* Host has less data than device expects to receive, case 13 */
592  pCsw->bCSWStatus = USB_CLASS_MSD_CSW_PHASEERROR;
593  USBD_StallEp(MSD_BULK_OUT);
594  SendCsw();
595  msdState = MSDD_IDLE;
596  }
597  }
598  return USB_STATUS_OK;
599  }
600 
601  if ((status == USB_STATUS_OK) &&
602  (USBD_GetUsbState() == USBD_STATE_CONFIGURED))
603  {
604  /* Stall both Ep's and wait for reset recovery */
605  USBD_StallEp(MSD_BULK_OUT);
606  USBD_StallEp(MSD_BULK_IN);
607  msdState = MSDD_WAITFOR_RECOVERY;
608  }
609 
610  return USB_STATUS_OK;
611 }
612 
613 /**************************************************************************/
618 __STATIC_INLINE bool CswMeaningful(void)
619 {
620  if ( ( pCbw->Reserved1 == 0 ) &&
621  ( pCbw->Obsolete == 0 ) &&
622  ( pCbw->Reserved2 == 0 ) &&
623  ( pCbw->Lun == 0 ) &&
624  ( pCbw->Reserved3 == 0 ) )
625  {
626  return true;
627  }
628 
629  return false;
630 }
631 
632 /**************************************************************************/
637 __STATIC_INLINE bool CswValid(void)
638 {
639  return pCbw->dCBWSignature == CBW_SIGNATURE ? true : false; /* Ascii USBC */
640 }
641 
642 /**************************************************************************/
646 __STATIC_INLINE void EnableNextCbw(void)
647 {
648  USBD_Read(MSD_BULK_OUT, (void*) &cbw, USB_FS_BULK_EP_MAXSIZE, CbwCallback);
649 }
650 
651 /**************************************************************************/
656 static void ProcessScsiCdb(void)
657 {
661  MSDSCSI_Read10_TypeDef *cbR10;
665 
666  SL_ALIGN(4)
668 
669  pCmdStatus->valid = false;
670  pCmdStatus->xferType = XFER_MEMORYMAPPED;
671  pCmdStatus->maxBurst = MSD_MAX_BURST;
672 
673  switch (pCbw->CBWCB[ 0 ])
674  {
675  case SCSI_INQUIRY:
676  cbI = (MSDSCSI_Inquiry_TypeDef*) &pCbw->CBWCB;
677 
678  if ((cbI->Evpd == 0) && (cbI->PageCode == 0))
679  {
680  /* Standard Inquiry data request */
681  pCmdStatus->valid = true;
682  pCmdStatus->direction = MSD_DIR_DATA_IN;
683  pCmdStatus->pData = (uint8_t*) &InquiryData;
684  pCmdStatus->xferLen = SL_MIN(SCSI_INQUIRYDATA_LEN,
685  __REV16(cbI->AllocationLength));
686  }
687  break;
688 
689  case SCSI_REQUESTSENSE:
690  cbRS = (MSDSCSI_RequestSense_TypeDef*) &pCbw->CBWCB;
691 
692  if ((cbRS->Desc == 0) && (cbRS->Reserved1 == 0) &&
693  (cbRS->Reserved2 == 0) && (cbRS->Reserved3 == 0))
694  {
695  pCmdStatus->valid = true;
696  pCmdStatus->direction = MSD_DIR_DATA_IN;
697  pCmdStatus->pData = (uint8_t*) pSenseData;
698  pCmdStatus->xferLen = SL_MIN(SCSI_REQUESTSENSEDATA_LEN,
699  cbRS->AllocationLength);
700  pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
701  }
702  break;
703 
704  case SCSI_READCAPACITY:
705  cbRC = (MSDSCSI_ReadCapacity_TypeDef*) &pCbw->CBWCB;
706 
707  if ((cbRC->Pmi == 0) && (cbRC->Lba == 0))
708  {
709  ReadCapData.LogicalBlockAddress = __REV(MSDDMEDIA_GetSectorCount() - 1);
710  ReadCapData.LogicalBlockLength = __REV(512);
711 
712  pCmdStatus->valid = true;
713  pCmdStatus->direction = MSD_DIR_DATA_IN;
714  pCmdStatus->pData = (uint8_t*) &ReadCapData;
715  pCmdStatus->xferLen = SCSI_READCAPACITYDATA_LEN;
716  }
717  break;
718 
719  case SCSI_READ10:
720  cbR10 = (MSDSCSI_Read10_TypeDef*) &pCbw->CBWCB;
721 
722  pCmdStatus->direction = MSD_DIR_DATA_IN;
723  pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
724  __REV(cbR10->Lba),
725  __REV16(cbR10->TransferLength));
726  break;
727 
728  case SCSI_WRITE10:
729  cbW10 = (MSDSCSI_Write10_TypeDef*) &pCbw->CBWCB;
730 
731  pCmdStatus->direction = MSD_DIR_DATA_OUT;
732  pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus,
733  __REV(cbW10->Lba),
734  __REV16(cbW10->TransferLength));
735  break;
736 
737  case SCSI_VERIFY10:
738  cbV10 = (MSDSCSI_Verify10_TypeDef*) &pCbw->CBWCB;
739 
740  if ((cbV10->BytChk == 0) && (cbV10->Reserved1 == 0) &&
741  (cbV10->Dpo == 0) && (cbV10->VrProtect == 0) &&
742  (cbV10->GroupNumber == 0) && (cbV10->Reserved2 == 0) &&
743  (cbV10->Restricted == 0))
744  {
745  pCmdStatus->valid = true;
746  pCmdStatus->direction = pCbw->Direction;
747  pCmdStatus->xferLen = 0;
748  }
749  break;
750 
751  case SCSI_TESTUNIT_READY:
752  pCmdStatus->valid = turResponse;
753  pCmdStatus->direction = pCbw->Direction;
754  pCmdStatus->xferLen = 0;
755  return;
756 
757  case SCSI_STARTSTOP_UNIT:
758  cbSSU = (MSDSCSI_StartStopUnit_TypeDef*) &pCbw->CBWCB;
759  if ((cbSSU->Reserved1 == 0) && (cbSSU->Reserved2 == 0) &&
760  (cbSSU->Reserved3 == 0) && (cbSSU->Reserved4 == 0) &&
761  (cbSSU->PowerCondition == 0) && (cbSSU->LoEj == 1) &&
762  (cbSSU->Start == 0))
763  {
764  // Eject media.
765  turResponse = false; // Set TEST UNIT READY response value.
766  }
767  pCmdStatus->valid = true;
768  pCmdStatus->direction = pCbw->Direction;
769  pCmdStatus->xferLen = 0;
770  pCmdStatus->xferType = XFER_INDIRECT;
771  break;
772  }
773 
774  if (!pCmdStatus->valid)
775  {
776  pCmdStatus->xferLen = 0;
777  pCmdStatus->direction = pCbw->Direction;
778  pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &IllegalSenseData;
779  }
780 }
781 
782 /**************************************************************************/
786 __STATIC_INLINE void SendCsw(void)
787 {
788  if ( ledPort != -1 )
789  GPIO_PinOutToggle((GPIO_Port_TypeDef)ledPort, ledPin);
790 
791  USBD_Write(MSD_BULK_IN, (void*) &csw, CSW_LEN, NULL);
792 }
793 
794 /**************************************************************************/
808 static void UsbXferBotData(uint8_t *data, uint32_t len,
809  USB_XferCompleteCb_TypeDef cb)
810 {
811  if (pCmdStatus->direction)
812  {
813  USBD_Write(MSD_BULK_IN, data, len, cb);
814  }
815  else
816  {
817  USBD_Read(MSD_BULK_OUT, data, len, cb);
818  }
819 }
820 
821 /**************************************************************************/
829 static void XferBotData(uint32_t length)
830 {
831  pCmdStatus->xferLen = length;
832  pCsw->dCSWDataResidue = pCbw->dCBWDataTransferLength;
833 
834  if (pCmdStatus->xferType == XFER_INDIRECT)
835  {
836  /* Access media in "background" polling loop, i.e. in MSDD_Handler() */
837  savedState = msdState;
838  msdState = MSDD_ACCESS_INDIRECT;
839  }
840  else
841  {
842  UsbXferBotData(pCmdStatus->pData,
843  SL_MIN(length, pCmdStatus->maxBurst),
844  XferBotDataCallback);
845  }
846 }
847 
848 /**************************************************************************/
867 static int XferBotDataCallback(USB_Status_TypeDef status,
868  uint32_t xferred, uint32_t remaining)
869 {
870  (void) status;
871  (void) remaining;
872 
873  pCmdStatus->xferLen -= xferred;
874  pCsw->dCSWDataResidue -= xferred;
875 
876  if (pCmdStatus->xferLen)
877  {
878  pCmdStatus->pData += xferred;
879  UsbXferBotData(pCmdStatus->pData,
880  SL_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst),
881  XferBotDataCallback);
882  }
883  else
884  {
885  if (msdState == MSDD_SEND_CSW)
886  {
887  SendCsw();
888  EnableNextCbw();
889  msdState = MSDD_WAITFOR_CBW;
890  }
891 
892  else if (msdState == MSDD_STALL_IN)
893  {
894  USBD_StallEp(MSD_BULK_IN);
895  msdState = MSDD_WAIT_FOR_INUNSTALLED;
896  }
897  }
898 
899  return USB_STATUS_OK;
900 }
901 
902 /**************************************************************************/
919 static int XferBotDataIndirectCallback(USB_Status_TypeDef status,
920  uint32_t xferred, uint32_t remaining)
921 {
922  (void) status;
923  (void) remaining;
924 
925  pCmdStatus->xferLen -= xferred;
926  pCsw->dCSWDataResidue -= xferred;
927 
928  if (pCmdStatus->direction)
929  {
930  pCmdStatus->lba += xferred / 512;
931  msdState = MSDD_ACCESS_INDIRECT;
932  }
933  else
934  {
935  msdState = MSDD_WRITE_INDIRECT;
936  }
937 
938  return USB_STATUS_OK;
939 }
940 
Clock management unit (CMU) API.
#define SCSI_TESTUNIT_READY
Definition: msdscsi.h:34
SCSI Inquiry response data typedef.
Definition: msdscsi.h:76
GPIO_Port_TypeDef
Definition: em_gpio.h:345
#define SCSI_STARTSTOPUNIT_LEN
Definition: msdscsi.h:47
uint32_t dCBWTag
Definition: msdbot.h:55
Status info for one BOT CBW -> Data I/O -> CSW cycle.
Definition: msdd.h:37
#define SCSI_REQUESTSENSEDATA_LEN
Definition: msdscsi.h:49
__STATIC_INLINE void GPIO_PinOutToggle(GPIO_Port_TypeDef port, unsigned int pin)
Toggle a single pin in GPIO port data out register.
Definition: em_gpio.h:881
SCSI Request Sense response data typedef.
Definition: msdscsi.h:155
uint32_t dCBWDataTransferLength
Definition: msdbot.h:56
SCSI Read Capacity Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:191
#define SL_ALIGN(X)
Macro for aligning a variable. Use this macro before the variable definition. X denotes the stora...
Definition: em_common.h:168
SCSI Read Capacity response data typedef.
Definition: msdscsi.h:214
SCSI Inquiry Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:57
#define SCSI_WRITE10_LEN
Definition: msdscsi.h:44
uint16_t TransferLength
Definition: msdscsi.h:243
#define SCSI_VERIFY10
Definition: msdscsi.h:41
void MSDD_StateChangeEvent(USBD_State_TypeDef oldState, USBD_State_TypeDef newState)
Called whenever the USB device has changed its device state.
Definition: msdd.c:410
uint32_t dCBWSignature
Definition: msdbot.h:54
SCSI interface for Mass Storage Devices (MSD).
SCSI Verify 10 Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:279
#define SCSI_READCAPACITY
Definition: msdscsi.h:38
Mass Storage class Device (MSD) driver.
#define SCSI_READ10_LEN
Definition: msdscsi.h:43
void GPIO_PinModeSet(GPIO_Port_TypeDef port, unsigned int pin, GPIO_Mode_TypeDef mode, unsigned int out)
Set the mode for a GPIO pin.
Definition: em_gpio.c:269
int MSDD_SetupCmd(const USB_Setup_TypeDef *setup)
Called whenever a USB setup command is received. This function overrides standard CLEAR_FEATURE comma...
Definition: msdd.c:319
General Purpose IO (GPIO) peripheral API.
SCSI Start Stop Unit Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:306
#define SCSI_STARTSTOP_UNIT
Definition: msdscsi.h:37
#define SCSI_READ10
Definition: msdscsi.h:39
#define MEDIA_BUFSIZ
Definition: msdd.h:32
uint8_t Lun
Definition: msdbot.h:71
#define SL_ATTRIBUTE_ALIGN(X)
GCC style macro for aligning a variable.
Definition: em_common.h:160
Definitions for the Bulk Only Transport protocol of USB Mass Storage devices.
uint8_t Obsolete
Definition: msdbot.h:62
SCSI Read 10 Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:225
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
#define SCSI_READCAPACITY_LEN
Definition: msdscsi.h:50
#define SCSI_REQUESTSENSE_LEN
Definition: msdscsi.h:48
bool MSDD_Handler(void)
Serve the MSD state machine. This function should be called on a regular basis from your main loop...
Definition: msdd.c:246
SCSI Request Sense Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:136
#define SCSI_READCAPACITYDATA_LEN
Definition: msdscsi.h:51
uint8_t Reserved1
Definition: msdbot.h:61
Bulk Only Transport (BOT) Command Block Wrapper (CBW) typedef.
Definition: msdbot.h:52
#define SCSI_INQUIRYDATA_LEN
Definition: msdscsi.h:46
uint8_t Direction
Definition: msdbot.h:63
SCSI Write 10 Command Descriptor Block (CDB) typedef.
Definition: msdscsi.h:252
Bulk Only Transport (BOT) Command Status Wrapper (CSW) typedef.
Definition: msdbot.h:93
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:137
#define SCSI_INQUIRY
Definition: msdscsi.h:36
#define SCSI_WRITE10
Definition: msdscsi.h:40
void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
Initialize MSD device.
Definition: msdd.c:203
#define SCSI_REQUESTSENSE
Definition: msdscsi.h:35
uint8_t Reserved2
Definition: msdbot.h:72
uint8_t Reserved3
Definition: msdbot.h:81
#define SCSI_VERIFY10_LEN
Definition: msdscsi.h:45
uint16_t AllocationLength
Definition: msdscsi.h:67
uint8_t CBWCB[16]
Definition: msdbot.h:85
uint16_t TransferLength
Definition: msdscsi.h:270