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í)行后運行,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è)備插入時如果主機控制器處于休眠狀態(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)文章
 PHP程序員玩轉(zhuǎn)Linux系列 Linux和Windows安裝nginx
這篇文章主要為大家詳細(xì)介紹了PHP程序員玩轉(zhuǎn)Linux系列文章,Linux和Windows安裝nginx教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
 服務(wù)器安裝寶塔面板無法遠程連接數(shù)據(jù)庫的解決方法
這篇文章主要介紹了服務(wù)器安裝寶塔面板無法遠程連接數(shù)據(jù)庫的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
 詳解Centos7.2安裝Nginx實現(xiàn)負(fù)載平衡
本篇文章主要介紹了詳解Centos7.2安裝Nginx實現(xiàn)負(fù)載平衡,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03
 在Ubuntu 24.04(Noble)上配置阿里源的操作步驟
在使用 Ubuntu 系統(tǒng)時,選擇一個快速且穩(wěn)定的軟件源(Repository)對于系統(tǒng)更新和軟件安裝至關(guān)重要,阿里云提供的 Ubuntu 鏡像源在國內(nèi)用戶中非常受歡迎,本文將介紹如何在 Ubuntu 24.04 (Noble) 上配置阿里源,需要的朋友可以參考下2025-07-07
 Linux中大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化的方法
這篇文章主要給大家介紹了關(guān)于Linux中大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
 linux查找大文件指定內(nèi)容的實現(xiàn)方法
今天小編就為大家分享一篇linux查找大文件指定內(nèi)容的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07

