您的位置:首页 > 运维架构 > Linux

Linux驱动编程 step-by-step (四) 字符设备的注册与设备节点的自动创建

2014-11-14 22:43 477 查看


字符设备的注册与设备节点的自动创建


cdev 结构


内核内部使用struct cdev<linux/cdev.h>来表示一个字符设备

struct cdev {

struct kobject kobj; //kobj设备模型以后介绍

struct module *owner;

const struct file_operations *ops;//文件操作

struct list_head list;

dev_t dev;//设备号

unsigned int count; //设备个数

};


注册字符设备


动态初始化:

struct cdev *my_cdev = cdev_alloc();

my_cdev->ops = &my_ops;


静态初始化:

struct cdev my_cdev;

cdev_init(&my_dev, &my_ops);


向内核注册(添加设备):

int cdev_add(struct cdev *dev, dev_t num, unsigned count);
dev: 指向以初始化的字符设备结构

num:
设备号

count:
所要添加的设备个数

返回值:

成功返回0 失败返回错误码,设备被注册时候可能立即会呗调用,所以在驱动程序还没有准备好处理设备操作时候不要先调用cdev_add


注销字符设备:

在不需要用西设备时候需要注销设备

void cdev_del(struct cdev *);


早期的方法

在2.6的内核之前注册字符设备有一个简单易用的方法,现在也可以使用但是不建议使用,因为到最后这个方法会从内核消失


注册字符设备:

static inline int register_chrdev(unsigned int major,

const char *name, const struct file_operations *fops);
major:
主设备号 (当major为0时表示有内核分配一个可用的主设备号并返回)

name:
驱动名

fops:
文件操作

缺点: 不能同时注册多个设备, 他是用一种默认的方式去建立一个cdev结构,而这样的话它不能使用大于255的主次设备号


注销设备:

static inline void unregister_chrdev(unsigned int major, const char *name)


设备节点的自动创建

在上一个程序中,虽然能够争取的得到一个设备号,但是并不会在/dev/目录下生成一个设备节点。


使用手动创建

mknod /dev/device_name c major minor

device_name:
指设备名,

c:
表述创建字符设备节点(同理b 表示创建块设备文件节点)

major:
主设备号

minor:
次设备号

在做测试时候这样做事可以理解的,而在作为一个模块要发行时候,这样就太不方面了,①要先查看设备是否成功创建,②查看注册设备的主设备号,③输入命令创建文件节点

当然可以写一个shell脚本来完成这些事情。


自动创建设备节点

需要的纤体内核空间支持udev,在内核配置,及busybox配置时候需要指定

内核中定义了struct class 与 struct devic结构<linux/device.h>

创建一个class结构

#define class_create(owner, name) \

({ \

static struct lock_class_key __key; \

__class_create(owner, name, &__key); \

})

owner表示拥有这个模块的指针

name 表示设备名

调用此函数后 创建了一个struct class结构放在sysfs下边,而后调用

struct device *device_create(struct class *cls,

struct device *parent,

dev_t devt, void *drvdata,

const char *fmt, ...)
在/dev目录下创建设备节点

cls :
是上边函数的创建的struct class结构指针

parent:
指向设备的父节点设备(如果没有填NULL

devt:
被添加设备的设备号

drvdata:
回调函数参数

fmt ,args:一个或者多个设备名

至此我们就自动创建了一个设备节点


删除设备节点

在设备不需要使用时候我们需要删除设备节点:

void device_destroy(struct class *class, dev_t devt);//删除设备节点

void class_destroy(struct class *cls);//删除sysfs下得struct class结构
至于深层的一些实现机制,没有细细研究,大家干兴趣可以参考相关资料


实例:


初始化 添加设备到内核

simple_cdev = cdev_alloc(); //动态初始化字符设备

if(simple_cdev != NULL)

{

simple_cdev->ops = &simple_fops; //文件操作

simple_cdev->owner = THIS_MODULE;

}

else

{

printk(KERN_ERR "alloc cdev err no memory");

unregister_chrdev_region(dev, DEV_COUNT); //如果分配资源出错则释放设备号

return -ENOMEM;

}

err = cdev_add(simple_cdev, dev, DEV_COUNT); //向内核添加设备

if(err < 0)

{

printk(KERN_ERR "add cdev err \n");

goto error1;

}

else

{

#if SIMPLE_DEBUG

printk(KERN_INFO "add char dev OK!\n");

#endif

}


自动创建设备节点

simple_class = class_create(THIS_MODULE, SIMPLE_NAME);

if(simple_class == NULL)

{

printk(KERN_ERR "create simple class error\n");

goto error2;

}

else

{

#if SIMPLE_DEBUG

printk(KERN_INFO "create simple class OK!\n");

#endif

}

simple_dev = device_create(simple_class, NULL, dev, NULL, SIMPLE_NAME);

if(simple_dev == NULL)

{

printk(KERN_ERR "create device error");

goto error3;

}

else

{

#if SIMPLE_DEBUG

printk(KERN_INFO "create simple device OK!\n");

#endif

}

删除设备节点,注销字符设备

dev = MKDEV(simple_major, simple_minor); //计算出设备号

device_destroy(simple_class, dev); //删除设备节点

class_destroy(simple_class);//删除并释放class结构

cdev_del(simple_cdev);//注销设备

cdev_put(simple_cdev);//对动态的设备需要使用cdev_put‘来释放资源
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: