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