/***************************************************************************//** * @brief * Initialize an USB connected Mass Storage Device. * Checks if the device is a valid MSD device. Will perform all * necessary MSD initialization. * * @note * This function assumes that prior calls to USBH_Init() and * USBH_WaitForDeviceConnectionB() have been performed. * The contents of the usbDeviceInfo data buffer will be overwritten. * * @param[in] usbDeviceInfo * Pointer to USB enumeration information. usbDeviceInfo must have been * initialized by a prior call to USBH_WaitForDeviceConnectionB(). * * @param[in] usbDeviceInfoSize * The size of the usbDeviceInfo data buffer. * * @return * Returns true on success, false otherwise. ******************************************************************************/ bool MSDH_Init(uint8_t *usbDeviceInfo, int usbDeviceInfoSize) { EFM32_ALIGN(4) MSDSCSI_InquiryData_TypeDef inquiryData __attribute__ ((aligned(4))); EFM32_ALIGN(4) MSDSCSI_ReadCapacityData_TypeDef capacityData __attribute__ ((aligned(4))); EFM32_ALIGN(4) MSDSCSI_RequestSenseData_TypeDef reqSenseData __attribute__ ((aligned(4))); bool ready; int result, i; /* Read all device descriptors. */ if (USBH_QueryDeviceB(usbDeviceInfo, usbDeviceInfoSize, USBH_GetPortSpeed()) != USB_STATUS_OK) return false; /* Check if a valid MSD device (will activate device if OK). */ if (!QualifyDevice(usbDeviceInfo)) return false; /* Initialize MSD SCSI module. */ if (!MSDSCSI_Init(BULK_OUT, BULK_IN)) return false; /* Do a SCSI Inquiry to get some info from the device. */ if (!MSDSCSI_Inquiry(&inquiryData)) { /* Do one retry. */ if (!MSDSCSI_Inquiry(&inquiryData)) return false; } memcpy(usbDeviceInfo, &inquiryData.T10VendorId, sizeof(inquiryData.T10VendorId)); usbDeviceInfo[ sizeof(inquiryData.T10VendorId) ] = '\0'; USB_PRINTF("\nSCSI Inquiry Vendor ID string : \"%s\"", usbDeviceInfo); memcpy(usbDeviceInfo, &inquiryData.ProductId, sizeof(inquiryData.ProductId)); usbDeviceInfo[ sizeof(inquiryData.ProductId) ] = '\0'; USB_PRINTF("\nSCSI Inquiry Product ID string : \"%s\"", usbDeviceInfo); memcpy(usbDeviceInfo, &inquiryData.ProductRevisionLevel, sizeof(inquiryData.ProductRevisionLevel)); usbDeviceInfo[ sizeof(inquiryData.ProductRevisionLevel) ] = '\0'; USB_PRINTF("\nSCSI Inquiry Product Revision string : \"%s\"", usbDeviceInfo); /* Is it a block device ? */ if ((inquiryData.PeripheralQualifier != 0) || (inquiryData.PeripheralDeviceType != 0)) return false; /* Wait for upto 5 seconds for device to become ready. */ i = 0; do { result = MSDSCSI_RequestSense(&reqSenseData); ready = MSDSCSI_TestUnitReady(); if (!ready) USBTIMER_DelayMs(500); i++; } while (!ready && i < 10 && result); if (!result) { USB_PRINTF("\n\nSCSI Request Sense execution error"); return false; } if (!ready) { USB_PRINTF("\n\nMSD device not ready"); return false; } /* Get device capacity. */ if (!MSDSCSI_ReadCapacity(&capacityData)) { USB_PRINTF("\n\nSCSI Read Capacity execution error"); return false; } USB_PRINTF("\n\nSCSI Read Capacity LBA count : %ld = %ld MiB", capacityData.LogicalBlockAddress, (uint32_t) (((uint64_t)capacityData.LogicalBlockAddress * capacityData.LogicalBlockLength) / (1024 * 1024))); USB_PRINTF("\nSCSI Read Capacity LBA size : %ld\n\n", capacityData.LogicalBlockLength); return true; }
/**************************************************************************//** * @brief main - the entrypoint after reset. *****************************************************************************/ int main(void) { int connectionResult; USBH_Init_TypeDef is = USBH_INIT_DEFAULT; BSP_Init(BSP_INIT_DEFAULT); /* Initialize DK board register access */ /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); ConsoleDebugInit(); /* Initialize DK UART port. */ printf("\n\nEFM32 USB Host device enumeration example.\n"); USBH_Init(&is); /* Initialize USB HOST stack */ for (;;) { /* Wait for device connection */ printf("\nWaiting for USB device plug-in...\n"); /* Wait for maximum 10 seconds. */ connectionResult = USBH_WaitForDeviceConnectionB( tmpBuf, 10 ); if ( connectionResult == USB_STATUS_OK ) { printf("\nA device was attached...\n"); if (USBH_QueryDeviceB(tmpBuf, sizeof(tmpBuf), USBH_GetPortSpeed()) == USB_STATUS_OK) { USBH_InitDeviceData(&device, tmpBuf, NULL, 0, USBH_GetPortSpeed()); printf( "\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s", device.devDesc.idVendor, device.devDesc.idProduct, USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW" ); GetDeviceStrings(); } else { printf("\nDevice enumeration failure, please unplug device...\n"); } while ( USBH_DeviceConnected() ){} printf("\n\nDevice removal detected..."); } else if ( connectionResult == USB_STATUS_DEVICE_MALFUNCTION ) { printf("\nA malfunctioning device was attached, please remove...\n"); } else if ( connectionResult == USB_STATUS_PORT_OVERCURRENT ) { printf( "\nVBUS overcurrent condition, please remove device.\n" ); } else if ( connectionResult == USB_STATUS_TIMEOUT ) { printf("\nNo device was attached...\n"); } USBH_Stop(); } }
/***************************************************************************//** * @brief * Check if a device is a valid Mass Storage Device. * A valid device will be fully enumerated and activated. * * @param[in] buf * Enumeration data buffer. * * @return * Returns true if a valid MSD device, false otherwise. ******************************************************************************/ static bool QualifyDevice(uint8_t *buf) { int i; bool retVal = false; bool epIn = false, epOut = false; if ((USBH_QGetDeviceDescriptor(buf)->bDeviceClass == 0) && (USBH_QGetDeviceDescriptor(buf)->bDeviceSubClass == 0) && (USBH_QGetDeviceDescriptor(buf)->bDeviceProtocol == 0) && (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceClass == USB_CLASS_MSD) && (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceSubClass == USB_CLASS_MSD_SCSI_CMDSET) && (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bInterfaceProtocol == USB_CLASS_MSD_BOT_TRANSPORT) && (USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints >= 2)) { /* * OK so far, scan through endpoints and look for one BULK IN and * one BULK OUT endpoint. */ for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++) { if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bmAttributes == USB_EPTYPE_BULK) { if (USBH_QGetEndpointDescriptor(buf, 0, 0, i)->bEndpointAddress & USB_EP_DIR_IN) { if (!epIn) { epIn = true; epInIndex = i; } } else { if (!epOut) { epOut = true; epOutIndex = i; } } } /* Success ? */ if (epIn && epOut) break; } if ((epIn && epOut) && (epInIndex < 2) && (epOutIndex < 2)) { /* * Some MSD devices has more than the two required bulk endpoints. * We will only accept devices where the two bulk endpoints are * the two first endpoints within the interface. */ USB_PRINTF("\nThis is a valid MSD device."); retVal = true; } } if (retVal == false) { USBH_PrintDeviceDescriptor(USBH_QGetDeviceDescriptor(buf)); USBH_PrintConfigurationDescriptor(USBH_QGetConfigurationDescriptor(buf, 0), USB_CONFIG_DESCSIZE); USBH_PrintInterfaceDescriptor(USBH_QGetInterfaceDescriptor(buf, 0, 0)); for (i = 0; i < USBH_QGetInterfaceDescriptor(buf, 0, 0)->bNumEndpoints; i++) { USBH_PrintEndpointDescriptor(USBH_QGetEndpointDescriptor(buf, 0, 0, i)); } USB_PRINTF("\nThis is not a valid MSD device, review device descriptors."); } else { /* All set, activate the device. */ USBH_InitDeviceData(&device, buf, ep, 2, USBH_GetPortSpeed()); PrintDeviceStrings(buf); USBH_SetAddressB(&device, DEV_ADDR); USBH_SetConfigurationB(&device, device.confDesc.bConfigurationValue); /* Assign Host Channels to the endpoints */ USBH_AssignHostChannel(BULK_OUT, 2); USBH_AssignHostChannel(BULK_IN, 3); USB_PRINTF("\n\nDevice VID/PID is 0x%04X/0x%04X, device bus speed is %s", device.devDesc.idVendor, device.devDesc.idProduct, USBH_GetPortSpeed() == PORT_FULL_SPEED ? "FULL" : "LOW"); } return retVal; }