usb5-写成usb驱动

usb总线驱动模型里也有struct usb_driver和struct  usb_device,这点与platform虚拟总线里的struct platform_devicestruct 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
	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);
makefile
ifneq ($(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 










posted on 2011-10-31 09:26  _song  阅读(509)  评论(0编辑  收藏  举报