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   {
00089     /* Do one retry. */
00090     if (!MSDSCSI_Inquiry(&inquiryData))
00091       return false;
00092   }
00093 
00094   memcpy(usbDeviceInfo, &inquiryData.T10VendorId, sizeof(inquiryData.T10VendorId));
00095   usbDeviceInfo[ sizeof(inquiryData.T10VendorId) ] = '\0';
00096   USB_PRINTF("\nSCSI Inquiry Vendor ID string        : \"%s\"", usbDeviceInfo);
00097 
00098   memcpy(usbDeviceInfo, &inquiryData.ProductId, sizeof(inquiryData.ProductId));
00099   usbDeviceInfo[ sizeof(inquiryData.ProductId) ] = '\0';
00100   USB_PRINTF("\nSCSI Inquiry Product ID string       : \"%s\"", usbDeviceInfo);
00101 
00102   memcpy(usbDeviceInfo, &inquiryData.ProductRevisionLevel, sizeof(inquiryData.ProductRevisionLevel));
00103   usbDeviceInfo[ sizeof(inquiryData.ProductRevisionLevel) ] = '\0';
00104   USB_PRINTF("\nSCSI Inquiry Product Revision string : \"%s\"", usbDeviceInfo);
00105 
00106   /* Is it a block device ? */
00107   if ((inquiryData.PeripheralQualifier != 0) ||
00108       (inquiryData.PeripheralDeviceType != 0))
00109     return false;
00110 
00111   /* Wait for upto 5 seconds for device to become ready. */
00112   i = 0;
00113   do
00114   {
00115     result = MSDSCSI_RequestSense(&reqSenseData);
00116     ready  = MSDSCSI_TestUnitReady();
00117     if (!ready)
00118       USBTIMER_DelayMs(500);
00119     i++;
00120   } while (!ready && i < 10 && result);
00121 
00122   if (!result)
00123   {
00124     USB_PRINTF("\n\nSCSI Request Sense execution error");
00125     return false;
00126   }
00127 
00128   if (!ready)
00129   {
00130     USB_PRINTF("\n\nMSD device not ready");
00131     return false;
00132   }
00133 
00134   /* Get device capacity. */
00135   if (!MSDSCSI_ReadCapacity(&capacityData))
00136   {
00137     USB_PRINTF("\n\nSCSI Read Capacity execution error");
00138     return false;
00139   }
00140 
00141   USB_PRINTF("\n\nSCSI Read Capacity LBA count         : %ld = %ld MiB",
00142              capacityData.LogicalBlockAddress,
00143              (uint32_t)
00144              (((uint64_t)capacityData.LogicalBlockAddress
00145                * capacityData.LogicalBlockLength) / (1024 * 1024)));
00146   USB_PRINTF("\nSCSI Read Capacity LBA size          : %ld\n\n",
00147              capacityData.LogicalBlockLength);
00148 
00149   return true;
00150 }
00151 
00152 /***************************************************************************/
00162 bool MSDH_GetSectorCount(uint32_t *sectorCount)
00163 {
00164   EFM32_ALIGN(4)
00165   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00166 
00167   if (!MSDSCSI_ReadCapacity(&capacityData))
00168     return false;
00169 
00170   *sectorCount = capacityData.LogicalBlockAddress;
00171 
00172   return true;
00173 }
00174 
00175 /***************************************************************************/
00185 bool MSDH_GetSectorSize(uint16_t *sectorSize)
00186 {
00187   EFM32_ALIGN(4)
00188   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00189 
00190   if (!MSDSCSI_ReadCapacity(&capacityData))
00191     return false;
00192 
00193   *sectorSize = (uint16_t) capacityData.LogicalBlockLength;
00194 
00195   return true;
00196 }
00197 
00198 /***************************************************************************/
00211 bool MSDH_GetBlockSize(uint32_t *blockSize)
00212 {
00213   EFM32_ALIGN(4)
00214   MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4)));
00215 
00216   if (!MSDSCSI_ReadCapacity(&capacityData))
00217     return false;
00218 
00219   *blockSize = capacityData.LogicalBlockLength;
00220 
00221   return true;
00222 }
00223 
00224 /***************************************************************************/
00240 bool MSDH_ReadSectors(uint32_t lba, uint16_t sectors, void *data)
00241 {
00242   return MSDSCSI_Read10(lba, sectors, data);
00243 }
00244 
00245 /***************************************************************************/
00261 bool MSDH_WriteSectors(uint32_t lba, uint16_t sectors, const void *data)
00262 {
00263   return MSDSCSI_Write10(lba, sectors, data);
00264 }
00265 
00268 /***************************************************************************/
00279 static bool QualifyDevice(uint8_t *buf)
00280 {
00281   int  i;
00282   bool retVal = false;
00283   bool epIn   = false, epOut = false;
00284 
00285   if ((USBH_QGetDeviceDescriptor(buf)->bDeviceClass == 0) &&
00286       (USBH_QGetDeviceDescriptor(buf)->bDeviceSubClass == 0) &&
00287       (USBH_QGetDeviceDescriptor(buf)->bDeviceProtocol == 0) &&
00288       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceClass == USB_CLASS_MSD) &&
00289       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceSubClass == USB_CLASS_MSD_SCSI_CMDSET) &&
00290       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceProtocol == USB_CLASS_MSD_BOT_TRANSPORT) &&
00291       (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints >= 2))
00292   {
00293     /*
00294      * OK so far, scan through endpoints and look for one BULK IN and
00295      * one BULK OUT endpoint.
00296      */
00297     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00298     {
00299       if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bmAttributes == USB_EPTYPE_BULK)
00300       {
00301         if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bEndpointAddress & USB_EP_DIR_IN)
00302         {
00303           if (!epIn)
00304           {
00305             epIn      = true;
00306             epInIndex = i;
00307           }
00308         }
00309         else
00310         {
00311           if (!epOut)
00312           {
00313             epOut      = true;
00314             epOutIndex = i;
00315           }
00316         }
00317       }
00318 
00319       /* Success ? */
00320       if (epIn && epOut)
00321         break;
00322     }
00323 
00324     if ((epIn && epOut) && (epInIndex < 2) && (epOutIndex < 2))
00325     {
00326       /*
00327        * Some MSD devices has more than the two required bulk endpoints.
00328        * We will only accept devices where the two bulk endpoints are
00329        * the two first endpoints within the interface.
00330        */
00331       USB_PRINTF("\nThis is a valid MSD device.");
00332       retVal = true;
00333     }
00334   }
00335 
00336   if (retVal == false)
00337   {
00338     USBH_PrintDeviceDescriptor(USBH_QGetDeviceDescriptor(buf));
00339     USBH_PrintConfigurationDescriptor(USBH_QGetConfigurationDescriptor(buf, 0), USB_CONFIG_DESCSIZE);
00340     USBH_PrintInterfaceDescriptor(USBH_QGetInterfaceDescriptor(buf, 0, 0));
00341 
00342     for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++)
00343     {
00344       USBH_PrintEndpointDescriptor(USBH_QGetEndpointDescriptor(buf, 0, 0, i));
00345     }
00346     USB_PRINTF("\nThis is not a valid MSD device, review device descriptors.");
00347   }
00348   else
00349   {
00350     /* All set, activate the device. */
00351 
00352     USBH_InitDeviceData(&device, buf, ep, 2, USBH_GetPortSpeed());
00353     PrintDeviceStrings(buf);
00354     USBH_SetAddressB(&device, DEV_ADDR);
00355     USBH_SetConfigurationB(&device, device.confDesc.bConfigurationValue);
00356 
00357     /* Assign Host Channels to the endpoints */
00358     USBH_AssignHostChannel(BULK_OUT, 2);
00359     USBH_AssignHostChannel(BULK_IN, 3);
00360 
00361     USB_PRINTF("\n\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s",
00362                device.devDesc.idVendor, device.devDesc.idProduct,
00363                USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW");
00364   }
00365 
00366   return retVal;
00367 }
00368 
00369 /***************************************************************************/
00376 static void PrintDeviceStrings(uint8_t *buf)
00377 {
00378   /* Get and print device string descriptors. */
00379 
00380   if (device.devDesc.iManufacturer)
00381   {
00382     USBH_GetStringB(&device, buf, 255, device.devDesc.iManufacturer,
00383                     USB_LANGID_ENUS);
00384     USBH_PrintString("\n\niManufacturer = \"",
00385                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00386   }
00387   else
00388   {
00389     USB_PRINTF("\n\niManufacturer = <NONE>");
00390   }
00391 
00392   if (device.devDesc.iProduct)
00393   {
00394     USBH_GetStringB(&device, buf, 255, device.devDesc.iProduct,
00395                     USB_LANGID_ENUS);
00396     USBH_PrintString("\niProduct      = \"",
00397                      (USB_StringDescriptor_TypeDef*) buf, "\"");
00398   }
00399   else
00400   {
00401     USB_PRINTF("\niProduct      = <NONE>");
00402   }
00403 
00404   if (device.devDesc.iSerialNumber)
00405   {
00406     USBH_GetStringB(&device, buf, 255, device.devDesc.iSerialNumber,
00407                     USB_LANGID_ENUS);
00408     USBH_PrintString("\niSerialNumber = \"",
00409                      (USB_StringDescriptor_TypeDef*) buf, "\"\n");
00410   }
00411   else
00412   {
00413     USB_PRINTF("\niSerialNumber = <NONE>\n");
00414   }
00415 }
00416