Smart210学习记录-------Linux设备驱动结构
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 };
1.struct file_operations {
2 struct module *owner;
3 /* 拥有该结构的模块的指针,一般为 THIS_MODULES */
4 loff_t(*llseek)(struct file *, loff_t, int);
5 /* 用来修改文件当前的读写位置 */
6 ssize_t(*read)(struct file *, char _ _user *, size_t, loff_t*);
7 /* 从设备中同步读取数据 */
8 ssize_t(*write)(struct file *, const char _ _user *, size_t, loff_t*);
9 /* 向设备发送数据*/
10 ssize_t(*aio_read)(struct kiocb *, char _ _user *, size_t, loff_t);
11 /* 初始化一个异步的读取操作*/
12 ssize_t(*aio_write)(struct kiocb *, const char _ _user *, size_t, loff_t);
13 /* 初始化一个异步的写入操作*/
14 int(*readdir)(struct file *, void *, filldir_t);
15 /* 仅用于读取目录,对于设备文件,该字段为 NULL */
16 unsigned int(*poll)(struct file *, struct poll_table_struct*);
17 /* 轮询函数,判断目前是否可以进行非阻塞的读取或写入*/
18 int(*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
19 /* 执行设备 I/O 控制命令*/
20 long(*unlocked_ioctl)(struct file *, unsigned int, unsigned long);
21 /* 不使用 BLK 的文件系统,将使用此种函数指针代替 ioctl */
22 long(*compat_ioctl)(struct file *, unsigned int, unsigned long);
23 /* 在 64 位系统上,32 位的 ioctl 调用,将使用此函数指针代替*/
24 int(*mmap)(struct file *, struct vm_area_struct*);
25 /* 用于请求将设备内存映射到进程地址空间*/
26 int(*open)(struct inode *, struct file*);
27 /* 打开 */
28 int(*flush)(struct file*);
29 int(*release)(struct inode *, struct file*);
30 /* 关闭*/
31 int (*fsync) (struct file *, struct dentry *, int datasync);
32 /* 刷新待处理的数据*/
33 int(*aio_fsync)(struct kiocb *, int datasync);
34 /* 异步 fsync */
35 int(*fasync)(int, struct file *, int);
36 /* 通知设备 FASYNC 标志发生变化*/
37 int(*lock)(struct file *, int, struct file_lock*);
38 ssize_t(*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int);
39 /* 通常为 NULL */
40 unsigned long(*get_unmapped_area)(struct file *,unsigned long, unsigned long,
41 unsigned long, unsigned long);
42 /* 在当前进程地址空间找到一个未映射的内存段 */
43 int(*check_flags)(int);
44 /* 允许模块检查传递给 fcntl(F_SETEL...)调用的标志 */
45 int(*dir_notify)(struct file *filp, unsigned long arg);
46 /* 对文件系统有效,驱动程序不必实现*/
47 int(*flock)(struct file *, int, struct file_lock*);
48 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t,
49 unsigned int); /* 由 VFS 调用,将管道数据粘接到文件 */
50 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,
51 unsigned int); /* 由 VFS 调用,将文件数据粘接到管道 */
52 int (*setlease)(struct file *, long, struct file_lock **);
53 };
Linux 2.6 内核提供了一组函数用于操作 cdev 结构体:
void cdev_init(struct cdev *, struct file_operations *); 用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
struct cdev *cdev_alloc(void); cdev_alloc()函数用于动态申请一个 cdev 内存
void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned); cdev_add()函数和 cdev_del()函数分别向系统添加和删除一个 cdev,完成字符设备的注册和注
销。对 cdev_add()的调用通常发生在字符设备驱动模块加载函数中,而对 cdev_del()函数的调用则
通常发生在字符设备驱动模块卸载函数中。
void cdev_del(struct cdev *);
cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中 12 位主设备号,20 位次设备号。使
用下列宏可以从 dev_t 获得主设备号和次设备号:
MAJOR(dev_t dev)
MINOR(dev_t dev)
而使用下列宏则可以通过主设备号和次设备号生成 dev_t:
MKDEV(int major, int minor)
分配和释放设备号
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);
void unregister_chrdev_region(dev_t from, unsigned count);
Linux字符设备的组成
/* 设备结构体
2 struct xxx_dev_t {
3 struct cdev cdev;
4 ...
5 } xxx_dev;
6 /* 设备驱动模块加载函数
7 static int _ _init xxx_init(void)
8 {
9 ...
10 cdev_init(&xxx_dev.cdev, &xxx_fops); /* 初始化 cdev */
xxx_dev.cdev.owner = THIS_MODULE;
/* 获取字符设备号*/
if (xxx_major) {
register_chrdev_region(xxx_dev_no, , DEV_NAME);
} else {
alloc_chrdev_region(&xxx_dev_no, , , DEV_NAME);
} ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, ); /* 注册设备*/
...
}
/*设备驱动模块卸载函数*/
static void _ _exit xxx_exit(void)
{
unregister_chrdev_region(xxx_dev_no, ); /* 释放占用的设备号*/
cdev_del(&xxx_dev.cdev); /* 注销设备*/
...
}
module_init(xxx_init);
module_exit(xxx_exit);
字符设备驱动的 file_operations 结构体中成员函数
/* 读设备*/
ssize_t xxx_read(struct file *filp, char __user *buf, size_t count,
loff_t*f_pos)
{
...
copy_to_user(buf, ..., ...);
...
}
/* 写设备*/
ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
...
copy_from_user(..., buf, ...);
...
}
/* ioctl 函数 */
int xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
...
switch (cmd) {
case XXX_CMD1:
...
break;
case XXX_CMD2:
...
break;
default:
/* 不能支持的命令 */
return - ENOTTY;
}
return ;
}
设备驱动的读函数中,filp 是文件结构体指针,buf 是用户空间内存的地址,该地址在内核空
间不能直接读写,count 是要读的字节数,f_pos 是读的位置相对于文件开头的偏移。
写函数同理
由于内核空间与用户空间的内存不能直接互访,因此借助了函数 copy_from_user()完成用户空间
到内核空间的拷贝,以及copy_to_user()完成内核空间到用户空间的拷贝,见代码第6行和第14行。
完成内核空间和用户空间内存拷贝的 copy_from_user()和 copy_to_user()的原型分别为:
unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);
上述函数均返回不能被复制的字节数,因此,如果完全复制成功,返回值为 0。
在字符设备驱动中,需要定义一个 file_operations 的实例,并将具体设备驱动的函数赋值给
file_operations 的成员,例如:
1 struct file_operations xxx_fops = {
2 .owner = THIS_MODULE,
3 .read = xxx_read,
4 .write = xxx_write,
5 .ioctl = xxx_ioctl,
6 ...
7 }
来自《linux设备驱动开发详解》
Smart210学习记录-------Linux设备驱动结构的更多相关文章
- Smart210学习记录------linux串口驱动
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...
- Smart210学习记录-----Linux i2c驱动
一:Linux i2c子系统简介: 1.Linux 的 I2C 体系结构分为 3 个组成部分: (1) I2C 核心. I2C 核心提供了 I2C 总线驱动和设备驱动的注册.注销方法,I2C 通信方法 ...
- Smart210学习记录------块设备
转自:http://bbs.chinaunix.net/thread-2017377-1-1.html 本章的目的用尽可能最简单的方法写出一个能用的块设备驱动.所谓的能用,是指我们可以对这个驱动生成的 ...
- Smart210学习记录-------linux内核模块
Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的Linux 操作系统映像.在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的 一个: #ma ...
- Smart210学习记录-------linux驱动中断
Linux中断 Linux 的中断处理分为两个半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操作.tasklet 和工作队列都是调度中断底半部的良好机制,tasklet 基于软中断实现.内核定 ...
- Smart210学习记录----nand flash驱动
[详解]如何编写Linux下Nand Flash驱动 :http://www.cnblogs.com/linux-rookie/articles/3016990.html 当读写文件请求到来的时候, ...
- Smart210学习记录------nor flash驱动
nor flash驱动与nand flash驱动的差别不大,只是设置不同的结构体而已,, nor flash驱动代码: #include <linux/module.h> #include ...
- Smart210学习记录-----linux定时器
1.内核定时器: Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list 在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器 1 stru ...
- Hasen的linux设备驱动开发学习之旅--时钟
/** * Author:hasen * 參考 :<linux设备驱动开发具体解释> * 简单介绍:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date ...
随机推荐
- c#和数据库技术基础之程序设计集散地-数据库
数据库,不明觉厉,今天我们就来数据库的神秘面纱 1.使用数据库的必要性 随着互联网技术的高速发展,截止到2013年我国网民的数量已接近6亿,网民数量的增长同事带动网上购物,微博,网络视频等新产业的发展 ...
- Oracle存储过程写法
create or replace procedure QIANFEIGL_JIAOKUANDY( cebenh varchar2, kehuh varchar2, hetongh varchar2, ...
- UESTC 2016 Summer Training #1 Div.2
最近意志力好飘摇..不知道坚不坚持得下去.. 这么弱还瞎纠结...可以滚了.. 水题都不会做.. LCS (A) 水 LCS (B) 没有看题 Gym 100989C 水 1D Cafeteria ( ...
- jQuery修改后代、兄弟样式
<div> <div >1</div> <div class="one"> 2 <div>2_1 <div> ...
- linux 下echo命令写入文件内容
http://blog.csdn.net/xukai871105/article/details/35834703 echo "Raspberry" > test.txt
- Redis persistence demystified - part 1
关于Redis我的一部分工作是阅读博客,论坛以及twitter时间线(time line).对于开发者来说,能够了解用户社区,非用户社区如果理解他正在开发的产品是非常重要的.据我所知,持久化特性是最易 ...
- 关于HTML5应用开发功耗调优化小结
HTML5的优化一直是困扰我的难题,特别是在移动端开发游戏和应用,所以对此进行了一些总结: 功耗优化点介绍 在移动设备中主要的功耗点在: 1. 网络的传输, 不管是3G网络还是WiFi传输都是移动设备 ...
- php解压zip文件
<?php header("Content-type:text/html;charset=utf-8"); function get_zip_originalsize($fi ...
- php unicode
在很多场合能看到unicode编码过的文字,如“\u6d3b\u52a8\u63a5\u53e3”,虽然程序会认识,但人眼无法阅读,很不方便,网络上很多人写了很多的转换函数,但是一个比一个臃肿,终于发 ...
- 【NOIP2015】提高组D1 解题报告
P1978神奇的幻方 Accepted 描述 幻方是一种很神奇的 N ∗ N 矩阵:它由数字 1,2,3, … … , N ∗ N 构成,且每行.每列及两条对角线上的数字之和都相同. 当 N 为奇数时 ...