※ 真實的驅(qū)動程序利用中斷與它們的設(shè)備同步
主設(shè)備號和次設(shè)備號
※ 主設(shè)備號標(biāo)識設(shè)備對應(yīng)的驅(qū)動程序;次設(shè)備號由內(nèi)核使用,用于正確確定設(shè)備文件所指的設(shè)備。我們可以通過次設(shè)備號獲得一個指向內(nèi)核設(shè)備的直接指針,也可將次設(shè)備號當(dāng)作設(shè)備本地數(shù)組的索引,不管用哪種方式,除了知道次設(shè)備號用來指向驅(qū)動程序所實現(xiàn)的設(shè)備之外,內(nèi)核本身基本上不關(guān)心關(guān)于次設(shè)備號的任何其他消息。
※ 設(shè)備編號的內(nèi)部表達
n 在內(nèi)核中,dev_t類型(在<linux/types.h>中定義)用來保存設(shè)備編號——包括主設(shè)備號和次設(shè)備號。
n MAJOR(dev_t dev); MINOR(dev_t dev) MKDEV(int major, int minor)
※ 分配和釋放設(shè)備編號
n <linux/fs.h>:
int register_chrdev_region(dev_t first, unsigned int count, char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,
unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);
驅(qū)動程序需要將設(shè)備編號和內(nèi)部函數(shù)連接起來,這些內(nèi)部函數(shù)用來實現(xiàn)設(shè)備的操作。
※ 動態(tài)分配主設(shè)備號
n 某些主設(shè)備號已經(jīng)靜態(tài)地分配給了大部分公用設(shè)備。在內(nèi)核源碼樹的Documentation/device.txt文件中可以找到這些設(shè)備的列表。
n 一旦驅(qū)動程序被廣泛使用,隨機選定的主設(shè)備號可能造成沖突和麻煩
n 強烈推薦你不要隨便選擇一個一個當(dāng)前不用的設(shè)備號做為主設(shè)備號,而使用動態(tài)分配機制獲取你的主設(shè)備號。
n 動態(tài)分配的缺點是,由于分配給你的主設(shè)備號不能保證總是一樣的,無法事先創(chuàng)建設(shè)備節(jié)點。然而這不是什么問題,這是因為一旦分配了設(shè)備號,你就可以從/proc/devices讀到。為了加載一個設(shè)備驅(qū)動程序,對insmod的調(diào)用被替換為一個簡單的腳本,它通過/proc/devices獲得新分配的主設(shè)備號,并創(chuàng)建節(jié)點
#!/bin/sh
module="scull"
device="scull"
mode="664"
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.ko $* || exit 1
# remove stale nodes
rm -f /dev/${device}[0-3]
major=$(awk "\\$2= =\"$module\" {print \\$1}" /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 -q '^staff:' /etc/group || group="wheel"
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
n 分配主設(shè)備號的最佳方式:默認采用動態(tài)分配,同時保留在加載甚至是編譯時指定主設(shè)備號的余地。
n Here's the code we use in scull 's source to get a major number:
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr_devs, "scull");
} else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
scull_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
return result;
}