時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(0)
參考2.6.14版本中的driver/usb/input/usbmouse.c。鼠標驅(qū)動可分為幾個部分:驅(qū)動加載部分、probe部分、open部分、urb回調(diào)函數(shù)處理部分。
下文陰影部分為注解。
一、??? 驅(qū)動加載部分
static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver);//注冊鼠標驅(qū)動
if (retval == 0)
info(DRIVER_VERSION ":" DRIVER_DESC);
return retval;
}
其中usb_mouse_driver的定義為:
static struct usb_driver usb_mouse_driver = {
.owner? = THIS_MODULE,
.name? = "usbmouse",
.probe? = usb_mouse_probe,
.disconnect??? = usb_mouse_disconnect,
.id_table??? = usb_mouse_id_table,
};
如果注冊成功的話,將會調(diào)用usb_mouse_probe。那么什么時候才算注冊成功呢?
和其它驅(qū)動注冊過程一樣,只有在其對應(yīng)的"總線"上發(fā)現(xiàn)匹配的"設(shè)備"才會調(diào)用probe。總線匹配的方法和具體總線相關(guān),如:platform_bus_type中是判斷驅(qū)動名稱和平臺設(shè)備名稱是否相同;那如何確認usb總線的匹配方法呢?
Usb設(shè)備是注冊在usb_bus_type總線下的。查看usb_bus_type的匹配方法。
struct bus_type usb_bus_type = {
.name =? "usb",
.match =??? usb_device_match,
.hotplug =??? usb_hotplug,
.suspend =??? usb_generic_suspend,
.resume =??? usb_generic_resume,
};
其中usb_device_match定義了匹配方法
static int usb_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* check for generic driver, which we don't match any device with */
if (drv == &usb_generic_driver)
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id (intf, usb_drv->id_table);
if (id)
return 1;
return 0;
}
可以看出usb的匹配方法是usb_match_id (intf, usb_drv->id_table),也就是說通過比對"dev中intf信息"和"usb_drv->id_table信息",如果匹配則說明驅(qū)動所對應(yīng)的設(shè)備已經(jīng)添加到總線上了,所以接下了就會調(diào)用drv中的probe方法注冊usb設(shè)備驅(qū)動。
usb_mouse_id_table的定義為:
static struct usb_device_id usb_mouse_id_table[] = {
{ USB_INTERFACE_INFO(3, 1, 2) },
{ }????? /* Terminating entry */
};
#define USB_INTERFACE_INFO(cl,sc,pr) \
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
.bInterfaceClass = (cl), \
.bInterfaceSubClass = (sc), \
.bInterfaceProtocol = (pr)
鼠標設(shè)備遵循USB人機接口設(shè)備(HID),在HID規(guī)范中規(guī)定鼠標接口類碼為:
接口類:0x03
接口子類:0x01
接口協(xié)議:0x02
這樣分類的好處是設(shè)備廠商可以直接利用標準的驅(qū)動程序。除了HID類以外還有Mass storage、printer、audio等
#define USB_DEVICE_ID_MATCH_INT_INFO \
(USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
匹配的過程為:
usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
/* proc_connectinfo in devio.c may call us with id == NULL. */
if (id == NULL)
return NULL;
intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);
/* It is important to check that id->driver_info is nonzero,
since an entry that is all zeroes except for a nonzero
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
id->driver_info; id++) {
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
continue;
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
//接口類
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
continue;
//接口子類
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
continue;
//遵循的協(xié)議
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
continue;
return id;
}
return NULL;
}
從中可以看出,只有當設(shè)備的接口類、接口子類、接口協(xié)議匹配鼠標驅(qū)動時鼠標驅(qū)動才會調(diào)用probe方法。
二、probe部分
static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
{
struct usb_device * dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_mouse *mouse;
int pipe, maxp;
char path[64];
interface = intf->cur_altsetting;
/* 以下是網(wǎng)絡(luò)的一段對cur_altsettin的解釋,下面就借花獻佛。usb 設(shè)備有一個configuration 的概念,表示配置,一個設(shè)備可以有多個配置,但只能同時激活一個,如:一些設(shè)備可以下載固件,或可以設(shè)置不同的全局模式,就像手機可以被設(shè)定為靜音模式或響鈴模式一樣。而這里又有一個setting,咋一看有些奇怪,這兩個詞不是一回事嗎.還是拿我們最熟悉的手機來打比方,configuration 不說了,setting,一個手機可能各種配置都確定了,是振動還是鈴聲已經(jīng)確定了,各種功能都確定了,但是聲音的大小還可以變吧,通常手機的音量是一格一格的變動,大概也就5,6 格,那么這個可以算一個setting 吧.這里cur_altsetting 就是表示的當前的這個setting,或者說設(shè)置??梢圆榭丛a中usb_interface 結(jié)構(gòu)定義的說明部分。從說明中可以看到一個接口可以有多種setting*/
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
/*根據(jù)HID規(guī)則,期望鼠標只有一個端點即中
關(guān)鍵詞標簽:Linux,USB鼠標驅(qū)動
相關(guān)閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址 dmidecode命令查看內(nèi)存型號 linux tc實現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負載