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