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  */
10 
11 #include <rtthread.h>
12 #include <drivers/usb_host.h>
13 
14 #define DBG_TAG    "usbhost.core"
15 #define DBG_LVL           DBG_INFO
16 #include <rtdbg.h>
17 
18 static struct uinstance dev[USB_MAX_DEVICE];
19 
20 /**
21  * This function will allocate an usb device instance from system.
22  *
23  * @param parent the hub instance to which the new allocated device attached.
24  * @param port the hub port.
25  *
26  * @return the allocate instance on successful, or RT_NULL on failure.
27  */
rt_usbh_alloc_instance(uhcd_t uhcd)28 uinst_t rt_usbh_alloc_instance(uhcd_t uhcd)
29 {
30     int i;
31 
32     /* lock scheduler */
33     rt_enter_critical();
34 
35     for(i=0; i<USB_MAX_DEVICE; i++)
36     {
37         /* to find an idle instance handle */
38         if(dev[i].status != DEV_STATUS_IDLE) continue;
39 
40         /* initialize the usb device instance */
41         rt_memset(&dev[i], 0, sizeof(struct uinstance));
42 
43         dev[i].status = DEV_STATUS_BUSY;
44         dev[i].index = i + 1;
45         dev[i].address = 0;
46         dev[i].max_packet_size = 0x8;
47         rt_list_init(&dev[i].pipe);
48         dev[i].hcd = uhcd;
49         /* unlock scheduler */
50         rt_exit_critical();
51         return &dev[i];
52     }
53 
54     /* unlock scheduler */
55     rt_exit_critical();
56 
57     return RT_NULL;
58 }
59 
60 /**
61  * This function will attatch an usb device instance to a host controller,
62  * and do device enumunation process.
63  *
64  * @param hcd the host controller driver.
65  * @param device the usb device instance.
66  *
67  * @return the error code, RT_EOK on successfully.
68  */
69 static struct uendpoint_descriptor ep0_out_desc =
70 {
71     /*endpoint descriptor*/
72     USB_DESC_LENGTH_ENDPOINT,
73     USB_DESC_TYPE_ENDPOINT,
74     0x00 | USB_DIR_OUT,
75     USB_EP_ATTR_CONTROL,
76     0x00,
77     0x00,
78 };
79 static struct uendpoint_descriptor ep0_in_desc =
80 {
81     /*endpoint descriptor*/
82     USB_DESC_LENGTH_ENDPOINT,
83     USB_DESC_TYPE_ENDPOINT,
84     0x00 | USB_DIR_IN,
85     USB_EP_ATTR_CONTROL,
86     0x00,
87     0x00,
88 };
rt_usbh_attatch_instance(uinst_t device)89 rt_err_t rt_usbh_attatch_instance(uinst_t device)
90 {
91     int i = 0;
92     rt_err_t ret = RT_EOK;
93     struct uconfig_descriptor cfg_desc;
94     udev_desc_t dev_desc;
95     uintf_desc_t intf_desc;
96     uep_desc_t ep_desc;
97     rt_uint8_t ep_index;
98     upipe_t pipe;
99     ucd_t drv;
100 
101     RT_ASSERT(device != RT_NULL);
102 
103     rt_memset(&cfg_desc, 0, sizeof(struct uconfig_descriptor));
104     dev_desc = &device->dev_desc;
105 
106     /* alloc address 0 ep0 pipe*/
107     ep0_out_desc.wMaxPacketSize = 8;
108     ep0_in_desc.wMaxPacketSize = 8;
109     rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
110     rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
111 
112     LOG_D("start enumnation");
113 
114     /* get device descriptor head */
115     ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8);
116     if(ret != RT_EOK)
117     {
118         rt_kprintf("get device descriptor head failed\n");
119         return ret;
120     }
121 
122     /* reset bus */
123     rt_usbh_hub_reset_port(device->parent_hub, device->port);
124     rt_thread_delay(2);
125     rt_usbh_hub_clear_port_feature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION);
126     /* set device address */
127     ret = rt_usbh_set_address(device);
128     if(ret != RT_EOK)
129     {
130         rt_kprintf("set device address failed\n");
131         return ret;
132     }
133     /* free address 0 ep0 pipe*/
134 
135     rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
136     rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
137 
138     /* set device max packet size */
139     ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
140     ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
141 
142     /* alloc true address ep0 pipe*/
143     rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
144     rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
145     LOG_D("get device descriptor length %d",
146                                 dev_desc->bLength);
147 
148     /* get full device descriptor again */
149     ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength);
150     if(ret != RT_EOK)
151     {
152         rt_kprintf("get full device descriptor failed\n");
153         return ret;
154     }
155 
156     LOG_D("Vendor ID 0x%x", dev_desc->idVendor);
157     LOG_D("Product ID 0x%x", dev_desc->idProduct);
158 
159     /* get configuration descriptor head */
160     ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18);
161     if(ret != RT_EOK)
162     {
163         rt_kprintf("get configuration descriptor head failed\n");
164         return ret;
165     }
166 
167     /* alloc memory for configuration descriptor */
168     device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength);
169     if(device->cfg_desc == RT_NULL)
170     {
171         return -RT_ENOMEM;
172     }
173     rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength);
174 
175     /* get full configuration descriptor */
176     ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION,
177         device->cfg_desc, cfg_desc.wTotalLength);
178     if(ret != RT_EOK)
179     {
180         rt_kprintf("get full configuration descriptor failed\n");
181         return ret;
182     }
183 
184     /* set configuration */
185     ret = rt_usbh_set_configure(device, 1);
186     if(ret != RT_EOK)
187     {
188         return ret;
189     }
190     for(i=0; i<device->cfg_desc->bNumInterfaces; i++)
191     {
192         /* get interface descriptor through configuration descriptor */
193         ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc);
194         if(ret != RT_EOK)
195         {
196             rt_kprintf("rt_usb_get_interface_descriptor error\n");
197             return -RT_ERROR;
198         }
199 
200         LOG_D("interface class 0x%x, subclass 0x%x",
201                                     intf_desc->bInterfaceClass,
202                                     intf_desc->bInterfaceSubClass);
203         /* alloc pipe*/
204         for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++)
205         {
206             rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc);
207             if(ep_desc != RT_NULL)
208             {
209                 if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK)
210                 {
211                     rt_kprintf("alloc pipe failed\n");
212                     return -RT_ERROR;
213                 }
214                 rt_usb_instance_add_pipe(device,pipe);
215             }
216             else
217             {
218                 rt_kprintf("get endpoint desc failed\n");
219                 return -RT_ERROR;
220             }
221         }
222         /* find driver by class code found in interface descriptor */
223         drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass,
224             intf_desc->bInterfaceSubClass);
225 
226         if(drv != RT_NULL)
227         {
228             /* allocate memory for interface device */
229             device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf));
230             if(device->intf[i] == RT_NULL)
231             {
232                 return -RT_ENOMEM;
233             }
234             device->intf[i]->drv = drv;
235             device->intf[i]->device = device;
236             device->intf[i]->intf_desc = intf_desc;
237             device->intf[i]->user_data = RT_NULL;
238 
239             /* open usb class driver */
240             ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]);
241             if(ret != RT_EOK)
242             {
243                 rt_kprintf("interface %d run class driver error\n", i);
244             }
245         }
246         else
247         {
248             rt_kprintf("find usb device driver failed\n");
249             continue;
250         }
251     }
252 
253     return RT_EOK;
254 }
255 
256 /**
257  * This function will detach an usb device instance from its host controller,
258  * and release all resource.
259  *
260  * @param device the usb device instance.
261  *
262  * @return the error code, RT_EOK on successfully.
263  */
rt_usbh_detach_instance(uinst_t device)264 rt_err_t rt_usbh_detach_instance(uinst_t device)
265 {
266     int i = 0;
267     rt_list_t * l;
268     if(device == RT_NULL)
269     {
270         rt_kprintf("no usb instance to detach\n");
271         return -RT_ERROR;
272     }
273 
274     /* free configration descriptor */
275     if (device->cfg_desc) {
276         for (i = 0; i < device->cfg_desc->bNumInterfaces; i++)
277         {
278             if (device->intf[i] == RT_NULL) continue;
279             if (device->intf[i]->drv == RT_NULL) continue;
280 
281             RT_ASSERT(device->intf[i]->device == device);
282 
283             LOG_D("free interface instance %d", i);
284             rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]);
285             rt_free(device->intf[i]);
286         }
287         rt_free(device->cfg_desc);
288     }
289 
290     rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
291     rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
292 
293     while(device->pipe.next!= &device->pipe)
294     {
295         l = device->pipe.next;
296         rt_list_remove(l);
297         rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list));
298     }
299     rt_memset(device, 0, sizeof(struct uinstance));
300 
301     return RT_EOK;
302 }
303 
304 /**
305  * This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance,
306  *
307  * @param device the usb device instance.
308  * @param type the type of descriptor bRequest.
309  * @param buffer the data buffer to save requested data
310  * @param nbytes the size of buffer
311  *
312  * @return the error code, RT_EOK on successfully.
313  */
rt_usbh_get_descriptor(uinst_t device,rt_uint8_t type,void * buffer,int nbytes)314 rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer,
315     int nbytes)
316 {
317     struct urequest setup;
318     int timeout = USB_TIMEOUT_BASIC;
319 
320     RT_ASSERT(device != RT_NULL);
321 
322     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
323         USB_REQ_TYPE_DEVICE;
324     setup.bRequest = USB_REQ_GET_DESCRIPTOR;
325     setup.wIndex = 0;
326     setup.wLength = nbytes;
327     setup.wValue = type << 8;
328 
329     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
330     {
331         if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
332         {
333             if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
334             {
335                 return RT_EOK;
336             }
337         }
338     }
339     return -RT_ERROR;
340 }
341 
342 /**
343  * This function will set an address to the usb device.
344  *
345  * @param device the usb device instance.
346  *
347  * @return the error code, RT_EOK on successfully.
348  */
rt_usbh_set_address(uinst_t device)349 rt_err_t rt_usbh_set_address(uinst_t device)
350 {
351     struct urequest setup;
352     int timeout = USB_TIMEOUT_BASIC;
353 
354     RT_ASSERT(device != RT_NULL);
355 
356     LOG_D("rt_usb_set_address");
357 
358     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
359         USB_REQ_TYPE_DEVICE;
360     setup.bRequest = USB_REQ_SET_ADDRESS;
361     setup.wIndex = 0;
362     setup.wLength = 0;
363     setup.wValue = device->index;
364 
365     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
366     {
367         return -RT_ERROR;
368     }
369     if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
370     {
371         device->address = device->index;
372     }
373 
374     return RT_EOK;
375 }
376 
377 /**
378  * This function will set a configuration to the usb device.
379  *
380  * @param device the usb device instance.
381  * @param config the configuration number.
382   *
383  * @return the error code, RT_EOK on successfully.
384  */
rt_usbh_set_configure(uinst_t device,int config)385 rt_err_t rt_usbh_set_configure(uinst_t device, int config)
386 {
387     struct urequest setup;
388     int timeout = USB_TIMEOUT_BASIC;
389 
390     /* check parameter */
391     RT_ASSERT(device != RT_NULL);
392 
393     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
394         USB_REQ_TYPE_DEVICE;
395     setup.bRequest = USB_REQ_SET_CONFIGURATION;
396     setup.wIndex = 0;
397     setup.wLength = 0;
398     setup.wValue = config;
399 
400     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
401     {
402         return -RT_ERROR;
403     }
404     if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
405     {
406         return -RT_ERROR;
407     }
408     return RT_EOK;
409 }
410 
411 /**
412  * This function will set an interface to the usb device.
413  *
414  * @param device the usb device instance.
415  * @param intf the interface number.
416  *
417  * @return the error code, RT_EOK on successfully.
418  */
rt_usbh_set_interface(uinst_t device,int intf)419 rt_err_t rt_usbh_set_interface(uinst_t device, int intf)
420 {
421     struct urequest setup;
422     int timeout = USB_TIMEOUT_BASIC;
423 
424     /* check parameter */
425     RT_ASSERT(device != RT_NULL);
426 
427     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
428         USB_REQ_TYPE_INTERFACE;
429     setup.bRequest = USB_REQ_SET_INTERFACE;
430     setup.wIndex = 0;
431     setup.wLength = 0;
432     setup.wValue = intf;
433 
434     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
435     {
436         return -RT_ERROR;
437     }
438 
439     return RT_EOK;
440 }
441 
442 /**
443  * This function will clear feature for the endpoint of the usb device.
444  *
445  * @param device the usb device instance.
446  * @param endpoint the endpoint number of the usb device.
447  *
448  * @return the error code, RT_EOK on successfully.
449  */
rt_usbh_clear_feature(uinst_t device,int endpoint,int feature)450 rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature)
451 {
452     struct urequest setup;
453     int timeout = USB_TIMEOUT_BASIC;
454 
455     /* check parameter */
456     RT_ASSERT(device != RT_NULL);
457 
458     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
459         USB_REQ_TYPE_ENDPOINT;
460     setup.bRequest = USB_REQ_CLEAR_FEATURE;
461     setup.wIndex = endpoint;
462     setup.wLength = 0;
463     setup.wValue = feature;
464 
465     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
466     {
467         return -RT_ERROR;
468     }
469 
470     return RT_EOK;
471 }
472 
473 /**
474  * This function will get an interface descriptor from the configuration descriptor.
475  *
476  * @param cfg_desc the point of configuration descriptor structure.
477  * @param num the number of interface descriptor.
478  * @intf_desc the point of interface descriptor point.
479  *
480  * @return the error code, RT_EOK on successfully.
481  */
rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc,int num,uintf_desc_t * intf_desc)482 rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
483     uintf_desc_t* intf_desc)
484 {
485     rt_uint32_t ptr, depth = 0;
486     udesc_t desc;
487 
488     /* check parameter */
489     RT_ASSERT(cfg_desc != RT_NULL);
490 
491     ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
492     while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
493     {
494         if(depth++ > 0x20)
495         {
496             *intf_desc = RT_NULL;
497             return -RT_EIO;
498         }
499         desc = (udesc_t)ptr;
500         if(desc->type == USB_DESC_TYPE_INTERFACE)
501         {
502             if(((uintf_desc_t)desc)->bInterfaceNumber == num)
503             {
504                 *intf_desc = (uintf_desc_t)desc;
505 
506                 LOG_D("rt_usb_get_interface_descriptor: %d", num);
507                 return RT_EOK;
508             }
509         }
510         ptr = (rt_uint32_t)desc + desc->bLength;
511     }
512 
513     rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
514     return -RT_EIO;
515 }
516 
517 /**
518  * This function will get an endpoint descriptor from the interface descriptor.
519  *
520  * @param intf_desc the point of interface descriptor structure.
521  * @param num the number of endpoint descriptor.
522  * @param ep_desc the point of endpoint descriptor point.
523  *
524  * @return the error code, RT_EOK on successfully.
525  */
rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc,int num,uep_desc_t * ep_desc)526 rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
527     uep_desc_t* ep_desc)
528 {
529     int count = 0, depth = 0;
530     rt_uint32_t ptr;
531     udesc_t desc;
532 
533     /* check parameter */
534     RT_ASSERT(intf_desc != RT_NULL);
535     RT_ASSERT(num < intf_desc->bNumEndpoints);
536     *ep_desc = RT_NULL;
537 
538     ptr = (rt_uint32_t)intf_desc + intf_desc->bLength;
539     while(count < intf_desc->bNumEndpoints)
540     {
541         if(depth++ > 0x20)
542         {
543             *ep_desc = RT_NULL;
544             return -RT_EIO;
545         }
546         desc = (udesc_t)ptr;
547         if(desc->type == USB_DESC_TYPE_ENDPOINT)
548         {
549             if(num == count)
550             {
551                 *ep_desc = (uep_desc_t)desc;
552 
553                 LOG_D("rt_usb_get_endpoint_descriptor: %d", num);
554                 return RT_EOK;
555             }
556             else count++;
557         }
558         ptr = (rt_uint32_t)desc + desc->bLength;
559     }
560 
561     rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num);
562     return -RT_EIO;
563 }
564 
rt_usb_hcd_pipe_xfer(uhcd_t hcd,upipe_t pipe,void * buffer,int nbytes,int timeout)565 int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout)
566 {
567     rt_size_t remain_size;
568     rt_size_t send_size;
569     remain_size = nbytes;
570     rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
571     do
572     {
573         LOG_D("pipe transform remain size,: %d", remain_size);
574         send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
575         if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, send_size, timeout) == send_size)
576         {
577             remain_size -= send_size;
578             pbuffer += send_size;
579         }
580         else
581         {
582             return 0;
583         }
584     }while(remain_size > 0);
585     return nbytes;
586 }
587