Linux-USB Gadget : Part 6: dummy hcd 驱动简介

Linux-USB Gadget : Part 6: dummy hcd 驱动简介

作者: zjujoe 转载请注明出处

Emailzjujoe@yahoo.com

BLOGhttp://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;

2024

2025         if (usb_disabled ())

2026                 return -ENODEV;

2027

2028         retval = platform_driver_register (&dummy_hcd_driver);

2029         if (retval < 0)

2030                 return retval;

2031

2032         retval = platform_driver_register (&dummy_udc_driver);

2033         if (retval < 0)

2034                 goto err_register_udc_driver;

2035

2036         retval = platform_device_register (&the_hcd_pdev);

2037         if (retval < 0)

2038                 goto err_register_hcd;

2039

2040         retval = platform_device_register (&the_udc_pdev);

2041         if (retval < 0)

2042                 goto err_register_udc;

2043         return retval;

2044

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 */

126

127         /* act like a net2280: high speed, six configurable endpoints */

128         "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",

129

130         /* or like pxa250: fifteen fixed function endpoints */

131         "ep 1in -bulk", "ep2out-bulk", "ep 3in -iso", "ep4out-iso", "ep 5in -int",

132         "ep 6in -bulk", "ep7out-bulk", "ep 8in -iso", "ep9out-iso", "ep 10in -int",

133         "ep 11in -bulk", "ep12out-bulk", "ep 13in -iso", "ep14out-iso",

134                 "ep 15in -int",

135

136         /* or like sa1100: two fixed function endpoints */

137         "ep1out-bulk", "ep 2in -bulk",

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;

1070

。。。

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);

1118                         ep->last_io = jiffies;

。。。

 

这里, 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;

1339                         int                             value = 1;

1340                         struct dummy_ep                 *ep2;

1341                         unsigned                        w_index;

1342                         unsigned                        w_value;

1343

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                         }

1352

。。。

1366

1367                         /* gadget driver never sees set_address or operations

1368                          * on standard feature flags.  some hardware doesn't

1369                          * even expose them.

1370                          */

1371                         ep->last_io = jiffies;

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;

1378                                 dum->address = w_value;

1379                                 maybe_set_status (urb, 0);

1380                                 dev_dbg (udc_dev(dum), "set_address = %d/n",

1381                                                 w_value);

1382                                 value = 0;

1383                                 break;

1384                         case USB_REQ_SET_FEATURE:

1385                                 if (setup.bRequestType == Dev_Request) {

1386                                         value = 0;

1387                                         switch (w_value) {

1388                                         case USB_DEVICE_REMOTE_WAKEUP:

1389                                                 break;

1390                                         case USB_DEVICE_B_HNP_ENABLE:

1391                                                 dum->gadget.b_hnp_enable = 1;

1392                                                 break;

1393                                         case USB_DEVICE_A_HNP_SUPPORT:

1394                                                 dum->gadget.a_hnp_support = 1;

1395                                                 break;

1396                                         case USB_DEVICE_A_ALT_HNP_SUPPORT:

1397                                                 dum->gadget.a_alt_hnp_support

1398                                                         = 1;

1399                                                 break;

1400                                         default:

1401                                                 value = -EOPNOTSUPP;

1402                                         }

1403                                         if (value == 0) {

1404                                                 dum->devstatus |=

1405                                                         (1 << w_value);

1406                                                 maybe_set_status (urb, 0);

1407                                         }

1408

1409                                 } else if (setup.bRequestType == Ep_Request) {

1410                                         // endpoint halt

1411                                         ep2 = find_endpoint (dum, w_index);

1412                                         if (!ep2) {

1413                                                 value = -EOPNOTSUPP;

1414                                                 break;

1415                                         }

1416                                         ep2->halted = 1;

1417                                         value = 0;

1418                                         maybe_set_status (urb, 0);

1419                                 }

1420                                 break;

1421                         case USB_REQ_CLEAR_FEATURE:

1422                                 if (setup.bRequestType == Dev_Request) {

1423                                         switch (w_value) {

1424                                         case USB_DEVICE_REMOTE_WAKEUP:

1425                                                 dum->devstatus &= ~(1 <<

1426                                                         USB_DEVICE_REMOTE_WAKEUP);

1427                                                 value = 0;

1428                                                 maybe_set_status (urb, 0);

1429                                                 break;

1430                                         default:

1431                                                 value = -EOPNOTSUPP;

1432                                                 break;

1433                                         }

1434                                 } else if (setup.bRequestType == Ep_Request) {

1435                                         // endpoint halt

1436                                         ep2 = find_endpoint (dum, w_index);

1437                                         if (!ep2) {

1438                                                 value = -EOPNOTSUPP;

1439                                                 break;

1440                                         }

1441                                         ep2->halted = 0;

1442                                         value = 0;

1443                                         maybe_set_status (urb, 0);

1444                                 }

1445                                 break;

1446                         case USB_REQ_GET_STATUS:

1447                                 if (setup.bRequestType == Dev_InRequest

1448                                                 || setup.bRequestType

1449                                                         == Intf_InRequest

1450                                                 || setup.bRequestType

1451                                                         == Ep_InRequest

1452                                                 ) {

1453                                         char *buf;

1454

1455                                         // device: remote wakeup, selfpowered

1456                                         // interface: nothing

1457                                         // endpoint: halt

1458                                         buf = (char *)urb->transfer_buffer;

1459                                         if (urb->transfer_buffer_length > 0) {

1460                                                 if (setup.bRequestType ==

1461                                                                 Ep_InRequest) {

1462         ep2 = find_endpoint (dum, w_index);

1463         if (!ep2) {

1464                 value = -EOPNOTSUPP;

1465                 break;

1466         }

1467         buf [0] = ep2->halted;

1468                                                 } else if (setup.bRequestType ==

1469                                                                 Dev_InRequest) {

1470                                                         buf [0] = (u8)

1471                                                                 dum->devstatus;

1472                                                 } else

1473                                                         buf [0] = 0;

1474                                         }

1475                                         if (urb->transfer_buffer_length > 1)

1476                                                 buf [1] = 0;

1477                                         urb->actual_length = min (2,

1478                                                 urb->transfer_buffer_length);

1479                                         value = 0;

1480                                         maybe_set_status (urb, 0);

1481                                 }

1482                                 break;

1483                         }

1484

1485                         /* gadget driver handles all other requests.  block

1486                          * until setup() returns; no reentrancy issues etc.

1487                          */

1488                         if (value > 0) {

1489                                 spin_unlock (&dum->lock);

1490                                 value = dum->driver->setup (&dum->gadget,

1491                                                 &setup);

1492                                 spin_lock (&dum->lock);

1493

1494                                 if (value >= 0) {

1495                                         /* no delays (max 64KB data stage) */

1496                                         limit = 64*1024;

1497                                         goto treat_control_like_bulk;

1498                                 }

1499                                 /* error, see below */

1500                         }

。。。

 

dummy_timer 函数中,首先处理: set feature, get feature, set address, get status 这几种类型的请求(根据注释,有些甚至是硬件来处理的),剩下的则交给 gadget 驱动的 setup 函数。

实验

首先编译出 dummy_hcd 等各种模块, 然后, 将其拷贝到目标机器。

实验1 g_zero + usbtest

启动机器,

 

/lib/modules # insmod ./dummy_hcd.ko

Using ./dummy_hcd.ko

dummy_hcd dummy_hcd: USB Host+Gadget Emulator, driver 02 May 2005

dummy_hcd dummy_hcd: Dummy host controller

dummy_hcd dummy_hcd: new USB bus registered, assigned bus number 1

usb usb1: configuration #1 chosen from 1 choice

hub 1-0:1.0: USB hub found

hub 1-0:1.0: 1 port detected

/lib/modules # usb usb1: dummy_bus_suspe

 

/lib/modules # insmod ./usbtest.ko

Using ./usbtest.ko

usbcore: registered new interface driver usbtest

 

/lib/modules # insmod ./g_zero.ko

Using ./g_zero.ko

dummy_udc dummy_udc: binding gadget driver 'zero'

zero gadget: Gadget Zero, version: St Patrick's Day 2004

zero gadget: using dummy_udc, OUT ep-b IN ep-a

dummy_hcd dummy_hcd: port status 0x00010101 has changes

usb usb1: dummy_bus_resume

/lib/modules # dummy_hcd dummy_hcd: port status 0x00010101 has changes

zero gadget: resume

dummy_hcd dummy_hcd: port status 0x00100503 has changes

usb 1-1: new high speed USB device using dummy_hcd and address 2

zero gadget: resume

dummy_hcd dummy_hcd: port status 0x00100503 has changes

dummy_udc dummy_udc: set_address = 2

usb 1-1: configuration #3 chosen from 2 choices

dummy_udc dummy_udc: enabled ep-a (ep 1in -bulk) maxpacket 512

dummy_udc dummy_udc: enabled ep-b (ep2out-bulk) maxpacket 512

zero gadget: buflen 4096

zero gadget: high speed config #3: source and sink data

usbtest 1-1:3.0: Linux gadget zero

usbtest 1-1:3.0: high speed {control in/out bulk-in bulk-out} tests (+alt)

 

/lib/modules # mount -t usbfs none /proc/bus/usb/

/lib/modules #

/lib/modules # ./testusb -a -c10 -t1 -s4096 -g32 -v32

unknown speed   /proc/bus/usb/001/002

/proc/bus/usb/001/002 test 1,    0.096635 secs

 

测试成功

 

实验2 file storage 测试

启动机器,

 

/lib/modules # insmod ./dummy_hcd.ko

Using ./dummy_hcd.ko

dummy_hcd dummy_hcd: USB Host+Gadget Emulator, driver 02 May 2005

dummy_hcd dummy_hcd: Dummy host controller

dummy_hcd dummy_hcd: new USB bus registered, assigned bus number 1

usb usb1: configuration #1 chosen from 1 choice

hub 1-0:1.0: USB hub found

hub 1-0:1.0: 1 port detected

/lib/modules # usb usb1: dummy_bus_suspe

 

/lib/modules # insmod ./g_file_storage.ko

Using ./g_file_storage.ko

dummy_udc dummy_udc: binding gadget driver 'g_file_storage'

g_file_storage gadget: File-backed Storage Gadget, version: 28 November 2005

g_file_storage gadget: Number of LUNs=1

g_file_storage gadget-lun0: ro=0, file: /dev/mtdblock5

dummy_hcd dummy_hcd: port status 0x00010101 has changes

usb usb1: dummy_bus_resume

/lib/modules #

/lib/modules # dummy_hcd dummy_hcd: port status 0x00010101 has changes

dummy_hcd dummy_hcd: port status 0x00100503 has changes

usb 1-1: new high speed USB device using dummy_hcd and address 2

dummy_hcd dummy_hcd: port status 0x00100503 has changes

dummy_udc dummy_udc: set_address = 2

usb 1-1: configuration #1 chosen from 1 choice

dummy_udc dummy_udc: enabled ep-a (ep 1in -bulk) maxpacket 512

dummy_udc dummy_udc: enabled ep-b (ep2out-bulk) maxpacket 512

g_file_storage gadget: high speed config #1

usb usb1: dummy_bus_suspend

 

 

/lib/modules # insmod ./usb-storage.ko

Using ./usb-storage.ko

Initializing USB Mass Storage driver...

usb usb1: dummy_bus_resume

dummy_hcd dummy_hcd: port status 0x00040503 has changes

scsi0 : SCSI emulation for USB Mass Storage devices

usb-storage: device found at 2

usb-storage: waiting for device to settle before scanning

usbcore: registered new interface driver usb-storage

USB Mass Storage support registered.

/lib/modules #

/lib/modules # scsi 0:0:0:0: Direct-Access     Linux    File-Stor Gadget 0302 PQ: 0 ANSI: 2

SCSI device sda: 65536 512-byte hdwr sectors (34 MB)

sda: Write Protect is off

sda: Mode Sense: 0f 00 00 00

sda: assuming drive cache: write through

SCSI device sda: 65536 512-byte hdwr sectors (34 MB)

sda: Write Protect is off

sda: Mode Sense: 0f 00 00 00

sda: assuming drive cache: write through

 sda: unknown partition table

sd 0:0:0:0: Attached scsi removable disk sda

usb-storage: device scan complete

 

测试成功。

 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值