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