1. 程式人生 > >Linux 核心/sys 檔案系統之sysfs 屬性檔案

Linux 核心/sys 檔案系統之sysfs 屬性檔案

屬性檔案分為:匯流排屬性檔案,CLASS屬性檔案,裝置屬性檔案,驅動屬性檔案


DEVICE_ATTR 巨集宣告有四個引數,分別是名稱、許可權位、讀函式、寫函式


28 struct attribute {
29 const char *name; //設定該檔案的名字
30 struct module *owner; //設定該檔案的屬主
31 mode_t mode; //設定該檔案的檔案操作許可權
32 };
/*linux/device.h*/
38 struct bus_attribute {
39 struct attribute attr;
40 ssize_t (*show)(struct bus_type *bus, char *buf);
41 ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
42 };


attribute中有兩個函式指標,show和store。
當訪問匯流排目錄中的name檔案時,就會觸發show函式,一般會將指定的資訊存放到陣列buf,並傳到使用者空間顯示。
當修改匯流排目錄中的name檔案是,就會觸發stroe函式,一般會將從使用者空間傳來的buf指標存放的count個位元組內容存放到核心中。

由此可以看到,通過這樣的檔案,就能實現sys目錄下的檔案與核心裝置模型之間的資料互動。

使用驅動(PCI)的 sysfs 屬性檔案, bind, unbind 和 new_id

    在裝置驅動 /sys/bus/*/driver/... 下可以看到很多驅動都有 bind, unbind, new_id 這三個屬性,

 
# <span class="boldcode"><strong>find /sys/bus/*/drivers/ -name bind -ls</strong></span>
... 

    每一個裝置驅動程式在程式內以某種方式註明了可用於哪些硬體,如所有的 PCI 驅動都使用 MODULE_DEVICE_TABLE 聲明瞭所能驅動的 PCI 硬體的 PCI 裝置號。但驅動程式不能預知未來,未來生產的新的硬體有可能相容現有硬體的工作方式,就還可以使用現有硬體驅動程式來工作。在 bind 和 unbind 發明以前,這種情況除了修改 PCI 裝置驅動程式的 DEVICE_TABLE 段落,重新編譯驅動程式,以外別無他法,在 2.6 

核心上添加了 bind 和 unbind 之後可以在不重新編譯的情況下對裝置和驅動之間進行手工方式地繫結。

    而且對於有些硬體裝置可以有多份驅動可用,但任何具體時刻只能有一個驅動程式來驅動這個硬體,這時可以使用 bind/unbind 來強制使用和不使用哪一個驅動程式;(注意關於多種驅動程式的選擇,更好的管理方法是使用 modprobe.conf 配置檔案,需要重啟才生效,而 bind/unbind 提供的是一種臨時的無需重啟立即生效的途徑;)

    使用它們可以強制繫結某個裝置使用或強制不使用某個驅動程式,操作方法就是通過 bind 和 unbind 介面。

 
#find /sys/-type f ( -name bind -or -name unbind -or -name new_id )
 -ls
    69    0 -rw-r--r--   1 root     root         4096 12月 12 22:12 
/sys/devices/virtual/vtconsole/vtcon0/bind
  3072    0 --w-------   1 root     root         4096 12月 12 22:15 
/sys/bus/platform/drivers/vesafb/unbind
[...]
  6489    0 --w-------   1 root     root         4096 12月 12 22:09 
/sys/bus/pci/drivers/8139too/unbind
  6490    0 --w-------   1 root     root         4096 12月 12 22:09 
/sys/bus/pci/drivers/8139too/bind
  6491    0 --w-------   1 root     root         4096 12月 12 22:15 
/sys/bus/pci/drivers/8139too/new_id 

    這個結果中特別提到了 8139too 這份驅動程式的這三個屬性檔案,

 
# find /sys/bus/pci/drivers/8139too/ -ls
  6435    0 drwxr-xr-x   2 root     root            0 12月 12 22:08 
/sys/bus/pci/drivers/8139too/
  6436    0 lrwxrwxrwx   1 root     root            0 12月 12 22:08 
/sys/bus/pci/drivers/8139too/0000:00:0e.0 ->
 ../../../../devices/pci0000:00/0000:00:0e.0
  6485    0 lrwxrwxrwx   1 root     root            0 12月 12 22:08 
/sys/bus/pci/drivers/8139too/module -> ../../../../module/8139too
  6488    0 --w-------   1 root     root         4096 12月 12 22:08 
/sys/bus/pci/drivers/8139too/uevent
  6489    0 --w-------   1 root     root         4096 12月 12 22:08 
/sys/bus/pci/drivers/8139too/unbind
  6490    0 --w-------   1 root     root         4096 12月 12 22:08 
/sys/bus/pci/drivers/8139too/bind
  6491    0 --w-------   1 root     root         4096 12月 12 22:08 
/sys/bus/pci/drivers/8139too/new_id
# echo 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind
-bash: echo: write error: 沒有那個裝置
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc 
pfifo_fast state 
UNKNOWN qlen 1000
    link/ether 00:14:2a:d1:16:72 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.102/24 brd 192.168.1.255 scope global eth0
3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
# echo -n 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
# echo -n 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/bind
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
4: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state 
DOWN qlen 1000
    link/ether 00:14:2a:d1:16:72 brd ff:ff:ff:ff:ff:ff 

    這一段操作過程演示瞭如何對 PCI 裝置 "0000:00:0e.0" 強制取消繫結 "8139too" 驅動和強制繫結 "8139too" 驅動:

    對 unbind 屬性寫入匯流排號碼(bus_id)即是強制取消繫結;
    對 bind 屬性寫入匯流排號碼(bus_id)即是強制繫結;
    注意,它要求的寫入的是匯流排號碼,對應於PCI裝置的匯流排號碼是按照 "domain(4位):bus(2位):slot(2位):function號(不限)" 的方式組織,是可以從其裝置 kobject 節點上找到,而其它型別的匯流排有各自不同的規則;

    請特別注意: 在這一個例子中, "echo 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind" 這第一個寫入命令以 "No such device" 為錯誤退出,而後續的 "echo -n" 命令則可以成功。這是因為核心在對匯流排號碼進行匹配時過於嚴格了,通常的 "echo" 命令寫入一個字串會以一個換行符結束輸出,核心所接收到的是帶有這個換行符的 bus_id 字串,將它與核心資料結構中的真正的 bus_id 字串相比較,當然不能找到;所幸的是,這個問題在最新的 2.6.28 開發中的核心上已已經解決,它將這個比較函式改為一個特殊實現的字串比較,自動忽略結尾處的換行符,在 2.6.28-rc6 核心上測試,不帶"-n"引數的 echo 命令已經可以寫入成功。

    而 new_id 屬性檔案也可以以另一種途徑解決新的裝置號問題:它是一個只寫的驅動屬性,可用於向其中寫新的裝置號。它支援寫入 2至7個十六進位制整形引數,分別代表 vendor, device, subvendor, subdevice, class, class_mask, driver_data 最少為 2個是因為一個 PCI裝置主要以廠商號(vendor)和裝置號(device)所唯一標定,其它 5個引數如果不輸入則預設值為 PCI_ANY_ID(0xffff)。

 5441    0 --w-------   1 root     root         4096 12月 14 18:15 
/sys/bus/pci/drivers/8139too/new_id

    從 8139too 驅動上可以看到它當前所靜態支援的裝置號碼列表,其中包括當前系統中的裝置 10ec:8139, 假設未來有一款 8140 裝置也滿足 8139 裝置的硬體通訊協議,於是可以使用 8139too 驅動程式來驅動它,操作如下

 
# echo '10ec 8140' > /sys/bus/pci/drivers/8139too/new_id 

    這在不更新驅動程式的情況下除錯裝置很有用處。