赞
踩
目前linux的发行版本都支持usb设备的热插拔。usb转串口设备从硬件上来说也是一个即插即用的usb设备。插入或拔出的时候,都是通过usb的hub集线器检测。那么是如何检测并自动安装对应接口的驱动的呢?---------------目前网络上找到的资料都是零散的,关键是没有找到跟本文linux5.4.0内核相对应的(很多参考资料都是针对2.6内核,如参考书LDD3)。
下文就基于linux5.4.0内核,将接口事件检测到自动安装驱动的环节一步步写下来,如有不妥之处,欢迎大家指正。(我自己被怎么自动安装驱动部分困扰了很久!)
一、热插拔事件的触发
1、当usb设备插入集线器hub时,插入的设备将拉高D+或D-,此时端口变化发生了变化,从而进入hub_irq中断。
2、hub_irq中断触发hub的event_list,从而进入hub_thread线程;
3、hub_thread调用hub_events()。
4、由于端口的变化,hub_events()函数进入hub_port_connect_change()。
1)分配一个usb设备配并初始化udev:
udev = usb_alloc_dev(hdev, hdev_bus, port1);// struct usb_device *udev
2)初始化设备配置usb_new_device(udev);
(1)usb_configure_device(udev)->usb_get_configuration(udev);
得到设备的描述符(包括设备描述符、配置描述符、接口描述符等),并分析和提取配置、接口等信息赋值给udev结构相应字段。
(2)device_add(&udev->dev);------------将usb设备注册到设备模型中
- int device_add(struct device *dev)
- {
- ................................
- kobject_uevent(&dev->kobj, KOBJ_ADD); //产生uevent事件,是linux设备模型中热插拔机制, 源码位于/usr/src/linux-5.4/lib/kobject_uevent.c
- ...............................
- };
这里的kobject_uevent()是实现自动加载驱动的关键。
二、根据检测的接口信息、自动安装对应驱动
这里不得不提到Linux uevent机制。它是内核与用户空间的一种通信机制。当有新的设备加入的时候,将设备的信息发送消息到用户态。如设备驱动模型的usb热插拔uevent,发出kobject_uevent()事件获取相关的环境变量,并通知到用户空间。而用户态有一个Udev的守护进程监听这个信息,并执行一些操作,比如可以加载驱动程序。
Udev 守护进程直接从内核接收设备的插入、拔出、改变状态等事件,并到规则库中进行匹配,以实现设备的触发事件。
Udev同时为连接在系统上面的设备节点提供一个动态设备目录。设备插入或移出系统的时候,Udev就在 /dev目录下面创建或者删除设备节点文件。如插入本文的激光雷达,就在 /dev下面生成serial文件夹,serial中包含两个文件夹/dev/serial/by-id和/dev/serial/by-path。
Udev使用modalias方法来加载设备驱动程序,而位于/lib/modules/5.4.0/modules.alias 的modalias文件用于协助Udev加载设备驱动。
1、modules.alias 文件
那么modules.alias 是如何产生的呢?这与宏定义MODULE_DEVICE_TABLE()有关。
在linux的设备模型中, 每一个设备都有VENDOR ID, _PRODUCT ID等信息。而每一个设备驱动程序,也需要表明自己能为哪些VENDOR ID, _PRODUCT ID的设备提供服务。以下以PL2303为例,在pl2303.c中,有如下定义:
- static const struct usb_device_id id_table[] = {
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID),
- .driver_info = PL2303_QUIRK_ENDPOINT_HACK },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
- ......
- }
- MODULE_DEVICE_TABLE(usb, id_table);
在安装模块的时候,depmod程序根据id_table信息,把相关的模块信息添加到/lib/modules/uname-r/modules.alias文件中。
- alias usb:v067Bp2303d*dc*dsc*dp*ic*isc*ip*in* pl2303
- ......
其中v代表Vendor ID,p代表PRODUCT ID,后面的*表示随意匹配。另外在/lib/modules/uname-r/modules.dep文件中还保存了模块之间的依赖关系(表示模块pl2303.ko依赖于模块usbserial.ko )。
kernel/drivers/usb/serial/pl2303.ko: kernel/drivers/usb/serial/usbserial.ko
2、udev的自动加载机制
udev 规则是定义在一个以 .rules 为扩展名的文件中,这些文件主要放在两个位置:
(1)/lib/udev/rules.d,这个目录用于存放系统安装的规则;
(2)/etc/udev/rules.d/, 这个目录存放本机规则,如激光雷达的自定义规则就放于此;
本文提到的serial驱动udev规则位于/lib/udev/rules.d/80-drivers.rules中。
如上所述kobject_uevent()把添加新设备的事件、以及相关信息(如设备的VendorID, ProductID等信息)通过netlink发送到用户态。在用户态的Udev进程得到信息后,根据/lib/udev/rules.d/80-drivers.rules的规则:
ENV{MODALIAS}=="?*", RUN{builtin}+="kmod load $env{MODALIAS}"
当有环境变量MODALIAS(就是modules.alias的信息格式)时,自动加载驱动程序。此时根据modules.alias和modules.dep文件,得知设备驱动模块为pl2303.ko,并且此模块依赖于 /usbserial.ko。如果此时usbserial.ko没有加载,就先加载usbserial.ko,接着再加载 pl2303.ko。
3、udevadm
udevadm是一个udev管理工具,可以获取内核发送的事件。输入命令:udevadm monitor --env。
- valian@valian-TM1703:~$ udevadm monitor --env
- monitor will print the received events for:
- UDEV - the event which udev sends out after rule processing
- KERNEL - the kernel uevent
插入我的激光雷达后,可以获得以下uevent信息。这里可以看到MODALIAS信息,这里的MODALIAS就是modules.alias文件匹配的格式。
- KERNEL[34996.845989] add /devices/pci0000:00/0000:00:14.0/usb1/1-4 (usb)
- ACTION=add
- BUSNUM=001
- DEVNAME=/dev/bus/usb/001/011
- DEVNUM=011
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4
- DEVTYPE=usb_device
- MAJOR=189
- MINOR=10
- PRODUCT=67b/2303/300
- SEQNUM=4188
- SUBSYSTEM=usb
- TYPE=0/0/0
-
- KERNEL[34996.847771] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0 (usb)
- ACTION=add
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0
- DEVTYPE=usb_interface
- INTERFACE=255/0/0
- MODALIAS=usb:v067Bp2303d0300dc00dsc00dp00icFFisc00ip00in00
- PRODUCT=67b/2303/300
- SEQNUM=4189
- SUBSYSTEM=usb
- TYPE=0/0/0
-
- KERNEL[34996.848910] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0 (usb-serial)
- ACTION=add
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0
- SEQNUM=4190
- SUBSYSTEM=usb-serial
-
- KERNEL[34996.849138] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0/tty/ttyUSB0 (tty)
- ACTION=add
- DEVNAME=/dev/ttyUSB0
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0/tty/ttyUSB0
- MAJOR=188
- MINOR=0
- SEQNUM=4191
- SUBSYSTEM=tty
-
- UDEV [34996.860612] add /devices/pci0000:00/0000:00:14.0/usb1/1-4 (usb)
- ACTION=add
- BUSNUM=001
- DEVNAME=/dev/bus/usb/001/011
- DEVNUM=011
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4
- DEVTYPE=usb_device
- DRIVER=usb
- ID_BUS=usb
- ID_MM_DEVICE_MANUAL_SCAN_ONLY=1
- ID_MODEL=USB-Serial_Controller
- ID_MODEL_ENC=USB-Serialx20Controller
- ID_MODEL_FROM_DATABASE=PL2303 Serial Port
- ID_MODEL_ID=2303
- ID_REVISION=0300
- ID_SERIAL=Prolific_Technology_Inc._USB-Serial_Controller
- ID_USB_INTERFACES=:ff0000:
- ID_VENDOR=Prolific_Technology_Inc.
- ID_VENDOR_ENC=Prolificx20Technologyx20Inc.
- ID_VENDOR_FROM_DATABASE=Prolific Technology, Inc.
- ID_VENDOR_ID=067b
- MAJOR=189
- MINOR=10
- PRODUCT=67b/2303/300
- SEQNUM=4188
- SUBSYSTEM=usb
- TYPE=0/0/0
- USEC_INITIALIZED=34996860449
-
- UDEV [34997.866782] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0 (usb)
- .MM_USBIFNUM=00
- ACTION=add
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0
- DEVTYPE=usb_interface
- DRIVER=pl2303
- ID_MODEL_FROM_DATABASE=PL2303 Serial Port
- ID_VENDOR_FROM_DATABASE=Prolific Technology, Inc.
- INTERFACE=255/0/0
- MODALIAS=usb:v067Bp2303d0300dc00dsc00dp00icFFisc00ip00in00
- PRODUCT=67b/2303/300
- SEQNUM=4189
- SUBSYSTEM=usb
- TYPE=0/0/0
- USEC_INITIALIZED=34996862068
-
- UDEV [34997.869061] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0 (usb-serial)
- .MM_USBIFNUM=00
- ACTION=add
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0
- DRIVER=pl2303
- SEQNUM=4190
- SUBSYSTEM=usb-serial
- USEC_INITIALIZED=34997868911
-
- UDEV [34997.873758] add /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0/tty/ttyUSB0 (tty)
- .ID_PORT=0
- .MM_USBIFNUM=00
- ACTION=add
- DEVLINKS=/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0 /dev/rplidar /dev/serial/by-path/pci-0000:00:14.0-usb-0:4:1.0-port0
- DEVNAME=/dev/ttyUSB0
- DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/ttyUSB0/tty/ttyUSB0
- ID_BUS=usb
- ID_MM_CANDIDATE=1
- ID_MODEL=USB-Serial_Controller
- ID_MODEL_ENC=USB-Serialx20Controller
- ID_MODEL_FROM_DATABASE=PL2303 Serial Port
- ID_MODEL_ID=2303
- ID_PATH=pci-0000:00:14.0-usb-0:4:1.0
- ID_PATH_TAG=pci-0000_00_14_0-usb-0_4_1_0
- ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
- ID_PCI_INTERFACE_FROM_DATABASE=XHCI
- ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
- ID_REVISION=0300
- ID_SERIAL=Prolific_Technology_Inc._USB-Serial_Controller
- ID_TYPE=generic
- ID_USB_DRIVER=pl2303
- ID_USB_INTERFACES=:ff0000:
- ID_USB_INTERFACE_NUM=00
- ID_VENDOR=Prolific_Technology_Inc.
- ID_VENDOR_ENC=Prolificx20Technologyx20Inc.
- ID_VENDOR_FROM_DATABASE=Prolific Technology, Inc.
- ID_VENDOR_ID=067b
- MAJOR=188
- MINOR=0
- SEQNUM=4191
- SUBSYSTEM=tty
- TAGS=:systemd:
- USEC_INITIALIZED=34997873660

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。