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