EFM32 Zero Gecko Software Documentation  efm32zg-doc-4.2.1
msdh.c
Go to the documentation of this file.
1 /**************************************************************************/
17 #include <inttypes.h>
18 #include "em_device.h"
19 #include "em_usb.h"
20 #include "msdscsi.h"
21 
24 #define DEV_ADDR 1 /* USB bus address */
25 #define BULK_OUT &ep[ epOutIndex ] /* Endpoint "handles" */
26 #define BULK_IN &ep[ epInIndex ]
27 
28 static void PrintDeviceStrings(uint8_t *buf);
29 static bool QualifyDevice(uint8_t *buf);
30 
31 static USBH_Device_TypeDef device;
32 static USBH_Ep_TypeDef ep[ 2 ];
33 static int epOutIndex;
34 static int epInIndex;
35 
38 /***************************************************************************/
59 bool MSDH_Init(uint8_t *usbDeviceInfo, int usbDeviceInfoSize)
60 {
61  EFM32_ALIGN(4)
62  MSDSCSI_InquiryData_TypeDef inquiryData __attribute__ ((aligned(4)));
63 
64  EFM32_ALIGN(4)
65  MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
66 
67  EFM32_ALIGN(4)
68  MSDSCSI_RequestSenseData_TypeDef reqSenseData __attribute__ ((aligned(4)));
69 
70  bool ready;
71  int result, i;
72 
73  /* Read all device descriptors. */
74  if (USBH_QueryDeviceB(usbDeviceInfo, usbDeviceInfoSize, USBH_GetPortSpeed())
75  != USB_STATUS_OK)
76  {
77  USB_PRINTF("\nUSB descriptor retrieval failed.");
78  return false;
79  }
80 
81  /* Check if a valid MSD device (will activate device if OK). */
82  if (!QualifyDevice(usbDeviceInfo))
83  return false;
84 
85  /* Initialize MSD SCSI module. */
86  if (!MSDSCSI_Init(BULK_OUT, BULK_IN))
87  {
88  USB_PRINTF("\nMSD BOT initialization failed.");
89  return false;
90  }
91 
92  /* Do a SCSI Inquiry to get some info from the device. */
93  if (!MSDSCSI_Inquiry(&inquiryData))
94  {
95  /* Do one retry. */
96  if (!MSDSCSI_Inquiry(&inquiryData))
97  {
98  USB_PRINTF("\nMSD SCSI Inquiry failed.");
99  return false;
100  }
101  }
102 
103  memcpy(usbDeviceInfo, &inquiryData.T10VendorId, sizeof(inquiryData.T10VendorId));
104  usbDeviceInfo[ sizeof(inquiryData.T10VendorId) ] = '\0';
105  USB_PRINTF("\nSCSI Inquiry Vendor ID string : \"%s\"", usbDeviceInfo);
106 
107  memcpy(usbDeviceInfo, &inquiryData.ProductId, sizeof(inquiryData.ProductId));
108  usbDeviceInfo[ sizeof(inquiryData.ProductId) ] = '\0';
109  USB_PRINTF("\nSCSI Inquiry Product ID string : \"%s\"", usbDeviceInfo);
110 
111  memcpy(usbDeviceInfo, &inquiryData.ProductRevisionLevel, sizeof(inquiryData.ProductRevisionLevel));
112  usbDeviceInfo[ sizeof(inquiryData.ProductRevisionLevel) ] = '\0';
113  USB_PRINTF("\nSCSI Inquiry Product Revision string : \"%s\"", usbDeviceInfo);
114 
115  /* Is it a block device ? */
116  if ((inquiryData.PeripheralQualifier != 0) ||
117  (inquiryData.PeripheralDeviceType != 0))
118  return false;
119 
120  /* Wait for upto 5 seconds for device to become ready. */
121  i = 0;
122  do
123  {
124  result = MSDSCSI_RequestSense(&reqSenseData);
125  ready = MSDSCSI_TestUnitReady();
126  if (!ready)
127  USBTIMER_DelayMs(500);
128  i++;
129  } while (!ready && i < 10 && result);
130 
131  if (!result)
132  {
133  USB_PRINTF("\n\nSCSI Request Sense execution error");
134  return false;
135  }
136 
137  if (!ready)
138  {
139  USB_PRINTF("\n\nMSD device not ready");
140  return false;
141  }
142 
143  /* Get device capacity. */
144  if (!MSDSCSI_ReadCapacity(&capacityData))
145  {
146  USB_PRINTF("\n\nSCSI Read Capacity execution error");
147  return false;
148  }
149 
150  USB_PRINTF("\n\nSCSI Read Capacity LBA count : %ld = %ld MiB",
151  capacityData.LogicalBlockAddress,
152  (uint32_t)
153  (((uint64_t)capacityData.LogicalBlockAddress
154  * capacityData.LogicalBlockLength) / (1024 * 1024)));
155  USB_PRINTF("\nSCSI Read Capacity LBA size : %ld\n\n",
156  capacityData.LogicalBlockLength);
157 
158  return true;
159 }
160 
161 /***************************************************************************/
171 bool MSDH_GetSectorCount(uint32_t *sectorCount)
172 {
173  EFM32_ALIGN(4)
174  MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
175 
176  if (!MSDSCSI_ReadCapacity(&capacityData))
177  return false;
178 
179  *sectorCount = capacityData.LogicalBlockAddress;
180 
181  return true;
182 }
183 
184 /***************************************************************************/
194 bool MSDH_GetSectorSize(uint16_t *sectorSize)
195 {
196  EFM32_ALIGN(4)
197  MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
198 
199  if (!MSDSCSI_ReadCapacity(&capacityData))
200  return false;
201 
202  *sectorSize = (uint16_t) capacityData.LogicalBlockLength;
203 
204  return true;
205 }
206 
207 /***************************************************************************/
220 bool MSDH_GetBlockSize(uint32_t *blockSize)
221 {
222  EFM32_ALIGN(4)
223  MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
224 
225  if (!MSDSCSI_ReadCapacity(&capacityData))
226  return false;
227 
228  *blockSize = capacityData.LogicalBlockLength;
229 
230  return true;
231 }
232 
233 /***************************************************************************/
249 bool MSDH_ReadSectors(uint32_t lba, uint16_t sectors, void *data)
250 {
251  return MSDSCSI_Read10(lba, sectors, data);
252 }
253 
254 /***************************************************************************/
270 bool MSDH_WriteSectors(uint32_t lba, uint16_t sectors, const void *data)
271 {
272  return MSDSCSI_Write10(lba, sectors, data);
273 }
274 
277 /***************************************************************************/
288 static bool QualifyDevice(uint8_t *buf)
289 {
290  int i;
291  bool retVal = false;
292  bool epIn = false, epOut = false;
293 
294  if ((USBH_QGetDeviceDescriptor(buf)->bDeviceClass == 0) &&
295  (USBH_QGetDeviceDescriptor(buf)->bDeviceSubClass == 0) &&
296  (USBH_QGetDeviceDescriptor(buf)->bDeviceProtocol == 0) &&
297  (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceClass == USB_CLASS_MSD) &&
298  (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceSubClass == USB_CLASS_MSD_SCSI_CMDSET) &&
299  (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceProtocol == USB_CLASS_MSD_BOT_TRANSPORT) &&
300  (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints >= 2))
301  {
302  /*
303  * OK so far, scan through endpoints and look for one BULK IN and
304  * one BULK OUT endpoint.
305  */
306  for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
307  {
308  if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bmAttributes == USB_EPTYPE_BULK)
309  {
310  if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bEndpointAddress & USB_EP_DIR_IN)
311  {
312  if (!epIn)
313  {
314  epIn = true;
315  epInIndex = i;
316  }
317  }
318  else
319  {
320  if (!epOut)
321  {
322  epOut = true;
323  epOutIndex = i;
324  }
325  }
326  }
327 
328  /* Success ? */
329  if (epIn && epOut)
330  break;
331  }
332 
333  if ((epIn && epOut) && (epInIndex < 2) && (epOutIndex < 2))
334  {
335  /*
336  * Some MSD devices has more than the two required bulk endpoints.
337  * We will only accept devices where the two bulk endpoints are
338  * the two first endpoints within the interface.
339  */
340  USB_PRINTF("\nThis is a valid MSD device.");
341  retVal = true;
342  }
343  }
344 
345  if (retVal == false)
346  {
347  USBH_PrintDeviceDescriptor(USBH_QGetDeviceDescriptor(buf));
348  USBH_PrintConfigurationDescriptor(USBH_QGetConfigurationDescriptor(buf, 0), USB_CONFIG_DESCSIZE);
349  USBH_PrintInterfaceDescriptor(USBH_QGetInterfaceDescriptor(buf, 0, 0));
350 
351  for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
352  {
353  USBH_PrintEndpointDescriptor(USBH_QGetEndpointDescriptor(buf, 0, 0, i));
354  }
355  USB_PRINTF("\nThis is not a valid MSD device, review device descriptors.");
356  }
357  else
358  {
359  /* All set, activate the device. */
360 
361  USBH_InitDeviceData(&device, buf, ep, 2, USBH_GetPortSpeed());
362  PrintDeviceStrings(buf);
363  USBH_SetAddressB(&device, DEV_ADDR);
364  USBH_SetConfigurationB(&device, device.confDesc.bConfigurationValue);
365 
366  /* Assign Host Channels to the endpoints */
367  USBH_AssignHostChannel(BULK_OUT, 2);
368  USBH_AssignHostChannel(BULK_IN, 3);
369 
370  USB_PRINTF("\n\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s",
371  device.devDesc.idVendor, device.devDesc.idProduct,
372  USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW");
373  }
374 
375  return retVal;
376 }
377 
378 /***************************************************************************/
385 static void PrintDeviceStrings(uint8_t *buf)
386 {
387  /* Get and print device string descriptors. */
388 
389  if (device.devDesc.iManufacturer)
390  {
391  USBH_GetStringB(&device, buf, 255, device.devDesc.iManufacturer,
392  USB_LANGID_ENUS);
393  USBH_PrintString("\n\niManufacturer = \"",
394  (USB_StringDescriptor_TypeDef*) buf, "\"");
395  }
396  else
397  {
398  USB_PRINTF("\n\niManufacturer = <NONE>");
399  }
400 
401  if (device.devDesc.iProduct)
402  {
403  USBH_GetStringB(&device, buf, 255, device.devDesc.iProduct,
404  USB_LANGID_ENUS);
405  USBH_PrintString("\niProduct = \"",
406  (USB_StringDescriptor_TypeDef*) buf, "\"");
407  }
408  else
409  {
410  USB_PRINTF("\niProduct = <NONE>");
411  }
412 
413  if (device.devDesc.iSerialNumber)
414  {
415  USBH_GetStringB(&device, buf, 255, device.devDesc.iSerialNumber,
416  USB_LANGID_ENUS);
417  USBH_PrintString("\niSerialNumber = \"",
418  (USB_StringDescriptor_TypeDef*) buf, "\"\n");
419  }
420  else
421  {
422  USB_PRINTF("\niSerialNumber = <NONE>\n");
423  }
424 }
425 
bool MSDSCSI_TestUnitReady(void)
Issue a SCSI Test Unit Ready command.
Definition: msdscsi.c:283
SCSI Inquiry response data typedef.
Definition: msdscsi.h:76
bool MSDH_WriteSectors(uint32_t lba, uint16_t sectors, const void *data)
Write sectors to device.
Definition: msdh.c:270
SCSI Request Sense response data typedef.
Definition: msdscsi.h:155
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
bool MSDH_ReadSectors(uint32_t lba, uint16_t sectors, void *data)
Read sectors from device.
Definition: msdh.c:249
SCSI Read Capacity response data typedef.
Definition: msdscsi.h:214
bool MSDH_GetBlockSize(uint32_t *blockSize)
Get blocksize from the device.
Definition: msdh.c:220
bool MSDSCSI_Write10(uint32_t lba, uint16_t sectors, const void *data)
Perform a SCSI Write(10) command.
Definition: msdscsi.c:307
bool MSDH_GetSectorSize(uint16_t *sectorSize)
Get sectorsize from the device.
Definition: msdh.c:194
SCSI interface for Mass Storage Devices (MSD).
bool MSDH_Init(uint8_t *usbDeviceInfo, int usbDeviceInfoSize)
Initialize an USB connected Mass Storage Device. Checks if the device is a valid MSD device...
Definition: msdh.c:59
bool MSDSCSI_RequestSense(MSDSCSI_RequestSenseData_TypeDef *data)
Issue a SCSI Request Sense command.
Definition: msdscsi.c:267
bool MSDH_GetSectorCount(uint32_t *sectorCount)
Get sectorcount from the device.
Definition: msdh.c:171
#define EFM32_ALIGN(X)
Definition: em_common.h:103
bool MSDSCSI_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
MSDSCSI module initialization.
Definition: msdscsi.c:157
bool MSDSCSI_Read10(uint32_t lba, uint16_t sectors, void *data)
Issue a SCSI Read(10) command.
Definition: msdscsi.c:213
bool MSDSCSI_ReadCapacity(MSDSCSI_ReadCapacityData_TypeDef *data)
Issue a SCSI Read Capacity command.
Definition: msdscsi.c:240
bool MSDSCSI_Inquiry(MSDSCSI_InquiryData_TypeDef *data)
Issue a SCSI Inquiry command.
Definition: msdscsi.c:189