Linux驱动编程 step-by-step (四)

似乎每一章介绍的内容比较少,但学习是一个循序渐进的过程,不在于一天学多少,重要的一天能真正的学懂多少,所以我主张一步一步来,从多个渠道去学习知识,实现互补。

本节测试代码传到此处了:char_step1 大家可以下载测试一下。

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

cdev 结构

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

structcdev{
structkobjectkobj;//kobj设备模型以后介绍
structmodule*owner;
conststructfile_operations*ops;//文件操作
structlist_headlist;
dev_tdev;//设备号
unsignedintcount;//设备个数
};

注册字符设备

动态初始化:

structcdev*my_cdev=cdev_alloc();
my_cdev->ops=&my_ops;

静态初始化:

structcdevmy_cdev;
cdev_init(&my_dev,&my_ops);

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

intcdev_add(structcdev*dev,dev_tnum,unsignedcount);
dev: 指向以初始化的字符设备结构
num: 设备号
count: 所要添加的设备个数
返回值:
成功返回0 失败返回错误码,设备被注册时候可能立即会呗调用,所以在驱动程序还没有准备好处理设备操作时候不要先调用cdev_add

注销字符设备:

在不需要用西设备时候需要注销设备
voidcdev_del(structcdev*);

早期的方法

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

注册字符设备:

staticinlineintregister_chrdev(unsignedintmajor,
constchar*name,conststructfile_operations*fops);
major: 主设备号 (当major为0时表示有内核分配一个可用的主设备号并返回)
name: 驱动名
fops: 文件操作
缺点: 不能同时注册多个设备, 他是用一种默认的方式去建立一个cdev结构,而这样的话它不能使用大于255的主次设备号

注销设备:

staticinlinevoidunregister_chrdev(unsignedintmajor,constchar*name)

设备节点的自动创建

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

使用手动创建

mknod/dev/device_namecmajorminor
device_name: 指设备名,
c: 表述创建字符设备节点(同理b 表示创建块设备文件节点)
major: 主设备号
minor: 次设备号
在做测试时候这样做事可以理解的,而在作为一个模块要发行时候,这样就太不方面了,①要先查看设备是否成功创建,②查看注册设备的主设备号,③输入命令创建文件节点
当然可以写一个shell脚本来完成这些事情。

自动创建设备节点

需要的纤体内核空间支持udev,在内核配置,及busybox配置时候需要指定
内核中定义了struct class 与 struct devic结构<linux/device.h>
创建一个class结构
#defineclass_create(owner,name)\
({\
staticstructlock_class_key__key;\
__class_create(owner,name,&__key);\
})
owner表示拥有这个模块的指针
name 表示设备名
调用此函数后 创建了一个struct class结构放在sysfs下边,而后调用
structdevice*device_create(structclass*cls,
structdevice*parent,
dev_tdevt,void*drvdata,
constchar*fmt,...)
在/dev目录下创建设备节点
cls : 是上边函数的创建的struct class结构指针
parent: 指向设备的父节点设备(如果没有填NULL
devt: 被添加设备的设备号
drvdata: 回调函数参数
fmt ,args:一个或者多个设备名
至此我们就自动创建了一个设备节点

删除设备节点

在设备不需要使用时候我们需要删除设备节点:
voiddevice_destroy(structclass*class,dev_tdevt);//删除设备节点
voidclass_destroy(structclass*cls);//删除sysfs下得structclass结构
至于深层的一些实现机制,没有细细研究,大家干兴趣可以参考相关资料

实例:

初始化 添加设备到内核

  1. simple_cdev=cdev_alloc();//动态初始化字符设备
  2. if(simple_cdev!=NULL)
  3. {
  4. simple_cdev->ops=&simple_fops;//文件操作
  5. simple_cdev->owner=THIS_MODULE;
  6. }
  7. else
  8. {
  9. printk(KERN_ERR"alloccdeverrnomemory");
  10. unregister_chrdev_region(dev,DEV_COUNT);//如果分配资源出错则释放设备号
  11. return-ENOMEM;
  12. }
  13. err=cdev_add(simple_cdev,dev,DEV_COUNT);//向内核添加设备
  14. if(err<0)
  15. {
  16. printk(KERN_ERR"addcdeverr\n");
  17. gotoerror1;
  18. }
  19. else
  20. {
  21. #ifSIMPLE_DEBUG
  22. printk(KERN_INFO"addchardevOK!\n");
  23. #endif
  24. }

自动创建设备节点

  1. simple_class=class_create(THIS_MODULE,SIMPLE_NAME);
  2. if(simple_class==NULL)
  3. {
  4. printk(KERN_ERR"createsimpleclasserror\n");
  5. gotoerror2;
  6. }
  7. else
  8. {
  9. #ifSIMPLE_DEBUG
  10. printk(KERN_INFO"createsimpleclassOK!\n");
  11. #endif
  12. }
  13. simple_dev=device_create(simple_class,NULL,dev,NULL,SIMPLE_NAME);
  14. if(simple_dev==NULL)
  15. {
  16. printk(KERN_ERR"createdeviceerror");
  17. gotoerror3;
  18. }
  19. else
  20. {
  21. #ifSIMPLE_DEBUG
  22. printk(KERN_INFO"createsimpledeviceOK!\n");
  23. #endif
  24. }

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

  1. dev=MKDEV(simple_major,simple_minor);//计算出设备号
  2. device_destroy(simple_class,dev);//删除设备节点
  3. class_destroy(simple_class);//删除并释放class结构
  4. cdev_del(simple_cdev);//注销设备
  5. cdev_put(simple_cdev);//对动态的设备需要使用cdev_put‘来释放资源
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值