※ 真實的驅動程序利用中斷與它們的設備同步
主設備號和次設備號
※ 主設備號標識設備對應的驅動程序;次設備號由內核使用,用于正確確定設備文件所指的設備。我們可以通過次設備號獲得一個指向內核設備的直接指針,也可將次設備號當作設備本地數組的索引,不管用哪種方式,除了知道次設備號用來指向驅動程序所實現的設備之外,內核本身基本上不關心關于次設備號的任何其他消息。
※ 設備編號的內部表達
n 在內核中,dev_t類型(在<linux/types.h>中定義)用來保存設備編號——包括主設備號和次設備號。
n MAJOR(dev_t dev); MINOR(dev_t dev) MKDEV(int major, int minor)
※ 分配和釋放設備編號
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);
驅動程序需要將設備編號和內部函數連接起來,這些內部函數用來實現設備的操作。
※ 動態分配主設備號
n 某些主設備號已經靜態地分配給了大部分公用設備。在內核源碼樹的Documentation/device.txt文件中可以找到這些設備的列表。
n 一旦驅動程序被廣泛使用,隨機選定的主設備號可能造成沖突和麻煩
n 強烈推薦你不要隨便選擇一個一個當前不用的設備號做為主設備號,而使用動態分配機制獲取你的主設備號。
n 動態分配的缺點是,由于分配給你的主設備號不能保證總是一樣的,無法事先創建設備節點。然而這不是什么問題,這是因為一旦分配了設備號,你就可以從/proc/devices讀到。為了加載一個設備驅動程序,對insmod的調用被替換為一個簡單的腳本,它通過/proc/devices獲得新分配的主設備號,并創建節點
#!/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 分配主設備號的最佳方式:默認采用動態分配,同時保留在加載甚至是編譯時指定主設備號的余地。
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;
}