Files
CherryUSB/class/hub/usbh_hub.c

619 lines
20 KiB
C
Raw Normal View History

/*
* Copyright (c) 2022, sakumisu
2022-02-08 11:44:46 +08:00
*
* SPDX-License-Identifier: Apache-2.0
2022-02-08 11:44:46 +08:00
*/
#include "usbh_hub.h"
#define DEV_FORMAT "/dev/hub%d"
2022-02-08 11:44:46 +08:00
2022-12-31 14:06:53 +08:00
#define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 100
#define DELAY_TIME_AFTER_RESET 200
2022-09-12 13:00:45 +08:00
#define EXTHUB_FIRST_INDEX 2
2022-09-11 23:03:23 +08:00
2022-02-08 11:44:46 +08:00
static uint32_t g_devinuse = 0;
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[32];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_EXTHUBS + 1][1];
2022-02-08 11:44:46 +08:00
usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
usb_osal_thread_t hub_thread;
usb_osal_mq_t hub_mq;
2022-02-08 11:44:46 +08:00
struct usbh_hub roothub;
2022-02-08 11:44:46 +08:00
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
struct usbh_hub exthub[CONFIG_USBHOST_MAX_EXTHUBS];
#endif
extern int usbh_hport_activate_ep0(struct usbh_hubport *hport);
extern int usbh_hport_deactivate_ep0(struct usbh_hubport *hport);
extern int usbh_enumerate(struct usbh_hubport *hport);
static void usbh_hub_thread_wakeup(struct usbh_hub *hub);
2022-02-08 11:44:46 +08:00
2022-09-23 21:58:36 +08:00
static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
2022-02-08 11:44:46 +08:00
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
2022-09-11 23:03:23 +08:00
static int usbh_hub_devno_alloc(void)
2022-02-08 11:44:46 +08:00
{
int devno;
2022-09-11 23:03:23 +08:00
for (devno = EXTHUB_FIRST_INDEX; devno < 32; devno++) {
2022-02-08 11:44:46 +08:00
uint32_t bitno = 1 << devno;
if ((g_devinuse & bitno) == 0) {
g_devinuse |= bitno;
2022-09-11 23:03:23 +08:00
return devno;
2022-02-08 11:44:46 +08:00
}
}
return -EMFILE;
}
static void usbh_hub_devno_free(uint8_t devno)
2022-02-08 11:44:46 +08:00
{
2022-09-11 23:03:23 +08:00
if (devno >= EXTHUB_FIRST_INDEX && devno < 32) {
2022-02-08 11:44:46 +08:00
g_devinuse &= ~(1 << devno);
}
}
2023-01-10 15:01:50 +08:00
#endif
static void usbh_hub_register(struct usbh_hub *hub)
{
usb_slist_add_tail(&hub_class_head, &hub->list);
}
static void usbh_hub_unregister(struct usbh_hub *hub)
{
usb_slist_remove(&hub_class_head, &hub->list);
}
static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
2022-02-08 11:44:46 +08:00
{
struct usb_setup_packet *setup;
int ret;
2022-02-08 11:44:46 +08:00
setup = hub->parent->setup;
2022-02-08 11:44:46 +08:00
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->ep0, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
memcpy(buffer, g_hub_buf, USB_SIZEOF_HUB_DESC);
return ret;
2022-02-08 11:44:46 +08:00
}
static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
2022-02-08 11:44:46 +08:00
{
struct usb_setup_packet *setup;
int ret;
2022-02-08 11:44:46 +08:00
setup = hub->parent->setup;
2022-02-08 11:44:46 +08:00
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = HUB_REQUEST_GET_STATUS;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 2;
ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
memcpy(buffer, g_hub_buf, 2);
return ret;
2022-02-08 11:44:46 +08:00
}
static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
2022-02-08 11:44:46 +08:00
{
struct usb_setup_packet *setup;
int ret;
2022-02-08 11:44:46 +08:00
setup = hub->parent->setup;
2022-02-08 11:44:46 +08:00
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->ep0, setup, g_hub_buf);
if (ret < 0) {
return ret;
}
memcpy(port_status, g_hub_buf, 4);
return ret;
2022-02-08 11:44:46 +08:00
}
static int _usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
2022-02-08 11:44:46 +08:00
{
struct usb_setup_packet *setup;
setup = hub->parent->setup;
2022-02-08 11:44:46 +08:00
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->ep0, setup, NULL);
2022-02-08 11:44:46 +08:00
}
static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
2022-02-08 11:44:46 +08:00
{
struct usb_setup_packet *setup;
setup = hub->parent->setup;
2022-02-08 11:44:46 +08:00
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->ep0, setup, NULL);
2022-02-08 11:44:46 +08:00
}
static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t 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 {
2022-09-11 23:03:23 +08:00
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);
2022-02-08 11:44:46 +08:00
}
return 0;
}
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(&roothub_setup, (uint8_t *)port_status);
} else {
return _usbh_hub_get_portstatus(hub, port, port_status);
}
}
static 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(setup, NULL);
} else {
return _usbh_hub_set_feature(hub, port, feature);
}
}
static 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(setup, NULL);
} else {
return _usbh_hub_clear_feature(hub, port, feature);
}
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
2022-09-09 22:18:02 +08:00
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);
}
}
static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
2022-02-08 11:44:46 +08:00
{
struct usb_endpoint_descriptor *ep_desc;
struct hub_port_status port_status;
2022-02-08 11:44:46 +08:00
int ret;
2022-09-11 23:03:23 +08:00
int index;
2022-02-08 11:44:46 +08:00
2022-09-11 23:03:23 +08:00
index = usbh_hub_devno_alloc();
if (index > (CONFIG_USBHOST_MAX_EXTHUBS + EXTHUB_FIRST_INDEX - 1)) {
USB_LOG_ERR("No memory to alloc hub class\r\n");
usbh_hub_devno_free(index);
2022-02-08 11:44:46 +08:00
return -ENOMEM;
}
2022-09-11 23:03:23 +08:00
struct usbh_hub *hub = &exthub[index - EXTHUB_FIRST_INDEX];
memset(hub, 0, sizeof(struct usbh_hub));
hub->hub_addr = hport->dev_addr;
hub->parent = hport;
2022-09-11 23:03:23 +08:00
hub->index = index;
hport->config.intf[intf].priv = hub;
2022-02-08 11:44:46 +08:00
ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
if (ret < 0) {
2022-02-08 11:44:46 +08:00
return ret;
}
parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
2022-02-08 11:44:46 +08:00
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
hub->child[port].port = port + 1;
hub->child[port].parent = hub;
2022-02-08 11:44:46 +08:00
}
2022-09-14 19:50:06 +08:00
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
2022-02-08 11:44:46 +08:00
if (ep_desc->bEndpointAddress & 0x80) {
2022-09-14 19:50:06 +08:00
usbh_hport_activate_epx(&hub->intin, hport, ep_desc);
2022-02-08 11:44:46 +08:00
} else {
return -1;
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
2022-09-11 22:43:51 +08:00
ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
return ret;
}
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
2022-09-11 23:03:23 +08:00
USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
return ret;
}
}
2022-09-09 22:18:02 +08:00
hub->connected = true;
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hub->index);
usbh_hub_register(hub);
USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
2022-02-08 11:44:46 +08:00
hub->int_buffer = g_hub_intbuf[hub->index - 1];
2022-09-15 20:46:14 +08:00
usbh_int_urb_fill(&hub->intin_urb, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
usbh_submit_urb(&hub->intin_urb);
2022-02-08 11:44:46 +08:00
return 0;
}
static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
2022-02-08 11:44:46 +08:00
{
struct usbh_hubport *child;
int ret = 0;
struct usbh_hub *hub = (struct usbh_hub *)hport->config.intf[intf].priv;
2022-02-08 11:44:46 +08:00
if (hub) {
usbh_hub_devno_free(hub->index);
2022-02-08 11:44:46 +08:00
if (hub->intin) {
usbh_pipe_free(hub->intin);
2022-02-08 11:44:46 +08:00
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
child = &hub->child[port];
usbh_hport_deactivate_ep0(child);
2022-02-08 11:44:46 +08:00
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
2022-12-30 20:57:54 +08:00
CLASS_DISCONNECT(child, i);
2022-02-08 11:44:46 +08:00
}
}
child->config.config_desc.bNumInterfaces = 0;
child->parent = NULL;
}
usbh_hub_unregister(hub);
memset(hub, 0, sizeof(struct usbh_hub));
2022-02-08 11:44:46 +08:00
if (hport->config.intf[intf].devname[0] != '\0')
USB_LOG_INFO("Unregister HUB Class:%s\r\n", hport->config.intf[intf].devname);
2022-02-08 11:44:46 +08:00
}
return ret;
}
#endif
2022-12-31 14:06:53 +08:00
static void usbh_hubport_release(struct usbh_hubport *child)
{
if (child->connected) {
child->connected = false;
usbh_hport_deactivate_ep0(child);
for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
CLASS_DISCONNECT(child, i);
}
}
child->config.config_desc.bNumInterfaces = 0;
}
}
static void usbh_hub_events(struct usbh_hub *hub)
{
struct usbh_hubport *child;
struct hub_port_status port_status;
uint8_t portchange_index;
uint16_t portstatus;
uint16_t portchange;
2022-02-08 11:44:46 +08:00
uint16_t mask;
uint16_t feat;
uint8_t speed;
2022-02-08 11:44:46 +08:00
int ret;
if (!hub->connected) {
2022-02-08 11:44:46 +08:00
return;
}
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
portchange_index = hub->int_buffer[0];
USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
2022-02-08 11:44:46 +08:00
if (!(portchange_index & (1 << (port + 1)))) {
2022-02-08 11:44:46 +08:00
continue;
}
portchange_index &= ~(1 << (port + 1));
USB_LOG_DBG("Port %d change\r\n", port + 1);
2022-02-08 11:44:46 +08:00
/* Read hub port status */
ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
2022-02-08 11:44:46 +08:00
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);
2022-02-08 11:44:46 +08:00
/* 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);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
USB_LOG_ERR("Failed to clear port %u, change mask:%04x, errorcode:%d\r\n", port + 1, mask, ret);
continue;
2022-02-08 11:44:46 +08:00
}
portchange &= (~mask);
2022-02-08 11:44:46 +08:00
}
mask <<= 1;
feat++;
}
portchange = port_status.wPortChange;
2022-02-08 11:44:46 +08:00
/* Second, if port changes, debounces first */
if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
uint16_t connection = 0;
uint16_t debouncestable = 0;
2022-12-31 14:06:53 +08:00
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);
2022-12-31 14:06:53 +08:00
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;
2022-12-31 14:06:53 +08:00
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);
}
2022-12-31 14:06:53 +08:00
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;
2022-02-08 11:44:46 +08:00
}
/* Last, check connect status */
if (portstatus & HUB_PORT_STATUS_CONNECTION) {
ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_RESET);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
USB_LOG_ERR("Failed to reset port %u,errorcode:%d\r\n", port, ret);
2022-02-08 11:44:46 +08:00
continue;
}
usb_osal_msleep(DELAY_TIME_AFTER_RESET);
/* Read hub port status */
ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
2022-02-08 11:44:46 +08:00
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);
2022-02-08 11:44:46 +08:00
if (ret < 0) {
USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port, ret);
2022-02-08 11:44:46 +08:00
}
}
if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
speed = USB_SPEED_HIGH;
} else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
speed = USB_SPEED_LOW;
2022-02-08 11:44:46 +08:00
} else {
speed = USB_SPEED_FULL;
2022-02-08 11:44:46 +08:00
}
child = &hub->child[port];
2022-12-31 14:06:53 +08:00
/** release child sources first */
usbh_hubport_release(child);
memset(child, 0, sizeof(struct usbh_hubport));
child->parent = hub;
child->connected = true;
child->port = port + 1;
child->speed = speed;
2023-02-23 17:53:42 +08:00
USB_LOG_INFO("New %s device on Hub %u, Port %u connected\r\n", speed_table[speed], hub->index, port + 1);
2023-02-23 17:53:42 +08:00
/* Configure EP0 with the default maximum packet size */
usbh_hport_activate_ep0(child);
if (usbh_enumerate(child) < 0) {
2023-02-23 17:53:42 +08:00
/** release child sources */
usbh_hubport_release(child);
USB_LOG_ERR("Port %u enumerate fail\r\n", port + 1);
}
2022-02-08 11:44:46 +08:00
} else {
2022-12-30 20:57:54 +08:00
child = &hub->child[port];
2022-12-31 14:06:53 +08:00
/** release child sources */
usbh_hubport_release(child);
2023-02-23 17:53:42 +08:00
USB_LOG_ERR("Failed to enable port %u\r\n", port + 1);
2022-12-31 14:06:53 +08:00
2022-02-08 11:44:46 +08:00
continue;
}
} else {
child = &hub->child[port];
2022-12-31 14:06:53 +08:00
/** release child sources */
usbh_hubport_release(child);
2023-02-23 17:53:42 +08:00
USB_LOG_INFO("Device on Hub %u, Port %u disconnected\r\n", hub->index, port + 1);
2022-02-08 11:44:46 +08:00
}
}
}
hub->int_buffer[0] = 0;
/* Start next hub int transfer */
if (!hub->is_roothub && hub->connected) {
usbh_submit_urb(&hub->intin_urb);
}
}
2022-02-08 11:44:46 +08:00
static void usbh_hub_thread(void *argument)
{
struct usbh_hub *hub;
int ret = 0;
2022-02-08 11:44:46 +08:00
usb_hc_init();
while (1) {
ret = usb_osal_mq_recv(hub_mq, (uint32_t *)&hub, 0xffffffff);
if (ret < 0) {
continue;
}
usbh_hub_events(hub);
2022-02-08 11:44:46 +08:00
}
}
static void usbh_roothub_register(void)
2022-02-08 11:44:46 +08:00
{
memset(&roothub, 0, sizeof(struct usbh_hub));
roothub.connected = true;
roothub.index = 1;
roothub.is_roothub = true;
roothub.parent = NULL;
roothub.hub_addr = 1;
roothub.hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
usbh_hub_register(&roothub);
}
static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
{
usb_osal_mq_send(hub_mq, (uint32_t)hub);
}
void usbh_roothub_thread_wakeup(uint8_t port)
{
roothub.int_buffer = g_hub_intbuf[roothub.index - 1];
roothub.int_buffer[0] |= (1 << port);
usbh_hub_thread_wakeup(&roothub);
}
int usbh_hub_initialize(void)
{
2022-09-14 19:50:06 +08:00
usbh_roothub_register();
hub_mq = usb_osal_mq_create(7);
if (hub_mq == NULL) {
return -1;
2022-02-08 11:44:46 +08:00
}
hub_thread = usb_osal_thread_create("usbh_hub", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, NULL);
if (hub_thread == NULL) {
return -1;
2022-02-08 11:44:46 +08:00
}
return 0;
2022-02-08 11:44:46 +08:00
}
#if CONFIG_USBHOST_MAX_EXTHUBS > 0
2022-12-31 15:55:07 +08:00
const struct usbh_class_driver hub_class_driver = {
2022-02-08 11:44:46 +08:00
.driver_name = "hub",
.connect = usbh_hub_connect,
.disconnect = usbh_hub_disconnect
};
2022-12-31 15:55:07 +08:00
CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
.class = USB_DEVICE_CLASS_HUB,
.subclass = 0,
.protocol = 0,
.vid = 0x00,
.pid = 0x00,
2022-12-31 15:55:07 +08:00
.class_driver = &hub_class_driver
2022-03-27 14:38:47 +08:00
};
2022-12-30 20:57:54 +08:00
#endif