10人参与 • 2025-07-22 • Linux
#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)
注册的结构体是struct usb_driver,主要填充name、probe、disconnect和id_table字段,其中name是驱动名称,到时会在/sys/bus/usb/drivers显示这个驱动名称,probe和disconnect会在usb设备插入和拔出时调用,id_table就是匹配列表,可以通过vid、pid匹配,也可以通过usb设备类型匹配。
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设备插入时,id_table信息匹配成功则调用 */ .disconnect = zslusb_disconnect, /* usb设备拔出时调用 */ .id_table = zslusb_id_table, /* id_table,用于匹配设备描述符 */ }; void zslusb_init(void) { usb_register(&zslusb_driver); /* 注册usb设备驱动,不申请设备号 */ }
执行后运行,usb设备插入和拔出就会调用zslusb_probe和zslusb_disconnect接口。
结果如下:
设备注册是调用usb_register接口注册,本质是usb_register_driver,在这个接口里主要是填充struct usb_driver结构体,把bus = &usb_bus_type,然后调用driver_register注册驱动。
设备插入时如果主机控制器处于休眠状态,会先通过 hcd_resume_work 恢复供电,调用 rpm_resume 和 usb_runtime_resume 唤醒 hub和恢复设备。随后 hub 检测到端口变化,通过hub工作队列 hub_wq 触发 hub_event,从而usb_new_device初始化新usb设备并device_add把usb设备注册到内核设备树,触发首次总线探测,bus_probe_device里遍历所有驱动,对每个驱动执行__device_attach_driver,通过match匹配到设备后调用通用usb驱动usb_generic_driver_probe,确保设备能被识别成基本usb设备,读取设备描述符和分配资源。配置完成后,为每个接口注册新设备(device_add),触发二次总线探测,匹配后调用入口函数usb_probe_interface。
设备插入 ├─ 休眠状态? → hcd_resume_work → rpm_resume → usb_runtime_resume → hub_resume └─ hub检测 → hub_wq → hub_event → usb_new_device → device_add ├─ 首次探测 → usb_generic_driver_probe(基础初始化) └─ 接口注册 → device_add → usb_probe_interface(驱动加载)
设备拔出是由硬件中断触发hub_irq,标记事件并触发软中断tasklet_hi_action,下半部tasklet调用 usb_giveback_urb_bh调度hub工作队列 hub_wq触发hub_event,调用usb_disconnect清理usb设备,禁用端点,device_del调用device_release_driver解绑驱动(释放软件资源),禁用设备(停用硬件端点),释放设备内存。
设备拔出 → 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(驱动清理) → usb_put_dev(内存释放)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论