字符设备驱动模块
来源:互联网 发布:淘宝手机贷款 编辑:程序博客网 时间:2024/06/05 20:22
当然,首先需要有对字符设备驱动的基础知识有所了解。
设备驱动分为三类:字符设备驱动、块设备驱动、网络设备驱动。
字符设备:是指那些必须以串行顺序依次访问的设备,如触摸屏、磁带驱动器、鼠标等。
块设备:可以用任意顺序访问,以块为单位进行操作,如硬盘、软驱等。不同于字符设备的是,块设备经过系统的快速缓冲。
网络设备:网络设备面向数据包的接受和发送而设计,它并不对应于文件系统的节点。因而内核和网络设备的通信与内核和字符设备、块设备的通信方式完全不同。
我们需要具体了解字符设备驱动的结构,在Linux2.6内核中,使用cdev结构体来描述一个字符设备。
1、cdev结构体
1 struct cdev {2 struct kobject kobj; //内嵌的kobject对象3 struct module *owner; //所属模块4 struct file_operations *ops; //文件操作结构体5 struct list_head list; 6 dev_t dev; //设备号7 unsigned int count; 8 };
其中cdev结构体的dev_t成员定义了设备号,为32位,其中主设备号12位,次设备号20位。使用下列宏可以从dev_t获得主设备号和次设备号:
MAJOR(dev_t dev)MINOR(dev_t dev)
而使用下列宏可以通过主设备号和次设备号生成dev_t:
MKDEV(int major , int minor)
2、Linux2.6内核提供了一组函数用于操作cdev结构体:
void cdev_init(struct cdev * , struct file_operations *);struct cdev *cdev_alloc(void);void cdev_put(struct cdev *p);int cdev_add(struct cdev * , dev_t unsigned);void cdev_del(struct cdev *);
cdev_init()函数用于初始化cdev的成员,并建立cdev和file_operations之间的连接,file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数。
1 void cdev_init(struct cdev *cdev , struct file_operations *fops)2 {3 memset(cdev, 0, sizeof *cdev);4 INIT_LIST_HEAD(&cdev->list);5 kobject_init(&cdev->kobj, &ktype_cdev_default);6 cdev->ops = fops; //将传入的文件操作结构体指针赋值给cdev的ops7 }
cdev_alloc()函数用于动态申请一个cdev内存。
1 struct cdev *cdev_alloc(void)2 {3 struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);4 if(p){5 INIT_LIST_HEAD(&p->list);6 kobject_init(&p->kobj, &ktype_cdev_dynamic);7 }8 return p;9 }
cdev_add()函数可以向系统添加一个cdev。
1 int cdev_add(struct cdev *p, dev_t dev, unsigned count)2 {3 p->dev = dev;4 p->count = count;5 return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);6 }
cdev_del()函数可以向系统删除一个cdev。
1 void cdev_del(struct cdev *p)2 {3 cdev_unmap(p->dev, p->count);4 kobject_put(&p->kobj);5 }
3、分配和释放设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name);int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
这两个函数用于向系统申请设备号。
简单记录一下,以便之后查阅:
register_chrdev_region,用于已知起始设备的设备号的情况。如果分配成功进行,register_chrdev_region 的返回值是 0;出错的情况下, 返回一个负的错误码,你不能存取请求的区域。
其中:
from是要分配设备编号范围的起始值。
count是所请求连续设备编号的个数。不能太大。
name是设备名,(要与该设备编号范围关联)。
alloc_chrdev_region,用于未知设备号,向系统动态申请未被占用的设备号的情况。与register_chrdev_region相比,它的优点是避开了设备号的冲突
其中:
*dev是一个输出参数,当设备成功完成调用后,它将保存已分配范围的第一个编号。
baseminor是要请求的第一个次设备号。一般为0。
count同样是所请求连续设备编号的次数。
*name同样是相应和设备名。
void unregister_chrdev_region(dev_t from, unsigned count);
注销字符设备,用于释放原先申请的设备号。
4、字符设备驱动模块的加载和卸载函数模版
//设备结构体struct xxx_dev_t { struct cdev *cdev; ...} xxx_dev;//设备驱动模块加载函数static int __init xxx_init(void){ ... cdev_init(&xxx_dev.cdev, &xxx_fops); //初始化cdev xxx_dev.cdev.owner = THIS_MODULE; //获取字符设备号 if(xxx_major) { register_chrdev_region(xxx_dev_no, 1, DEV_NAME); }else{ alloc_chrdev_region(&xxx_dev_no, 1, DEV_NAME); } ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); //注册设备 ...}//设备驱动模块卸载函数static void __exit xxx_exit(void){ unregister_chrdev_region(xxx_dev_no, 1); //释放占用的设备号 cdev_del(&xxx_dev.cdev); //注销设备}
这里也需要了解一下,关于file_operations结构体及一些常用的函数。
1、file_operations结构体
具体解释,此处就不细写了。可以看《Linux设备驱动开发详解》、也可以移步到file_operations, file 和inode、file_operations结构体介绍、file_operations结构体详细分析
如对.open,.release这样用法有困惑的,请移步解密file_operations结构体中的一些细节
2、字符设备驱动模块常用的一些函数:open、release(close)、read、write、ioctl等等,需要掌握。
linux3.0 已经移除了ioctl函数,而用了两个函数来代替,具体可以度娘。
最后,还要提一下字符设备驱动一些要注意的点:设备名和设备号、信号量的同步与互斥、中断与异常、阻塞等
- 字符设备驱动模块
- 模块驱动添加字符设备驱动
- 内核模块编程笔记 - 字符设备驱动
- Linux内核模块编程-字符设备驱动
- linux 字符设备驱动(一)模块与设备
- 字符设备驱动模块 之 基本通用模块
- linux驱动模块开发(二)----字符设备驱动
- linux 驱动程序 设备模块 设备号 设备文件创建 设备注册 字符驱动设备分析
- Scull字符设备驱动模块的内存使用分析
- Linux 2.6内核 动态加载字符设备驱动模块
- Linux 内核模块编程的第一个字符设备驱动
- linux内核模块开发之字符设备驱动
- Driver:模块参数、系统调用、字符设备驱动框架
- 字符设备驱动模块与测试代码编写(转)
- 手把手教你学linux驱动开发:模块编程、虚拟字符设备编程、LED字符设备驱动
- 字符设备驱动--- 设备操作
- 字符设备驱动更新
- 字符设备驱动模板
- logistic回归原理
- Linux内核驱动模块的删除
- Hibernate数据库框架的入门
- Nginx的初步探索
- 命令模式
- 字符设备驱动模块
- Mac OS系统通过ssh远程连接服务器或VPS,类似window上的putty
- 解析XML文件——DOM基本操作
- Mac OS下安装串口调试工具minicom
- Mac OS系统安装Mysql
- Mac OS系统APP软件推荐
- Windows下Qt 5.2 for Android开发入门
- 神奇6位数_2014决赛第二题
- 通过shell脚本实现从文件中读取数据的几种方法