123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743 |
- /*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "usbh_core.h"
- #include "usbh_hub.h"
- #undef USB_DBG_TAG
- #define USB_DBG_TAG "usbh_hub"
- #include "usb_log.h"
- #define DEV_FORMAT "/dev/hub%d"
- #define HUB_DEBOUNCE_TIMEOUT 1500
- #define HUB_DEBOUNCE_STEP 25
- #define HUB_DEBOUNCE_STABLE 100
- #define DELAY_TIME_AFTER_RESET 200
- #define EXTHUB_FIRST_INDEX 2
- USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
- USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_BUS][CONFIG_USBHOST_MAX_EXTHUBS + 1][USB_ALIGN_UP(1, CONFIG_USB_ALIGN_SIZE)];
- extern int usbh_enumerate(struct usbh_hubport *hport);
- extern void usbh_hubport_release(struct usbh_hubport *hport);
- static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
- #if CONFIG_USBHOST_MAX_EXTHUBS > 0
- static struct usbh_hub g_hub_class[CONFIG_USBHOST_MAX_EXTHUBS];
- static uint32_t g_devinuse = 0;
- static struct usbh_hub *usbh_hub_class_alloc(void)
- {
- uint8_t devno;
- for (devno = 0; devno < CONFIG_USBHOST_MAX_EXTHUBS; devno++) {
- if ((g_devinuse & (1U << devno)) == 0) {
- g_devinuse |= (1U << devno);
- memset(&g_hub_class[devno], 0, sizeof(struct usbh_hub));
- g_hub_class[devno].index = EXTHUB_FIRST_INDEX + devno;
- return &g_hub_class[devno];
- }
- }
- return NULL;
- }
- static void usbh_hub_class_free(struct usbh_hub *hub_class)
- {
- uint8_t devno = hub_class->index - EXTHUB_FIRST_INDEX;
- if (devno < 32) {
- g_devinuse &= ~(1U << devno);
- }
- memset(hub_class, 0, sizeof(struct usbh_hub));
- }
- static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
- {
- struct usb_setup_packet *setup;
- int ret;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
- setup->wIndex = 0;
- setup->wLength = USB_SIZEOF_HUB_DESC;
- ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
- return ret;
- }
- memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_DESC);
- return ret;
- }
- static int _usbh_hub_get_hub_ss_descriptor(struct usbh_hub *hub, uint8_t *buffer)
- {
- struct usb_setup_packet *setup;
- int ret;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
- setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
- setup->wIndex = 0;
- setup->wLength = USB_SIZEOF_HUB_SS_DESC;
- ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
- return ret;
- }
- memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_SS_DESC);
- return ret;
- }
- #endif
- static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
- {
- struct usb_setup_packet *setup;
- int ret;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_GET_STATUS;
- setup->wValue = 0;
- setup->wIndex = port;
- setup->wLength = 4;
- ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
- return ret;
- }
- memcpy(port_status, g_hub_buf[hub->bus->busid], 4);
- return ret;
- }
- static int _usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
- {
- struct usb_setup_packet *setup;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_SET_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
- return usbh_control_transfer(hub->parent, setup, NULL);
- }
- static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
- {
- struct usb_setup_packet *setup;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
- return usbh_control_transfer(hub->parent, setup, NULL);
- }
- static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
- {
- struct usb_setup_packet *setup;
- setup = hub->parent->setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
- setup->wValue = depth;
- setup->wIndex = 0;
- setup->wLength = 0;
- return usbh_control_transfer(hub->parent, setup, NULL);
- }
- #if CONFIG_USBHOST_MAX_EXTHUBS > 0
- static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
- {
- (void)length;
- if (desc->bLength != USB_SIZEOF_HUB_DESC) {
- USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
- return -1;
- } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -2;
- } else {
- USB_LOG_RAW("Hub Descriptor:\r\n");
- USB_LOG_RAW("bLength: 0x%02x \r\n", desc->bLength);
- USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
- USB_LOG_RAW("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
- USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
- USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
- USB_LOG_RAW("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
- USB_LOG_RAW("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
- USB_LOG_RAW("PortPwrCtrlMask: 0x%02x \r\n", desc->PortPwrCtrlMask);
- }
- return 0;
- }
- static int parse_hub_ss_descriptor(struct usb_hub_ss_descriptor *desc, uint16_t length)
- {
- (void)length;
- if (desc->bLength < USB_SIZEOF_HUB_SS_DESC) {
- USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
- return -1;
- } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB3) {
- USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
- return -2;
- } else {
- USB_LOG_RAW("SuperSpeed Hub Descriptor:\r\n");
- USB_LOG_RAW("bLength: 0x%02x \r\n", desc->bLength);
- USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", desc->bDescriptorType);
- USB_LOG_RAW("bNbrPorts: 0x%02x \r\n", desc->bNbrPorts);
- USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
- USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x \r\n", desc->bPwrOn2PwrGood);
- USB_LOG_RAW("bHubContrCurrent: 0x%02x \r\n", desc->bHubContrCurrent);
- USB_LOG_RAW("DeviceRemovable: 0x%02x \r\n", desc->DeviceRemovable);
- }
- return 0;
- }
- #endif
- static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
- {
- struct usb_setup_packet roothub_setup;
- struct usb_setup_packet *setup;
- if (hub->is_roothub) {
- setup = &roothub_setup;
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_GET_STATUS;
- setup->wValue = 0;
- setup->wIndex = port;
- setup->wLength = 4;
- return usbh_roothub_control(hub->bus, &roothub_setup, (uint8_t *)port_status);
- } else {
- return _usbh_hub_get_portstatus(hub, port, port_status);
- }
- }
- int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
- {
- struct usb_setup_packet roothub_setup;
- struct usb_setup_packet *setup;
- if (hub->is_roothub) {
- setup = &roothub_setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_SET_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
- return usbh_roothub_control(hub->bus, setup, NULL);
- } else {
- return _usbh_hub_set_feature(hub, port, feature);
- }
- }
- int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
- {
- struct usb_setup_packet roothub_setup;
- struct usb_setup_packet *setup;
- if (hub->is_roothub) {
- setup = &roothub_setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
- setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
- setup->wValue = feature;
- setup->wIndex = port;
- setup->wLength = 0;
- return usbh_roothub_control(hub->bus, setup, NULL);
- } else {
- return _usbh_hub_clear_feature(hub, port, feature);
- }
- }
- static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
- {
- struct usb_setup_packet roothub_setup;
- struct usb_setup_packet *setup;
- if (hub->is_roothub) {
- setup = &roothub_setup;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
- setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
- setup->wValue = depth;
- setup->wIndex = 0;
- setup->wLength = 0;
- return usbh_roothub_control(hub->bus, setup, NULL);
- } else {
- return _usbh_hub_set_depth(hub, depth);
- }
- }
- #if CONFIG_USBHOST_MAX_EXTHUBS > 0
- static void hub_int_complete_callback(void *arg, int nbytes)
- {
- struct usbh_hub *hub = (struct usbh_hub *)arg;
- if (nbytes > 0) {
- usbh_hub_thread_wakeup(hub);
- } else if (nbytes == -USB_ERR_NAK) {
- /* Restart timer to submit urb again */
- USB_LOG_DBG("Restart timer\r\n");
- usb_osal_timer_start(hub->int_timer);
- } else {
- }
- }
- static void hub_int_timeout(void *arg)
- {
- struct usbh_hub *hub = (struct usbh_hub *)arg;
- usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
- usbh_submit_urb(&hub->intin_urb);
- }
- static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
- {
- struct usb_endpoint_descriptor *ep_desc;
- struct hub_port_status port_status;
- int ret;
- struct usbh_hub *hub = usbh_hub_class_alloc();
- if (hub == NULL) {
- USB_LOG_ERR("Fail to alloc hub_class\r\n");
- return -USB_ERR_NOMEM;
- }
- hub->hub_addr = hport->dev_addr;
- hub->parent = hport;
- hub->bus = hport->bus;
- hub->speed = hport->speed;
- hport->self = hub;
- hport->config.intf[intf].priv = hub;
- if (hport->depth > HUB_MAX_DEPTH) {
- USB_LOG_ERR("Hub depth(%d) is overflow\r\n", hport->depth);
- return -USB_ERR_INVAL;
- }
- /*
- * Super-Speed hubs need to know their depth to be able to
- * parse the bits of the route-string that correspond to
- * their downstream port number.
- *
- */
- if ((hport->depth != 0) && (hport->speed == USB_SPEED_SUPER)) {
- ret = usbh_hub_set_depth(hub, hport->depth - 1);
- if (ret < 0) {
- USB_LOG_ERR("Unable to set hub depth \r\n");
- return ret;
- }
- }
- /* Get hub descriptor. */
- if (hport->speed == USB_SPEED_SUPER) {
- ret = _usbh_hub_get_hub_ss_descriptor(hub, (uint8_t *)&hub->hub_ss_desc);
- if (ret < 0) {
- return ret;
- }
- parse_hub_ss_descriptor(&hub->hub_ss_desc, USB_SIZEOF_HUB_SS_DESC);
- hub->nports = hub->hub_ss_desc.bNbrPorts;
- hub->powerdelay = hub->hub_ss_desc.bPwrOn2PwrGood * 2;
- hub->tt_think = 0U;
- } else {
- ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
- if (ret < 0) {
- return ret;
- }
- parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
- hub->nports = hub->hub_desc.bNbrPorts;
- hub->powerdelay = hub->hub_desc.bPwrOn2PwrGood * 2;
- hub->tt_think = ((hub->hub_desc.wHubCharacteristics & HUB_CHAR_TTTT_MASK) >> 5);
- }
- for (uint8_t port = 0; port < hub->nports; port++) {
- hub->child[port].port = port + 1;
- hub->child[port].parent = hub;
- hub->child[port].bus = hport->bus;
- }
- if (hport->device_desc.bDeviceProtocol == HUB_PROTOCOL_MTT) {
- hub->ismtt = 1;
- } else {
- hub->ismtt = 0;
- }
- ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
- if (ep_desc->bEndpointAddress & 0x80) {
- USBH_EP_INIT(hub->intin, ep_desc);
- } else {
- return -1;
- }
- for (uint8_t port = 0; port < hub->nports; port++) {
- ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
- if (ret < 0) {
- return ret;
- }
- }
- usb_osal_msleep(hub->powerdelay);
- for (uint8_t port = 0; port < hub->nports; port++) {
- ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
- USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
- if (ret < 0) {
- return ret;
- }
- }
- hub->connected = true;
- snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hub->index);
- USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
- hub->int_buffer = g_hub_intbuf[hub->bus->busid][hub->index - 1];
- hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed), hub_int_timeout, hub, 0);
- if (hub->int_timer == NULL) {
- USB_LOG_ERR("No memory to alloc int_timer\r\n");
- return -USB_ERR_NOMEM;
- }
- usb_osal_timer_start(hub->int_timer);
- return 0;
- }
- static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
- {
- struct usbh_hubport *child;
- int ret = 0;
- struct usbh_hub *hub = (struct usbh_hub *)hport->config.intf[intf].priv;
- if (hub) {
- if (hub->intin) {
- usbh_kill_urb(&hub->intin_urb);
- }
- if (hub->int_timer) {
- usb_osal_timer_delete(hub->int_timer);
- }
- for (uint8_t port = 0; port < hub->nports; port++) {
- child = &hub->child[port];
- usbh_hubport_release(child);
- child->parent = NULL;
- }
- if (hport->config.intf[intf].devname[0] != '\0') {
- USB_LOG_INFO("Unregister HUB Class:%s\r\n", hport->config.intf[intf].devname);
- }
- usbh_hub_class_free(hub);
- }
- return ret;
- }
- #endif
- static void usbh_hub_events(struct usbh_hub *hub)
- {
- struct usbh_hubport *child;
- struct hub_port_status port_status;
- uint16_t portchange_index;
- uint16_t portstatus;
- uint16_t portchange;
- uint16_t mask;
- uint16_t feat;
- uint8_t speed;
- int ret;
- size_t flags;
- if (!hub->connected) {
- return;
- }
- flags = usb_osal_enter_critical_section();
- memcpy(&portchange_index, hub->int_buffer, 2);
- usb_osal_leave_critical_section(flags);
- for (uint8_t port = 0; port < hub->nports; port++) {
- USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
- if (!(portchange_index & (1 << (port + 1)))) {
- continue;
- }
- portchange_index &= ~(1 << (port + 1));
- USB_LOG_DBG("Port %d change\r\n", port + 1);
- /* Read hub port status */
- ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
- continue;
- }
- portstatus = port_status.wPortStatus;
- portchange = port_status.wPortChange;
- USB_LOG_DBG("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
- /* First, clear all change bits */
- mask = 1;
- feat = HUB_PORT_FEATURE_C_CONNECTION;
- while (portchange) {
- if (portchange & mask) {
- ret = usbh_hub_clear_feature(hub, port + 1, feat);
- if (ret < 0) {
- USB_LOG_ERR("Failed to clear port %u, change mask:%04x, errorcode:%d\r\n", port + 1, mask, ret);
- continue;
- }
- portchange &= (~mask);
- }
- mask <<= 1;
- feat++;
- }
- portchange = port_status.wPortChange;
- /* Second, if port changes, debounces first */
- if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
- uint16_t connection = 0;
- uint16_t debouncestable = 0;
- for (uint32_t debouncetime = 0; debouncetime < HUB_DEBOUNCE_TIMEOUT; debouncetime += HUB_DEBOUNCE_STEP) {
- /* Read hub port status */
- ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
- continue;
- }
- portstatus = port_status.wPortStatus;
- portchange = port_status.wPortChange;
- USB_LOG_DBG("Port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
- if (!(portchange & HUB_PORT_STATUS_C_CONNECTION) &&
- ((portstatus & HUB_PORT_STATUS_CONNECTION) == connection)) {
- debouncestable += HUB_DEBOUNCE_STEP;
- if (debouncestable >= HUB_DEBOUNCE_STABLE) {
- break;
- }
- } else {
- debouncestable = 0;
- connection = portstatus & HUB_PORT_STATUS_CONNECTION;
- }
- if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
- usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_CONNECTION);
- }
- usb_osal_msleep(HUB_DEBOUNCE_STEP);
- }
- /** check if debounce ok */
- if (debouncestable < HUB_DEBOUNCE_STABLE) {
- USB_LOG_ERR("Failed to debounce port %u\r\n", port + 1);
- break;
- }
- /* Last, check connect status */
- if (portstatus & HUB_PORT_STATUS_CONNECTION) {
- ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_RESET);
- if (ret < 0) {
- USB_LOG_ERR("Failed to reset port %u,errorcode:%d\r\n", port, ret);
- continue;
- }
- usb_osal_msleep(DELAY_TIME_AFTER_RESET);
- /* Read hub port status */
- ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
- if (ret < 0) {
- USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
- continue;
- }
- portstatus = port_status.wPortStatus;
- portchange = port_status.wPortChange;
- if (!(portstatus & HUB_PORT_STATUS_RESET) && (portstatus & HUB_PORT_STATUS_ENABLE)) {
- if (portchange & HUB_PORT_STATUS_C_RESET) {
- ret = usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_RESET);
- if (ret < 0) {
- USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port, ret);
- }
- }
- /*
- * Figure out device speed. This is a bit tricky because
- * HUB_PORT_STATUS_POWER_SS and HUB_PORT_STATUS_LOW_SPEED share the same bit.
- */
- if (portstatus & HUB_PORT_STATUS_POWER) {
- if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
- speed = USB_SPEED_HIGH;
- } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
- speed = USB_SPEED_LOW;
- } else {
- speed = USB_SPEED_FULL;
- }
- } else if (portstatus & HUB_PORT_STATUS_POWER_SS) {
- speed = USB_SPEED_SUPER;
- } else {
- USB_LOG_WRN("Port %u does not enable power\r\n", port + 1);
- continue;
- }
- child = &hub->child[port];
- /** release child sources first */
- usbh_hubport_release(child);
- memset(child, 0, sizeof(struct usbh_hubport));
- child->parent = hub;
- child->depth = (hub->parent ? hub->parent->depth : 0) + 1;
- child->connected = true;
- child->port = port + 1;
- child->speed = speed;
- child->bus = hub->bus;
- child->mutex = usb_osal_mutex_create();
- USB_LOG_INFO("New %s device on Bus %u, Hub %u, Port %u connected\r\n", speed_table[speed], hub->bus->busid, hub->index, port + 1);
- if (usbh_enumerate(child) < 0) {
- /** release child sources */
- usbh_hubport_release(child);
- USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
- }
- } else {
- child = &hub->child[port];
- /** release child sources */
- usbh_hubport_release(child);
- /** some USB 3.0 ip may failed to enable USB 2.0 port for USB 3.0 device */
- USB_LOG_WRN("Failed to enable port %u\r\n", port + 1);
- continue;
- }
- } else {
- child = &hub->child[port];
- /** release child sources */
- usbh_hubport_release(child);
- USB_LOG_INFO("Device on Bus %u, Hub %u, Port %u disconnected\r\n", hub->bus->busid, hub->index, port + 1);
- }
- }
- }
- /* Start next hub int transfer */
- if (!hub->is_roothub && hub->connected) {
- usb_osal_timer_start(hub->int_timer);
- }
- }
- static void usbh_hub_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
- {
- struct usbh_hub *hub;
- int ret = 0;
- struct usbh_bus *bus = (struct usbh_bus *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
- usb_hc_init(bus);
- while (1) {
- ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
- if (ret < 0) {
- continue;
- }
- usbh_hub_events(hub);
- }
- }
- void usbh_hub_thread_wakeup(struct usbh_hub *hub)
- {
- usb_osal_mq_send(hub->bus->hub_mq, (uintptr_t)hub);
- }
- int usbh_hub_initialize(struct usbh_bus *bus)
- {
- char thread_name[32] = { 0 };
- struct usbh_hub *hub;
- hub = &bus->hcd.roothub;
- hub->connected = true;
- hub->index = 1;
- hub->is_roothub = true;
- hub->parent = NULL;
- hub->hub_addr = 1;
- hub->nports = CONFIG_USBHOST_MAX_RHPORTS;
- hub->int_buffer = bus->hcd.roothub_intbuf;
- hub->bus = bus;
- bus->hub_mq = usb_osal_mq_create(7);
- if (bus->hub_mq == NULL) {
- USB_LOG_ERR("Failed to create hub mq\r\n");
- return -1;
- }
- snprintf(thread_name, 32, "usbh_hub%u", bus->busid);
- bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus);
- if (bus->hub_thread == NULL) {
- USB_LOG_ERR("Failed to create hub thread\r\n");
- return -1;
- }
- return 0;
- }
- int usbh_hub_deinitialize(struct usbh_bus *bus)
- {
- struct usbh_hubport *hport;
- struct usbh_hub *hub;
- size_t flags;
- flags = usb_osal_enter_critical_section();
- hub = &bus->hcd.roothub;
- for (uint8_t port = 0; port < hub->nports; port++) {
- hport = &hub->child[port];
- usbh_hubport_release(hport);
- }
- usb_hc_deinit(bus);
- usb_osal_leave_critical_section(flags);
- usb_osal_mq_delete(bus->hub_mq);
- usb_osal_thread_delete(bus->hub_thread);
- return 0;
- }
- #if CONFIG_USBHOST_MAX_EXTHUBS > 0
- const struct usbh_class_driver hub_class_driver = {
- .driver_name = "hub",
- .connect = usbh_hub_connect,
- .disconnect = usbh_hub_disconnect
- };
- CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
- .match_flags = USB_CLASS_MATCH_INTF_CLASS,
- .bInterfaceClass = USB_DEVICE_CLASS_HUB,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .id_table = NULL,
- .class_driver = &hub_class_driver
- };
- #endif
|