/** * \brief Device enumeration step 17 (LPM only) * Check LPM support through the BOS descriptor received * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step17_lpm( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { UNUSED(add); if (status == UHD_TRANS_STALL) { free(uhc_dev_enum->lpm_desc); uhc_dev_enum->lpm_desc = NULL; } else if ((status != UHD_TRANS_NOERROR) || (payload_trans < sizeof(usb_dev_lpm_desc_t)) || (uhc_dev_enum->lpm_desc->bos.bDescriptorType != USB_DT_BOS) || (payload_trans != le16_to_cpu(uhc_dev_enum->lpm_desc->bos.wTotalLength))) { uhc_enumeration_error((status==UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT:UHC_ENUM_FAIL); return; } else if (status == UHD_TRANS_NOERROR) { // Check LPM support if ((uhc_dev_enum->lpm_desc->capa_ext.bDescriptorType != USB_DT_DEVICE_CAPABILITY) || (uhc_dev_enum->lpm_desc->capa_ext.bDevCapabilityType != USB_DC_USB20_EXTENSION) || (!(uhc_dev_enum->lpm_desc->capa_ext.bmAttributes & (USB_DC_EXT_LPM)))) { free(uhc_dev_enum->lpm_desc); uhc_dev_enum->lpm_desc = NULL; } } uhc_enum_try = 0; UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_SUCCESS); }
/** * \brief Device enumeration step 15 * Enables UHI interfaces * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step15( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { UNUSED(add); if ((status!=UHD_TRANS_NOERROR) || (payload_trans!=0)) { for(uint8_t i = 0; i < UHC_NB_UHI; i++) { uhc_uhis[i].uninstall(uhc_dev_enum); } uhc_enumeration_error((status == UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT : UHC_ENUM_FAIL); return; } // Enable all UHIs supported for (uint8_t i = 0; i < UHC_NB_UHI; i++) { uhc_uhis[i].enable(uhc_dev_enum); } #ifdef USB_HOST_LPM_SUPPORT // Check LPM support if (g_uhc_device_root.dev_desc.bcdUSB >= LE16(USB_V2_1)) { // Device can support LPM // Start LPM support check uhc_enumeration_step16_lpm(); return; } uhc_dev_enum->lpm_desc = NULL; #endif uhc_enum_try = 0; UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_SUCCESS); }
/** * \brief Device enumeration step 15 * Enables UHI interfaces * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step15( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { UNUSED(add); if ((status!=UHD_TRANS_NOERROR) || (payload_trans!=0)) { for(uint8_t i = 0; i < UHC_NB_UHI; i++) { uhc_uhis[i].uninstall(uhc_dev_enum); } uhc_enumeration_error((status == UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT : UHC_ENUM_FAIL); return; } // Enable all UHIs supported for (uint8_t i = 0; i < UHC_NB_UHI; i++) { #if UHC_PRINT_DBG print_dbg("\r\n enabling UHI, idx: "); print_dbg_ulong(i); #endif uhc_uhis[i].enable(uhc_dev_enum); } uhc_enum_try = 0; UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_SUCCESS); }
/** * \brief Manage error during device enumeration * * \param status Enumeration error occurred */ static void uhc_enumeration_error(uhc_enum_status_t status) { if (status == UHC_ENUM_DISCONNECT) { uhc_enum_try = 0; return; // Abort enumeration process } uhd_ep_free(uhc_dev_enum->address, 0xFF); // Free USB configuration descriptor buffer if (uhc_dev_enum->conf_desc != NULL) { free(uhc_dev_enum->conf_desc); uhc_dev_enum->conf_desc = NULL; } uhc_dev_enum->address = 0; if (uhc_enum_try++ < UHC_ENUM_NB_TRY) { // Restart enumeration at beginning uhc_enumeration_step1(); return; } // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); UHC_ENUM_EVENT(uhc_dev_enum, status); uhc_enum_try = 0; }
/** * \brief Device enumeration step 14 * Enable USB configuration, if unless one USB interface is supported by UHIs. * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step14( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { usb_setup_req_t req; bool b_conf_supported = false; UNUSED(add); if ((status != UHD_TRANS_NOERROR) || (payload_trans < sizeof(usb_conf_desc_t)) || (uhc_dev_enum->conf_desc->bDescriptorType != USB_DT_CONFIGURATION) || (payload_trans != le16_to_cpu(uhc_dev_enum->conf_desc->wTotalLength))) { uhc_enumeration_error((status==UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT:UHC_ENUM_FAIL); return; } // Check if unless one USB interface is supported by UHIs for (uint8_t i = 0; i < UHC_NB_UHI; i++) { switch (uhc_uhis[i].install(uhc_dev_enum)) { case UHC_ENUM_SUCCESS: b_conf_supported = true; break; case UHC_ENUM_UNSUPPORTED: break; default: // USB host hardware limitation // Free all endpoints uhd_ep_free(UHC_DEVICE_ENUM_ADD,0xFF); UHC_ENUM_EVENT(uhc_dev_enum,UHC_ENUM_HARDWARE_LIMIT); // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); return; } } if (!b_conf_supported) { // No USB interface supported UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_UNSUPPORTED); // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); return; } // Enable device configuration req.bmRequestType = USB_REQ_RECIP_DEVICE | USB_REQ_TYPE_STANDARD | USB_REQ_DIR_OUT; req.bRequest = USB_REQ_SET_CONFIGURATION; req.wValue = uhc_dev_enum->conf_desc->bConfigurationValue; req.wIndex = 0; req.wLength = 0; if (!uhd_setup_request(UHC_DEVICE_ENUM_ADD, &req, NULL, 0, NULL, uhc_enumeration_step15)) { uhc_enumeration_error(UHC_ENUM_MEMORY_LIMIT); return; } }
/** * \brief Device enumeration step 13 * Requests a complete Get configuration descriptor. * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step13( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { uint8_t conf_num; uint16_t conf_size; uint16_t bus_power = 0; usb_setup_req_t req; UNUSED(add); if ((status != UHD_TRANS_NOERROR) || (payload_trans != sizeof(usb_conf_desc_t)) || (uhc_dev_enum->conf_desc->bDescriptorType != USB_DT_CONFIGURATION)) { uhc_enumeration_error((status == UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT:UHC_ENUM_FAIL); return; } #ifdef USB_HOST_HUB_SUPPORT uhc_device_t *dev; dev = uhc_dev_enum; while (1) { if (dev->conf_desc->bmAttributes & USB_CONFIG_ATTR_SELF_POWERED) { // The device or a parent HUB is SELF power, then no power on root break; } if (dev == (&g_uhc_device_root)) { bus_power = uhc_dev_enum->conf_desc->bMaxPower * 2; break; // End of USB tree } // Go to USB HUB parent dev = dev->hub; } #else if (!(uhc_dev_enum->conf_desc->bmAttributes &USB_CONFIG_ATTR_SELF_POWERED)) { bus_power = uhc_dev_enum->conf_desc->bMaxPower * 2; } #endif if ((bus_power + uhc_power_running) > USB_HOST_POWER_MAX) { // USB interfaces consumption too high UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_OVERCURRENT); // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); return; } #ifdef USB_HOST_HUB_SUPPORT uhc_dev_enum->power = bus_power; uhc_power_running += bus_power; #endif // Save information about USB configuration descriptor size conf_size = le16_to_cpu(uhc_dev_enum->conf_desc->wTotalLength); conf_num = uhc_dev_enum->conf_desc->bConfigurationValue; Assert(conf_num); // Re alloc USB configuration descriptor free(uhc_dev_enum->conf_desc); uhc_dev_enum->conf_desc = malloc(conf_size); if (uhc_dev_enum->conf_desc == NULL) { Assert(false); uhc_enumeration_error(UHC_ENUM_MEMORY_LIMIT); return; } // Send USB device descriptor request req.bmRequestType = USB_REQ_RECIP_DEVICE | USB_REQ_TYPE_STANDARD | USB_REQ_DIR_IN; req.bRequest = USB_REQ_GET_DESCRIPTOR; req.wValue = (USB_DT_CONFIGURATION << 8) | (conf_num - 1); req.wIndex = 0; req.wLength = conf_size; if (!uhd_setup_request(UHC_DEVICE_ENUM_ADD, &req, (uint8_t *) uhc_dev_enum->conf_desc, conf_size, NULL, uhc_enumeration_step14)) { uhc_enumeration_error(UHC_ENUM_MEMORY_LIMIT); return; } }
/** * \brief Device enumeration step 14 * Enable USB configuration, if unless one USB interface is supported by UHIs. * * \param add USB address of the setup request * \param status Transfer status * \param payload_trans Number of data transfered during DATA phase */ static void uhc_enumeration_step14( usb_add_t add, uhd_trans_status_t status, uint16_t payload_trans) { usb_setup_req_t req; bool b_conf_supported = false; UNUSED(add); ///////////////////////////////// ///// TESTING #if UHC_PRINT_DBG print_dbg("\r\n received device descriptor. "); print_dbg("\r\n address: "); print_dbg_hex(uhc_dev_enum -> address); print_dbg("\r\n speed: "); print_dbg_hex(uhc_dev_enum -> speed); print_dbg("\r\n\r\n"); print_dbg("\r\n dev desc -> bLength : "); print_dbg_hex(uhc_dev_enum->dev_desc.bLength); print_dbg("\r\n dev desc -> bDescriptorType : "); print_dbg_hex(uhc_dev_enum->dev_desc.bDescriptorType); print_dbg("\r\n dev desc -> bcdUSB : "); print_dbg_hex(uhc_dev_enum->dev_desc.bcdUSB); print_dbg("\r\n dev desc -> bDeviceClass : "); print_dbg_hex(uhc_dev_enum->dev_desc.bDeviceClass); print_dbg("\r\n dev desc -> bDeviceSubClass : "); print_dbg_hex(uhc_dev_enum->dev_desc.bDeviceSubClass); print_dbg("\r\n dev desc -> bDeviceProtocol : "); print_dbg_hex(uhc_dev_enum->dev_desc.bDeviceProtocol); print_dbg("\r\n dev desc -> bMaxPacketSize0 : "); print_dbg_hex(uhc_dev_enum->dev_desc.bMaxPacketSize0); print_dbg("\r\n dev desc -> idVendor : "); print_dbg_hex(uhc_dev_enum->dev_desc.idVendor); print_dbg("\r\n dev desc -> idProduct : "); print_dbg_hex(uhc_dev_enum->dev_desc.idProduct); print_dbg("\r\n dev desc -> bcdDevice : "); print_dbg_hex(uhc_dev_enum->dev_desc.bcdDevice); print_dbg("\r\n dev desc -> iManufacturer : "); print_dbg_hex(uhc_dev_enum->dev_desc.iManufacturer); print_dbg("\r\n dev desc -> iProduct : "); print_dbg_hex(uhc_dev_enum->dev_desc.iProduct); print_dbg("\r\n dev desc -> iSerialNumber : "); print_dbg_hex(uhc_dev_enum->dev_desc.iSerialNumber); print_dbg("\r\n dev desc -> bNumConfigurations : "); print_dbg_hex(uhc_dev_enum->dev_desc.bNumConfigurations); print_dbg("\r\n\r\n"); print_dbg("\r\n conf desc -> bLength : "); print_dbg_hex(uhc_dev_enum->conf_desc->bLength); print_dbg("\r\n conf desc -> bDescriptorType : "); print_dbg_hex(uhc_dev_enum->conf_desc->bDescriptorType); print_dbg("\r\n conf desc -> wTotalLength : "); print_dbg_hex(uhc_dev_enum->conf_desc->wTotalLength); print_dbg("\r\n conf desc -> bNumInterfaces : "); print_dbg_hex(uhc_dev_enum->conf_desc->bNumInterfaces); print_dbg("\r\n conf desc -> bConfigurationValue : "); print_dbg_hex(uhc_dev_enum->conf_desc->bConfigurationValue); print_dbg("\r\n conf desc -> iConfiguration : "); print_dbg_hex(uhc_dev_enum->conf_desc->iConfiguration); print_dbg("\r\n conf desc -> bmAttributes : "); print_dbg_hex(uhc_dev_enum->conf_desc->bmAttributes); print_dbg("\r\n conf desc -> bMaxPower : "); print_dbg_hex(uhc_dev_enum->conf_desc->bMaxPower); #endif ///////////////////////////////// ///////////////////////////////// if ((status != UHD_TRANS_NOERROR) || (payload_trans < sizeof(usb_conf_desc_t)) || (uhc_dev_enum->conf_desc->bDescriptorType != USB_DT_CONFIGURATION) || (payload_trans != le16_to_cpu(uhc_dev_enum->conf_desc->wTotalLength))) { uhc_enumeration_error((status==UHD_TRANS_DISCONNECT)? UHC_ENUM_DISCONNECT:UHC_ENUM_FAIL); return; } // Check if unless one USB interface is supported by UHIs for (uint8_t i = 0; i < UHC_NB_UHI; i++) { switch (uhc_uhis[i].install(uhc_dev_enum)) { case UHC_ENUM_SUCCESS: b_conf_supported = true; break; case UHC_ENUM_UNSUPPORTED: break; default: // USB host hardware limitation // Free all endpoints uhd_ep_free(UHC_DEVICE_ENUM_ADD,0xFF); UHC_ENUM_EVENT(uhc_dev_enum,UHC_ENUM_HARDWARE_LIMIT); // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); return; } } if (!b_conf_supported) { // No USB interface supported UHC_ENUM_EVENT(uhc_dev_enum, UHC_ENUM_UNSUPPORTED); // Abort enumeration, set line in suspend mode uhc_enumeration_suspend(); return; } // Enable device configuration req.bmRequestType = USB_REQ_RECIP_DEVICE | USB_REQ_TYPE_STANDARD | USB_REQ_DIR_OUT; req.bRequest = USB_REQ_SET_CONFIGURATION; req.wValue = uhc_dev_enum->conf_desc->bConfigurationValue; req.wIndex = 0; req.wLength = 0; // print_dbg("\r\n device enumeration successful; calling uhd_setup_request in uhc.c"); if (!uhd_setup_request(UHC_DEVICE_ENUM_ADD, &req, NULL, 0, NULL, uhc_enumeration_step15)) { uhc_enumeration_error(UHC_ENUM_MEMORY_LIMIT); return; } }