linux裝置驅動學習(二)–字元裝置驅動

來源:互聯網
上載者:User

字元裝置驅動:

1.一般我們都採用動態分配裝置號的API:

int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

dev是經用於輸出的函數,在成功完成調用以後將儲存分配範圍的第一個編號。

void unregister_chrdev_region(dev_t first,unsigned int count);

上面的函數為驅動程式的使用分配裝置編號,但是他們並沒有告訴核心拿這些編號做什麼。在使用者空間可訪問上述裝置之前,驅動程式需要將裝置編號和內建函式聯絡起來。

為了能夠動態產生裝置號,並且能夠建立裝置節點,對insmod的調用可以替換為一個簡單的指令碼。動態分配的缺點就是不能自動產生裝置節點。

#!bin/sh

module="scull"

device="scull"

mod="664"

 

/sbin/insmod  ./$module.ko $*||exit 1 調用insmod並使用路徑名來指定模組位置。

 

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

 

group="stuff"

 

chgrp  $group  /dev/${device}[0-3]

chmod $mod  /dev/${device}[0-3]

 

2.獲得主裝置號的代碼:

scull採用這種現實方式,他使用了sucll_major,用來儲存所選擇的裝置號(也有一個用於次裝置號的scull_minor)該變數的初始化值是SCUL_MAJOR在,這個宏定義在scull.h中,預設為0,使用者可以使用預設值或選擇特定裝置號。

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_INFO  "can't get major %d/n",scull_major);

     return result;

}

前邊說過alloc_chrdev_region中dev是僅用作輸出的參數。然後通過MAJOR(dev)獲得主裝置號。

在這部分中,比較重要的是在用函數擷取裝置編號後,其中的參數name是和該編號範圍關聯的裝置名稱,它將出現在/proc/devices和sysfs中。

看到這裡,就可以理解為什麼mdev和udev可以動態、自動地產生當前系統需要的裝置檔案。udev就是通過讀取sysfs下的資訊來識別硬體裝置的.
(請看《理解和認識udev》
URL:http://blog.chinaunix.net/u/6541/showart_396425.html)

 

3.file_operations中幾個選項:

unsigned int (*poll)(struct file *,struct poll_table_struct *)

poll方法是poll,epoll,select這三個系統調用的後台實現,這三個系統調用可以用來查詢某個或多個檔案描述符(多個檔案描述符通過構建一個fd_set來實現)上的讀取或寫入是否被阻塞,poll方法應該返回一個為掩碼,用來指出非阻塞的讀取或寫入是否可能,並且也會向核心提供將調用進程置於休眠狀態直到I/O變為可能時的資訊。

 

4. file結構體中有private_data結構體,通常這個變數通過強制類型轉換,變為裝置所需的結構體,儲存有用的資源。

5.核心用inode結構在內部表示檔案,因此它和file結構不同,後者表示開啟的檔案描述符。對於單個檔案,可能會有許多多個表示開啟檔案描述符的file結構,但他們都指向單個inode結構。

在inode結構體中有一個struct cdev *i_cdev欄位, struct cdev是表示字元裝置的核心內部結構,當inode指向一個字元裝置時,該欄位包含了指向struct cdev結構的指標。

6.前邊知道,核心內部使用struct cdev結構表示字元裝置。在核心調用裝置操作之前,必須分配並註冊一個或多個以上的結構:

struct cdev *my_cdev = cdev_alloc();

my_cdev->ops = &my_fops;

分配一個cdev結構。

void cdev_init(struct cdev *cdev,struct file_operations *fops);

進行裝置初始化。

void cdev_add(struct cdev *dev,dev_t num,int count);

將裝置添加到核心中。 dev為cdev裝置,num為裝置號,count一般取1.

struct cdev提供了核心與裝置之間的介面。

static void scull_setup_cdev(struct scull_cdev *dev,int index)

{

    int err,devno = MKDEV(scull_major,scull_minor + index);

    cdev_init(&dev->cdev,&scull_fops);

    dev->cdev.ower = THIS_MODULE;

    dev->cdev.ops   =  &scull_fops;

    err = cdev_add(&dev->cdev,devno,1);

    if(err){

       ....

     }

    return 0;

}

 

7.open函數

int (*open)(struct inode *inode,struct file *filp)

其中inode的在其i_cdev欄位中包含了我們所需要的資訊,即我們設定的cdev結構。唯一的問題是我們不需要cdev結構本身,而是要知道包含cdev結構的scull_dev結構。這裡運用container_of宏來完成,該宏可以通過結構體成員得到包含該成員的結構體本身:

container_of(pointer,container_type,container_field);

該宏需要一個container_field欄位的指標,該欄位包含在container_type類型的結構體中,然後返回包含該欄位的結構體指標,在scull_open中,這個宏用來找到合適的裝置結構。

struct scull_dev *dev;

dev = container_of(inode->i_cdev,struct  scull_dev,cdev);

filp->private_data = dev;

這段代碼首先定義了一個scull_dev裝置其中包含了i_cdev欄位(包含cdev),然後通過container_of找到包含cdev欄位的scull_dev結構體,然後將該結構體賦值給filp的私人成員變數。

其中open要完成的一個任務就是分配並填寫置於filp->private_data裡的資料結構。

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;

  

   if((filp->f_flags & O_ACCMODE) == O_WRONLY){

        scull_trim(dev);  /*負責釋放整個記憶體地區*/

   }

   return 0;

}

8.release/close的作用

釋放由open分配的,儲存在filp->private_data中的資料結構。

在最後一次關閉操作時關閉裝置。

這裡有個問題就是就是關閉裝置的次數,可能會大於open裝置的次數,比如dup/fork系統調用都會在不調用open的情況下建立已開啟檔案的副本,但每個副本都在程式終止前被關閉。

原因在於:並不是每個close系統調用都會引起對release方法的調用,只有真正釋放裝置資料結構的close才會調用release方法的調用。核心對每個file結構維護其被使用多少次的計數器。對於dup/fork等系統調用,並不會建立新的資料結構(僅由open建立,在open函數中通過申請並初始化的cdev結構,運用container_of求出包含cdev的scull_dev結構,並賦值給filp->private_data,從而分配一個新的資料結構),他們只是增加對資料結構的計數。當file結構的計數減為零時,才會調用close,執行release.

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.