msdh.c

Go to the documentation of this file.
00001 /**************************************************************************/
00017 #include <inttypes.h>
00018 #include "em_device.h"
00019 #include "em_usb.h"
00020 #include "msdscsi.h"
00021 
00024 #define DEV_ADDR    1                 /* USB bus address    */
00025 #define BULK_OUT    &ep[ epOutIndex ] /* Endpoint "handles" */
00026 #define BULK_IN     &ep[ epInIndex  ]
00027 
00028 static void PrintDeviceStrings(uint8_t *buf);
00029 static bool QualifyDevice(uint8_t *buf);
00030 
00031 static USBH_Device_TypeDef device;
00032 static USBH_Ep_TypeDef     ep[ 2 ];
00033 static int                 epOutIndex;
00034 static int                 epInIndex;
00035 
00038 /***************************************************************************/
00059 bool MSDH_Init(uint8_t *usbDeviceInfo, int usbDeviceInfoSize)
00060 {
00061   EFM32_ALIGN(4)
00062   MSDSCSI_InquiryData_TypeDef inquiryData  __attribute__ ((aligned(4)));
00063 
00064   EFM32_ALIGN(4)
00065   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00066 
00067   EFM32_ALIGN(4)
00068   MSDSCSI_RequestSenseData_TypeDef reqSenseData __attribute__ ((aligned(4)));
00069 
00070   bool ready;
00071   int  result, i;
00072 
00073   /* Read all device descriptors. */
00074   if (USBH_QueryDeviceB(usbDeviceInfo, usbDeviceInfoSize, USBH_GetPortSpeed())
00075       != USB_STATUS_OK)
00076     return false;
00077 
00078   /* Check if a valid MSD device (will activate device if OK). */
00079   if (!QualifyDevice(usbDeviceInfo))
00080     return false;
00081 
00082   /* Initialize MSD SCSI module. */
00083   if (!MSDSCSI_Init(BULK_OUT, BULK_IN))
00084     return false;
00085 
00086   /* Do a SCSI Inquiry to get some info from the device. */
00087   if (!MSDSCSI_Inquiry(&inquiryData))
00088     return false;
00089 
00090   memcpy(usbDeviceInfo, &inquiryData.T10VendorId, sizeof(inquiryData.T10VendorId));
00091   usbDeviceInfo[ sizeof(inquiryData.T10VendorId) ] = '\0';
00092   USB_PRINTF("\nSCSI Inquiry Vendor ID string        : \"%s\"", usbDeviceInfo);
00093 
00094   memcpy(usbDeviceInfo, &inquiryData.ProductId, sizeof(inquiryData.ProductId));
00095   usbDeviceInfo[ sizeof(inquiryData.ProductId) ] = '\0';
00096   USB_PRINTF("\nSCSI Inquiry Product ID string       : \"%s\"", usbDeviceInfo);
00097 
00098   memcpy(usbDeviceInfo, &inquiryData.ProductRevisionLevel, sizeof(inquiryData.ProductRevisionLevel));
00099   usbDeviceInfo[ sizeof(inquiryData.ProductRevisionLevel) ] = '\0';
00100   USB_PRINTF("\nSCSI Inquiry Product Revision string : \"%s\"", usbDeviceInfo);
00101 
00102   /* Is it a block device ? */
00103   if ((inquiryData.PeripheralQualifier != 0) ||
00104       (inquiryData.PeripheralDeviceType != 0))
00105     return false;
00106 
00107   /* Wait for upto 5 seconds for device to become ready. */
00108   i = 0;
00109   do
00110   {
00111     result = MSDSCSI_RequestSense(&reqSenseData);
00112     ready  = MSDSCSI_TestUnitReady();
00113     if (!ready)
00114       USBTIMER_DelayMs(500);
00115     i++;
00116   } while (!ready && i < 10 && result);
00117 
00118   if (!result)
00119   {
00120     USB_PRINTF("\n\nSCSI Request Sense execution error");
00121     return false;
00122   }
00123 
00124   if (!ready)
00125   {
00126     USB_PRINTF("\n\nMSD device not ready");
00127     return false;
00128   }
00129 
00130   /* Get device capacity. */
00131   if (!MSDSCSI_ReadCapacity(&capacityData))
00132   {
00133     USB_PRINTF("\n\nSCSI Read Capacity execution error");
00134     return false;
00135   }
00136 
00137   USB_PRINTF("\n\nSCSI Read Capacity LBA count         : %ld = %ld MiB",
00138              capacityData.LogicalBlockAddress,
00139              (capacityData.LogicalBlockAddress * capacityData.LogicalBlockLength) / (1024 * 1024));
00140   USB_PRINTF("\nSCSI Read Capacity LBA size          : %ld\n\n", capacityData.LogicalBlockLength);
00141 
00142   return true;
00143 }
00144 
00145 /***************************************************************************/
00155 bool MSDH_GetSectorCount(uint32_t *sectorCount)
00156 {
00157   EFM32_ALIGN(4)
00158   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00159 
00160   if (!MSDSCSI_ReadCapacity(&capacityData))
00161     return false;
00162 
00163   *sectorCount = capacityData.LogicalBlockAddress;
00164 
00165   return true;
00166 }
00167 
00168 /***************************************************************************/
00178 bool MSDH_GetSectorSize(uint16_t *sectorSize)
00179 {
00180   EFM32_ALIGN(4)
00181   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00182 
00183   if (!MSDSCSI_ReadCapacity(&capacityData))
00184     return false;
00185 
00186   *sectorSize = (uint16_t) capacityData.LogicalBlockLength;
00187 
00188   return true;
00189 }
00190 
00191 /***************************************************************************/
00204 bool MSDH_GetBlockSize(uint32_t *blockSize)
00205 {
00206   EFM32_ALIGN(4)
00207   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00208 
00209   if (!MSDSCSI_ReadCapacity(&capacityData))
00210     return false;
00211 
00212   *blockSize = capacityData.LogicalBlockLength;
00213 
00214   return true;
00215 }
00216 
00217 /***************************************************************************/
00233 bool MSDH_ReadSectors(uint32_t lba, uint16_t sectors, void *data)
00234 {
00235   return MSDSCSI_Read10(lba, sectors, data);
00236 }
00237 
00238 /***************************************************************************/
00254 bool MSDH_WriteSectors(uint32_t lba, uint16_t sectors, const void *data)
00255 {
00256   return MSDSCSI_Write10(lba, sectors, data);
00257 }
00258 
00261 /***************************************************************************/
00272 static bool QualifyDevice(uint8_t *buf)
00273 {
00274   int  i;
00275   bool retVal = false;
00276   bool epIn   = false, epOut = false;
00277 
00278   if ((USBH_QGetDeviceDescriptor(buf)->bDeviceClass == 0) &&
00279       (USBH_QGetDeviceDescriptor(buf)->bDeviceSubClass == 0) &&
00280       (USBH_QGetDeviceDescriptor(buf)->bDeviceProtocol == 0) &&
00281       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceClass == USB_CLASS_MSD) &&
00282       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceSubClass == USB_CLASS_MSD_SCSI_CMDSET) &&
00283       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceProtocol == USB_CLASS_MSD_BOT_TRANSPORT) &&
00284       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints >= 2))
00285   {
00286     /*
00287      * OK so far, scan through endpoints and look for one BULK IN and
00288      * one BULK OUT endpoint.
00289      */
00290     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00291     {
00292       if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bmAttributes == USB_EPTYPE_BULK)
00293       {
00294         if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bEndpointAddress & USB_EP_DIR_IN)
00295         {
00296           if (!epIn)
00297           {
00298             epIn      = true;
00299             epInIndex = i;
00300           }
00301         }
00302         else
00303         {
00304           if (!epOut)
00305           {
00306             epOut      = true;
00307             epOutIndex = i;
00308           }
00309         }
00310       }
00311 
00312       /* Success ? */
00313       if (epIn && epOut)
00314         break;
00315     }
00316 
00317     if ((epIn && epOut) && (epInIndex < 2) && (epOutIndex < 2))
00318     {
00319       /*
00320        * Some MSD devices has more than the two required bulk endpoints.
00321        * We will only accept devices where the two bulk endpoints are
00322        * the two first endpoints within the interface.
00323        */
00324       USB_PRINTF("\nThis is a valid MSD device.");
00325       retVal = true;
00326     }
00327   }
00328 
00329   if (retVal == false)
00330   {
00331     USBH_PrintDeviceDescriptor(USBH_QGetDeviceDescriptor(buf));
00332     USBH_PrintConfigurationDescriptor(USBH_QGetConfigurationDescriptor(buf, 0), USB_CONFIG_DESCSIZE);
00333     USBH_PrintInterfaceDescriptor(USBH_QGetInterfaceDescriptor(buf, 0, 0));
00334 
00335     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00336     {
00337       USBH_PrintEndpointDescriptor(USBH_QGetEndpointDescriptor(buf, 0, 0, i));
00338     }
00339     USB_PRINTF("\nThis is not a valid MSD device, review device descriptors.");
00340   }
00341   else
00342   {
00343     /* All set, activate the device. */
00344 
00345     USBH_InitDeviceData(&device, buf, ep, 2, USBH_GetPortSpeed());
00346     USBH_SetAddressB(&device, DEV_ADDR);
00347     USBH_SetConfigurationB(&device, device.confDesc.bConfigurationValue);
00348 
00349     /* Assign Host Channels to the endpoints */
00350     USBH_AssignHostChannel(BULK_OUT, 2);
00351     USBH_AssignHostChannel(BULK_IN, 3);
00352 
00353     USB_PRINTF("\n\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s",
00354                device.devDesc.idVendor, device.devDesc.idProduct,
00355                USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW");
00356 
00357     PrintDeviceStrings(buf);
00358   }
00359 
00360   return retVal;
00361 }
00362 
00363 /***************************************************************************/
00370 static void PrintDeviceStrings(uint8_t *buf)
00371 {
00372   /* Get and print device string descriptors. */
00373 
00374   if (device.devDesc.iManufacturer)
00375   {
00376     USBH_GetStringB(&device, buf, 255, device.devDesc.iManufacturer,
00377                     USB_LANGID_ENUS);
00378     USBH_PrintString("\n\niManufacturer = \"",
00379                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00380   }
00381   else
00382   {
00383     USB_PRINTF("\n\niManufacturer = <NONE>");
00384   }
00385 
00386   if (device.devDesc.iProduct)
00387   {
00388     USBH_GetStringB(&device, buf, 255, device.devDesc.iProduct,
00389                     USB_LANGID_ENUS);
00390     USBH_PrintString("\niProduct      = \"",
00391                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00392   }
00393   else
00394   {
00395     USB_PRINTF("\niProduct      = <NONE>");
00396   }
00397 
00398   if (device.devDesc.iSerialNumber)
00399   {
00400     USBH_GetStringB(&device, buf, 255, device.devDesc.iSerialNumber,
00401                     USB_LANGID_ENUS);
00402     USBH_PrintString("\niSerialNumber = \"",
00403                      (USB_StringDescriptor_TypeDef*) buf, "\"\n");
00404   }
00405   else
00406   {
00407     USB_PRINTF("\niSerialNumber = <NONE>\n");
00408   }
00409 }
00410