自动创建设备节点class_create 和device_create

    刚开始学习驱动的时候,每次都需要mknod /dev/timer c 500 0 这样手动去创建一个设备节点;实际上Linux内核提供一组函数,可以用来在驱动模块加载的时候自动在/dev目录下创建相应的设备节点,并在下载的时候删该节点


device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)和device_destroy(struct class *class,dev_t devt)配对使用

class_create(owner, name)和class_destroy(struct class *cls);配对使用





代码实现:

/*

*************************************************************************

环境:ubuntu 12.04  

交叉编译工具:arm-none-linux-gnueabi-

开发板:exynos4412

***********************************************************************************

*/

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/cdev.h>  //字符设备的头文件

#include <asm/uaccess.h>

#include <linux/timer.h>

#include <linux/device.h>


#define MA 300 //主设备号


struct class *my_class; //定义一个class 用于udev自动创建一个节点



MODULE_LICENSE("Dual BSD/GPL"); //模块许可声明  三要素之一


int timer_major=MA; //主设备号  用于区分不同种类的设备


//timer设备结构体

struct timer_dev {

struct cdev cdev; //cdev结构体

int counter;  //一共经历了多少秒

struct timer_list s_timer;//设备要使用定时器

}timer_dev;

//定时器处理函数

static void timer_handle(unsigned long arg) {

mod_timer(&timer_dev.s_timer,jiffies+HZ);

timer_dev.counter++;

printk(KERN_NOTICE"current jiffies %d\n",jiffies);

}


//文件打开函数

int timer_open (struct inode *inode,struct file *filp) {

//初始化定时器

init_timer(&timer_dev.s_timer);   //初始化定时器

timer_dev.s_timer.function=timer_handle; //指定定时器处理函数

timer_dev.s_timer.expires=jiffies+HZ;  //


add_timer(&timer_dev.s_timer);//添加注册定时器

timer_dev.counter=0; //计数清零

return 0;

}

//文件关闭函数

int timer_release(struct inode *inode,struct file *filp) {

del_timer(&timer_dev.s_timer);

printk("timer release \n");

return 0;

}

//文件读函数

static ssize_t timer_read (struct file * filp,char __user *buf,size_t count,loff_t *ppos) {

if(put_user(timer_dev.counter,(int *)buf))

return -EFAULT;

else

return sizeof(unsigned int);

}

//文件操作结构体

static const struct file_operations timer_fops = {

.owner  =  THIS_MODULE,

.open    =  timer_open,

.release  =  timer_release,

.read  =  timer_read,

};

//初始化并注册cdev

static void timer_setup_cdev (struct timer_dev *dev,int index) {

int err,devno =MKDEV(timer_major,index);  //获取设备号

cdev_init(&dev->cdev,&timer_fops);    //字符设备初始化

err=cdev_add(&dev->cdev,devno,1);    //添加一个字符设备到系统中

if(err) //异常判断

{

printk(KERN_NOTICE"Error %d adding LED%d",err,index);

}

}


//设备驱动模块加载函数

int timer_init(void) {


int ret;

dev_t devno =MKDEV(timer_major,0); //得到设备号

/*

*MKDEV(MAJOR,MIN);

*MAJOR:主设备号   指是哪一类设备

*MIN:  次设备号   指具体哪一个设备

*/

ret=register_chrdev_region(devno,1,"timmer");//注册设备号

/*

*注册一个字符设备号(静态分配)

*为一个字符驱动获取一个或多个设备编号

*register_chrdev_region(dev_id,DEVICE_NUM,DEVICE_NAME);

*dev_id  分配的起始设备编号(一般是0)

*DEVICE_NUM: 请求的连接设备编号的总数(不能太大,避免别的主设备号冲突)

*DEVICE_NAME: 是应当连接到这个编号的设备名字

*/

if(ret<0) 

return ret;

timer_setup_cdev(&timer_dev,0);  //初始化处理函数

//自动创建一个设备节点

my_class=class_create(THIS_MODULE,"timer");

if(IS_ERR(my_class)) {

printk("Err:failed in creating class.\n");

return -1;

}

//注册这个设备节点

device_create(my_class,NULL,devno,NULL,"timer_dev");

printk("timer init two ok\n");

return 0;

}

//设备驱动模块卸载函数

void timer_exit(void) {

dev_t devno =MKDEV(timer_major,0); //得到设备号


cdev_del(&timer_dev.cdev);

device_destroy(my_class,devno); //注销这个设备节点

class_destroy(my_class);//删除一个设备节点

unregister_chrdev_region(MKDEV(timer_major,0),1);//释放设备号

printk("timer exit ok\n");

}

module_init(timer_init); //模块加载入口声明  三要素之一

module_exit(timer_exit);  //模块卸载入口声明  三要素之一

执行结果:

[root@farsight]#ls

a.out     dev       lib       mnt       root      sys       timer.o   usr

bin       etc       linuxrc   proc      sbin      timer.ko  tmp       var

加载驱动模块:

[root@farsight]#insmod timer.ko

[   47.760000] timer init two ok

查看驱动模块加载信息

[root@farsight]#lsmod

timer 2172 0 - Live 0xbf000000 (O)

查看自动创建的设备节点

[root@farsight]#ls -l /dev/timer_dev

crw-rw----    1 0        0         300,   0 Jan  1 00:00 /dev/timer_dev

可以看到自动创建设备节点成功

卸载驱动模块:

[root@farsight]#rmmod timer

[  243.960000] timer exit ok

再次加载也能成功

[root@farsight]#insmod timer.ko

[  304.940000] timer init two ok


如果没有配对使用,重新加载的时候会报错

//class_destroy(my_class);//删除一个设备节点 

 我将这一行屏蔽掉,看运行结果

[root@farsight]#insmod timer.ko

[  445.950000] timer init two ok

[root@farsight]#rmmod timer.ko

[root@farsight]#insmod timer.ko

insmod: can't insert 'timer.ko': File exists

当在加载的时候就出现这样的错误


将下面两行屏蔽掉

//device_destroy(my_class,devno); //注销这个设备节点

//class_destroy(my_class);//删除一个设备节点

结果:


[root@farsight]#insmod timer.ko

[   58.595000] timer init two ok

[root@farsight]#ls -l /dev/timer_dev

crw-rw----    1 0        0         300,   0 Jan  1 00:00 /dev/timer_dev

[root@farsight]#rmmod timer

[   84.430000] timer exit ok

第一次加载时没有问题的,卸载的时候问题就来了,可以看到,显示是成功的的,但是看下面的查询,是没有删除成功的


[root@farsight]#ls -l /dev/timer_dev

crw-rw----    1 0        0         300,   0 Jan  1 00:00 /dev/timer_dev

在此加载就会出现下面的问题

[root@farsight]#insmod timer.ko

[  103.780000] ------------[ cut here ]------------

[  103.785000] WARNING: CPU: 0 PID: 1203 at fs/sysfs/dir.c:52 sysfs_warn_dup+0x68/0x84()

[  103.795000] sysfs: cannot create duplicate filename '/class/timer'

[  103.800000] Modules linked in: timer(O+) [last unloaded: timer]

[  103.805000] CPU: 0 PID: 1203 Comm: insmod Tainted: G           O 3.14.0 #2

[  103.810000] [<c0013e10>] (unwind_backtrace) from [<c0011240>] (show_stack+0x10/0x14)

[  103.820000] [<c0011240>] (show_stack) from [<c03b874c>] (dump_stack+0x64/0xb4)

[  103.825000] [<c03b874c>] (dump_stack) from [<c001ce74>] (warn_slowpath_common+0x68/0x88)

[  103.835000] [<c001ce74>] (warn_slowpath_common) from [<c001cf28>] (warn_slowpath_fmt+0x30/0x40)

[  103.845000] [<c001cf28>] (warn_slowpath_fmt) from [<c01092e8>] (sysfs_warn_dup+0x68/0x84)

[  103.850000] [<c01092e8>] (sysfs_warn_dup) from [<c0109388>] (sysfs_create_dir_ns+0x84/0x8c)

[  103.860000] [<c0109388>] (sysfs_create_dir_ns) from [<c01d6240>] (kobject_add_internal+0x9c/0x2c0)

[  103.870000] [<c01d6240>] (kobject_add_internal) from [<c01d6484>] (kset_register+0x20/0x3c)

[  103.880000] [<c01d6484>] (kset_register) from [<c02482b8>] (__class_register+0xac/0x198)

[  103.885000] [<c02482b8>] (__class_register) from [<c02483e4>] (__class_create+0x40/0x6c)

[  103.895000] [<c02483e4>] (__class_create) from [<bf004168>] (init_module+0x6c/0xec [timer])

[  103.900000] [<bf004168>] (init_module [timer]) from [<c00087b4>] (do_one_initcall+0x30/0x144)

[  103.910000] [<c00087b4>] (do_one_initcall) from [<c0074f9c>] (load_module+0x173c/0x1c68)

[  103.920000] [<c0074f9c>] (load_module) from [<c00755a4>] (SyS_init_module+0xdc/0xe0)

[  103.925000] [<c00755a4>] (SyS_init_module) from [<c000e420>] (ret_fast_syscall+0x0/0x30)

[  103.935000] ---[ end trace 11ebc48fbb16ce8a ]---

[  103.940000] ------------[ cut here ]------------

[  103.945000] WARNING: CPU: 0 PID: 1203 at lib/kobject.c:240 kobject_add_internal+0x238/0x2c0()

[  103.950000] kobject_add_internal failed for timer with -EEXIST, don't try to register things with the same name in the same directory.

[  103.965000] Modules linked in: timer(O+) [last unloaded: timer]

[  103.970000] CPU: 0 PID: 1203 Comm: insmod Tainted: G        W  O 3.14.0 #2

[  103.975000] [<c0013e10>] (unwind_backtrace) from [<c0011240>] (show_stack+0x10/0x14)

[  103.985000] [<c0011240>] (show_stack) from [<c03b874c>] (dump_stack+0x64/0xb4)

[  103.990000] [<c03b874c>] (dump_stack) from [<c001ce74>] (warn_slowpath_common+0x68/0x88)

[  104.000000] [<c001ce74>] (warn_slowpath_common) from [<c001cf28>] (warn_slowpath_fmt+0x30/0x40)

[  104.010000] [<c001cf28>] (warn_slowpath_fmt) from [<c01d63dc>] (kobject_add_internal+0x238/0x2c0)

[  104.020000] [<c01d63dc>] (kobject_add_internal) from [<c01d6484>] (kset_register+0x20/0x3c)

[  104.025000] [<c01d6484>] (kset_register) from [<c02482b8>] (__class_register+0xac/0x198)

[  104.035000] [<c02482b8>] (__class_register) from [<c02483e4>] (__class_create+0x40/0x6c)

[  104.040000] [<c02483e4>] (__class_create) from [<bf004168>] (init_module+0x6c/0xec [timer])

[  104.050000] [<bf004168>] (init_module [timer]) from [<c00087b4>] (do_one_initcall+0x30/0x144)

[  104.060000] [<c00087b4>] (do_one_initcall) from [<c0074f9c>] (load_module+0x173c/0x1c68)

[  104.065000] [<c0074f9c>] (load_module) from [<c00755a4>] (SyS_init_module+0xdc/0xe0)

[  104.075000] [<c00755a4>] (SyS_init_module) from [<c000e420>] (ret_fast_syscall+0x0/0x30)

[  104.085000] ---[ end trace 11ebc48fbb16ce8b ]---

[  104.085000] Err:failed in creating class.

insmod: can't insert 'timer.ko': Operation not permitted

[root@farsight]#


总结:在驱动编写中,很多函数是成对使用的,需要特别注意,一般有申请就有释放,有新增就有删除

你可能感兴趣的:(linux,include,应用层)