Linux-USB Gadget : Part 6: dummy hcd 驱动简介
作者: zjujoe 转载请注明出处
Email:zjujoe@yahoo.com
BLOG:http://blog.csdn.net/zjujoe
前言
一直没有弄明白 dummy hcd 到底有什么用,因为它位于 gadget 目录里,以为是一个软件模拟的 udc 驱动。但是想想 gadget
驱动功能需要主机端触发,不知道这么一个假的 udc 驱动到底怎么触发数据传输。
今天简单的分析了一下代码。发现原来 dummy hcd 包含了 host controller 及 device controller 驱动, 这样, 就可以在同一台机器上进行 host 和 device 端的传输。如果你正在写主机端的 client 驱动或者设备端的 gadget 驱动,使用 dummy hcd 是很高效的。 下面简单分析一下这个驱动。
代码
看一下初始化代码:
2021 static int __init init (void)
2022 {
2023
int retval;
2025 if (usb_disabled
())
2028 retval
= platform_driver_register
(&dummy_hcd_driver);
2029 if
(retval < 0)
2030
return retval;
2032 retval
= platform_driver_register
(&dummy_udc_driver);
2033 if
(retval < 0)
2034
goto err_register_udc_driver;
2036 retval
= platform_device_register
(&the_hcd_pdev);
2037 if
(retval < 0)
2038
goto err_register_hcd;
2040 retval
= platform_device_register
(&the_udc_pdev);
2041 if
(retval < 0)
2042
goto err_register_udc;
2043 return
retval;
2045 err_register_udc:
2046 platform_device_unregister
(&the_hcd_pdev);
2047 err_register_hcd:
2048 platform_driver_unregister
(&dummy_udc_driver);
2049 err_register_udc_driver:
2050 platform_driver_unregister
(&dummy_hcd_driver);
2051 return
retval;
2052 }
2053 module_init
(init);
同时注册了 usb 主机端、设备端 的驱动及设备。再看一下该“设备”提供的 “端点”:
124
static const char *const ep_name [] =
{
125 ep0name, /*
everyone has ep0 */
127 /* act like a net2280: high
speed, six configurable endpoints */
128 "ep-a", "ep-b",
"ep-c", "ep-d", "ep-e", "ep-f",
130 /*
or like pxa250: fifteen fixed function endpoints */
131 "ep
"ep
132 "ep
"ep
"ep9out-iso", "ep
133 "ep
134
"ep
136 /*
or like sa1100: two fixed function endpoints */
137 "ep1out-bulk", "ep
138 };
可见,dummy_hcd 提供了丰富的端点类型。可以用来测试各种上层驱动。
再研究一下数据是怎么在host 端和 client 端进行传输的, 我们使用
kft 工具画出一次数据传输的函数调用流程:
数据通过 usb_submit_urb 提交后,函数
dummy_timer 会调用 transfer 函数进行数据传输:
1065
/* transfer up to a frame's worth; caller must own lock */
1066
static int
1067
transfer
(struct dummy
*dum, struct urb
*urb, struct dummy_ep
*ep, int limit)
1068
{
1069 struct dummy_request *req;
1111 /* else transfer
packet(s) */
1112 ubuf = urb->transfer_buffer
+ urb->actual_length;
1113 rbuf = req->req.buf +
req->req.actual;
1114 if (to_host)
1115 memcpy (ubuf,
rbuf, len);
1116 else
1117 memcpy (rbuf,
ubuf, len);
。。。
这里, transfer 函数会调用 memcpy 进行数据 ”传输”。
再看一下控制传输, 先看调用图:
以及代码:
1238 /* drive both sides of the transfers; looks
like irq handlers to
1239
* both drivers except the
callbacks aren't in_irq().
1240
*/
1241
static void dummy_timer
(unsigned long _dum)
1242
{
。。。
1336
/* handle control requests */
1337
if (ep == &dum->ep [0] && ep->setup_stage) {
1338 struct usb_ctrlrequest setup;
1341 unsigned w_index;
1342 unsigned w_value;
1344
setup =
*(struct usb_ctrlrequest*)
urb->setup_packet;
1345 w_index = le16_to_cpu(setup.wIndex);
1346 w_value = le16_to_cpu(setup.wValue);
1347 if (le16_to_cpu(setup.wLength)
!=
1348 urb->transfer_buffer_length)
{
1349 maybe_set_status
(urb, -EOVERFLOW);
1350 goto
return_urb;
1351 }
。。。
1367 /* gadget driver
never sees set_address or operations
1368 * on standard feature
flags. some hardware doesn't
1369 * even expose them.
1370 */
1372 ep->setup_stage =
0;
1373 ep->halted = 0;
1374 switch (setup.bRequest)
{
1375 case USB_REQ_SET_ADDRESS:
1376 if (setup.bRequestType
!= Dev_Request)
1377 break;
1379 maybe_set_status
(urb, 0);
1380 dev_dbg (udc_dev(dum),
"set_address = %d/n",
1381
w_value);