Linux Device Driver study: scull解析

來源:互聯網
上載者:User

曆時將近兩個月,終於化零為整,對《Linux裝置驅動程式》(3rd edition)中第三章scull驅動有了詳細的瞭解,下面對scull的驅動進行解析,方便以後的查看。

一、建立字元驅動的步驟:

1、獲得裝置號:

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);

上述兩個函數,前者為在確定主裝置號(first)的時候,進行裝置號的註冊,後者為自動獲得主裝置號並註冊(獲得的裝置號存入dev中)。

2、將裝置操作函數與裝置號聯絡到一起:

初始化:void cdev_init(struct cdev *dev, struct file_operations *fops);

添加到核心中:int cdev_add(struct cdev *dev, dev_t num, unsigned int count)

注意:步驟2用到的fops已經初始化完成,設計裝置驅動的open,read,write,release等函數;而需要定義全域變數struct cdev my_cdev,或在驅動代碼中利用kalloc對其分配空間。


二、代碼常式:

可參考本書內建的常式,附件中的main.c中scull_init_module的實現。


三、scull驅動程式碼分析以及應用程式調用scull

1、scull驅動代碼中的全域變數:struct scull_dev *scull_devices;           //通過在scull_init_module中為其分配空間;

scull_major, scull_minor:裝置號

2、當scull驅動編譯完成,且安裝到核心中後,可利用應用程式進行讀取來驗證。如:file1=fopen("/dev/scull0", "rb+");  stringlen = fwrite(stringBuffer, 1, sizeof(stringBuffer), file1)  

3、關於fopen的實現:

a)應用程式在調用fopen庫函數後,會執行底層應用函數介面int open(const char *path, int oflags),進而會執行到核心代碼  long do_sys_open(int dfd, const char __user *filename, int flags, int mode)  (核心代碼open.c檔案中)。do_sys_open實現通過filename得到struct
file *f,並把f與int fd綁定,返回fd。得到的fd即為open函數的傳回值。

b)scull驅動中的open函數int scull_open(struct inode *inode, struct file *filp)

struct scull_dev *dev;

dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */

在scull驅動中主要是通過filp->private_data(指向dev),進行資料的write和read。

在看這段代碼時,有很多疑問,如inode->i_cdev應該是指向的之前在scull驅動中定義的scull_devices.dev部分,那麼是在什麼時候jiangscull_devices.dev的地址賦值給的inode->i_cdev;再有就是scull_open與核心代碼中的do_sys_open之間的關係。自己的理解如下:

(1)scull_init_module調用scull_setup_cdev函數,其中scull_setup_cdev實現cdev_init和cdev_add的功能,cdev_add實現告訴核心,對應的裝置代碼對應特定的裝置檔案和操作函數(scull_devices以及其中的f_ops),即在核心中進行註冊,之後通過裝置號就可找到對應的scull_devices。在進行節點建立時(mknod),會用到裝置號(如:mknod /dev/scull0 -C
$majorNumber 0),此時建立的inode,其i_cdev已經指向了對應特定裝置號的scull_devices。

(2)核心源碼do_sys_open主要實現通過檔案路徑path得到file指標f,並與對應的控制代碼fd綁定。

do_sys_open調用struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);do_filp_open函數中實質性的開啟工作是do_last函數。

在do_last函數中,無論open_flag中的標誌位判斷該檔案是不是需要被建立,最後都會調用函數nameidata_to_filp,nameidata_to_filp會調用__dentry_open,在__dentry_open函數中會調用到f->f_op->open也就是scull_open。

關於檔案節點是否需要建立在調用f_op 的時刻會有不同,需要建立節點時,在__open_namei_create之後調用nameidata_to_filp;不需要建立節點時,在finish_open中調用nameidata_to_filp。

(3)在scull驅動過程中,通過file->private_data來傳遞scull_devices的地址(主要在scull_open代碼中實現),進而對scull_devices的data資料去進行讀寫。


4、scull_devices指向的資料空間(可參考,第三章61頁的圖片):

在進行scull_write和scull_read時,調用scull_follow函數,實現對資料空間的分配(kmalloc)

struct scull_dev {
struct scull_qset *data;  /* Pointer to first quantum set */
int quantum;              /* the current quantum size */
int qset;                 /* the current array size */
unsigned long size;       /* amount of data stored here */
unsigned int access_key;  /* used by sculluid and scullpriv */
struct semaphore sem;     /* mutual exclusion semaphore     */
struct cdev cdev;
  /* Char device structure */
};

struct scull_qset {
void **data;
struct scull_qset *next;
};

struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};




參考資料:

1、《LInux裝置驅動程式》第三章

2、Linux核心源碼

3、關於核心代碼open的解析:http://www.cublog.cn/u3/119372/showart_2518539.html

4、關於file->private_data   http://linux.chinaunix.net/techdoc/develop/2007/09/09/967423.shtml


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.