查看主、次設備號
字元設備驅動的特殊檔案,可以通過ls-l輸出的第一列中的“c”標明。/dev下還有塊設備,它們用“b”來識別。儘管如下介紹的某些內容也適用於塊設備,但我們這章只關注字元設備。
如果你執行ls-l命令,在設備檔案條目中的最新修改日期前你會看到二個數(用逗號分隔),這個位置通常顯示檔案長度。這二個數就是相應設備的主設備號和次設備號。下面的列表給出了我使用的系統上的一些設備。它們的主設備號是1,1,而次設備號是3,5。
crw-rw-rw- 1 root root 1, 3 Feb23 1999 null
crw-rw-rw- 1 root root 1, 5 Feb23 1999 zero
主設備號識別設備對應的驅動程式。例如,/dev/null和/dev/zero都由驅動程式1管理,而所有的虛擬控制台和串口終端都由驅動程式4管理,同樣,vcs1和 vcsa1由驅動程式7管理。當設備打開(open)時,核心利用主設備號分派執行相應的驅動程式。
次設備號只由相應的設備驅動程式使用;核心的其他部分不使用它,僅將它傳遞給驅動程式。所以一個驅動程式管理若干個設備並不為奇(如上面的例子所示),次序號提供了一種區分它們的方法。 儘管2.4版本的核心引入了一種新的特性(可選):設備檔案系統,devfs。如果使用了這種檔案系統,那設備檔案將變得簡單,但也很原來有很大的不同。另一方面,這新的檔案系統帶來了一些用戶可見的不兼容特性。
套用
當沒有使用devfs時,向系統增加一個驅動程式意味著要賦值它一個主設備號。這一賦值過程應該在驅動程式(模組)的初始化過程中完成,它調用如下函式,這個函式定義在<linux/fs.h>:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
返回值提示成功或者失敗。返回一個負值,表示出錯;返回零或正值,表示成功。參數major是所請求的主設備號,name是你的設備的名字,它將在/proc/devices中出現,fops是一個指向函式佇列的指針,利用它完成對設備函式的調用。
主設備號是一個用來索引靜態字元設備組的整數,“動態分配主設備號”將在本章的稍後部分中介紹怎樣選擇一個主設備號。2.0核心支持128個設備驅動,而2.2和2.4核心支持256個(保留數值0和255為將來使用)。而次版本號(8位位元組的數)並沒有傳遞給 register_chrdev函式,因為次版本號是驅動程式自己使用的。開發團隊為了增加核心可能支持的設備數量而帶來了很大的壓力,在開發樹2.5版本核心的目標中,設備號至少是16位的。
一旦設備驅動程式註冊到核心表中,它的操作都與分配的主設備號匹配,何時在字元設備檔案上操作都與它的主設備號相關聯,核心都會通過 file_operations結構體查找並調用相應的驅動程式中的函式。為了這個原因,傳遞給 register_chrdev的指針應該是指向驅動程式中的全局結構體,而不是一個局部的一個模組初始化函式。
接下來的問題就是如何給程式一個名字以被它們用來請求你的設備驅動程式。這個名字必須插入到/dev目錄中,並與你的驅動程式的主設備號和次設備號相連。
在檔案系統上創建一個設備節點的命令是mknod,而且你必須是超級用戶才能操作。除了要創建的節點名字外,該命令還帶三個參數。例如,命令:
mknod /dev/scull0 c 254 0
創建一個字元設備(c),主設備號是254,次設備號是0。由於歷史原因,次設備號應該在0-255範圍內,有時它們存儲在一個位元組中。存在很多原因擴展可使用的次設備號的範圍,但就現在而言,仍然有8位限制。
請注意:如果一旦用mknod生成了一個特別的設備檔案,它就永遠存在了硬碟上,除非你明白的刪除了它。你可以通過執行命令"rm"命令來刪除例子中的設備。
rm /dev/scull0
動態分配主設備號
某些主設備號已經靜態地指派給了大部分常見設備。在核心原始碼樹的Documentation/device.txt檔案中可以找到這些設備的列表。由於許多編號已經分配了,為新設備選擇一個唯一的編號是很困難的——可配置的設備要比主設備號多得多。
所幸,可以對主設備號進行動態分配。如果調用register_chrdev時將major設為0,則該函式會自動選擇一個空閒的號碼並返回作為該設備的主設備號。返回的主設備號總是正值,而返回負值時表明出錯。注意如下兩種情況的細微差別:若調用者請求一個動態的主設備號時函式register_chrdev返回值為所分配的主設備號,而當成功地註冊到一個預先定義的主設備號時(即不採用動態分配而採用靜態指派方式),函式返回值為0而非主設備號。
對於private dirvers,強烈建議使用動態分配的方法來得到主設備號。相反,如果你的設備普遍套用在大多數場合甚至要被包含在官方的核心樹中,你就需要指派一個主設備號作為專用。
動態分配的缺點是:由於分配給你的主設備號不能保證總是一樣的,因而你無法用mknod命令事先創建設備節點(即設備檔案)(可在載入模組時用腳本自動創建)。這意味著你將不能使用Chapter 11中介紹的關於“按需載入模組(loading-on-demandof your driver)”的先進特性。對於用於一般用途的驅動程式,這不是什麼問題,因為一旦分配了設備號,你就可以從/proc/devices讀取相關的設備號信息。
為了載入一個用動態分配來得到主設備號的驅動程式,對 insmod的調用需要被替換為一個簡單的腳本,這個腳本先調用insmod,再讀/proc/devices以得到主設備號,並創建設備檔案。
實例
下面這個腳本,scull_load,是scull發行中的一部分。使用以模組形式發行的驅動程式的用戶可以從系統的rc.local檔案中調用這個腳本,或者在需要模組時手工調用。rc.local可在/etc/rc.d/下找到。(中文版中還提到一種方法:使用kerneld。)
#!/bin/sh
module=”scull”
device =”scull”
mode =”664”
#invoke insmod with all
arguments we were passed
#and use a pathname, as
newer modutils don’t look in. by default
/sbin/insmod –f ./$module.o
$* || exit
#remove stale nodes
rm –f /dev/$(device)[0-3]
major=’awk “
[url=file://///$2==/]\\$2==\[/url]
”$module\” {print
[url=file://///$1]\\$1[/url]
}” /proc/devices’
mknod /dev/${device}0 c
$major 0
mknod /dev/${device}1 c
$major 1
mknod /dev/${device}2 c
$major 2
mknod /dev/${device}3 c
$major 3
#give appropriate group/permissions, and change the group.
#Not all distributions have staff; some have “wheel” instead.
group=”staff”
grep ‘^staff:’ /etc/group
> /dev/null || group=’wheel’
chgrp $group
/dev/${device}[0-3]
chmod $mode
/dev/${device}[0-3]
只要重新定義腳本中的變數並對mknod命令行進行修正該腳本同樣可以用於其驅動程式。
讀者可能對最後幾行迷惑不解:為什麼要改變設備的組(group)和訪問許可權(mode)呢?原因是該腳本只能由超級用戶運行,因而新建的設備檔案自然屬於root。默認許可權位只允許root對其有寫訪問許可權,而其他用戶只有讀許可權。通常設備檔案需要不同的訪問策略,比如只對某一組用戶開放訪問許可權,因而需要改變某些情況下的訪問許可權。