• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbh_hub.h"
7 
8 #define DEV_FORMAT "/dev/hub%d"
9 
10 #define HUB_DEBOUNCE_TIMEOUT   1500
11 #define HUB_DEBOUNCE_STEP      25
12 #define HUB_DEBOUNCE_STABLE    100
13 #define DELAY_TIME_AFTER_RESET 200
14 
15 #define EXTHUB_FIRST_INDEX 2
16 
17 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[32];
18 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USB_ALIGN_SIZE];
19 
20 usb_slist_t hub_class_head = USB_SLIST_OBJECT_INIT(hub_class_head);
21 
22 usb_osal_thread_t hub_thread;
23 usb_osal_mq_t hub_mq;
24 
25 struct usbh_hub roothub;
26 
27 extern int usbh_hport_activate_ep0(struct usbh_hubport *hport);
28 extern int usbh_hport_deactivate_ep0(struct usbh_hubport *hport);
29 extern int usbh_enumerate(struct usbh_hubport *hport);
30 static void usbh_hub_thread_wakeup(struct usbh_hub *hub);
31 
32 static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
33 
34 #ifdef CONFIG_USBHOST_XHCI
usbh_get_roothub_port(unsigned int port)35 struct usbh_hubport *usbh_get_roothub_port(unsigned int port)
36 {
37     return &roothub.child[port - 1];
38 }
39 #endif
40 
41 #if CONFIG_USBHOST_MAX_EXTHUBS > 0
42 static struct usbh_hub g_hub_class[CONFIG_USBHOST_MAX_EXTHUBS];
43 static uint32_t g_devinuse = 0;
44 
usbh_hub_class_alloc(void)45 static struct usbh_hub *usbh_hub_class_alloc(void)
46 {
47     int devno;
48 
49     for (devno = 0; devno < CONFIG_USBHOST_MAX_EXTHUBS; devno++) {
50         if ((g_devinuse & (1 << devno)) == 0) {
51             g_devinuse |= (1 << devno);
52             memset(&g_hub_class[devno], 0, sizeof(struct usbh_hub));
53             g_hub_class[devno].index = EXTHUB_FIRST_INDEX + devno;
54             return &g_hub_class[devno];
55         }
56     }
57     return NULL;
58 }
59 
usbh_hub_class_free(struct usbh_hub * hub_class)60 static void usbh_hub_class_free(struct usbh_hub *hub_class)
61 {
62     int devno = hub_class->index - EXTHUB_FIRST_INDEX;
63 
64     if (devno >= 0 && devno < 32) {
65         g_devinuse &= ~(1 << devno);
66     }
67     memset(hub_class, 0, sizeof(struct usbh_hub));
68 }
69 #endif
70 
usbh_hub_register(struct usbh_hub * hub)71 static void usbh_hub_register(struct usbh_hub *hub)
72 {
73     usb_slist_add_tail(&hub_class_head, &hub->list);
74 }
75 
76 #if CONFIG_USBHOST_MAX_EXTHUBS > 0
usbh_hub_unregister(struct usbh_hub * hub)77 static void usbh_hub_unregister(struct usbh_hub *hub)
78 {
79     usb_slist_remove(&hub_class_head, &hub->list);
80 }
81 
_usbh_hub_get_hub_descriptor(struct usbh_hub * hub,uint8_t * buffer)82 static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
83 {
84     struct usb_setup_packet *setup;
85     int ret;
86 
87     setup = hub->parent->setup;
88 
89     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
90     setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
91 
92     /* TODO: hub descriptor has some difference between USB 2.0 and USB 3.x,
93        and we havn't handle the difference here */
94     if ((hub->parent->speed == USB_SPEED_SUPER) ||
95         (hub->parent->speed == USB_SPEED_SUPER_PLUS)) {
96         setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
97     } else {
98         setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
99     }
100 
101     setup->wIndex = 0;
102     setup->wLength = USB_SIZEOF_HUB_DESC;
103 
104     ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
105     if (ret < 0) {
106         return ret;
107     }
108     memcpy(buffer, g_hub_buf, USB_SIZEOF_HUB_DESC);
109     return ret;
110 }
111 #if 0
112 static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
113 {
114     struct usb_setup_packet *setup;
115     int ret;
116 
117     setup = hub->parent->setup;
118 
119     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
120     setup->bRequest = HUB_REQUEST_GET_STATUS;
121     setup->wValue = 0;
122     setup->wIndex = 0;
123     setup->wLength = 2;
124 
125     ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
126     if (ret < 0) {
127         return ret;
128     }
129     memcpy(buffer, g_hub_buf, 2);
130     return ret;
131 }
132 #endif
133 #endif
134 
_usbh_hub_get_portstatus(struct usbh_hub * hub,uint8_t port,struct hub_port_status * port_status)135 static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
136 {
137     struct usb_setup_packet *setup;
138     int ret;
139 
140     setup = hub->parent->setup;
141 
142     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
143     setup->bRequest = HUB_REQUEST_GET_STATUS;
144     setup->wValue = 0;
145     setup->wIndex = port;
146     setup->wLength = 4;
147 
148     ret = usbh_control_transfer(hub->parent->ep0, setup, g_hub_buf);
149     if (ret < 0) {
150         return ret;
151     }
152     memcpy(port_status, g_hub_buf, 4);
153     return ret;
154 }
155 
_usbh_hub_set_feature(struct usbh_hub * hub,uint8_t port,uint8_t feature)156 static int _usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
157 {
158     struct usb_setup_packet *setup;
159 
160     setup = hub->parent->setup;
161 
162     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
163     setup->bRequest = HUB_REQUEST_SET_FEATURE;
164     setup->wValue = feature;
165     setup->wIndex = port;
166     setup->wLength = 0;
167 
168     return usbh_control_transfer(hub->parent->ep0, setup, NULL);
169 }
170 
_usbh_hub_clear_feature(struct usbh_hub * hub,uint8_t port,uint8_t feature)171 static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
172 {
173     struct usb_setup_packet *setup;
174 
175     setup = hub->parent->setup;
176 
177     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
178     setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
179     setup->wValue = feature;
180     setup->wIndex = port;
181     setup->wLength = 0;
182 
183     return usbh_control_transfer(hub->parent->ep0, setup, NULL);
184 }
185 
_usbh_hub_set_depth(struct usbh_hub * hub,uint16_t depth)186 static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
187 {
188     struct usb_setup_packet *setup;
189 
190     setup = hub->parent->setup;
191 
192     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
193     setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
194     setup->wValue = depth;
195     setup->wIndex = 0;
196     setup->wLength = 0;
197 
198     return usbh_control_transfer(hub->parent->ep0, setup, NULL);
199 }
200 
201 #if CONFIG_USBHOST_MAX_EXTHUBS > 0
parse_hub_descriptor(struct usb_hub_descriptor * desc,uint16_t length)202 static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
203 {
204     if (desc->bLength != USB_SIZEOF_HUB_DESC) {
205         USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
206         return -1;
207     } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB) {
208         USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
209         return -2;
210     } else {
211         USB_LOG_RAW("Hub Descriptor:\r\n");
212         USB_LOG_RAW("bLength: 0x%02x             \r\n", desc->bLength);
213         USB_LOG_RAW("bDescriptorType: 0x%02x     \r\n", desc->bDescriptorType);
214         USB_LOG_RAW("bNbrPorts: 0x%02x           \r\n", desc->bNbrPorts);
215         USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
216         USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x      \r\n", desc->bPwrOn2PwrGood);
217         USB_LOG_RAW("bHubContrCurrent: 0x%02x    \r\n", desc->bHubContrCurrent);
218         USB_LOG_RAW("DeviceRemovable: 0x%02x     \r\n", desc->DeviceRemovable);
219         USB_LOG_RAW("PortPwrCtrlMask: 0x%02x     \r\n", desc->PortPwrCtrlMask);
220     }
221     return 0;
222 }
223 #endif
224 
usbh_hub_get_portstatus(struct usbh_hub * hub,uint8_t port,struct hub_port_status * port_status)225 static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
226 {
227     struct usb_setup_packet roothub_setup;
228     struct usb_setup_packet *setup;
229 
230     if (hub->is_roothub) {
231         setup = &roothub_setup;
232         setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
233         setup->bRequest = HUB_REQUEST_GET_STATUS;
234         setup->wValue = 0;
235         setup->wIndex = port;
236         setup->wLength = 4;
237         return usbh_roothub_control(&roothub_setup, (uint8_t *)port_status);
238     } else {
239         return _usbh_hub_get_portstatus(hub, port, port_status);
240     }
241 }
242 
usbh_hub_set_feature(struct usbh_hub * hub,uint8_t port,uint8_t feature)243 static int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
244 {
245     struct usb_setup_packet roothub_setup;
246     struct usb_setup_packet *setup;
247 
248     if (hub->is_roothub) {
249         setup = &roothub_setup;
250         setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
251         setup->bRequest = HUB_REQUEST_SET_FEATURE;
252         setup->wValue = feature;
253         setup->wIndex = port;
254         setup->wLength = 0;
255         return usbh_roothub_control(setup, NULL);
256     } else {
257         return _usbh_hub_set_feature(hub, port, feature);
258     }
259 }
260 
usbh_hub_clear_feature(struct usbh_hub * hub,uint8_t port,uint8_t feature)261 static int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
262 {
263     struct usb_setup_packet roothub_setup;
264     struct usb_setup_packet *setup;
265 
266     if (hub->is_roothub) {
267         setup = &roothub_setup;
268         setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
269         setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
270         setup->wValue = feature;
271         setup->wIndex = port;
272         setup->wLength = 0;
273         return usbh_roothub_control(setup, NULL);
274     } else {
275         return _usbh_hub_clear_feature(hub, port, feature);
276     }
277 }
278 
usbh_hub_set_depth(struct usbh_hub * hub,uint16_t depth)279 static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
280 {
281     struct usb_setup_packet roothub_setup;
282     struct usb_setup_packet *setup;
283 
284     if (hub->is_roothub) {
285         setup = &roothub_setup;
286         setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
287         setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
288         setup->wValue = depth;
289         setup->wIndex = 0;
290         setup->wLength = 0;
291         return usbh_roothub_control(setup, NULL);
292     } else {
293         return _usbh_hub_set_depth(hub, depth);
294     }
295 }
296 
297 #if CONFIG_USBHOST_MAX_EXTHUBS > 0
hub_int_complete_callback(void * arg,int nbytes)298 static void hub_int_complete_callback(void *arg, int nbytes)
299 {
300     struct usbh_hub *hub = (struct usbh_hub *)arg;
301 
302     if (nbytes > 0) {
303         usbh_hub_thread_wakeup(hub);
304     }
305 }
306 
usbh_hub_connect(struct usbh_hubport * hport,uint8_t intf)307 static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
308 {
309     struct usb_endpoint_descriptor *ep_desc;
310     struct hub_port_status port_status;
311     int ret;
312 
313     struct usbh_hub *hub = usbh_hub_class_alloc();
314     if (hub == NULL) {
315         USB_LOG_ERR("Fail to alloc hub_class\r\n");
316         return -ENOMEM;
317     }
318 
319     hub->hub_addr = hport->dev_addr;
320     hub->parent = hport;
321 
322     hport->config.intf[intf].priv = hub;
323 
324     ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
325     if (ret < 0) {
326         return ret;
327     }
328 
329     parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
330 
331     for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
332         hub->child[port].port = port + 1;
333         hub->child[port].parent = hub;
334     }
335 
336     ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
337     if (ep_desc->bEndpointAddress & 0x80) {
338         usbh_hport_activate_epx(&hub->intin, hport, ep_desc);
339     } else {
340         return -1;
341     }
342 
343     if (hport->speed == USB_SPEED_SUPER) {
344         uint16_t depth = 0;
345         struct usbh_hubport *parent = hport->parent->parent;
346         while (parent) {
347             depth++;
348             parent = parent->parent->parent;
349         }
350 
351         ret = usbh_hub_set_depth(hub, depth);
352         if (ret < 0) {
353             return ret;
354         }
355     }
356 
357     for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
358         ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
359         if (ret < 0) {
360             return ret;
361         }
362     }
363 
364     for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
365         ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
366         USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
367         if (ret < 0) {
368             return ret;
369         }
370     }
371 
372     hub->connected = true;
373     snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hub->index);
374     usbh_hub_register(hub);
375     USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
376 
377     hub->int_buffer = g_hub_intbuf[hub->index - 1];
378     usbh_int_urb_fill(&hub->intin_urb, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
379     usbh_submit_urb(&hub->intin_urb);
380     return 0;
381 }
382 
usbh_hub_disconnect(struct usbh_hubport * hport,uint8_t intf)383 static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
384 {
385     struct usbh_hubport *child;
386     int ret = 0;
387 
388     struct usbh_hub *hub = (struct usbh_hub *)hport->config.intf[intf].priv;
389 
390     if (hub) {
391         if (hub->intin) {
392             usbh_pipe_free(hub->intin);
393         }
394 
395         for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
396             child = &hub->child[port];
397             usbh_hport_deactivate_ep0(child);
398             for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
399                 if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
400                     CLASS_DISCONNECT(child, i);
401                 }
402             }
403 
404             child->config.config_desc.bNumInterfaces = 0;
405             child->parent = NULL;
406         }
407 
408         if (hport->config.intf[intf].devname[0] != '\0') {
409             USB_LOG_INFO("Unregister HUB Class:%s\r\n", hport->config.intf[intf].devname);
410             usbh_hub_unregister(hub);
411         }
412 
413         usbh_hub_class_free(hub);
414     }
415     return ret;
416 }
417 #endif
418 
usbh_hubport_release(struct usbh_hubport * child)419 static void usbh_hubport_release(struct usbh_hubport *child)
420 {
421     if (child->connected) {
422         child->connected = false;
423         usbh_hport_deactivate_ep0(child);
424         for (uint8_t i = 0; i < child->config.config_desc.bNumInterfaces; i++) {
425             if (child->config.intf[i].class_driver && child->config.intf[i].class_driver->disconnect) {
426                 CLASS_DISCONNECT(child, i);
427             }
428         }
429         child->config.config_desc.bNumInterfaces = 0;
430     }
431 }
432 
usbh_hubport_enumerate_thread(void * argument)433 static void usbh_hubport_enumerate_thread(void *argument)
434 {
435     struct usbh_hubport *child = (struct usbh_hubport *)argument;
436 
437     /* Configure EP0 with the default maximum packet size */
438     usbh_hport_activate_ep0(child);
439 
440     if (usbh_enumerate(child) < 0) {
441         /** release child sources */
442         usbh_hubport_release(child);
443         USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
444     }
445     usb_osal_thread_delete(NULL);
446 }
447 
usbh_hub_events(struct usbh_hub * hub)448 static void usbh_hub_events(struct usbh_hub *hub)
449 {
450     struct usbh_hubport *child;
451     struct hub_port_status port_status;
452     uint8_t portchange_index;
453     uint16_t portstatus;
454     uint16_t portchange;
455     uint16_t mask;
456     uint16_t feat;
457     uint8_t speed;
458     int ret;
459 
460     if (!hub->connected) {
461         return;
462     }
463 
464     portchange_index = hub->int_buffer[0];
465     hub->int_buffer[0] = 0;
466 
467     for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
468         USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
469 
470         if (!(portchange_index & (1 << (port + 1)))) {
471             continue;
472         }
473         portchange_index &= ~(1 << (port + 1));
474         USB_LOG_DBG("Port %d change\r\n", port + 1);
475 
476         /* Read hub port status */
477         ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
478         if (ret < 0) {
479             USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
480             continue;
481         }
482 
483         portstatus = port_status.wPortStatus;
484         portchange = port_status.wPortChange;
485 
486         USB_LOG_DBG("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
487 
488         /* First, clear all change bits */
489         mask = 1;
490         feat = HUB_PORT_FEATURE_C_CONNECTION;
491         while (portchange) {
492             if (portchange & mask) {
493                 ret = usbh_hub_clear_feature(hub, port + 1, feat);
494                 if (ret < 0) {
495                     USB_LOG_ERR("Failed to clear port %u, change mask:%04x, errorcode:%d\r\n", port + 1, mask, ret);
496                     continue;
497                 }
498                 portchange &= (~mask);
499             }
500             mask <<= 1;
501             feat++;
502         }
503 
504         portchange = port_status.wPortChange;
505 
506         /* Second, if port changes, debounces first */
507         if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
508             uint16_t connection = 0;
509             uint16_t debouncestable = 0;
510             for (uint32_t debouncetime = 0; debouncetime < HUB_DEBOUNCE_TIMEOUT; debouncetime += HUB_DEBOUNCE_STEP) {
511                 /* Read hub port status */
512                 ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
513                 if (ret < 0) {
514                     USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
515                     continue;
516                 }
517 
518                 portstatus = port_status.wPortStatus;
519                 portchange = port_status.wPortChange;
520 
521                 USB_LOG_DBG("Port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
522 
523                 if (!(portchange & HUB_PORT_STATUS_C_CONNECTION) &&
524                     ((portstatus & HUB_PORT_STATUS_CONNECTION) == connection)) {
525                     debouncestable += HUB_DEBOUNCE_STEP;
526                     if (debouncestable >= HUB_DEBOUNCE_STABLE) {
527                         break;
528                     }
529                 } else {
530                     debouncestable = 0;
531                     connection = portstatus & HUB_PORT_STATUS_CONNECTION;
532                 }
533 
534                 if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
535                     usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_CONNECTION);
536                 }
537 
538                 usb_osal_msleep(HUB_DEBOUNCE_STEP);
539             }
540 
541             /** check if debounce ok */
542             if (debouncestable < HUB_DEBOUNCE_STABLE) {
543                 USB_LOG_ERR("Failed to debounce port %u\r\n", port + 1);
544                 break;
545             }
546 
547             /* Last, check connect status */
548             if (portstatus & HUB_PORT_STATUS_CONNECTION) {
549                 ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_RESET);
550                 if (ret < 0) {
551                     USB_LOG_ERR("Failed to reset port %u,errorcode:%d\r\n", port, ret);
552                     continue;
553                 }
554 
555                 usb_osal_msleep(DELAY_TIME_AFTER_RESET);
556                 /* Read hub port status */
557                 ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
558                 if (ret < 0) {
559                     USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
560                     continue;
561                 }
562 
563                 portstatus = port_status.wPortStatus;
564                 portchange = port_status.wPortChange;
565                 if (!(portstatus & HUB_PORT_STATUS_RESET) && (portstatus & HUB_PORT_STATUS_ENABLE)) {
566                     if (portchange & HUB_PORT_STATUS_C_RESET) {
567                         ret = usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_RESET);
568                         if (ret < 0) {
569                             USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port, ret);
570                         }
571                     }
572 
573                     if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
574                         speed = USB_SPEED_HIGH;
575                     } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
576                         speed = USB_SPEED_LOW;
577                     }
578 #ifdef CONFIG_USBHOST_XHCI
579                     else {
580                         extern uint8_t usbh_get_port_speed(struct usbh_hub * hub, const uint8_t port);
581 
582                         /* USB3.0 speed cannot get from portstatus, checkout port speed instead */
583                         uint8_t super_speed = usbh_get_port_speed(hub, port + 1);
584                         if (super_speed > USB_SPEED_HIGH) {
585                             /* assert that when using USB 3.0 ports, attached device must also be USB 3.0 speed */
586                             speed = super_speed;
587                         } else {
588                             speed = USB_SPEED_FULL;
589                         }
590                     }
591 #else
592                     else {
593                         speed = USB_SPEED_FULL;
594                     }
595 #endif
596 
597                     child = &hub->child[port];
598                     /** release child sources first */
599                     usbh_hubport_release(child);
600 
601                     memset(child, 0, sizeof(struct usbh_hubport));
602                     child->parent = hub;
603                     child->connected = true;
604                     child->port = port + 1;
605                     child->speed = speed;
606 
607                     USB_LOG_INFO("New %s device on Hub %u, Port %u connected\r\n", speed_table[speed], hub->index, port + 1);
608 
609                     /* create disposable thread to enumerate device on current hport, do not block hub thread */
610                     child->thread = usb_osal_thread_create("usbh_enum", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hubport_enumerate_thread, (void *)child);
611                 } else {
612                     child = &hub->child[port];
613                     /** release child sources */
614                     usbh_hubport_release(child);
615 
616                     /** some USB 3.0 ip may failed to enable USB 2.0 port for USB 3.0 device */
617                     USB_LOG_WRN("Failed to enable port %u\r\n", port + 1);
618 
619                     continue;
620                 }
621             } else {
622                 child = &hub->child[port];
623                 /** release child sources */
624                 usbh_hubport_release(child);
625                 USB_LOG_INFO("Device on Hub %u, Port %u disconnected\r\n", hub->index, port + 1);
626             }
627         }
628     }
629 
630     /* Start next hub int transfer */
631     if (!hub->is_roothub && hub->connected) {
632         usbh_submit_urb(&hub->intin_urb);
633     }
634 }
635 
usbh_hub_thread(void * argument)636 static void usbh_hub_thread(void *argument)
637 {
638     struct usbh_hub *hub;
639     int ret = 0;
640 
641     usb_hc_init();
642     while (1) {
643         ret = usb_osal_mq_recv(hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
644         if (ret < 0) {
645             continue;
646         }
647         usbh_hub_events(hub);
648     }
649 }
650 
usbh_roothub_register(void)651 static void usbh_roothub_register(void)
652 {
653     memset(&roothub, 0, sizeof(struct usbh_hub));
654 
655     roothub.connected = true;
656     roothub.index = 1;
657     roothub.is_roothub = true;
658     roothub.parent = NULL;
659     roothub.hub_addr = 1;
660     roothub.hub_desc.bNbrPorts = CONFIG_USBHOST_MAX_RHPORTS;
661     usbh_hub_register(&roothub);
662 }
663 
usbh_hub_thread_wakeup(struct usbh_hub * hub)664 static void usbh_hub_thread_wakeup(struct usbh_hub *hub)
665 {
666     usb_osal_mq_send(hub_mq, (uintptr_t)hub);
667 }
668 
usbh_roothub_thread_wakeup(uint8_t port)669 void usbh_roothub_thread_wakeup(uint8_t port)
670 {
671     roothub.int_buffer = g_hub_intbuf[roothub.index - 1];
672     roothub.int_buffer[0] |= (1 << port);
673     usbh_hub_thread_wakeup(&roothub);
674 }
675 
usbh_hub_initialize(void)676 int usbh_hub_initialize(void)
677 {
678     usbh_roothub_register();
679 
680     hub_mq = usb_osal_mq_create(7);
681     if (hub_mq == NULL) {
682         return -1;
683     }
684 
685     hub_thread = usb_osal_thread_create("usbh_hub", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, NULL);
686     if (hub_thread == NULL) {
687         return -1;
688     }
689     return 0;
690 }
691 #if CONFIG_USBHOST_MAX_EXTHUBS > 0
692 const struct usbh_class_driver hub_class_driver = {
693     .driver_name = "hub",
694     .connect = usbh_hub_connect,
695     .disconnect = usbh_hub_disconnect
696 };
697 
698 CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
699     .match_flags = USB_CLASS_MATCH_INTF_CLASS,
700     .class = USB_DEVICE_CLASS_HUB,
701     .subclass = 0,
702     .protocol = 0,
703     .vid = 0x00,
704     .pid = 0x00,
705     .class_driver = &hub_class_driver
706 };
707 #endif
708