主次設備號
主次設備號
主設備號被系統用來確定驅動程序(設備類型:如USB設備,硬碟設備),次設備號被驅動程序用來確定具體的設備。
字元設備驅動的特殊文件,可以通過ls-l輸出的第一列中的“c”標明。/dev下還有塊設備,它們用“b”來識別。儘管如下介紹的某些內容也適用於塊設備,但我們這章只關注字元設備。
如果你執行ls-l命令,在設備文件條目中的最新修改日期前你會看到二個數(用逗號分隔),這個位置通常顯示文件長度。這二個數就是相應設備的主設備號和次設備號。下面的列表給出了我使用的系統上的一些設備。它們的主設備號是1,1,而次設備號是3,5。
crw-rw-rw- 1 root root 1, 5 Feb23 1999 zero
主設備號識別設備對應的驅動程序。例如,/dev/null和/dev/zero都由驅動程序1管理,而所有的虛擬控制台和串口終端都由驅動程序4管理,同樣,vcs1和 vcsa1由驅動程序7管理。當設備打開(open)時,內核利用主設備號分派執行相應的驅動程序。
次設備號只由相應的設備驅動程序使用;內核的其他部分不使用它,僅將它傳遞給驅動程序。所以一個驅動程序管理若干個設備並不為奇(如上面的例子所示),次序號提供了一種區分它們的方法。儘管2.4版本的內核引入了一種新的特性(可選):設備文件系統,devfs。如果使用了這種文件系統,那設備文件將變得簡單,但也很原來有很大的不同。另一方面,這新的文件系統帶來了一些用戶可見的不兼容特性。
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讀取相關的設備號信息。
下面這個腳本,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對其有寫訪問許可權,而其他用戶只有讀許可權。通常設備文件需要不同的訪問策略,比如只對某一組用戶開放訪問許可權,因而需要改變某些情況下的訪問許可權。