天天看點

linux裝置驅動模型及其他,Linux裝置驅動模型

Udev

先前所需的硬體檔案節點都需要在/dev下靜态建立,随2.4核而來的devfs,帶來了動态裝置節點建立。Devfs雖然提供了in-memory filesystem建立節點的方法,但是節點命名依然取決于裝置驅動。命名管理和核心結合的不好,The place for policy is in header files, kernel module parameters, or user space。Udev将裝置管理交給使用者空間。

Udev依賴于以下技術:(1)、核心sysfs支援,sysfs啟動時挂載到/sys下(可檢視/etc/fstab);(2)、一系列使用者空間工具:udevd和udevinfo;(3)、定義在/etc/udev/rules.d/目錄下的使用者定義規則

使用Udev:

1、首先從sysfs的相關檔案中擷取檔案屬性。假設DVD:/dev/sr0,CD-RW:/dev/sr1。使用udevinfo來收集裝置資訊。bash> udevinfo -a -p /sys/block/sr0

Code View:bash> udevinfo -a -p /sys/block/sr0

...

looking at the device chain at

'/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4':

BUS=?usb?

ID=?1-4?

SYSFS{bConfigurationValue}=?1?

...

SYSFS{idProduct}=?0701?

SYSFS{idVendor}=?05e3?

SYSFS{manufacturer}=?Genesyslogic?

SYSFS{maxchild}=?0?

SYSFS{product}=?USB Mass Storage Device?

...

bash> udevinfo -a -p /sys/block/sr1

...

looking at the device chain at

'/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-3':

BUS=?usb?

ID=?1-3?

SYSFS{bConfigurationValue}=?2?

...

SYSFS{idProduct}=?0302?

SYSFS{idVendor}=?0dbf?

SYSFS{manufacturer}=?Addonics?

SYSFS{maxchild}=?0?

SYSFS{product}=?USB to IDE Cable?

...

2、使用收集的産品資訊來辨識裝置并加入udev命名規則,建立一個/etc/udev/rules.d/40-cdvd.rules并加入如下規則:BUS="usb", SYSFS{idProduct}="0701", SYSFS{idVendor}="05e3",

KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbdvd"

BUS="usb", SYSFS{idProduct}="0302", SYSFS{idVendor}="0dbf",

KERNEL="sr[0-9]*", NAME="%k", SYMLINK="usbcdrw"規則1的意思是:無論何時它發現一個産品id為0x0701,vender ID是0x05e3,而且名字以sr開頭的usb裝置,都會在/dev下建立一個同名的節點,并produce一個命名為usbdvd的符号連結給那個節點。為了測試您規則中的文法錯誤,在/sys/block/sr*上運作udevtest。為了打開/var/log/messages的verbose messages,設定/etc/udev/udev.conf中的udev_log為"yes".為使新加入的規則在/dev下生效,使用udevstart重新開機udev,然後您的dvd驅動會辨別為/dev/usbdvd。您可以使用mount /dev/usbdvd /mnt/dvd來挂載。udev的其他功能:Linux熱插拔管理、自動按需加載子產品、下載下傳微代碼到需要的裝置。Sysfs, Kobjects,and Device Classes一般用于bus和核心實作領域,隐藏在提供給裝置驅動的API服務中。sysfs是核心架構裝置模型的使用者空間實作,和procfs一樣都是記憶體檔案系統,包含了核心資料結構的相關資訊。procfs是核心的一般性質的視窗,而sysfs則專注于裝置模型。sysfs不是用于替代procfs,因為程序描述符資訊和sysctl參數都屬于procfs,而非sysfs。udev依賴于sysfs實作大部分功能。kobjects常嵌入在大的結構體裡面,主要包括kref(參數計數管理,kref_init初始化,kref_get()增加計數,kref_put()減少計數,并在計數為0的時候釋放kobject),指向所屬kset的指針,kobj_type(描述kobject類型);kobjects與sysfs密切相關,每個核心instantiated的kobject都有一個sysfs representation。裝置類是驅動中能用到的另一個接口,類接口抽象了認為每一個裝置都會屬于一個裝置類中,如usb滑鼠、PS/2鍵盤等屬于輸入類,而且在/sys/class/input/下擁有接口。Figure 4.4. Sysfs hierarchy of a USB mouse.Code View:[/sys]

+[block]

-[bus]—[usb]—[devices]—[usb2]—[2-2]—[2-2:1.0]-[usbendpoint:usbdev2.2-ep81]

-[class]-[input]—[mouse2]—[device]—[bus]—[usbendpoint:usbdev2.2-ep81]

-[usb_device]—[usbdev2.2]—[device]—[bus]

-[usb_endpoint]—[usbdev2.2-ep00]—[device]

—[usbdev2.2-ep81]—[device]

-[devices]—[pci0000:00]—[0000:00:1d:1]—[usb2]—[2-2]—[2-2:1.0]

+[firmware]

+[fs]

+[kernel]

+[module]

+[power]

類程式設計接口建立在kobjects和sysfs之上,讓我們來看一下RTC:

bash> modprobe rtc

bash> ls -lR /sys/class/misc

drwr-xr-x 2 root root 0 Jan 15 01:23 rtc

/sys/class/misc/rtc:

total 0

-r--r--r-- 1 root root 4096 Jan 15 01:23 dev

--w------- 1 root root 4096 Jan 15 01:23 uevent

bash> ls -l /dev/rtc

crw-r--r-- 1 root root 10, 135 Jan 15 01:23 /dev/rtc

/sys/class/misc/rtc/dev包含了裝置的主次裝置号,/sys/class/misc/rtc/uevent用于coldplugging,/dev/rtc被應用程式用于通路RTC驅動。Misc驅動使用misc_register()初始化,裡面的代碼和下面的類似:

dev = MKDEV(MISC_MAJOR, misc->minor);

misc->class = class_device_create(misc_class, NULL, dev,

misc->dev,

"%s", misc->name);

if (IS_ERR(misc->class)) {

err = PTR_ERR(misc->class);

goto out;

}

下圖展示了在classes、kobjects、sysfs和udev之間的轉換,最終導緻了/sys和/dev裡面的檔案的産生。

linux裝置驅動模型及其他,Linux裝置驅動模型

另外一個好的抽象是bus-device-driver程式設計接口。以I2C為例,I2C核心層對監測到的每一個I2C總線擴充卡使用bus_register()注冊,當I2C用戶端裝置如EEPROM被監測到時,由device_register()注冊,最終I2C EEPROM用戶端驅動程式使用driver_register()注冊自身,這些注冊直接使用I2C核提供的服務。bus_register()會在/sys/bus增加入口,device_register()在/sys/devices下增加入口,struct bus_type,struct device,struct device_driver是主要使用的資料結構。Hotplug和Coldplug在系統運作時動态接入的裝置叫熱插拔裝置,而在系統啟動前就事先接入的叫冷插拔裝置。在以前核心使用在/proc中注冊的輔助程式通知使用者空間有裝置接入,而現在當核心監測到熱插拔時,它們使用netlink sockets向使用者空間發送uevents。netlink是核心和使用者空間通信的有效工具,在使用者空間管理裝置節點建立和删除的udevd接收到uevents并管理hotplug。以下是熱插拔的發展曆程:To see how hotplug handling has evolved recently, let's consider progressive levels of udev running different versions of the 2.6 kernel:

With a udev-039 package and a 2.6.9 kernel, when the kernel detects a hotplug event, it invokes the user space helper registered with /proc/sys/kernel/hotplug. This defaults to /sbin/hotplug, which receives attributes of the hotplugged device in its environment. /sbin/hotplug looks inside the hotplug configuration directory (usually /etc/hotplug.d/default/) and runs, for example, /etc/hotplug.d/default/10-udev.hotplug, after executing other scripts under /etc/hotplug/.

bash> ls -l /etc/hotplug.d/default/

...

lrwcrwxrwx 1 root root 14 May 11 2005 10-udev.hotplug -> /sbin/udevsend

...

When /sbin/udevsend thus gets executed, it passes the hotplugged device information to udevd.

With udev-058 and a 2.6.11 kernel, the story changes somewhat. The udevsend utility replaces /sbin/hotplug:

bash> cat /proc/sys/kernel/hotplug

/sbin/udevsend

With the latest levels of udev and the kernel, udevd assumes full responsibility of managing hotplug without depending on udevsend. It now pulls hotplug events directly from the kernel via netlink sockets (see Figure 4.4). /proc/sys/kernel/hotplug contains nothing:

bash> cat /proc/sys/kernel/hotplug

bash>

Udev還可以處理coldplug,因為udev是使用者空間程式而且在核心啟動後才started,需要基于coldplug裝置上模拟熱插拔事件。在boot 時,核心在sysfs下建立名為uevent的檔案for all devices,并且emits coldplug events to those files,當udev啟動時,它讀取/sys下面所有的uevent檔案并為每個冷插拔裝置産生熱插拔事件。

Microcode Download

裝置驅動used to把微代碼存在頭檔案的static數組中,但是這不好,因為微代碼常因為裝置廠商的不同而是分布的as binary images,解決方案是在使用者空間儲存微代碼,然後将它們在需要時傳遞給核心。Sysfs和udev提供了實作的架構。

以下是Intel PRO/Wireless 2100 WiFi mini PCI card 微代碼下載下傳的例子:在http://ipw2100.sourceforge.net/firmware.php下載下傳并存放在您系統的/lib/firmware/裡面,而且您已經插入了驅動子產品ipw2100.ko:1、在初始化時,驅動喚醒request_firmware(..,"ipw2100-1.3.fw",..);2、這dispatch一個熱插拔uevent to使用者空間,along with the identity of the requested microcode image。3、Udevd接收到uevent并responds by invoking /sbin/firmware_helper,對于這點,它使用如下在/etc/udev/rules.d/下面的類似的規則:ACTION=="add", SUBSYSTEM=="firmware", RUN="/sbin/firmware_helper"4、/sbin/firmware_helper進入/lib/firmware/并且定位微代碼Image ipw2100-1.3.fw。它dumps the image to /sys/class/0000:02:02.0/data(0000:02:02是PCI bus:device:function,是WiFi卡的标記);5、驅動接收到微代碼并且把它下載下傳到裝置,當完成後,它調用release_firmware()來釋放相應的資料結構。6、驅動執行剩下的初始化和WiFi擴充卡。Module Autoload自動按需下載下傳核心子產品是Linux支援的有效特性,為了解核心如何發出"module fault"并且udev如何處理它,讓我插入Xircom CardBus Ethernet adapter into a laptop's PC Card slot:1、在編譯時,對所支援裝置的辨識就作為驅動子產品對象的一部分産生,如drivers/net/tulip/xircom_cb.c下的:static struct pci_device_id xircom_pci_table[] = {

{0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},

{0,},

};

MODULE_DEVICE_TABLE(pci, xircom_pci_table);這聲明了該驅動支援任意PCI vender ID為0x115D和PCI device ID為0x0003的卡,當您安裝了該驅動子產品後,depmod工具檢視module image并且解釋在device table裡面的ID,然後将下面的entry加入 /lib/modules/kernel-version/modules.alias:alias pci:v0000115Dd00000003sv*sd*bc*sc*i* xircom_cb,這裡v表示VenderID,d代表DeviceID,sv代表subvenderID,*代表通配。

2、當您在CardBus插槽中熱插拔Xircom card時,核心産生一個uevent聲稱對新插入裝置的辨認。您可以使用udevmonitor來檢視産生的uevent:

bash> udevmonitor --env

...

MODALIAS=pci:v0000115Dd00000003sv0000115Dsd00001181bc02sc00i00

...

3、Udevd經netlink socket接收到uevent,并喚醒modprobe with 上述的核心傳遞給它的MODALIAS。

modprobe pci:v0000115Dd00000003sv0000115Dsd00001181bc02sc00i00

4、modprobe在/lib/modules/kernel-version/modules.alias中發現相符的entry,并進而插入xircom_cb:

bash> lsmod

Module      Size   Used by

xircom_cb   10433 0

...

現在該card就可以上網沖浪了。

一部分不支援在嵌入式裝置上使用Udev的原因:

Udev on Embedded Devices

One school of thought deprecates the use of udev in favor of statically created device nodes on embedded devices for the following reasons:

Udev creates /dev nodes during each reboot, compared to static nodes that are created only once during software install. If your embedded device uses flash storage, flash pages that hold /dev nodes suffer an erase-write cycle on each boot in the case of the former, and this reduces flash life span. (Flash memory is discussed in detail in Chapter 17, "Memory Technology Devices.") You do have the option of mounting /dev over a RAM-based filesystem, however.

Udev contributes to increased boot time.

Udev features such as dynamic creation of /dev nodes and autoloading of modules create a degree of indeterminism that some solution designers prefer to avoid on special-purpose embedded devices, especially ones that do not interact with the outside world via hotpluggable buses. According to this point of view, static node creation and boot-time insertion of any modules provide more control over the system and make it easier to test.