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 minordevice_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‘来释放资源
相关文章推荐
- Linux驱动编程 step-by-step (四) 字符设备的注册与设备节点的自动创建
- linux驱动开发--字符设备:自动创建设备节点
- linux驱动入门之自动分配主设备号/创建设备节点
- Linux驱动开发之四-----LED改进测试(增加自动创建设备节点)
- 【Linux驱动】自动创建设备节点
- linux字符设备驱动 自动创建设备节点的的方法
- Linux创建字符设备 自动生成设备节点
- linux字符设备驱动总结之:全自动创建设备及节点
- linux字符设备驱动中自动创建设备节点
- Linux 字符设备驱动结构(二)—— 自动创建设备节点
- 一步一步学习 Linux 驱动之自动创建设备节点
- Linux创建字符设备 自动生成设备节点
- Linux驱动编程 step-by-step (八) 阻塞型字符设备驱动
- TQ2440 LINUX 2.6.30.4 LED驱动感言,从最初的打印字符,到自动分配设备号,到自动创建设备节点,到次设备号分控led
- Linux驱动编程 step-by-step (三) 字符设备中 重要的数据结构
- TQ2440 LINUX 2.6.30.4 LED驱动感言,从最初的打印字符,到自动分配设备号,到自动创建设备节点,到此设备号分控led
- linux驱动开发--字符设备:创建一组设备节点
- Linux创建字符设备 自动生成设备节点
- Linux驱动开发--自动创建设备文件节点
- Linux驱动编程 step-by-step (九)字符设备模拟pipe的驱动程序