分享

Linux udev识别移动设备

 slimfeng 2019-09-04

udev是什么

udev 是Linux kernel 2.6系列的设备管理器。它主要的功能是管理/dev目录底下的设备节点。它同时也是用来接替devfs及hotplug的功能,这意味着它要在添加/删除硬件时处理/dev目录以及所有用户空间的行为,包括加载firmware时。

udev系统由三个部分组成:

libudev函数库,可以用来获取设备的信息,/usr/include/libudev.h。

udevd守护进程,处于用户空间,用于管理虚拟/dev

管理命令udevadm,用来诊断出错情况,/usr/bin/udevadm。

udev运行方式

udev是一个通用的内核设备管理器。它以守护进程的方式运行于Linux系统,并监听在新设备初始化或设备从系统中移除时,内核(通过netlinksocket)所发出的uevent。

系统提供了一套规则用于匹配可发现的设备事件和属性的导出值。匹配规则可能命名并创建设备节点,并运行配置程序来对设备进行设置。udev规则可以匹配像内核子系统、内核设备名称、设备的物理等属性,或设备序列号的属性。规则也可以请求外部程序提供信息来命名设备,或指定一个永远一样的自定义名称来命名设备,而不管设备什么时候被系统发现。下一部分介绍怎么通过编写udev规则文件来管理udev设备

Udev工作流程

 

udev规则文件编写

主要的udev配置文件是/etc/udev/udev.conf。这个文件通常很短,可能只是包含几行#开头的注释,然后有如下选项:

udev_root=“/dev/”

udev_rules=“/etc/udev/rules.d/”

udev_log=“err“

其中udev_rules非常重要,表示udev规则存储的目录,这个目录存储的是以.rules结束的文件。每一个文件处理一系列规则来帮助udev分配名字给设备文件以保证能被内核识别。/etc/udev/rules.d下面可能有好几个udev规则文件,这些文件一部分是udev包安装的,另外一部分则是可能是别的硬件或者软件包生成的。

下面介绍udev规则文件的语法。

 

 

udev键/值对操作符

 

 

操作符

匹配或赋值

解释

==

匹配

相等比较

!=

匹配

不等比较

=

赋值

分配一个特定的值给该键,他可以覆盖之前的赋值。

+=

赋值

追加特定的值给已经存在的键

:=

赋值

分配一个特定的值给该键,后面的规则不可能覆盖它

 

udev常用的匹配赋值键

 

ACTION

事件 (uevent) 的行为,例如:add( 添加设备 )、remove( 删除设备 )。

KERNEL

内核设备名称,例如:sda, cdrom。

DEVPATH

设备的 devpath 路径。

SUBSYSTEM

设备的子系统名称,例如:sda 的子系统为 block。

BUS

设备在 devpath 里的总线名称,例如:usb

DRIVER

设备在 devpath 里的设备驱动名称,例如:ide-cdrom。

ID

设备在 devpath 里的识别号。

SYSFS{filename}

SYSFS{filename}: 设备的 devpath 路径下,设备的属性文件“filename”里的内容。

ENV{key}

环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键。

PROGRAM

调用外部命令。

RESULT

外部命令 PROGRAM 的返回结果

NAME

根据这个规则创建的设备文件的文件名。注意:仅仅第一行的NAME描述是有效的,后面的均忽略

SYMLINK

根据规则创建的字符连接名

GROUP

设备文件所在的组。

OWNER

设备文件的属组

MODE

设备文件的权限,采用8进制

ATTRS{文件}

匹配设备及其所有父设备在sysfs中的属性值。 如果指定了多个 ATTRS 匹配, 那么必须在同一个设备上全部匹配成功,才算最终匹配成功

 

libudev说明

前面大致了解了udev相关的功能和原理,下面将描述如何通过libudev来实现相关功能。

libudev提供了在本地系统上检测、枚举设备的各种API函数。

Libudev使用过程如下

(参考: http://blog.csdn.net/coroutines/article/details/38067805)

1. 初始化

首先调用udev_new,创建一个udev library context。udev library context采用引用记数机制,创建的context默认引用记数为1,使用udev_ref和udev_unref增加或减少引用记数,如果引用记数为0,则释放内部资源。

2. 枚举设备

使用udev_enumrate_new创建一个枚举器,用于扫描系统已接设备。使用udev_enumrate_ref和udev_enumrate_unref增加或减少引用记数。

使用udev_enumrate_add_match/nomatch_xxx系列函数增加枚举的过滤器,过滤关键字以字符表示,如"block"设备。

使用udev_enumrate_scan_xxx系列函数扫描/sys目录下,所有与过滤器匹配的设备。扫描完成后的数据结构是一个链表,使用udev_enumerate_get_list_entry获取链表的首个结点,使用udev_list_entry_foreach遍历整个链表。

3. 监控设备插拔 udev的设备插拔基于netlink实现。

使用udev_monitor_new_from_netlink创建一个新的monitor,函数的第二个参数是事件源的名称,可选"kernel"或"udev"。基于"kernel"的事件通知要早于"udev",但相关的设备结点未必创建完成,所以一般应用的设计要基于"udev"进行监控。

使用udev_monitor_filter_add_match_subsystem_devtype增加一个基于设备类型的udev事件过滤器,例如: "block"设备。

使用udev_monitor_enable_receiving启动监控过程。监控可以使用udev_monitor_get_fd获取一个文件描述符,基于返回的fd可以执行poll操作,简化程序设计。

插拔事件到达后,可以使用udev_monitor_receive_device获取产生事件的设备映射。调用udev_device_get_action可以获得一个字符串:"add"或者"remove",以及"change", "online", "offline"等,但后三个未知什么情况下会产生。

4、获取设备信息

使用udev_list_entry_get_name可以得到一个设备结点的sys路径,基于这个路径使用udev_device_new_from_syspath可以创建一个udev设备的映射,用于获取设备属性。获取设备属性使用udev_device_get_properties_list_entry,返回一个存储了设备所有属性信息的链表,使用udev_list_entry_foreach遍历链表,使用udev_list_entry_get_name和udev_list_entry_get_value获取属性的名称和值。

 

liudev识别移动设备

首先得知道什么是usb设备的VID和PID。

据USB规范的规定,所有的USB设备都有供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,供应商ID(VID)由供应商向USB执行论坛申请,每个供应商的VID是唯一的,PID由供应商自行决定,理论上来说,不同的产品、相同产品的不同型号、相同型号的不同设计的产品最好采用不同的PID,以便区别相同厂家的不同设备。

上面提到,分别调用udev_new,udev_monitor_new_from_netlink,

udev_monitor_filter_add_match_subsystem_devtype,dev_monitor_enable_receiving,dev_monitor_get_fd,udev_monitor_receive_device函数来监控插入的设备。如下图所示

然后通过udev_device_get_sysattr_value(dev,"idVendor")判断VID是否是该设备的VID,通过udev_device_get_sysattr_value(dev,"idProduct")来判断PID是否是该设备的PID,如果都符合,那么就能识别出这个设备,然后进行相应的操作。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多