LDD3: usb-skeleton模块编译和测试
usb-skeleton模块可以用来测试支持bulk传输端口的usb设备,如usb存储。它将用户空间的读写数据操作转换成bulk端口的数据传输,即将用户write的数据从bulk out端口发送,read的请求数据从bulk in端口接收。
一个简单的测试方法是通过usb-skeleton模块读取usb存储设备上第一个block的数据(一般为MBR或PBR数据块)。
如果用qemu测试,可参考qemu: usb存储设备仿真
根据usb mass storage class bulk-only传输协议,一次读数据传输流程为:
a. H->D : [bulk out] 31字节CBW(Command Block Wrapper)数据块
b. D->H : [bulk in ] n字节数据块
c. D->H : [bulk in ] 13字节CSW(Command Status Wrapper)数据快
其中CBW由标志 “USBC” 开始,包含15字节数据头和16字节实际命令(常用的为SCSI或UFI命令集)。CSW由标志 “USBS” 开始。
读数据块命令选择SCSI和UFI都支持的READ(10)命令。
编译
首先把模块绑定的设备信息修改为要测试的设备,比如绑定qemu虚拟的usb存储设备:
#define USB_SKEL_VENDOR_ID 0x46F4
#define USB_SKEL_PRODUCT_ID 0x0001
有一些编译错误如下:
fatal error: linux/config.h: No such file or directory
删除 #include
fatal error: linux/smp_lock.h: No such file or directory
与这头文件相关的是大内核锁机制,在新的内核已经移除,删除相关代码:
#include
lock_kernel();
unlock_kernel();
应改为使用细粒度锁,不过在这个简单测试里可以忽略竞态
error: implicit declaration of function ‘err’
error: implicit declaration of function ‘dbg’
error: implicit declaration of function ‘info’
自定义一下这几个函数:
#define err(fmt, arg...) printk(KERN_ERR fmt "\n" , ##arg)
#define info(fmt, arg...) printk(KERN_INFO fmt "\n" , ##arg)
#define dbg(fmt, arg...) printk(KERN_DEBUG fmt "\n" , ##arg)
warning: passing argument 5 of ‘usb_bulk_msg’ from incompatible pointer type [enabled by default]&count, HZ*10);
note: expected ‘int *’ but argument is of type ‘size_t *’
在64位平台编译出现的参数类型不匹配警告,因为size_t是64位的,而int是32位的,修改如下:
static ssize_t skel_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{int actual_cnt;...retval = usb_bulk_msg(dev->udev,...&actual_cnt, HZ*10);if (!retval) {if (copy_to_user(buffer, dev->bulk_in_buffer, actual_cnt))retval = -EFAULT;elseretval = actual_cnt;}
error: implicit declaration of function ‘usb_buffer_free’
error: implicit declaration of function ‘usb_buffer_alloc’
这两个函数已由 usb_free_coherent 和 usb_alloc_coherent 替代,参数不变。
warning: passing argument 6 of ‘usb_fill_bulk_urb’ from incompatible pointer type
callback函数参数发生了变化,修改为:
static void skel_write_bulk_callback(struct urb *urb)
error: unknown field ‘mode’ specified in initializer
error: unknown field ‘owner’ specified in initializer
mode 已从 usb_class_driver 结构移除, owner 已从 usb_driver 结构移除,删掉即可。
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.owner = THIS_MODULE,
运行
如果 usb-storage 驱动已运行,则测试设备会自动绑定该驱动而无法绑定 usb-skeleton 模块,可以先卸载 usb-storage 模块或通过下面命令将设备接口与驱动解绑,再安装 usb-skeleton 模块:
# echo "1-1:1.0" > /sys/bus/usb/drivers/usb-storage/unbind
“1-1:1.0” 为测试设备接口的地址,可通过下面信息查看:
usb 1-1: New USB device found, idVendor=46f4, idProduct=0001
...
usb-storage 1-1:1.0: USB Mass Storage device detected
安装并运行结果如下:
/ # lsusb
Bus 001 Device 002: ID 46f4:0001
Bus 001 Device 001: ID 1d6b:0002
Bus 002 Device 001: ID 1d6b:0001
/ #
/ # insmod /lib/modules/3.12.74/usb-skeleton.ko
USB Skeleton device now attached to USBSkel-0
usbcore: registered new interface driver skeleton
/ #
/ # ls /sys/class/usbmisc/
skel0
/ #
/ # ls -l /sys/class/usbmisc/skel0/
total 0
-r--r--r-- 1 0 0 4096 Oct 8 14:29 dev
lrwxrwxrwx 1 0 0 0 Oct 8 14:29 device -> ../../../1-1:1.0
drwxr-xr-x 2 0 0 0 Oct 8 14:29 power
lrwxrwxrwx 1 0 0 0 Oct 8 14:29 subsystem -> ../../../../../../../../class/usbmisc
-rw-r--r-- 1 0 0 4096 Oct 8 14:29 uevent
/ #
/ # cat /sys/class/usbmisc/skel0/dev
180:0
/ #
/ # ls /sys/bus/usb/drivers/skeleton/
1-1:1.0 bind module new_id remove_id uevent unbind
/ #
/ # ls -l /dev/skel0
crw------- 1 0 0 180, 0 Oct 8 14:28 /dev/skel0
usb_register_dev 不仅会在 /sys/class/usbmisc/ 下创建 skel0 目录,还会在 /dev 下创建 skel0 设备文件,该文件的读写操作即为 skel_fops 所定义的操作。
测试
用户空间的测试代码如下:
#include
#include
#include
#include
#include
#include static void memdump(char *buf, int size)
{
#define LINE_SZ 16int len, i;while (size) {len = (size > LINE_SZ) ? LINE_SZ : size;for (i = 0; i < len; i++)fprintf(stdout, " %02x", (unsigned char)buf[i]);for (; i < LINE_SZ; i++)fprintf(stdout, " ");fprintf(stdout, " : ");for (i = 0; i < len; i++) {if ((buf[i] >= '0') && (buf[i] <= 'z'))fprintf(stdout, "%c", buf[i]);elsefprintf(stdout, ".");}fprintf(stdout, "\n");size -= len;buf += len;}
}#define DEVICE "/dev/skel0"
#define BLK_SZ 512
#define CBW_SZ 31
#define CSW_SZ 13/* CBW with SCSI READ(10), read 1 block from block 0 */
static char cbw_read10[CBW_SZ] = {0x55, 0x53, 0x42, 0x43, 0x74, 0x65, 0x73, 0x74,0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x0A,0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};int main(void)
{char buf[BLK_SZ], *pbuf;int fd, ret, done = 0;fd = open(DEVICE, O_RDWR);if (fd < 0) {fprintf(stderr, "Failed to open '%s': %s\n", DEVICE, strerror(errno));return -1;}fprintf(stdout, "%s opened\n", DEVICE);/* send CBW with READ(10) command */memcpy(buf, cbw_read10, CBW_SZ);if (write(fd, buf, CBW_SZ) != CBW_SZ) {fprintf(stderr, "Failed to send CBW: %s\n", strerror(errno));close(fd);return -1;}fprintf(stdout, "Sent CBW with READ(10):\n");memdump(buf, CBW_SZ);/* read block 0 */pbuf = buf;while (done < BLK_SZ) {ret = read(fd, pbuf, (BLK_SZ - done));if (ret <= 0) {fprintf(stderr, "Failed to read block 0 (done %d): %s\n",done, strerror(errno));close(fd);return -1;}done += ret;pbuf += ret;}fprintf(stdout, "Read block 0:\n");memdump(buf, BLK_SZ);/* get CSW */if (read(fd, buf, CSW_SZ) != CSW_SZ) {fprintf(stderr, "Failed to get CSW: %s\n", strerror(errno));close(fd);return -1;}fprintf(stdout, "Got CSW:\n");memdump(buf, CSW_SZ);close(fd);return 0;}
编译:
$ gcc -static -o usbtest usbtest.c
运行:
/lib/modules/3.12.74 # ./usbtest
/dev/skel0 opened
Sent CBW with READ(10):55 53 42 43 74 65 73 74 00 02 00 00 80 00 0a 28 : USBCtest........00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 : ...............
Read block 0:eb 3c 90 6d 6b 66 73 2e 66 61 74 00 02 04 01 00 : .<.mkfs.fat.....02 00 02 00 00 f8 40 00 20 00 40 00 00 00 00 00 : ......@...@.....00 00 01 00 80 00 29 79 4e ed 63 4e 4f 20 4e 41 : .......yN.cNO.NA4d 45 20 20 20 20 46 41 54 31 36 20 20 20 0e 1f : ME....FAT16.....be 5b 7c ac 22 c0 74 0b 56 b4 0e bb 07 00 cd 10 : .[....t.V.......5e eb f0 32 e4 cd 16 cd 19 eb fe 54 68 69 73 20 : ^..2.......This.69 73 20 6e 6f 74 20 61 20 62 6f 6f 74 61 62 6c : is.not.a.bootabl65 20 64 69 73 6b 2e 20 20 50 6c 65 61 73 65 20 : e.disk...Please.69 6e 73 65 72 74 20 61 20 62 6f 6f 74 61 62 6c : insert.a.bootabl65 20 66 6c 6f 70 70 79 20 61 6e 64 0d 0a 70 72 : e.floppy.and..pr65 73 73 20 61 6e 79 20 6b 65 79 20 74 6f 20 74 : ess.any.key.to.t72 79 20 61 67 61 69 6e 20 2e 2e 2e 20 0d 0a 00 : ry.again........00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa : ..............U.
Got CSW:55 53 42 53 74 65 73 74 00 00 00 00 00 : USBStest.....
/lib/modules/3.12.74 #
可看到读取的第一个block数据为PBR,该设备采用FAT16格式。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
