Linux USB驅(qū)動注冊方式
注冊接口
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)注冊的結(jié)構(gòu)體是struct usb_driver,主要填充name、probe、disconnect和id_table字段,其中name是驅(qū)動名稱,到時會在/sys/bus/usb/drivers顯示這個驅(qū)動名稱,probe和disconnect會在USB設(shè)備插入和拔出時調(diào)用,id_table就是匹配列表,可以通過VID、PID匹配,也可以通過USB設(shè)備類型匹配。
示例代碼
static int zslusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usbdev;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int i = 0;
usbdev = interface_to_usbdev(intf);
interface = intf->cur_altsetting;
printk(KERN_INFO "%s:num:%d \n",__func__,interface->desc.bNumEndpoints);
for (i = 0;i<interface->desc.bNumEndpoints;i++)
{
endpoint = &interface->endpoint[0].desc;
printk(KERN_INFO "%s: %x %x\n",__func__,endpoint->bEndpointAddress,endpoint->bmAttributes);
printk(KERN_INFO "%s: %x %x %x\n",__func__,interface->desc.bInterfaceClass,interface->desc.bInterfaceSubClass,interface->desc.bInterfaceProtocol);
}
return 0;
}
static void zslusb_disconnect(struct usb_interface *intf)
{
printk(KERN_INFO "%s: \n",__func__);
dump_stack();
}
static struct usb_device_id zslusb_id_table [] = {
{ USB_DEVICE(0x413D, 0x2113) },
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_KEYBOARD)},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, zsl_usb_id_table);
static struct usb_driver zslusb_driver = {
.name = "zslusb",
.probe = zslusb_probe, /* usb設(shè)備插入時,id_table信息匹配成功則調(diào)用 */
.disconnect = zslusb_disconnect, /* usb設(shè)備拔出時調(diào)用 */
.id_table = zslusb_id_table, /* id_table,用于匹配設(shè)備描述符 */
};
void zslusb_init(void)
{
usb_register(&zslusb_driver); /* 注冊usb設(shè)備驅(qū)動,不申請設(shè)備號 */
}執(zhí)行后運(yùn)行,USB設(shè)備插入和拔出就會調(diào)用zslusb_probe和zslusb_disconnect接口。
結(jié)果如下:
- 插入設(shè)備

- 拔掉設(shè)備

調(diào)用關(guān)系
設(shè)備注冊是調(diào)用usb_register接口注冊,本質(zhì)是usb_register_driver,在這個接口里主要是填充struct usb_driver結(jié)構(gòu)體,把bus = &usb_bus_type,然后調(diào)用driver_register注冊驅(qū)動。
設(shè)備插入時如果主機(jī)控制器處于休眠狀態(tài),會先通過 hcd_resume_work 恢復(fù)供電,調(diào)用 rpm_resume 和 usb_runtime_resume 喚醒 Hub和恢復(fù)設(shè)備。隨后 Hub 檢測到端口變化,通過hub工作隊列 hub_wq 觸發(fā) hub_event,從而usb_new_device初始化新USB設(shè)備并device_add把USB設(shè)備注冊到內(nèi)核設(shè)備樹,觸發(fā)首次總線探測,bus_probe_device里遍歷所有驅(qū)動,對每個驅(qū)動執(zhí)行__device_attach_driver,通過match匹配到設(shè)備后調(diào)用通用USB驅(qū)動usb_generic_driver_probe,確保設(shè)備能被識別成基本USB設(shè)備,讀取設(shè)備描述符和分配資源。配置完成后,為每個接口注冊新設(shè)備(device_add),觸發(fā)二次總線探測,匹配后調(diào)用入口函數(shù)usb_probe_interface。
設(shè)備插入
├─ 休眠狀態(tài)? → hcd_resume_work → rpm_resume → usb_runtime_resume → hub_resume
└─ Hub檢測 → hub_wq → hub_event → usb_new_device → device_add
├─ 首次探測 → usb_generic_driver_probe(基礎(chǔ)初始化)
└─ 接口注冊 → device_add → usb_probe_interface(驅(qū)動加載)設(shè)備拔出是由硬件中斷觸發(fā)hub_irq,標(biāo)記事件并觸發(fā)軟中斷tasklet_hi_action,下半部Tasklet調(diào)用 usb_giveback_urb_bh調(diào)度hub工作隊列 hub_wq觸發(fā)hub_event,調(diào)用usb_disconnect清理USB設(shè)備,禁用端點,device_del調(diào)用device_release_driver解綁驅(qū)動(釋放軟件資源),禁用設(shè)備(停用硬件端點),釋放設(shè)備內(nèi)存。
設(shè)備拔出 → hub_irq → tasklet_hi_action → usb_giveback_urb_bh → hub_wq → hub_event
├─ usb_disconnect → usb_disable_device(禁用端點+終止URB)
└─ device_del → device_release_driver → zslusb_disconnect(驅(qū)動清理) → usb_put_dev(內(nèi)存釋放)總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解CentOS5.5 下搭建 PHP 環(huán)境(最佳的LAMP環(huán)境)
本篇文章詳細(xì)介紹了詳解CentOS5.5 下搭建 PHP 環(huán)境(最佳的LAMP環(huán)境),有需要的小伙伴可以參考下。2016-10-10
Ubuntu Apahce2.4下無法訪問JS目錄的問題解決
這篇文章主要給大家介紹了如何解決Ubuntu Apahce2.4下無法訪問JS目錄的問題,文中介紹的非常詳細(xì),相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03
centos安裝jdk1.8時出現(xiàn)沒有/lib/ld-linux.so.2:這個文件的原因分析
這篇文章主要介紹了centos安裝jdk1.8時出現(xiàn)沒有/lib/ld-linux.so.2:這個文件的原因分析,通過使用一個簡單的命令可以幫助我們解決,需要的朋友跟隨腳本之家小編一起看看吧2018-08-08
linux中高并發(fā)socket最大連接數(shù)的優(yōu)化詳解
這篇文章主要給大家介紹了關(guān)于linux中高并發(fā)socket最大連接數(shù)優(yōu)化的相關(guān)資料,文中介紹的很詳細(xì),相信對大家具有一定的參考價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-02-02
Linux之platform平臺設(shè)備驅(qū)動詳解
Linux設(shè)備驅(qū)動模型中,Platform總線作為虛擬總線統(tǒng)一管理無物理總線依賴的嵌入式設(shè)備,通過platform_driver和platform_device注冊,結(jié)合設(shè)備樹的of_match_table匹配機(jī)制,實現(xiàn)驅(qū)動與設(shè)備的自動綁定,確保無論注冊順序如何均能正確觸發(fā)probe函數(shù)2025-07-07
使用VMware 15 安裝虛擬機(jī)和使用CentOS 8的步驟詳解
這篇文章主要介紹了使用VMware 15 安裝虛擬機(jī)和使用CentOS 8的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01

