2012年3月24日 星期六

Linux驅動程式--chapter 3

對於新手還真的有點辛苦的一章,一邊念著一邊看著原始碼,這一章節作者寫了個scull的character device的module,先利用了一些script(mknod)將這些虛擬裝置建構出來

首先替module本身與裝置連結,所以要註冊裝置的編號,在linux 2.6中使用major number跟minor number組成一個獨一無二的編號
MKDEV(scull_major, scull_minor)
跟著使用register_chrdev_region註冊數個裝置(依序,如果之前minor number是2, count是3,就會註冊2~4這幾個裝置),或者使用alloc_chrdev_region動態配置

因為作者使用記憶體取代實際可能為磁碟或者其他硬體裝得部份,所以他有些結構需要初始化,scull_devices這個變數對應每個虛擬裝置的相關資料

接著填充一些必要得功能,其中最重要的是struct file_operations這個結構,他包含了許多character device應該具備有的功能,如果沒有的話則保持NULL,如果使用者使用了不再表格內的function call,就會回傳錯誤。底下是一個範例

struct file_operations scull_fops = {
.owner =    THIS_MODULE,
.llseek =   scull_llseek,
.read =     scull_read,
.write =    scull_write,
.ioctl =    scull_ioctl,
.open =     scull_open,
.release =  scull_release,
};

該結構內並不完全都是function pointer,其中.owner就是表示這個module本身,THIS_MODULE是一個macro
另外可以看到就是read/write、llseek跟open/release這幾個常見的操作,但是為何不是close而是release,這是因為linux一般會對裝置紀錄一個count,表示有多少人或者process這在使用這個資源,只有當count為0的時候才會真真的close

接著必須對每個device作file_operations跟device的對應,使用cdev_init輸入兩個參數,分別是該裝置所需用到的資料結構(struct scull_dev)以及file_operations這個結構,作者假設有四個裝置,就分配要配置四份,但是file_operations這些操作是共用的

這裡有點好玩的是,並沒有強制規定同樣的file device必須有同樣的,甚至因為傳入的是指標,表示可以在半路抽換介面@@a,真是一個好玩的狀況!!

仔細觀察file_operations就會發見到,很多地方需要使用到struct file以及struct inode這兩個參數(由kernel傳入),inode裡面有個成員i_cdev,這裡面包含之前用cdev_init配給某個device的資料結構,需要透過struct scull_dev *dev = container_of(inode->i_cdev, struct scull_dev, cdev);這個巨集取出,這樣就可以知道process正在存取哪個device,並且使用相對應的資料空間

另外討論到記憶體的管理,如作者之前提過得,在kernel space並不能使用一般的libc函數,也就是malloc/free之類的記憶體配置不能使用,這裡必須使用kmalloc/kfree。另外值得注意的一點是如何在user space以及kernel space之間傳遞資料,這裡使用
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count)
unsigned long copy_from_user(void *to, const void __user*from, unsigned long count)
在這兩個呼叫,kernel還必須要檢查適當地存取權限,還有處理使用者指向的記憶體可能是page fault的問題

所以整體來說,簡化的架構就是

  • 註冊裝置
  • 初始化相對應裝置的資料
  • 完成file_operations表格
  • 完成相對應操作的函數 
  • 最後記得要清理資料

沒有留言:

張貼留言