1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-12-12 Yi Qiu first version
9 * 2021-02-23 Leslie Lee provide possibility for multi usb host
10 */
11
12 #include <rtthread.h>
13 #include <drivers/usb_host.h>
14
15 #define USB_THREAD_STACK_SIZE 4096
16
17 #define DBG_TAG "usb.host.hub"
18 #define DBG_LVL DBG_INFO
19 #include <rtdbg.h>
20
21
22 // static struct rt_messagequeue *usb_mq;
23 static struct uclass_driver hub_driver;
24 // static struct uhub root_hub;
25
root_hub_ctrl(struct uhcd * hcd,rt_uint16_t port,rt_uint8_t cmd,void * args)26 static rt_err_t root_hub_ctrl(struct uhcd *hcd, rt_uint16_t port, rt_uint8_t cmd, void *args)
27 {
28 switch(cmd)
29 {
30 case RH_GET_PORT_STATUS:
31 (*(rt_uint32_t *)args) = hcd->roothub->port_status[port-1];
32 break;
33 case RH_SET_PORT_STATUS:
34 hcd->roothub->port_status[port-1] = (*(rt_uint32_t *)args);
35 break;
36 case RH_CLEAR_PORT_FEATURE:
37 switch(((rt_uint32_t)args))
38 {
39 case PORT_FEAT_C_CONNECTION:
40 hcd->roothub->port_status[port-1] &= ~PORT_CCSC;
41 break;
42 case PORT_FEAT_C_ENABLE:
43 hcd->roothub->port_status[port-1] &= ~PORT_PESC;
44 break;
45 case PORT_FEAT_C_SUSPEND:
46 hcd->roothub->port_status[port-1] &= ~PORT_PSSC;
47 break;
48 case PORT_FEAT_C_OVER_CURRENT:
49 hcd->roothub->port_status[port-1] &= ~PORT_POCIC;
50 break;
51 case PORT_FEAT_C_RESET:
52 hcd->roothub->port_status[port-1] &= ~PORT_PRSC;
53 break;
54 }
55 break;
56 case RH_SET_PORT_FEATURE:
57 switch((rt_uint32_t)args)
58 {
59 case PORT_FEAT_CONNECTION:
60 hcd->roothub->port_status[port-1] |= PORT_CCSC;
61 break;
62 case PORT_FEAT_ENABLE:
63 hcd->roothub->port_status[port-1] |= PORT_PESC;
64 break;
65 case PORT_FEAT_SUSPEND:
66 hcd->roothub->port_status[port-1] |= PORT_PSSC;
67 break;
68 case PORT_FEAT_OVER_CURRENT:
69 hcd->roothub->port_status[port-1] |= PORT_POCIC;
70 break;
71 case PORT_FEAT_RESET:
72 hcd->ops->reset_port(port);
73 break;
74 case PORT_FEAT_POWER:
75 break;
76 case PORT_FEAT_LOWSPEED:
77 break;
78 case PORT_FEAT_HIGHSPEED:
79 break;
80 }
81 break;
82 default:
83 return -RT_ERROR;
84 }
85 return RT_EOK;
86 }
rt_usbh_root_hub_connect_handler(struct uhcd * hcd,rt_uint8_t port,rt_bool_t isHS)87 void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS)
88 {
89 struct uhost_msg msg;
90 msg.type = USB_MSG_CONNECT_CHANGE;
91 msg.content.hub = hcd->roothub;
92 hcd->roothub->port_status[port - 1] |= PORT_CCS | PORT_CCSC;
93 if(isHS)
94 {
95 hcd->roothub->port_status[port - 1] &= ~PORT_LSDA;
96 }
97 else
98 {
99 hcd->roothub->port_status[port - 1] |= PORT_LSDA;
100 }
101 rt_usbh_event_signal(hcd, &msg);
102 }
103
rt_usbh_root_hub_disconnect_handler(struct uhcd * hcd,rt_uint8_t port)104 void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port)
105 {
106 struct uhost_msg msg;
107 msg.type = USB_MSG_CONNECT_CHANGE;
108 msg.content.hub = hcd->roothub;
109 hcd->roothub->port_status[port - 1] |= PORT_CCSC;
110 hcd->roothub->port_status[port - 1] &= ~PORT_CCS;
111 rt_usbh_event_signal(hcd, &msg);
112 }
113
114 /**
115 * This function will do USB_REQ_GET_DESCRIPTOR bRequest for the device instance
116 * to get usb hub descriptor.
117 *
118 * @param intf the interface instance.
119 * @buffer the data buffer to save usb hub descriptor.
120 * @param nbytes the size of buffer
121 *
122 * @return the error code, RT_EOK on successfully.
123 */
rt_usbh_hub_get_descriptor(struct uinstance * device,rt_uint8_t * buffer,rt_size_t nbytes)124 rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes)
125 {
126 struct urequest setup;
127 int timeout = USB_TIMEOUT_BASIC;
128
129 /* parameter check */
130 RT_ASSERT(device != RT_NULL);
131
132 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
133 setup.bRequest = USB_REQ_GET_DESCRIPTOR;
134 setup.wIndex = 0;
135 setup.wLength = nbytes;
136 setup.wValue = USB_DESC_TYPE_HUB << 8;
137
138 if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
139 {
140 if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
141 {
142 return RT_EOK;
143 }
144 }
145 return -RT_FALSE;
146 }
147
148 /**
149 * This function will do USB_REQ_GET_STATUS bRequest for the device instance
150 * to get usb hub status.
151 *
152 * @param intf the interface instance.
153 * @buffer the data buffer to save usb hub status.
154 *
155 * @return the error code, RT_EOK on successfully.
156 */
rt_usbh_hub_get_status(struct uinstance * device,rt_uint32_t * buffer)157 rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer)
158 {
159 struct urequest setup;
160 int timeout = USB_TIMEOUT_BASIC;
161
162 /* parameter check */
163 RT_ASSERT(device != RT_NULL);
164
165 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
166 setup.bRequest = USB_REQ_GET_STATUS;
167 setup.wIndex = 0;
168 setup.wLength = 4;
169 setup.wValue = 0;
170 if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
171 {
172 if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, 4, timeout) == 4)
173 {
174 return RT_EOK;
175 }
176 }
177 return -RT_FALSE;
178 }
179
180 /**
181 * This function will do USB_REQ_GET_STATUS bRequest for the device instance
182 * to get hub port status.
183 *
184 * @param intf the interface instance.
185 * @port the hub port to get status.
186 * @buffer the data buffer to save usb hub status.
187 *
188 * @return the error code, RT_EOK on successfully.
189 */
rt_usbh_hub_get_port_status(uhub_t hub,rt_uint16_t port,rt_uint32_t * buffer)190 rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint32_t* buffer)
191 {
192 struct urequest setup;
193 int timeout = USB_TIMEOUT_BASIC;
194
195 /* parameter check */
196 RT_ASSERT(hub != RT_NULL);
197
198 /* get roothub port status */
199 if(hub->is_roothub)
200 {
201 root_hub_ctrl(hub->hcd, port, RH_GET_PORT_STATUS,
202 (void*)buffer);
203 return RT_EOK;
204 }
205
206 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER;
207 setup.bRequest = USB_REQ_GET_STATUS;
208 setup.wIndex = port;
209 setup.wLength = 4;
210 setup.wValue = 0;
211
212 if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
213 {
214 if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, buffer, 4, timeout) == 4)
215 {
216 return RT_EOK;
217 }
218 }
219 return -RT_FALSE;
220 }
221
222 /**
223 * This function will do USB_REQ_CLEAR_FEATURE bRequest for the device instance
224 * to clear feature of the hub port.
225 *
226 * @param intf the interface instance.
227 * @port the hub port.
228 * @feature feature to be cleared.
229 *
230 * @return the error code, RT_EOK on successfully.
231 */
rt_usbh_hub_clear_port_feature(uhub_t hub,rt_uint16_t port,rt_uint16_t feature)232 rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature)
233 {
234 struct urequest setup;
235 int timeout = USB_TIMEOUT_BASIC;
236
237 /* parameter check */
238 RT_ASSERT(hub != RT_NULL);
239
240 /* clear roothub feature */
241 if(hub->is_roothub)
242 {
243 root_hub_ctrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE,
244 (void*)(rt_uint32_t)feature);
245 return RT_EOK;
246 }
247
248 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
249 USB_REQ_TYPE_OTHER;
250 setup.bRequest = USB_REQ_CLEAR_FEATURE;
251 setup.wIndex = port;
252 setup.wLength = 0;
253 setup.wValue = feature;
254
255 if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
256 {
257 return RT_EOK;
258 }
259 return -RT_FALSE;
260 }
261
262 /**
263 * This function will do USB_REQ_SET_FEATURE bRequest for the device instance
264 * to set feature of the hub port.
265 *
266 * @param intf the interface instance.
267 * @port the hub port.
268 * @feature feature to be set.
269 *
270 * @return the error code, RT_EOK on successfully.
271 */
rt_usbh_hub_set_port_feature(uhub_t hub,rt_uint16_t port,rt_uint16_t feature)272 rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port,
273 rt_uint16_t feature)
274 {
275 struct urequest setup;
276 int timeout = USB_TIMEOUT_BASIC;
277
278 /* parameter check */
279 RT_ASSERT(hub != RT_NULL);
280
281 /* clear roothub feature */
282 if(hub->is_roothub)
283 {
284 root_hub_ctrl(hub->hcd, port, RH_SET_PORT_FEATURE,
285 (void*)(rt_uint32_t)feature);
286 return RT_EOK;
287 }
288
289 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
290 USB_REQ_TYPE_OTHER;
291 setup.bRequest = USB_REQ_SET_FEATURE;
292 setup.wIndex = port;
293 setup.wLength = 0;
294 setup.wValue = feature;
295
296 if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
297 {
298 return RT_EOK;
299 }
300 else return -RT_FALSE;
301 }
302
303 /**
304 * This function will rest hub port, it is invoked when sub device attached to the hub port.
305 *
306 * @param intf the interface instance.
307 * @param port the hub port.
308 *
309 * @return the error code, RT_EOK on successfully.
310 */
rt_usbh_hub_reset_port(uhub_t hub,rt_uint16_t port)311 rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port)
312 {
313 rt_err_t ret;
314 rt_uint32_t pstatus;
315
316 /* parameter check */
317 RT_ASSERT(hub != RT_NULL);
318
319 rt_thread_delay(50);
320
321 /* reset hub port */
322 ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET);
323 if(ret != RT_EOK) return ret;
324
325 while(1)
326 {
327 ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
328 if(!(pstatus & PORT_PRS)) break;
329 }
330
331 /* clear port reset feature */
332 ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET);
333 if(ret != RT_EOK) return ret;
334
335 rt_thread_delay(50);
336
337 return RT_EOK;
338 }
339
340 /**
341 * This function will do debouce, it is invoked when sub device attached to the hub port.
342 *
343 * @param device the usb instance.
344 * @param port the hub port.
345 *
346 * @return the error code, RT_EOK on successfully.
347 */
rt_usbh_hub_port_debounce(uhub_t hub,rt_uint16_t port)348 rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port)
349 {
350 rt_err_t ret;
351 int i = 0, times = 20;
352 rt_uint32_t pstatus;
353 rt_bool_t connect = RT_TRUE;
354 int delayticks = USB_DEBOUNCE_TIME / times;
355 if (delayticks < 1)
356 delayticks = 1;
357
358 /* parameter check */
359 RT_ASSERT(hub != RT_NULL);
360
361 for(i=0; i<times; i++)
362 {
363 ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
364 if(ret != RT_EOK) return ret;
365
366 if(!(pstatus & PORT_CCS))
367 {
368 connect = RT_FALSE;
369 break;
370 }
371
372 rt_thread_delay(delayticks);
373 }
374
375 if(connect) return RT_EOK;
376 else return -RT_ERROR;
377 }
378
379 /**
380 * This function will poll all the hub ports to detect port status, especially connect and
381 * disconnect events.
382 *
383 * @param intf the interface instance.
384 *
385 * @return the error code, RT_EOK on successfully.
386 */
rt_usbh_hub_port_change(uhub_t hub)387 static rt_err_t rt_usbh_hub_port_change(uhub_t hub)
388 {
389 int i;
390 rt_bool_t reconnect;
391
392 /* parameter check */
393 RT_ASSERT(hub != RT_NULL);
394
395 /* get usb device instance */
396 for (i = 0; i < hub->num_ports; i++)
397 {
398 rt_err_t ret;
399 struct uinstance* device;
400 rt_uint32_t pstatus = 0;
401
402 reconnect = RT_FALSE;
403
404 /* get hub port status */
405 ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
406 if(ret != RT_EOK) continue;
407
408 LOG_D("port %d status 0x%x", i + 1, pstatus);
409
410 /* check port status change */
411 if (pstatus & PORT_CCSC)
412 {
413 /* clear port status change feature */
414 rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION);
415 reconnect = RT_TRUE;
416 }
417
418 if(pstatus & PORT_PESC)
419 {
420 rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE);
421 reconnect = RT_TRUE;
422 }
423
424 if(reconnect)
425 {
426 if(hub->child[i] != RT_NULL && hub->child[i]->status != DEV_STATUS_IDLE)
427 {
428 rt_usbh_detach_instance(hub->child[i]);
429
430 /* Child device have been detach. Set hub->child[i] to NULL. */
431 hub->child[i] = RT_NULL;
432 }
433
434 ret = rt_usbh_hub_port_debounce(hub, i + 1);
435 if(ret != RT_EOK) continue;
436
437 /* allocate an usb instance for new connected device */
438 device = rt_usbh_alloc_instance(hub->hcd);
439 if(device == RT_NULL) break;
440
441 /* set usb device speed */
442 device->speed = (pstatus & PORT_LSDA) ? 1 : 0;
443 device->parent_hub = hub;
444 device->hcd = hub->hcd;
445 device->port = i + 1;
446 hub->child[i] = device;
447
448 /* reset usb roothub port */
449 rt_usbh_hub_reset_port(hub, i + 1);
450
451 /* attatch the usb instance to the hcd */
452 rt_usbh_attatch_instance(device);
453 }
454 }
455
456 return RT_EOK;
457 }
458
459 /**
460 * This function is the callback function of hub's int endpoint, it is invoked when data comes.
461 *
462 * @param context the context of the callback function.
463 *
464 * @return none.
465 */
rt_usbh_hub_irq(void * context)466 static void rt_usbh_hub_irq(void* context)
467 {
468 upipe_t pipe;
469 uhub_t hub;
470 int timeout = USB_TIMEOUT_BASIC;
471
472 RT_ASSERT(context != RT_NULL);
473
474 pipe = (upipe_t)context;
475 hub = (uhub_t)pipe->user_data;
476
477 if(pipe->status != UPIPE_STATUS_OK)
478 {
479 LOG_D("hub irq error");
480 return;
481 }
482
483 rt_usbh_hub_port_change(hub);
484
485 LOG_D("hub int xfer...");
486
487 /* parameter check */
488 RT_ASSERT(pipe->inst->hcd != RT_NULL);
489
490 rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout);
491 }
492
493 /**
494 * This function will run usb hub class driver when usb hub is detected and identified
495 * as a hub class device, it will continue to do the enumulate process.
496 *
497 * @param arg the argument.
498 *
499 * @return the error code, RT_EOK on successfully.
500 */
501
rt_usbh_hub_enable(void * arg)502 static rt_err_t rt_usbh_hub_enable(void *arg)
503 {
504 int i = 0;
505 rt_err_t ret = RT_EOK;
506 uep_desc_t ep_desc = RT_NULL;
507 uhub_t hub;
508 struct uinstance* device;
509 struct uhintf* intf = (struct uhintf*)arg;
510 upipe_t pipe_in = RT_NULL;
511 int timeout = USB_TIMEOUT_LONG;
512 /* paremeter check */
513 RT_ASSERT(intf != RT_NULL);
514
515 /* get usb device instance */
516 device = intf->device;
517
518 /* create a hub instance */
519 hub = rt_malloc(sizeof(struct uhub));
520 RT_ASSERT(hub != RT_NULL);
521 rt_memset(hub, 0, sizeof(struct uhub));
522
523 /* make interface instance's user data point to hub instance */
524 intf->user_data = (void*)hub;
525
526 /* get hub descriptor head */
527 ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8);
528 if(ret != RT_EOK)
529 {
530 rt_kprintf("get hub descriptor failed\n");
531 return -RT_ERROR;
532 }
533
534 /* get full hub descriptor */
535 ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc,
536 hub->hub_desc.length);
537 if(ret != RT_EOK)
538 {
539 rt_kprintf("get hub descriptor again failed\n");
540 return -RT_ERROR;
541 }
542
543 /* get hub ports number */
544 /* If hub device supported ports over USB_HUB_PORT_NUM(Ex: 8 port hub). Set hub->num_ports to USB_HUB_PORT_NUM */
545 if(hub->hub_desc.num_ports > USB_HUB_PORT_NUM)
546 hub->num_ports = USB_HUB_PORT_NUM;
547 else
548 hub->num_ports = hub->hub_desc.num_ports;
549
550 hub->hcd = device->hcd;
551 hub->self = device;
552
553 /* reset all hub ports */
554 for (i = 0; i < hub->num_ports; i++)
555 {
556 rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER);
557 rt_thread_delay(hub->hub_desc.pwron_to_good
558 * 2 * RT_TICK_PER_SECOND / 1000 );
559 }
560
561 if(intf->intf_desc->bNumEndpoints != 1)
562 return -RT_ERROR;
563
564 /* get endpoint descriptor from interface descriptor */
565 rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc);
566 if(ep_desc == RT_NULL)
567 {
568 rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
569 return -RT_ERROR;
570 }
571
572 /* the endpoint type of hub class should be interrupt */
573 if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT)
574 {
575 /* the endpoint direction of hub class should be in */
576 if(ep_desc->bEndpointAddress & USB_DIR_IN)
577 {
578 /* allocate a pipe according to the endpoint type */
579 pipe_in = rt_usb_instance_find_pipe(device,ep_desc->bEndpointAddress);
580 if(pipe_in == RT_NULL)
581 {
582 return -RT_ERROR;
583 }
584 rt_usb_pipe_add_callback(pipe_in,rt_usbh_hub_irq);
585 }
586 else return -RT_ERROR;
587 }
588
589 /* parameter check */
590 RT_ASSERT(device->hcd != RT_NULL);
591 pipe_in->user_data = hub;
592 rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer,
593 pipe_in->ep.wMaxPacketSize, timeout);
594 return RT_EOK;
595 }
596
597 /**
598 * This function will be invoked when usb hub plug out is detected and it would clean
599 * and release all hub class related resources.
600 *
601 * @param arg the argument.
602 *
603 * @return the error code, RT_EOK on successfully.
604 */
rt_usbh_hub_disable(void * arg)605 static rt_err_t rt_usbh_hub_disable(void* arg)
606 {
607 int i;
608 uhub_t hub;
609 struct uhintf* intf = (struct uhintf*)arg;
610
611 /* paremeter check */
612 RT_ASSERT(intf != RT_NULL);
613
614 LOG_D("rt_usbh_hub_stop");
615 hub = (uhub_t)intf->user_data;
616
617 for(i=0; i<hub->num_ports; i++)
618 {
619 if(hub->child[i] != RT_NULL)
620 rt_usbh_detach_instance(hub->child[i]);
621 }
622
623 if(hub != RT_NULL) rt_free(hub);
624
625 return RT_EOK;
626 }
627
628 /**
629 * This function will register hub class driver to the usb class driver manager.
630 * and it should be invoked in the usb system initialization.
631 *
632 * @return the error code, RT_EOK on successfully.
633 */
rt_usbh_class_driver_hub(void)634 ucd_t rt_usbh_class_driver_hub(void)
635 {
636 hub_driver.class_code = USB_CLASS_HUB;
637
638 hub_driver.enable = rt_usbh_hub_enable;
639 hub_driver.disable = rt_usbh_hub_disable;
640
641 return &hub_driver;
642 }
643
644 /**
645 * This function is the main entry of usb hub thread, it is in charge of
646 * processing all messages received from the usb message buffer.
647 *
648 * @param parameter the parameter of the usb host thread.
649 *
650 * @return none.
651 */
rt_usbh_hub_thread_entry(void * parameter)652 static void rt_usbh_hub_thread_entry(void* parameter)
653 {
654 uhcd_t hcd = (uhcd_t)parameter;
655 while(1)
656 {
657 struct uhost_msg msg;
658
659 /* receive message */
660 if (rt_mq_recv(hcd->usb_mq, &msg, sizeof(struct uhost_msg), RT_WAITING_FOREVER) < 0)
661 continue;
662
663 switch (msg.type)
664 {
665 case USB_MSG_CONNECT_CHANGE:
666 rt_usbh_hub_port_change(msg.content.hub);
667 break;
668 case USB_MSG_CALLBACK:
669 /* invoke callback */
670 msg.content.cb.function(msg.content.cb.context);
671 break;
672 default:
673 break;
674 }
675 }
676 }
677
678 /**
679 * This function will post an message to the usb message queue,
680 *
681 * @param msg the message to be posted
682 *
683 * @return the error code, RT_EOK on successfully.
684 */
rt_usbh_event_signal(uhcd_t hcd,struct uhost_msg * msg)685 rt_err_t rt_usbh_event_signal(uhcd_t hcd, struct uhost_msg* msg)
686 {
687 RT_ASSERT(msg != RT_NULL);
688
689 /* send message to usb message queue */
690 rt_mq_send(hcd->usb_mq, (void*)msg, sizeof(struct uhost_msg));
691
692 return RT_EOK;
693 }
694
695 /**
696 * This function will initialize usb hub thread.
697 *
698 * @return none.
699 *
700 */
rt_usbh_hub_init(uhcd_t hcd)701 void rt_usbh_hub_init(uhcd_t hcd)
702 {
703 rt_thread_t thread;
704 /* create root hub for hcd */
705 hcd->roothub = rt_malloc(sizeof(struct uhub));
706 if(hcd->roothub == RT_NULL)
707 {
708 LOG_E("hcd->roothub: allocate buffer failed.");
709 return;
710 }
711 rt_memset(hcd->roothub, 0, sizeof(struct uhub));
712 hcd->roothub->is_roothub = RT_TRUE;
713 hcd->roothub->hcd = hcd;
714 hcd->roothub->num_ports = hcd->num_ports;
715 /* create usb message queue */
716
717 hcd->usb_mq = rt_mq_create(hcd->parent.parent.name, 32, 16, RT_IPC_FLAG_FIFO);
718
719 /* create usb hub thread */
720 thread = rt_thread_create(hcd->parent.parent.name, rt_usbh_hub_thread_entry, hcd,
721 USB_THREAD_STACK_SIZE, 8, 20);
722 if(thread != RT_NULL)
723 {
724 /* startup usb host thread */
725 rt_thread_startup(thread);
726 }
727 }
728