Linux USB驅(qū)動(dòng)注冊(cè)方式
注冊(cè)接口
#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)注冊(cè)的結(jié)構(gòu)體是struct usb_driver,主要填充name、probe、disconnect和id_table字段,其中name是驅(qū)動(dòng)名稱,到時(shí)會(huì)在/sys/bus/usb/drivers顯示這個(gè)驅(qū)動(dòng)名稱,probe和disconnect會(huì)在USB設(shè)備插入和拔出時(shí)調(diào)用,id_table就是匹配列表,可以通過(guò)VID、PID匹配,也可以通過(guò)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è)備插入時(shí),id_table信息匹配成功則調(diào)用 */
.disconnect = zslusb_disconnect, /* usb設(shè)備拔出時(shí)調(diào)用 */
.id_table = zslusb_id_table, /* id_table,用于匹配設(shè)備描述符 */
};
void zslusb_init(void)
{
usb_register(&zslusb_driver); /* 注冊(cè)u(píng)sb設(shè)備驅(qū)動(dòng),不申請(qǐng)?jiān)O(shè)備號(hào) */
}執(zhí)行后運(yùn)行,USB設(shè)備插入和拔出就會(huì)調(diào)用zslusb_probe和zslusb_disconnect接口。
結(jié)果如下:
- 插入設(shè)備

- 拔掉設(shè)備

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

