linux 驱动 :设备节点的自创建「掘金·日新计划」

201 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

前言

linux驱动的初始化过程分为三部分。
1设备编号的申请,在/proc/devices里出现;2设备的注册,其中包括对设备的操作;3设备节点的注册,出现在/dev目录下。

字符设备的注册

涉及到的结构体是 struct cdev,包含于linux/cdev.h头文件中。 定义结构如下

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

cdev是2.6内核以来新的字符设备注册方式,以前使用的注册接口是int register_chedev(unsigned int major,const char*name,struct file_operations *fops),对于咱们学习新的驱动来说,只要了解即可。开发时候尽量使用新的注册接口,因为旧的注册机制会在将来的内核实现中消失。
有两种注册方式:静态和动态。
静态方式,实体结构需要调用cdev_init接口初始化,需要赋值owner成员。

static void init_cdev_static(dev_t DevId)
{
    int err;
    struct cdev sDev;
    cdev_init(&sDev,&MyFOps);
    sDev.owner = THIS_MODULE;
    err = cdev_add(&sDev,DevId,1);
    if(err) printk(KERN_ALERT "cdev_add err [%d]] !!\n",err);
    return err;
}
动态方式,不需要调用cdev_init接口初始化,需要代码里主动对owner和ops进行赋值。
static int init_cdev_dyn(dev_t DevId)
{
    int err = 0;
    MyDev = cdev_alloc();
    if(MyDev == NULL) {
        printk(KERN_ALERT "cdev_alloc fail\n");
        return -1;;
    }
    MyDev->ops = &MyFOps;
    MyDev->owner = THIS_MODULE;
    err = cdev_add(MyDev,DevId,1);

    if(err) printk(KERN_ALERT "cdev_add err [%d]] !!\n",err);
    return err;
}
cdev_add函数一旦成功返回,设备就成功在系统中存在,且可被调用操作了。所以需要等待所有的设备操作完全准备好,才能调用cdev_add接口。

字符设备的自创建

需要的接口位于 linux/device.h头文件里。
首先使用class_create(owner, name) 接口创建类,类会在 /sys/class下创建个相应的文件夹。
再次使用 device_create(truct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) 创建逻辑设备,和相应的类关联起来,并自动在/dev下创建逻辑设备节点。

以下是示例代码。

int DevCreate(dev_t devId)
{
    TestDri = class_create(THIS_MODULE,"TestDri");
    if(IS_ERR(TestDri)){
        printk(KERN_ALERT "class_create err\n");
        return -1;
    }
    device_create(TestDri,NULL,devId,NULL,"zsy001");
    return 0;
}

查看/sys下效果

image.png /dev下可自动创建出设备节点。

image.png

由此,完成对设备节点的自创建工作。