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