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