九鼎创展论坛

标题: class_create&device_create_file [打印本页]

作者: armeasy    时间: 2014-10-22 00:15
标题: class_create&device_create_file
使用udev在/dev/下动态生成设备文件

create_chrdev.c
---------------------------------------------
#include <linux/types.h>     //dev_t
#include <linux/cdev.h>      //struct cdev
#include <linux/fs.h>        //alloc_chrdev_region()
#include <linux/device.h>    //class_create()

dev_t                  devid;
static struct cdev     *led_cdev;
static int             led_Major = 0;
static int             led_Minor = 0;
static struct class    *led_class;

static struct file_operations led_fops = {
    .owner        = THIS_MODULE,
};

static int __init hello_init(void)
{
    int err;

    //初始化cdev
    led_cdev        = cdev_alloc();
    cdev_init(led_cdev, &led_fops);
    led_cdev->owner = THIS_MODULE;

    //动态获取主设备号(dev_t devid中包含"主设备号"和"次设备号"信息)
    alloc_chrdev_region(&devid, 66, 1, "led");
    led_Major = MAJOR(devid);
    led_Minor = MINOR(devid);
    printk(KERN_INFO "I was assigned major number %d.\n", led_Major);
    printk(KERN_INFO "I was assigned minor number %d.\n", led_Minor);

    //注册字符设备 (1)
    err = cdev_add(led_cdev, devid, 1);
    if (err) {
        printk(KERN_NOTICE "Error %d adding device\n", err);
        return -1;
    }

    led_class = class_create(THIS_MODULE, "led_class1");
    if (IS_ERR(led_class)) {
        printk(KERN_INFO "create class error\n");
        return -1;
    }
    class_device_create(led_class, NULL, devid, NULL, "led" "%d", MINOR(devid));   


    return 0;
}

static void __exit hello_exit(void)
{
    unregister_chrdev_region(devid, 1);
    cdev_del(led_cdev);

    class_device_destroy(led_class, devid);
    class_destroy(led_class);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zengxiaolong ");
MODULE_DESCRIPTION("A sample driver");
MODULE_SUPPORTED_DEVICE("testdevice");


(1)cdev_add()执行后将会在/proc/devices文件中看到"252 led",但是在/dev/目录下没有生成相应的设备文件。直到class_device_create()执行后才会在/dev/目录下生成设备文件led66。而class_create()执行后会在/sys/class/目录下生成led_class1目录

Makefile
---------------------------------------------
all: default
obj-m += create_chrdev.o

default:
    make -C /home/zxl/soft/kernel/linux-2.6.22 M=`pwd` modules
clean:

    make -C /home/zxl/soft/kernel/linux-2.6.22 M=`pwd` clean






Sysfs文件系统与Linux设备模型

sysfs把连接在系统上的设备和总线组织成为一个分级的目录及文件,它们可以由用户空间存取,向用户空间导出内核数据结构以及它们的属性,这其中就包括设备的主次设备号。新的设备文件系统udev的工作过程就依赖于sysfs文件系统的这些功能特点。udev文件系统在用户空间工作,它可以根据sysfs文件系统导出的信息(设备号等),动态建立和删除设备文件,而不再需要使用mknod来手动建立设备文件,也不必为查找设备号(尤其是驱动中动态申请产生的设备号)而头疼。

kobject内核对象提供了基本的对象管理能力,是linux 2.6设备模型的核心结构,每个在内核中注册的kobject对象都对应于sysfs文件系统的一个目录,这可以通过以下函数调用体现:

kobject_add()-> kobject_add_varg()->kobject_add_internal()->create_dir()->sysfs_create_dir()

(好像已经不存在kobject_register函数了)

sysfs文件系统下的所有目录,其最终的建立过程都是通过注册添加kobjectlinux设备层次来实现的,举两个例子:

1class

class_register-> __class_register-> kset_register-> kobject_add_internal

2device

device_register-> device_add-> kobject_add

因此,对应于一个设备,在sysfs文件系统下不是一个文件,而是一个目录,目录名字的来源是kobject对象的name域。目录中会有两个文件和若干目录,这两个文件是设备的属性文件。我们可以看看device_add函数的实现,其中有:

912 error = device_create_file(dev, &uevent_attr);

913 if (error)

914 goto attrError;

915

916 if (MAJOR(dev->devt)) {

917 error = device_create_file(dev, &devt_attr);

918 if (error)

919 goto ueventattrError;

其中会在sysfs文件系统对应设备目录下创建两个属性文件(可以看看device_create_file函数的实现,是调用sysfs_create_file),其中有两个参数是两个结构体指针,两个结构体的定义如下:

311 static struct device_attribute uevent_attr =

312 __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);


428 static struct device_attribute devt_attr =

429 __ATTR(dev, S_IRUGO, show_dev, NULL);

再看看_ATTR:

48 #define __ATTR(_name,_mode,_show,_store) { \

49 .attr = {.name = __stringify(_name), .mode = _mode }, \

50 .show = _show, \

51 .store = _store, \

52 }

再看看__stringify

19 #define __stringify_1(x) #x

20 #define __stringify(x) __stringify_1(x)

(真是无底洞呀,到这为止吧!)这两个宏看起来很怪异,有人说这个定义很奇妙,具体奇妙在哪目前我还没体会到,等有机会再补充(留个脚印吧)。简单来说,它们的功能就是x转化为字符串,所以ueventdev就转化为“uevent”和”dev“了,把它们赋给name,这就是sysfs具体设备目录下的两个文件ueventdev名字的来源了!

这两个属性文件的内容是怎么等到的呢?sysfs是虚拟文件系统,大家应该知道proc文件系统吧,类似地它们都是在内存中,内容都是动态生成的而不是存储在非易失存储器中。大家应该注意到属性结构体中有两个函数指针showstore,在这里被赋值了

422 static ssize_t show_dev(struct device *dev, struct device_attribute *attr,

423 char *buf)

424 {

425 return print_dev_t(buf, dev->devt);

426 }







欢迎光临 九鼎创展论坛 (http://bbs.9tripod.com/) Powered by Discuz! X3.2