Linux udev識別移動設備

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,如果都符合,那麼就能識別出這個設備,然後進行相應的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章