0%

Linux 自动在 /dev 下创建设备文件

insmod *.ko 之后,部分驱动需要执行 mknod 才能正常工作,区别如下

现象

针对驱动实现不同,使用不同,主要在于是否需要手动创建设备文件

mknod /dev/panel0 c 22 0
insmod /lib/modules/ `uname -r` /panel.ko

设备管理

Linux 中有手动和自动两种设备管理,一种是 mknod,在 insmod/dev 下必须有对应的设备文件,需要 mknod 来创建;另外一种在驱动中自动创建

利用 udev(mdev) 来实现设备文件的自动创建,首先应保证支持 udev(mdev),由 busybox 配置。

在驱动用加入对 mdev 的支持主要做的就是:在驱动初始化的代码里调用 class_create(...) 为该设备创建一个 class,再为每个设备调用 device_create(...) 创建对应的设备。

内核中定义的 struct class 结构体,顾名思义,一个 struct class 结构体类型变量对应一个类,内核同时提供了 class_create(…) 函数,可以用它来创建一个类,这个类存放于 sysfs 下面,一旦创建好了这个类,再调用 device_create(…) 函数来在 /dev 目录下创建相应的设备节点。

这样,加载模块的时候,用户空间中的 mdev 会自动响应 device_create() 函数,去 /sysfs 下寻找对应的类从而创建设备节点。


#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

static int major = 250;
static int minor=0;
static dev_t devno;
static struct class *cls;
static struct device *test_device;

static int hello_open (struct inode *inode, struct file *filep)
{
    printk("hello_open \n");
    return 0;
}
static struct file_operations hello_ops=
{
    .open = hello_open,
};

static int hello_init(void)
{
    int ret;
    printk("hello_init \n");


    devno = MKDEV(major,minor);
    ret = register_chrdev(major,"hello",&hello_ops);

    cls = class_create(THIS_MODULE, "myclass");
    if(IS_ERR(cls))
    {
        unregister_chrdev(major,"hello");
        return -EBUSY;
    }
    test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello
    if(IS_ERR(test_device))
    {
        class_destroy(cls);
        unregister_chrdev(major,"hello");
        return -EBUSY;
    }
    return 0;
}
static void hello_exit(void)
{
    device_destroy(cls,devno);
    class_destroy(cls);
    unregister_chrdev(major,"hello");
    printk("hello_exit \n");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

下面可以看几个 class 几个名字的对应关系:
mknod

不同内核版本区别

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
#   define CLASS_DEV_CREATE(class, devt, device, id)      device_create(class, devt, device, NULL, "hello%d", id)
#   define CLASS_DEV_DESTROY(class, devt)                 device_destroy(class, devt)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#   define CLASS_DEV_CREATE(class, devt, device, id)      device_create(class, devt, device, NULL, "hello%d", id)
#   define CLASS_DEV_DESTROY(class, devt)                 device_destroy(class, devt)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
#   define CLASS_DEV_CREATE(class, devt, device, id)      class_device_create(class, devt, device, NULL, "hello%d", id)
#   define CLASS_DEV_DESTROY(class, devt)                 class_device_destroy(class, devt)
#else
#   define CLASS_DEV_CREATE(class, devt, device, id)      device_create_drvdata(class, devt, device, "hello%d", id)
#   define CLASS_DEV_DESTROY(classs, devt)                device_destroy(class, devt)
#endif

mdev

echo "mdev..."
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s

mdev.conf 如下

null                   0:0 666
zero                   0:0 666
urandom                0:0 444

kmem                   0:9 000
mem                    0:9 640
port                   0:9 640

console                0:5 600
ptmx                   0:5 660
pty[a-z].              0:0 660
tty[a-z].              0:0 660
tty[0-9][0-9]          0:0 660

ttyS[0-9]              0:20 640

sd[a-z][0-9]*          0:6 660 * /etc/hotplug/usb/automount.sh $MDEV $ACTION
fd[0-9]*    0:11 660
hd[a-z]*    0:6 660

Ref

  1. Linux 字符设备驱动结构(二)—— 自动创建设备节点
  2. 自动在 /dev/ 下创建设备文件
  3. 内核驱动模块如何在 /dev 文件下自动创建设备