Linux字元驅動中動態分配裝置號與動態產生裝置節點

來源:互聯網
上載者:User

轉自:http://www.cnblogs.com/zhuyp1015/archive/2012/05/22/2514008.html  bird1015的部落格

在編寫Linux核心驅動程式的時候,如果不動態產生裝置號的話,需要自己手動分配裝置號,有可能你分配的裝置號會與已有裝置號相同而產生衝突。因此推薦自動分配裝置號。使用下面的函數:

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

該函數需要傳遞給它指定的第一個次裝置號baseminor(一般為0)和要分配的裝置數count,以及裝置名稱,調用該函數後自動分配得到的裝置號儲存在dev中。

當使用了alloc_chrdev_region()動態分配裝置號之後,需要依次使用:

 

cdev_init(struct cdev * cdev,const struct file_operations * fops)

cdev_add(struct cdev * p,dev_t dev,unsigned count)

將字元裝置註冊到核心中。通過上面三個函數就可以動態產生裝置號了。

在卸載的時候需要使用:unregister_chrdev_region(dev_t from,unsigned count) 來釋放裝置編號

 

動態建立裝置號之後,將驅動載入到核心,通過 : cat /proc/devices   命令可以查看裝置號

 

如果上層應用程式需要訪問驅動程式,則需要為該驅動建立裝置節點。

如果手動建立裝置結點需要這樣做:(這裡假設通過 cat /proc/devices 發現字元裝置 CDEV_ZHU的裝置號為 254)

$mknod  /dev/CDEV_ZHU c 254 0

 

如果我們在驅動裡面動態建立的話需要這樣做:

cdev_class = class_create(owner,name)         // cdev_class 為 struct class 類型

然後使用:

device_create(_cls,_parent,_devt,_device,_fmt)

當動態建立了裝置節點之後,在卸載的時候需要使用:

device_destroy(_cls,_device)  和 class_destroy(struct class * cls)

來銷毀裝置和類。

下面給出一組測試代碼:(該組代碼實現了應用程式通過開啟驅動訪問和修改驅動的一個全域變數 “global_var”)

/*驅動部分:globalvar.c */

#include <linux/module.h> 
#include <linux/init.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include <asm/device.h>  //下面這三個標頭檔是由於動態建立需要加的
#include <linux/device.h>
#include <linux/cdev.h>

 
MODULE_LICENSE("GPL"); 
 
#define DEVICE_NAME  "CDEV_ZHU"
static struct class *cdev_class; 
 
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*); 
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*); 
 
//初始化字元裝置驅動的 file_operations 結構體 
struct file_operations globalvar_fops =  

    read: globalvar_read, 
    write: globalvar_write, 
};

static int global_var = 0;      //CDEV_ZHU裝置的全域變數

dev_t dev = 0;                 //這裡是動態分配裝置號和動態建立裝置結點需要用到的
struct cdev  dev_c;
 
static int __init globalvar_init(void) 

    int ret,err; 
 
    //註冊裝置驅動 
 
    ret = alloc_chrdev_region(&dev, 0, 1,DEVICE_NAME); //動態分配裝置號
    if (ret) 
    { 
        printk("globalvar register failure\n"); 
    unregister_chrdev_region(dev,1);
    return ret;
    } 
    else 
    { 
        printk("globalvar register success\n"); 
    }

   cdev_init(&dev_c, &globalvar_fops);
 
   err = cdev_add(&dev_c, dev, 1);

   if(err)
   {
    printk(KERN_NOTICE "error %d adding FC_dev\n",err);
    unregister_chrdev_region(dev, 1);
    return err;
   }
 
 cdev_class = class_create(THIS_MODULE, DEVICE_NAME);//動態建立裝置結點
 if(IS_ERR(cdev_class))
 {  
        printk("ERR:cannot create a cdev_class\n");  
    unregister_chrdev_region(dev, 1);
    return -1;
    }
 device_create(cdev_class,NULL, dev, 0, DEVICE_NAME);
 
    return ret; 

 
static void __exit globalvar_exit(void) 

 
    //登出裝置驅動 
    
 device_destroy(cdev_class, dev);
 class_destroy(cdev_class);
 unregister_chrdev_region(dev,1);
 printk("globalvar_exit \n");

 
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off) 

    //將 global_var 從核心空間複製到使用者空間 
    if(copy_to_user(buf, &global_var, sizeof(int))) 
    { 
        return    - EFAULT;     
    }   
    return sizeof(int); 

 
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off) 

    //將使用者空間的資料複製到核心空間的 global_var 
    if(copy_from_user(&global_var, buf, sizeof(int))) 
    { 
        return    - EFAULT; 
    }   
    return sizeof(int); 

 
module_init(globalvar_init); 
module_exit(globalvar_exit);

/*應用程式: globalvartest.c  */

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 
#include <fcntl.h> 
int main() 

    int fd, num; 
    //開啟"/dev/CDEV_ZHU"
    fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR); 
    if (fd != -1 ) 
    { 
      //初次讀 global_var 
        read(fd, &num, sizeof(int)); 
        printf("The globalvar is %d\n", num); 
 
      //寫 global_var 
        printf("Please input the num written to globalvar\n"); 
        scanf("%d", &num); 
        write(fd, &num, sizeof(int)); 
 
      //再次讀 global_var 
        read(fd, &num, sizeof(int)); 
        printf("The globalvar is %d\n", num); 
 
        //關閉“/dev/CDEV_ZHU” 
        close(fd); 
    } 
    else 
    { 
        printf("Device open failure\n"); 
    }

    return 0;
}

說明:這個程式是我修改了“深入淺出Linux裝置編程”這本書的代碼的來的,在項目中使用動態建立裝置節點和動態產生裝置號比較方便,於是就在這裡分享了。

使用一個簡單的makefile將(驅動) globalvar.c  編譯過後 使用 insmod globalvar.ko 將驅動載入到核心,然後就將globalvartest.c 產生的可執行檔運行起來就可以操作驅動中的全域變數了。不用像書上一樣還要在命令列去建立裝置節點。

相關文章

聯繫我們

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