arduino usb串口驱动_linux的usb转串口热插拔检测、驱动的自动安装

目前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。

f1db0fc9aff8ae906d99ced1baea024c.png
图一 serial文件夹

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值