Linux設備文件自動生成


第一種是使用mknod手工創建:# mknod <devfilename> <devtype> <major> <minor>

第二種是自動創建設備節點:利用udev(mdev)來實現設備文件的自動創建,首先應保證支持udev(mdev),由busybox配置。

      具體udev相關知識這里不詳細闡述,可以移步Linux 文件系統與設備文件系統 —— udev 設備文件系統,這里主要講使用方法。     

    在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼里調用class_create(...)為該設備創建一個class,再為每個設備調用device_create(...)創建對應的設備

    內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創建一個類,這個類存放於sysfs下面,一旦創建好了這個類,再調用 device_create(…)函數來在/dev目錄下創建相應的設備節點。

     這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創建設備節點。 

下面是兩個函數的解析:

支持字符設備文件自動生成
linux/device.h

struct class *class_create(struct module *owner, const char *name);
/*
  功能:在/sys/class目錄下創建一個目錄,目錄名是name指定的
  參數:
    struct module *owner - THIS_MODULE
    const char *name - 設備名
  返回值:
    成功:class指針
    失敗: - bool IS_ERR(const void *ptr)  判斷是否出錯
         long PTR_ERR(const void *ptr)  轉換錯誤碼
*/
void class_destroy(struct class *cls);
/*
  功能:刪除class指針指向的目錄
  參數:
    struct class *cls - class指針
*/
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
/* 
  功能:
    在class指針指向的目錄下再創建一個目錄,目錄名由const char *fmt, ...指出、並導出設備信息(dev_t)
  參數:
    struct class *cls - class指針
    struct device *parent - 父對象,NULL
    dev_t devt - 設備號
    void *drvdata - 驅動私有數據
    const char *fmt, ... - fmt是目錄名字符串格式,...就是不定參數
  返回值:
    成功 - device指針
    失敗 - bool IS_ERR(const void *ptr)  判斷是否出錯
       long PTR_ERR(const void *ptr)   轉換錯誤碼
*/
void device_destroy(struct class *cls, dev_t devt);
/*
  功能:刪除device_create創建的目錄
  參數:
    struct class *cls - class指針
    dev_t devt - 設備號
*/

創建次序
struct class *class_create(struct module *owner, const char *name);
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
刪除次序
void device_destroy(struct class *cls, dev_t devt);
void class_destroy(struct class *cls);

實例:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/device.h>

MODULE_LICENSE("GPL");

static struct class *cls = NULL;

static int major = 0;
static int minor = 0;
const  int count = 6;

#define DEVNAME    "demo"

static struct cdev *demop = NULL;

//打開設備
static int demo_open(struct inode *inode, struct file *filp)
{
    //get command and pid
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);return 0;
}

//關閉設備
static int demo_release(struct inode *inode, struct file *filp)
{
    //get major and minor from inode
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);
    return 0;
}

static struct file_operations fops = {
    .owner    = THIS_MODULE,
    .open    = demo_open,
    .release= demo_release,
};

static int __init demo_init(void)
{
    dev_t devnum;
    int ret, i;
    struct device *devp = NULL;

    //1. alloc cdev obj
    demop = cdev_alloc();
    if(NULL == demop){
        return -ENOMEM;
    }
    //2. init cdev obj
    cdev_init(demop, &fops);

    ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
    if(ret){
        goto ERR_STEP;
    }
    major = MAJOR(devnum);

    //3. register cdev obj
    ret = cdev_add(demop, devnum, count);
    if(ret){
        goto ERR_STEP1;
    }
    cls = class_create(THIS_MODULE, DEVNAME);
    if(IS_ERR(cls)){
        ret = PTR_ERR(cls);
        goto ERR_STEP1;
    }
    for(i = minor; i < (count+minor); i++){
        devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
        if(IS_ERR(devp)){
            ret = PTR_ERR(devp);
            goto ERR_STEP2;
        }
    }
    return 0;

ERR_STEP2:
    for(--i; i >= minor; i--){
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

ERR_STEP1:
    unregister_chrdev_region(devnum, count);

ERR_STEP:
    cdev_del(demop);

    //get command and pid
    printk(KERN_INFO "%s : %s : %d - fail.\n", __FILE__, __func__, __LINE__);
    return ret;
}

static void __exit demo_exit(void)
{
    int i;
    //get command and pid
    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);

    for(i=minor; i < (count+minor); i++){
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

    unregister_chrdev_region(MKDEV(major, minor), count);

    cdev_del(demop);
}

module_init(demo_init);
module_exit(demo_exit);

下面可以看幾個class幾個名字的對應關系:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM