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

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