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