msdh.c

Go to the documentation of this file.
00001 /**************************************************************************/
00035 #include <inttypes.h>
00036 #include "em_device.h"
00037 #include "em_usb.h"
00038 #include "msdscsi.h"
00039 
00042 #define DEV_ADDR    1                 /* USB bus address    */
00043 #define BULK_OUT    &ep[ epOutIndex ] /* Endpoint "handles" */
00044 #define BULK_IN     &ep[ epInIndex  ]
00045 
00046 static void PrintDeviceStrings(uint8_t *buf);
00047 static bool QualifyDevice(uint8_t *buf);
00048 
00049 static USBH_Device_TypeDef device;
00050 static USBH_Ep_TypeDef     ep[ 2 ];
00051 static int                 epOutIndex;
00052 static int                 epInIndex;
00053 
00056 /***************************************************************************/
00077 bool MSDH_Init(uint8_t *usbDeviceInfo, int usbDeviceInfoSize)
00078 {
00079   EFM32_ALIGN(4)
00080   MSDSCSI_InquiryData_TypeDef inquiryData  __attribute__ ((aligned(4)));
00081 
00082   EFM32_ALIGN(4)
00083   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00084 
00085   EFM32_ALIGN(4)
00086   MSDSCSI_RequestSenseData_TypeDef reqSenseData __attribute__ ((aligned(4)));
00087 
00088   bool ready;
00089   int  result, i;
00090 
00091   /* Read all device descriptors. */
00092   if (USBH_QueryDeviceB(usbDeviceInfo, usbDeviceInfoSize, USBH_GetPortSpeed())
00093       != USB_STATUS_OK)
00094     return false;
00095 
00096   /* Check if a valid MSD device (will activate device if OK). */
00097   if (!QualifyDevice(usbDeviceInfo))
00098     return false;
00099 
00100   /* Initialize MSD SCSI module. */
00101   if (!MSDSCSI_Init(BULK_OUT, BULK_IN))
00102     return false;
00103 
00104   /* Do a SCSI Inquiry to get some info from the device. */
00105   if (!MSDSCSI_Inquiry(&inquiryData))
00106     return false;
00107 
00108   memcpy(usbDeviceInfo, &inquiryData.T10VendorId, sizeof(inquiryData.T10VendorId));
00109   usbDeviceInfo[ sizeof(inquiryData.T10VendorId) ] = '\0';
00110   USB_PRINTF("\nSCSI Inquiry Vendor ID string        : \"%s\"", usbDeviceInfo);
00111 
00112   memcpy(usbDeviceInfo, &inquiryData.ProductId, sizeof(inquiryData.ProductId));
00113   usbDeviceInfo[ sizeof(inquiryData.ProductId) ] = '\0';
00114   USB_PRINTF("\nSCSI Inquiry Product ID string       : \"%s\"", usbDeviceInfo);
00115 
00116   memcpy(usbDeviceInfo, &inquiryData.ProductRevisionLevel, sizeof(inquiryData.ProductRevisionLevel));
00117   usbDeviceInfo[ sizeof(inquiryData.ProductRevisionLevel) ] = '\0';
00118   USB_PRINTF("\nSCSI Inquiry Product Revision string : \"%s\"", usbDeviceInfo);
00119 
00120   /* Is it a block device ? */
00121   if ((inquiryData.PeripheralQualifier != 0) ||
00122       (inquiryData.PeripheralDeviceType != 0))
00123     return false;
00124 
00125   /* Wait for upto 5 seconds for device to become ready. */
00126   i = 0;
00127   do
00128   {
00129     result = MSDSCSI_RequestSense(&reqSenseData);
00130     ready  = MSDSCSI_TestUnitReady();
00131     if (!ready)
00132       USBTIMER_DelayMs(500);
00133     i++;
00134   } while (!ready && i < 10 && result);
00135 
00136   if (!result)
00137   {
00138     USB_PRINTF("\n\nSCSI Request Sense execution error");
00139     return false;
00140   }
00141 
00142   if (!ready)
00143   {
00144     USB_PRINTF("\n\nMSD device not ready");
00145     return false;
00146   }
00147 
00148   /* Get device capacity. */
00149   if (!MSDSCSI_ReadCapacity(&capacityData))
00150   {
00151     USB_PRINTF("\n\nSCSI Read Capacity execution error");
00152     return false;
00153   }
00154 
00155   USB_PRINTF("\n\nSCSI Read Capacity LBA count         : %ld = %ld MiB",
00156              capacityData.LogicalBlockAddress,
00157              (capacityData.LogicalBlockAddress * capacityData.LogicalBlockLength) / (1024 * 1024));
00158   USB_PRINTF("\nSCSI Read Capacity LBA size          : %ld\n\n", capacityData.LogicalBlockLength);
00159 
00160   return true;
00161 }
00162 
00163 /***************************************************************************/
00173 bool MSDH_GetSectorCount(uint32_t *sectorCount)
00174 {
00175   EFM32_ALIGN(4)
00176   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00177 
00178   if (!MSDSCSI_ReadCapacity(&capacityData))
00179     return false;
00180 
00181   *sectorCount = capacityData.LogicalBlockAddress;
00182 
00183   return true;
00184 }
00185 
00186 /***************************************************************************/
00196 bool MSDH_GetSectorSize(uint16_t *sectorSize)
00197 {
00198   EFM32_ALIGN(4)
00199   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00200 
00201   if (!MSDSCSI_ReadCapacity(&capacityData))
00202     return false;
00203 
00204   *sectorSize = (uint16_t) capacityData.LogicalBlockLength;
00205 
00206   return true;
00207 }
00208 
00209 /***************************************************************************/
00222 bool MSDH_GetBlockSize(uint32_t *blockSize)
00223 {
00224   EFM32_ALIGN(4)
00225   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00226 
00227   if (!MSDSCSI_ReadCapacity(&capacityData))
00228     return false;
00229 
00230   *blockSize = capacityData.LogicalBlockLength;
00231 
00232   return true;
00233 }
00234 
00235 /***************************************************************************/
00251 bool MSDH_ReadSectors(uint32_t lba, uint16_t sectors, void *data)
00252 {
00253   return MSDSCSI_Read10(lba, sectors, data);
00254 }
00255 
00256 /***************************************************************************/
00272 bool MSDH_WriteSectors(uint32_t lba, uint16_t sectors, const void *data)
00273 {
00274   return MSDSCSI_Write10(lba, sectors, data);
00275 }
00276 
00279 /***************************************************************************/
00290 static bool QualifyDevice(uint8_t *buf)
00291 {
00292   int  i;
00293   bool retVal = false;
00294   bool epIn   = false, epOut = false;
00295 
00296   if ((USBH_QGetDeviceDescriptor(buf)->bDeviceClass == 0) &&
00297       (USBH_QGetDeviceDescriptor(buf)->bDeviceSubClass == 0) &&
00298       (USBH_QGetDeviceDescriptor(buf)->bDeviceProtocol == 0) &&
00299       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceClass == USB_CLASS_MSD) &&
00300       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceSubClass == USB_CLASS_MSD_SCSI_CMDSET) &&
00301       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceProtocol == USB_CLASS_MSD_BOT_TRANSPORT) &&
00302       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints >= 2))
00303   {
00304     /*
00305      * OK so far, scan through endpoints and look for one BULK IN and
00306      * one BULK OUT endpoint.
00307      */
00308     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00309     {
00310       if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bmAttributes == USB_EPTYPE_BULK)
00311       {
00312         if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bEndpointAddress & USB_EP_DIR_IN)
00313         {
00314           if (!epIn)
00315           {
00316             epIn      = true;
00317             epInIndex = i;
00318           }
00319         }
00320         else
00321         {
00322           if (!epOut)
00323           {
00324             epOut      = true;
00325             epOutIndex = i;
00326           }
00327         }
00328       }
00329 
00330       /* Success ? */
00331       if (epIn && epOut)
00332         break;
00333     }
00334 
00335     if ((epIn && epOut) && (epInIndex < 2) && (epOutIndex < 2))
00336     {
00337       /*
00338        * Some MSD devices has more than the two required bulk endpoints.
00339        * We will only accept devices where the two bulk endpoints are
00340        * the two first endpoints within the interface.
00341        */
00342       USB_PRINTF("\nThis is a valid MSD device.");
00343       retVal = true;
00344     }
00345   }
00346 
00347   if (retVal == false)
00348   {
00349     USBH_PrintDeviceDescriptor(USBH_QGetDeviceDescriptor(buf));
00350     USBH_PrintConfigurationDescriptor(USBH_QGetConfigurationDescriptor(buf, 0), USB_CONFIG_DESCSIZE);
00351     USBH_PrintInterfaceDescriptor(USBH_QGetInterfaceDescriptor(buf, 0, 0));
00352 
00353     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00354     {
00355       USBH_PrintEndpointDescriptor(USBH_QGetEndpointDescriptor(buf, 0, 0, i));
00356     }
00357     USB_PRINTF("\nThis is not a valid MSD device, review device descriptors.");
00358   }
00359   else
00360   {
00361     /* All set, activate the device. */
00362 
00363     USBH_InitDeviceData(&device, buf, ep, 2, USBH_GetPortSpeed());
00364     USBH_SetAddressB(&device, DEV_ADDR);
00365     USBH_SetConfigurationB(&device, device.confDesc.bConfigurationValue);
00366 
00367     /* Assign Host Channels to the endpoints */
00368     USBH_AssignHostChannel(BULK_OUT, 2);
00369     USBH_AssignHostChannel(BULK_IN, 3);
00370 
00371     USB_PRINTF("\n\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s",
00372                device.devDesc.idVendor, device.devDesc.idProduct,
00373                USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW");
00374 
00375     PrintDeviceStrings(buf);
00376   }
00377 
00378   return retVal;
00379 }
00380 
00381 /***************************************************************************/
00388 static void PrintDeviceStrings(uint8_t *buf)
00389 {
00390   /* Get and print device string descriptors. */
00391 
00392   if (device.devDesc.iManufacturer)
00393   {
00394     USBH_GetStringB(&device, buf, 255, device.devDesc.iManufacturer,
00395                     USB_LANGID_ENUS);
00396     USBH_PrintString("\n\niManufacturer = \"",
00397                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00398   }
00399   else
00400   {
00401     USB_PRINTF("\n\niManufacturer = <NONE>");
00402   }
00403 
00404   if (device.devDesc.iProduct)
00405   {
00406     USBH_GetStringB(&device, buf, 255, device.devDesc.iProduct,
00407                     USB_LANGID_ENUS);
00408     USBH_PrintString("\niProduct      = \"",
00409                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00410   }
00411   else
00412   {
00413     USB_PRINTF("\niProduct      = <NONE>");
00414   }
00415 
00416   if (device.devDesc.iSerialNumber)
00417   {
00418     USBH_GetStringB(&device, buf, 255, device.devDesc.iSerialNumber,
00419                     USB_LANGID_ENUS);
00420     USBH_PrintString("\niSerialNumber = \"",
00421                      (USB_StringDescriptor_TypeDef*) buf, "\"\n");
00422   }
00423   else
00424   {
00425     USB_PRINTF("\niSerialNumber = <NONE>\n");
00426   }
00427 }
00428