usb总线驱动模型里也有struct usb_driver和struct usb_device,这点与platform虚拟总线里的struct platform_device和struct platform_driver相似。不同之处是
platform模型中,需要写两个驱动文件,分别是driver.ko和device.ko,然后分别insmod。
usb驱动只需要写一个驱动文件driver,只insmod driver.ko即可,为什么不insmod device.ko了呢?因为没写,恩,不必写。因为usb是实际的总线,当有usb设备插入的时候usbcore就会自动对该设备执行枚举,枚举之后usbcore就获知了该设备的相关资源,然后把资源信息返回给能匹配的驱动。
简言之,
平台驱动的insmod device.ko是一个模仿usb设备插入的动作,device.ko中记录了资源信息,通过insmod device,平台核心获取device的资源信息返回给匹配的驱动。
usb驱动模型中资源信息在储存在设备中呢,在usb设备插入时通过枚举,usbcore把资源信息读出来塞进返回给匹配的驱动。
怎么匹配的呢?对于platform是通过driver的名字和device的名字匹配的。对于usb模型,us_driver中有usb_device_id table,记录该驱动可以处理的设备 的idVerdor和idProduct
当usb设备插入时,usbcore通过枚举过程获知当前设备的信息,包括两个id,然后和注册在usb总线上的各个usb驱动里的usb_device_id table比较,有相同的的话,就调用哪个驱动的probe函数,并把该设备的资源信息(inteface)作为参数交给probe.这样哪个驱动就达到处理这个设备的目的了.
当然,先插入usb设备再insmod driver.ko,这种情况下去匹配两者的实现跟上面类似。
一下是linux/drivers/hid/usbhid/usbmouse.c里的一个usb_device_id table
如果只声明支持一个设备可以用如下宏
linux/include/usb.h
*****************************************************************************************************************************************************************************
一下是一个最简单的usb测试程序(比较完整的见linux-2.6.32.2/drivers/usb/usb-skeleton.c),仅测试一下usbcore对设备枚举玩,是否能够成功和此驱动匹配而进入probe函数
在板子上,先不要插usb设备
****************************************************************************************************************************************************************
另外在mini2440上已经有一个配置,
Device Drivers ---> [*] HID Devices ---> <*> USB Human Interface Device (full HID) support
这个驱动貌似通吃所有hid设备,包括mouse kbd,自定义hid等。所以如果我插入我的自定义hid设备时,就会被usbcore把我的设备优先匹配给这个驱动(即使我自己写的驱动已经insmod),这个驱动会在其probe函数中为我的设备自动创建一个input驱动,设备文件在/dev/input/eventx(x=1 2 3 ...)。但是我的设备没有按鼠标或键盘的数据格式给主机usbcore传送数据(当然我也不想这样传输,因为我的设备是自定义hid设备,当然要自定义的数据及格式,当然也不想让这个驱动去处理我的设备发来的数据)。
目前的解决办法是把这个选项给禁掉。这样usbcore就会把我的自定义hid设备匹配给我自己写的驱动了。
当然禁掉之后,usb鼠标 键盘都不能用了。不过可以配置一下另外一个鼠标和键盘的驱动,也可用的。如下
Device Drivers ---> [*] HID Devices --->USB HID Boot Protocol drivers ---> <*> USB HIDBP Keyboard (simple Boot) support
<*> USB HIDBP Mouse (simple Boot) support
不过要想出现USB HID Boot Protocol drivers项目,需要一些操作,在Kconfig文件line 47如下
USB符号不要选择为空(要选择m或y),USB_HID符号不要选择为y。最后那个符号EMBEDDED暂时没找到在哪里配的,就删掉了。即
再看一下/linux-2.6.32.2/drivers/hid/usbhid/Makefile,
<*> USB Human Interface Device (full HID) support 对应的驱动应该是/linux-2.6.32.2/drivers/hid/usbhid/usbhid.c
<*> USB HIDBP Keyboard (simple Boot) support 对应的驱动是/linux-2.6.32.2/drivers/hid/usbhid/usbkbd.c
<*> USB HIDBP Keyboard (simple Boot) support 对应的驱动是/linux-2.6.32.2/drivers/hid/usbhid/usbmouse.c
后两者还好说,目录下确实有usbkbd.c和usbmouse.c,但是没有usbhid.c文件,那么usbhid.o哪里来的呢?恩,没人规定usbhid.o非得只由usbhid.c才能生成。
同目录下有一个文件.usbhid.o.cmd ,记录了usbhid.o由hid-quirks.o和hid-core.o生成。目前为止感觉很麻烦の。
platform模型中,需要写两个驱动文件,分别是driver.ko和device.ko,然后分别insmod。
usb驱动只需要写一个驱动文件driver,只insmod driver.ko即可,为什么不insmod device.ko了呢?因为没写,恩,不必写。因为usb是实际的总线,当有usb设备插入的时候usbcore就会自动对该设备执行枚举,枚举之后usbcore就获知了该设备的相关资源,然后把资源信息返回给能匹配的驱动。
简言之,
平台驱动的insmod device.ko是一个模仿usb设备插入的动作,device.ko中记录了资源信息,通过insmod device,平台核心获取device的资源信息返回给匹配的驱动。
usb驱动模型中资源信息在储存在设备中呢,在usb设备插入时通过枚举,usbcore把资源信息读出来塞进返回给匹配的驱动。
怎么匹配的呢?对于platform是通过driver的名字和device的名字匹配的。对于usb模型,us_driver中有usb_device_id table,记录该驱动可以处理的设备 的idVerdor和idProduct
当usb设备插入时,usbcore通过枚举过程获知当前设备的信息,包括两个id,然后和注册在usb总线上的各个usb驱动里的usb_device_id table比较,有相同的的话,就调用哪个驱动的probe函数,并把该设备的资源信息(inteface)作为参数交给probe.这样哪个驱动就达到处理这个设备的目的了.
当然,先插入usb设备再insmod driver.ko,这种情况下去匹配两者的实现跟上面类似。
一下是linux/drivers/hid/usbhid/usbmouse.c里的一个usb_device_id table
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) },
{ }
};
在linux/include/hid.h#define USB_INTERFACE_CLASS_HID 3//在usb协议的接口描述符的bInterfaceClass字段如果为3,表示该设备为hid设备
#define USB_INTERFACE_SUBCLASS_BOOT 1//在usb协议的接口描述符的bInterfaceSubClass字段如果为1,表示是hid的子类:支持bios引导的hid
#define USB_INTERFACE_PROTOCOL_MOUSE 2//在usb协议的接口描述符的bInterfaceProtocol字段如果为2,表示协议为鼠标(在支持bios引导时用的,键盘协议为1)
USB_INTERFACE_INFO在linux/include/usb.h中定义,如下#define USB_INTERFACE_INFO(cl, sc, pr) \
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
.bInterfaceClass = (cl), \
.bInterfaceSubClass = (sc), \
.bInterfaceProtocol = (pr)
所以它表示只要是hid设备,且支持bios引导,且引导时的协议为mouse,则此驱动都可以处理。如果只声明支持一个设备可以用如下宏
linux/include/usb.h
#define USB_DEVICE(vend,prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
比如在usb_device_id里 添加一项,USB_DEVICE(0606,0001)*****************************************************************************************************************************************************************************
一下是一个最简单的usb测试程序(比较完整的见linux-2.6.32.2/drivers/usb/usb-skeleton.c),仅测试一下usbcore对设备枚举玩,是否能够成功和此驱动匹配而进入probe函数
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "song"
#define DRIVER_DESC "usb test"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
static int test_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
printk("probe\n");
return 0;
}
static void test_usb_disconnect(struct usb_interface *intf)
{
printk("disconnect\n");
}
static struct usb_device_id test_usb_id_table [] = {
{USB_DEVICE(0x0606,0x0001) },
{}
};
MODULE_DEVICE_TABLE (usb, test_usb_id_table);
static struct usb_driver test_usb_driver = {
.name = "test_song",
.probe = test_usb_probe,
.disconnect = test_usb_disconnect,
.id_table = test_usb_id_table,
};
static int __init test_usb_init(void)
{
int retval = usb_register(&test_usb_driver);
if (retval == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
return retval;
}
static void __exit test_usb_exit(void)
{
usb_deregister(&test_usb_driver);
}
module_init(test_usb_init);
module_exit(test_usb_exit);
makefileifneq ($(KERNELRELEASE),)
obj-m := test_usb.o
else
KDIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2
#KDIR := /lib/modules/`uname -r`/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
而设备侧(我的是sic8051f320单片机,内含usb从接口)的设备描述符和接口描述符,报告描述符设置如下,一下是一个自定义hid设备的部分描述符的设置code DEVICE_DESCRIPTOR DeviceDesc =
{
18, // bLength
0x01, // bDescriptorType
SWAP16(0x0200), // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
EP0_PACKET_SIZE, // bMaxPacketSize0
SWAP16(USB_HID_VID), // idVendor 0x0606 和linux侧驱动中的对应
SWAP16(USB_HID_PID), // idProduct 0x0001 和linux侧驱动中的对应
0x0001, // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01 // bNumConfigurations
}; //end of DeviceDesc
{
0x09, // bLength
0x04, // bDescriptorType
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x02, // bNumEndpoints
0x03, // bInterfaceClass 指定为hid类
0x00, // bInterfaceSubClass 非鼠标键盘 0
0x00, // bInterfaceProcotol 非鼠标键盘 0
0x00 // iInterface
}, //end of InterfaceDesc
//Report descriptor
code unsigned char ReportDesc[] =
{
// 0x06, 0x00, 0xFF,// ; Usage Page
0x05, 0x01, //桌面设备
// 0x09, 0x01,// ; Usage
0x09, 0x00, //未定义用途,结合接口描述符的bInterfaceClass=03,则为自动以hid
0xA1, 0x01, // ; Collection//用未定义用途开集合
0x09, 0x01,// ; Usage
0x95, 0x20,// ; Report Count
0x75, 0x08,// ; Report Size
0x15, 0x00,// ; Logical Minimum
0x26, 0xFF, 0x00,// ; Logical Maximum
0x81, 0x02,// ; Input
0x09, 0x02,// ; Usage
0x95, 0x20,// ; Report Count
0x75, 0x08,// ; Report Size
0x91, 0x02,// ; Output
0xC0
};
在板子上,先不要插usb设备
[root@FriendlyARM plg]# insmod test_usb.ko
usbcore: registered new interface driver test_song
test_usb: v1.0:usb test
插上设备,信息如下,出现probe信息,说明成功匹配到驱动[root@FriendlyARM plg]# usb 1-1.1: new full speed USB device using s3c2410-ohci and address 8
usb 1-1.1: New USB device found, idVendor=0606, idProduct=0001//厂商和产品id。不要受迷惑,是0x0606和0x0001
usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.1: Product: nRF24LU1 ADapter
usb 1-1.1: Manufacturer: Weisdigital
usb 1-1.1: SerialNumber: Ver1.0 N000
usb 1-1.1: configuration #1 chosen from 1 choice//以上这些信息由usbcore在枚举完设备打印出来
probe
拔出设备,触发函数test_usb_disconnect,信息如下usb 1-1.1: USB disconnect, address 8
disconnect
****************************************************************************************************************************************************************
另外在mini2440上已经有一个配置,
Device Drivers ---> [*] HID Devices ---> <*> USB Human Interface Device (full HID) support
这个驱动貌似通吃所有hid设备,包括mouse kbd,自定义hid等。所以如果我插入我的自定义hid设备时,就会被usbcore把我的设备优先匹配给这个驱动(即使我自己写的驱动已经insmod),这个驱动会在其probe函数中为我的设备自动创建一个input驱动,设备文件在/dev/input/eventx(x=1 2 3 ...)。但是我的设备没有按鼠标或键盘的数据格式给主机usbcore传送数据(当然我也不想这样传输,因为我的设备是自定义hid设备,当然要自定义的数据及格式,当然也不想让这个驱动去处理我的设备发来的数据)。
目前的解决办法是把这个选项给禁掉。这样usbcore就会把我的自定义hid设备匹配给我自己写的驱动了。
当然禁掉之后,usb鼠标 键盘都不能用了。不过可以配置一下另外一个鼠标和键盘的驱动,也可用的。如下
Device Drivers ---> [*] HID Devices --->USB HID Boot Protocol drivers ---> <*> USB HIDBP Keyboard (simple Boot) support
<*> USB HIDBP Mouse (simple Boot) support
不过要想出现USB HID Boot Protocol drivers项目,需要一些操作,在Kconfig文件line 47如下
menu "USB HID Boot Protocol drivers"
depends on USB!=n && USB_HID!=y && EMBEDDED
即USB符号不要选择为空(要选择m或y),USB_HID符号不要选择为y。最后那个符号EMBEDDED暂时没找到在哪里配的,就删掉了。即
menu "USB HID Boot Protocol drivers"
depends on USB!=n && USB_HID!=y
按照上面设置以后就会make menuconfig里就会出现USB HID Boot Protocol drivers项目。再看一下/linux-2.6.32.2/drivers/hid/usbhid/Makefile,
# Multipart objects.
usbhid-objs := hid-core.o hid-quirks.o
# Optional parts of multipart objects.
ifeq ($(CONFIG_USB_HIDDEV),y)
usbhid-objs += hiddev.o
endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += hid-pidff.o
endif
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.
可知<*> USB Human Interface Device (full HID) support 对应的驱动应该是/linux-2.6.32.2/drivers/hid/usbhid/usbhid.c
<*> USB HIDBP Keyboard (simple Boot) support 对应的驱动是/linux-2.6.32.2/drivers/hid/usbhid/usbkbd.c
<*> USB HIDBP Keyboard (simple Boot) support 对应的驱动是/linux-2.6.32.2/drivers/hid/usbhid/usbmouse.c
后两者还好说,目录下确实有usbkbd.c和usbmouse.c,但是没有usbhid.c文件,那么usbhid.o哪里来的呢?恩,没人规定usbhid.o非得只由usbhid.c才能生成。
同目录下有一个文件.usbhid.o.cmd ,记录了usbhid.o由hid-quirks.o和hid-core.o生成。目前为止感觉很麻烦の。
arm-linux-ld -EL -r -o drivers/hid/usbhid/usbhid.o drivers/hid/usbhid/hid-core.o drivers/hid/usbhid/hid-quirks.o