博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux字符设备驱动框架(一):cdev接口
阅读量:5262 次
发布时间:2019-06-14

本文共 3956 字,大约阅读时间需要 13 分钟。

/************************************************************************************

*本文为个人学习记录,如有错误,欢迎指正。

*本文参考资料: 

*        

*        

*        

*        

*        

************************************************************************************/

1. 字符设备

字符设备是指在I/O传输过程中以字节为单位进行传输的设备。其特点是,不能随机读取字符设备的某一数据,只能按照字节的先后顺序读取数据。常见的字符设备有串口、键盘、鼠标等。

字符设备相关数据结构详见。

 2. 字符设备驱动框架

2.1 注册驱动

(1)动态申请cdev内存

/* *所在文件:/kernel/fs/char_dev.c*参数:无*返回值:*    成功: cdev 对象首地址*    失败:NULL */struct cdev *cdev_alloc(void);  

(2)初始化cdev

初始化cdev,建立cdev与file_operations之间的关联。

/* *所在文件:/kernel/fs/char_dev.c*参数:*        struct cdev *p:                 被初始化的cdev对象  *        const struct file_operations *p:字符设备操作方法集*返回值:无 */void cdev_init(struct cdev *p, const struct file_operations *p); 

(3)申请设备号

1)指定设备号

/**所在文件:/kernel/fs/char_dev.c*参数:*    dev_t from:        起始设备号*    unsigned count:    需注册的次设备个数*    const char *name:  设备名称*返回值:*    0:   注册成功*    负数: 注册失败*/int register_chrdev_region(dev_t from, unsigned count, const char *name);

2)系统自动分配设备号

/**所在文件:/kernel/fs/char_dev.c*参数:*    dev_t *dev:         输出型参数,系统自动分配的设备号*    unsigned baseminor: 次设备的起始编号*    unsigned count:     次设备的个数*    const char *name:   设备名称*返回值:*    0:   注册成功*    负数: 注册失败*/int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

(4)注册cdev设备对象

将cdev添加至系统字符设备链表中。

/* *所在文件:/kernel/fs/char_dev.c*参数:*        struct cdev *p:被初始化的cdev对象  *        dev_t dev:     起始设备号*        unsigned count:该设备连续的次设备号的个数*返回值:*         成功:返回0*         失败:返回负数*/int cdev_add(struct cdev *p, dev_t dev, unsigned count);

2.2 创建设备文件

创建设备文件的细节详见。

(1)在/sys中导出设备类信息

/* *所在文件:/kernel/include/linux/device.h*参数:*        owner:类所属模块,一般为THIS_MODULE*        name: 类名*返回值:*        struct class *:指向所创建的类*/#define class_create(owner, name)        \({                                       \    static struct lock_class_key __key;  \    __class_create(owner, name, &__key); \})

(2)创建设备文件

/* *所在文件:/kernel/driver/base/core.c*参数:*        struct class *class:  被初始化的cdev对象  *        struct device *parent:父设备*        dev_t dev:            设备号*        void *drvdata:     设备的回调数据*        const char *fmt:      设备名*返回值:*        struct device *:      指向所创建的设备*/struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);

2.3 实现设备操作

根据需要实现file_operations中的函数,常用的函数如下:

(1)read、write

Linux下各个进程都有自己独立的进程空间,即使是将内核的数据映射到用户进程,该数据的PID也会自动转变为该用户进程的PID,由于这种机制的存在,我们不能直接将数据从内核空间和用户空间进行拷贝,而需要专门的拷贝数据函数/宏:

long copy_from_user(void *to, const void __user * from, unsigned long n)long copy_to_user(void __user *to, const void *from, unsigned long n)

有了这两个函数,内核中的read,write就可以实现内核空间和用户空间的数据拷贝。

(2)ioctl

虽然在文件操作结构体"structfile_operations"中有很多对应的设备操作函数,但是有些命令是实在找不到对应的操作函数。如CD-ROM的驱动,想要一个弹出光驱的操作,这种操作并不是所有的字符设备都需要的,所以文件操作结构体也不会有对应的函数操作。

出于这样的原因,ioctl就有它的用处了——一些没办法归类的函数就统一放在ioctl这个函数操作中,通过指定的命令来实现对应的操作。所以,ioctl函数里面都实现了多个的对硬件的操作,通过应用层传入的命令来调用相应的操作。

ioctl函数使用的详细方法,详见。

/* *参数:*    struct inode *inode和struct file *filp: ioctl的操作有可能是要修改文件的属性,或者访问硬件。要修改文件属性的话,就要用到这两个结构体了,所以这里传来了它们的指针。*       unsigned int cmd: 命令*       unsigned long arg:参数*返回值: 无 */int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

2.4 注销驱动

(1)注销cdev

将cdev对象从系统字符设备链表中剔除,并清理cdev所占的内存资源。

/* *所在文件:/kernel/fs/char_dev.c*参数:*        struct cdev *p:被注销的cdev对象  *返回值:    无*/void cdev_del(struct cdev *p);

(2)释放设备号

/* *所在文件:/kernel/fs/char_dev.c*参数:*        dev_t from:被注销设备的起始设备号*        unsigned count:该设备连续的次设备号个数*返回值:    无*/void unregister_chrdev_region(dev_t from, unsigned count);

(3)删除设备类

/* *所在文件:/kernel/driver/base/class.c*参数:*        struct class *cls:设备类*返回值:    无*/void class_destroy(struct class *cls);

(4)删除设备文件

/* *所在文件:/kernel/driver/base/core.c*参数:*        struct class *class:设备类*        dev_t devt:            设备号*返回值:    无*/void device_destroy(struct class *class, dev_t devt);

3. 实例

 详见。

转载于:https://www.cnblogs.com/linfeng-learning/p/9370973.html

你可能感兴趣的文章
实现MyLinkedList类深入理解LinkedList
查看>>
自定义返回模型
查看>>
C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 客户端多网络支持
查看>>
HDU 4122
查看>>
Suite3.4.7和Keil u3自带fx2.h、fx2regs.h文件的异同
查看>>
打飞机游戏【来源于Crossin的编程教室 http://chuansong.me/account/crossincode 】
查看>>
理解git对象
查看>>
[LeetCode] Merge Intervals
查看>>
【翻译自mos文章】当点击完 finishbutton后,dbca 或者dbua hang住
查看>>
Apache配置反向代理、负载均衡和集群(mod_proxy方式)
查看>>
Linux编程简介——gcc
查看>>
一种高效的序列化方式——MessagePack
查看>>
2019年春季学期第四周作业
查看>>
2019春第十周作业
查看>>
解决ThinkPHP关闭调试模式时报错的问题汇总
查看>>
【APT】SqlServer游标使用
查看>>
关于ExecuteNonQuery()返回值为-1
查看>>
Firefox修復QQ快速登錄
查看>>
PAT——1060. 爱丁顿数
查看>>
分布式技术追踪 2017年第二十期
查看>>