天天看點

使用cdev_add注冊字元裝置

在前面已經提到裝置号有主裝置号和次裝置号,其中主裝置号表示裝置類 型,對應于确定的驅動程式,具備相同主裝置号的裝置之間共用同一個驅動程 序,而用次裝置号來辨別具體實體裝置。是以在建立字元裝置之前,必須先獲 得裝置的編号(可能需要配置設定多個裝置号)。

在 Linux 2.6 的版本中,用 dev_t 類型來描述裝置号(dev_t 是 32 位數值類型,其 中高 12 位表示主裝置号,低 20 位表示次裝置号)。用兩個宏 MAJOR 和 MINOR 分别 獲得 dev_t 裝置号的主裝置号和次裝置号,而且用 MKDEV 宏來實作逆過程,即組合 主裝置号和次裝置号而獲得 dev_t 類型裝置号。

配置設定裝置号有靜态和動态的兩種方法。靜态配置設定(register_chrdev_region()函數)是 指在事先知道裝置主裝置号的情況下,通過參數函數指定第一個裝置号(它的次裝置 号通常為 0)而向系統申請配置設定一定數目的裝置号。動态配置設定(alloc_chrdev_region()) 是指通過參數僅設定第一個次裝置号(通常為 0,事先不會知道主裝置号)和要配置設定 的裝置數目而系統動态配置設定所需的裝置号。通過 unregister_chrdev_region()函數釋放已配置設定的(無論是靜态的還是動态的)設 備号。

在Linux 2.6核心中的字元裝置用cdev結構來描述,其定義如下:

struct cdev   
{  
    struct kobject kobj;  
    struct module *owner; //所屬子產品  
    const struct file_operations *ops; //檔案操作結構  
    struct list_head list;  
    dev_t dev; //裝置号,int 類型,高12位為主裝置号,低20位為次裝置号  
    unsigned int count;  
};        

下面一組函數用來對cdev結構進行操作:

struct cdev *cdev_alloc(void);//配置設定一個cdev  
void cdev_init(struct cdev *, const struct file_operations *);//初始化cdev的file_operation  
void cdev_put(struct cdev *p);// //減少使用計數  
//注冊裝置,通常發生在驅動子產品的加載函數中  
int cdev_add(struct cdev *, dev_t, unsigned);   
//登出裝置,通常發生在驅動子產品的解除安裝函數中  
void cdev_del(struct cdev *);  
           

使用cdev_add注冊字元裝置前應該先調用register_chrdev_region或alloc_chrdev_region配置設定裝置号。register_chrdev_region函數用于指定裝置号的情況,alloc_chrdev_region函數用于動态申請裝置号,系統自動傳回沒有占用的裝置号。

int register_chrdev_region(dev_t from, unsigned count, const char *name) ;  
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name); 

       
函數傳入值

first:要配置設定的裝置号的初始值

 count:要配置設定(釋放)的裝置号數目

 name:要申請裝置号的裝置名稱(在/proc/devices 和 sysfs 中顯示) 

dev:動态配置設定的第一個裝置号

函數傳回值

                成功:0(隻限于兩種注冊函數)

                出錯: 1(隻限于兩種注冊函數)

alloc_chrdev_region申請一個動态主裝置号,并申請一系列次裝置号。baseminor為起始次裝置号,count為次裝置号的數量。登出裝置号(cdev_del)後使用unregister_chrdev_region:

  1. void unregister_chrdev_region(dev_t from,unsigned count) ; 
這裡講解 2.6 核心中的字元裝置的注冊和登出過程。 在 Linux 核心中使用 struct cdev 結構來描述字元裝置,我們在驅動程式中必 須将已配置設定到的裝置号以及裝置操作接口(即為 struct file_operations 結構)賦予 struct cdev 結構變量。首先使用 cdev_alloc()函數向系統申請配置設定 struct cdev 結構, 再用 cdev_init()函數初始化已配置設定到的結構并與 file_operations 結構關聯起來。最 後調用 cdev_add()函數将裝置号與 struct  cdev 結構進行關聯并向核心正式報告新 裝置的注冊,這樣新裝置可以被用起來了。 如果要從系統中删除一個裝置,則要調用 cdev_del()函數。

例1.4  cdev_add注冊字元裝置執行個體

代碼見CD光牒\src\1drivermodel\1-4cdev。核心代碼如下所示:

  1. struct file_operations simple_fops = {  
  2.     .owner =    THIS_MODULE,  
  3.     .read =     simple_read,  
  4.     .write =    simple_write,  
  5.     .open =     simple_open,  
  6.     .release =  simple_release,  
  7. };  
  8. /*******************************************************  
  9.                 MODULE ROUTINE  
  10. *******************************************************/  
  11. void simple_cleanup_module(void)  
  12. {  
  13.     dev_t devno = MKDEV(simple_MAJOR, simple_MINOR);  
  14.     if (simple_devices)   
  15.     {  
  16.         cdev_del(&simple_devices->cdev);  
  17.         kfree(simple_devices);  
  18.     }  
  19.     unregister_chrdev_region(devno,1);  
  20. }  
  21. //子產品初始化  
  22. int simple_init_module(void)  
  23. {  
  24.     int result;  
  25.     dev_t dev = 0;  
  26.     dev = MKDEV(simple_MAJOR, simple_MINOR);  
  27.     result = register_chrdev_region(dev, 1, "DEMO");//申請裝置号  
  28.     if (result < 0)   
  29.     {  
  30.         printk(KERN_WARNING "DEMO: can't get major %d\n", simple_MAJOR);  
  31.         return result;  
  32.     }  
  33.     simple_devices = kmalloc(sizeof(struct simple_dev), GFP_KERNEL);  
  34.     if (!simple_devices)  
  35.     {  
  36.         result = -ENOMEM;  
  37.         goto fail;  
  38.     }  
  39.     memset(simple_devices, 0, sizeof(struct simple_dev));  
  40.     //初始化裝置結構  
  41.     cdev_init(&simple_devices->cdev, &simple_fops);  
  42.     simple_devices->cdev.owner = THIS_MODULE;  
  43.     simple_devices->cdev.ops = &simple_fops;  
  44.     result = cdev_add (&simple_devices->cdev, dev, 1);//添加字元裝置  
  45.     if(result)  
  46.     {  
  47.         printk(KERN_NOTICE "Error %d adding DEMO\n", result);  
  48.         goto fail;  
  49.     }  
  50.     return 0;  
  51. fail:  
  52.     simple_cleanup_module();  
  53.     return result;  
  54. }  
  55. module_init(simple_init_module);  
  56. module_exit(simple_cleanup_module);  

本例的應用層代碼與運作結果同上例。