`
peizhiinfo
  • 浏览: 1427455 次
文章分类
社区版块
存档分类
最新评论

Linux字符设备驱动(二)

 
阅读更多

字符设备驱动之结构体

.字符设备驱动的数据结构

大部分驱动程序操作都涉及到三个重要的内核数据结构,分别是file_operationsfileinode,它们的定义都在<linux/fs.h>

1.file_operations:是一个函数指针的集合

1>应用程序VFS之间的接口系统调用,而VFS磁盘文件系统以及普通设备之间的接口是file_operations结构体成员函数;file_operations结构体中成员函数是字符设备驱动与内核的接口,是用户空间对Linux进行系统调用最终的落实者,这个结构体包含对文件打开,关闭,读写,控制的一系列成员函数

2>由于字符设备的上层没有磁盘文件系统,所以字符设备的file_operations成员函数就直接由设备驱动提供了,file_operations正是字符设备驱动的核心

3>而对于块设备而言,ext2,fat,jffs2等文件系统中会实现对VFSfile_operations成员函数,设备驱动层将看不到file_operations的存在。磁盘文件系统和设备驱动会将磁盘上文件的访问最终转换成对磁盘上柱面和扇区的访问

4>file_operations的成员

static const struct file_operations XXX_fops =

{

.owner = THIS_MODULE,

.llseek = XXX_llseek,

.open = XXX _open,

.read = XXX _read,

.write = XXX _write,

.ioctl = XXX _ioctl,

.release = XXX _release,

};

(1)struct module *owner

第一个 file_operations 成员根本不是一个操作; 它是一个指向拥有这个结构的模块的指针. 这个成员用来在它的操作还在被使用时阻止模块被卸载. 几乎所有程序中, 它被简单初始化为 THIS_MODULE, 一个在 <linux/module.h> 中定义的宏.

(2)loff_t (*llseek) (struct file *, loff_t, int);

文件定位函数,合法时返回文件的当前位置,不合法返回-EINVAL

第一个参数为file指针

第二个为请求偏移量

第三个为文件定位的起始地址:一般为010表示文件开头,1表示当前位置

(3)ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

读函数,利用copy_to_user()函数让内核读取用户空间的数据,并返回访问的字节数

(4)ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

写函数利用copy_from_user()函数让用户向文件写入数据,并返回写入的字节数

(5)int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

执行I/O控制命令

(6)int (*open) (struct inode *, struct file *);

打开文件

(7)int (*release) (struct inode *, struct file *)

关闭文件

2. struct file:文件结构体(只介绍和字符设备有关的数据项目)

关于具体struct file请参考VFS中的目录项对象和文件对象

1>文件结构体代表一个打开的文件(设备对应于设备文件),系统中每个打开的文件在内核空间都有一个关联的struct file.它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构

2>字符设备驱动用到的变量,文件读写模式mode,标志f_flags都是设备驱动关心的内容,而私有数据指针private_data在设备驱动中被广泛使用,大多被用于指向设备驱动自定义的设备结构体。

3>struct file

struct file {

940 /*

941 * fu_list becomes invalid after file_free is called and queued via

942 * fu_rcuhead for RCU freeing

943 */

951 const struct file_operations *f_op;

957 unsigned int f_flags;

958 fmode_t f_mode;

959 loff_t f_pos;

960 struct fown_struct f_owner;

969 void *private_data;

970

979};

(1)fmode_t f_mode

文件模式确定文件是可读的或者是可写的(或者都是), 通过位 FMODE_READ FMODE_WRITE. 你可能想在你的 open 或者 ioctl 函数中检查这个成员的读写许可, 但是你不需要检查读写许可, 因为内核在调用你的方法之前检查. 当文件还没有为那种存取而打开时读或写的企图被拒绝, 驱动甚至不知道这个情况.

(2)unsigned int f_flags

这些是文件标志, 例如 O_RDONLY, O_NONBLOCK, O_SYNC. 驱动应当检查 O_NONBLOCK 标志来看是否是请求非阻塞操作;其他标志很少使用. 所有的标志在头文件 <linux/fcntl.h> 中定义.

(3)void *private_data

open 系统调用设置这个指针为 NULL, 在为驱动调用 open 方法之前. 你可自由使用这个成员或者忽略它; 你可以使用这个成员来指向分配的数据, 但是接着你必须记住在内核销毁文件结构之前, release 方法中释放那个内存. private_data 是一个有用的资源, 在系统调用间保留状态信息.

(4) loff_t f_pos;

当前读写位置. loff_t 在所有平台都是 64 ( gcc 术语里是 long long ). 驱动可以读这个值, 如果它需要知道文件中的当前位置, 但是正常地不应该改变它; 读和写应当使用它们作为最后参数而收到的指针来更新一个位置, 代替直接作用于 filp->f_pos. 这个规则的一个例外是在 llseek 方法中, 它的目的就是改变文件位置.

(5) struct file_operations *f_op;

和文件关联的操作. 内核安排指针作为它的 open 实现的一部分, 接着读取它当它需要分派任何的操作时. filp->f_op 中的值从不由内核保存为后面的引用; 这意味着你可改变你的文件关联的文件操作, 在你返回调用者之后新方法会起作用. 例如, 关联到主编号 1 (/dev/null, /dev/zero, 等等) open 代码根据打开的次编号来替代 filp->f_op 中的操作. 这个做法允许实现几种行为, 在同一个主编号下而不必在每个系统调用中引入开销. 替换文件操作的能力是面向对象编程的"方法重载"的内核对等体.

3>驱动程序中经常会使用如下类似的代码来检测用户打开文件的读写方式。

if (flie->f_mode & FMODE_WRITE)//用户要求可写

{

}

4>用下面的代码判断以阻塞还是非阻塞方式打开设备文件

if (file->f_flags & O_NONBLOCK)//非阻塞

{

}

else //阻塞

{

}

3.struct inode 结构

------------------------------------------------------------------------------------

此处还是主要介绍和字符设备驱动相关的变量成员,详细请参考《Linux内核编程之文件系统()

------------------------------------------------------------------------------------

虚拟文件系统中的每个文件都关联到恰哈一个inode,用于管理文件的属性(包含文件访问权限,属主,组,大小,生成时间,访问时间,最后修改时间等信息,它是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录,文件的桥梁)

struct inode {

741 /* RCU path lookup touches following: */

742 umode_t i_mode;

766 dev_t i_rdev;

786 struct list_head i_devices;

787 union {

788 struct pipe_inode_info *i_pipe;

789 struct block_device *i_bdev;

790 struct cdev *i_cdev;

791 };

812 void *i_private; /* fs or device private pointer */

};

1>i_mode:为唯一地标示与一个设备文件关联的设备,内核在i_mode中中存储了文件类型(面向块,或者面向字符)

2>i_rdev:中存储了主从设备号。主从设备号在内核中合并为一种变量类型dev_t.

3>i_fop:是一组函数指针的集合,包括许多文件操作(如打开,读取,写入等),这些由虚拟文件系统使用来处理块设备

4>内核会根据inode标示块设备还是字符设备,来使用i_bdevi_cdev指向更多具体的信息。

对于代表设备文件的节点, 这个成员包含实际的设备编号.

5>struct cdev *i_cdev;

struct cdev 是内核的内部结构, 代表字符设备; 这个成员包含一个指针, 指向这个结构, 当节点指的是一个字符设备文件时.

4.cdev结构体

Linux中使用cdev结构体描述字符设备,cdev结构体定义:

12struct cdev {

13 struct kobject kobj;

14 struct module *owner;

15 const struct file_operations *ops;

16 struct list_head list;

17 dev_t dev;

18 unsigned int count;

19};

1>kobj是一个嵌入在该结构中的内核对象。它用于该数据结构的一般管理(是一个重要的数据结构,后在后面对其进行详细的介绍)

2>owner指向提供驱动程序的模块

3>ops是一组文件操作,实现了与硬件通信的具体操作。

4>dev指定了设备号

5>count表示与该设备关联的从设备的数目

6>list用来实现一个链表,其中包含所有表示该设备的设备特殊文件的inode.

分享到:
评论

相关推荐

    linux字符设备驱动实例

    本例子是一个linux字符设备驱动的最简单的例子,有详细的说明,适合初次接触者。

    Linux字符设备驱动总结

    linux 字符设备驱动 字符设备是指在I/O传输过程中以字符为单位进行传输的设备,例如键盘,打印机等。请注意,以字符为单位并不一定意味着是以字节为单位,因为有的编码规则规定,1个字符占16比特,合2个字节。  在...

    嵌入式Linux字符设备驱动的设计与应用

    嵌入式Linux字符设备驱动的设计与应用 嵌入式Linux字符设备驱动的设计与应用

    Linux下支持阻塞操作的字符设备驱动

    Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动...

    深入浅出 Linux字符设备驱动程序解析

    深入浅出 Linux字符设备驱动程序解析

    Linux字符设备驱动实现

    编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序。可以有一个读,一个写进程共享该字符设备,进行聊天;也可以由多个读和多个写进程共享该字符设备,进行聊天

    Linux字符设备驱动实验代码

    简单的字符设备的驱动程序,并对所编写的设备驱动程序进行测试,了解Linux操作系统如何管理字符设备。由于网上许多资源不完整,本资源整合了许多内容。包括驱动程序memdev.c,memdev.h,app-mem.c,MakeFile文件。...

    linux字符设备驱动程序学习笔记

    详细介绍了linux字符设备驱动程序,对各个名词做了自己的理解,在学习中的笔记,有错误还请海涵

    linux字符设备驱动模型

    linux字符设备驱动模型

    基于Linux字符设备驱动程序的设计与实现

    Linux 设备驱动程序是为特定的硬件提供给用户程序的 一组标准化接口,它隐藏了设备工作的细节。Linux 系统下 驱动程序是运行在内核态的,是和...Linux 系统的设备分为3 种类型,分别是字符设备、 块设备和网络设备。

    Linux 字符设备驱动程序的设计

    介绍了Linux 字符设备驱动程序中建立设备,初始化设备、设备的资源分配和如 何访问设备的方法及相关函数的实现.

    嵌入式Linux下字符型设备驱动程序的开发

    嵌入式Linux下字符型设备驱动程序的开发,驱动开发入门首选~

    最简单的linux字符设备驱动

    一个最简单的字符设备驱动程序,包括LDD第三版前三章的内容。 关键是书中并未讲的太细,关于mknod以及如何自己写一个程序使用自己的驱动,我的代码中有详细的过程,也在blog中写明了驱动模块的思路以及常见问题的...

    linux字符设备驱动

    1)编写一个简单的字符设备驱动程序,该字符设备包括打开、读、写、I/O控制与释放五个基本操作。 2)编写一个测试程序,测试字符设备驱动程序的正确性。 3)要求在实验报告中列出Linux内核的版本与内核加载的过程

    Linux增加字符设备驱动实验

    Linux增加字符设备驱动实验,可以打印出一个hello world

    Linux字符设备驱动(转载)

    概括的说,字符设备驱动主要要做三件事:1、定义一个结构体static struct file_operations变量,其内定义一些设备的打开、关闭、读、写、控制函数;2、在结构体外分别实现结构体中定义的这些函数;3、向内核中注册或...

    Linux字符设备驱动架构分析

    Linux字符设备驱动架构分析,Linux字符设备驱动架构分析,Linux字符设备驱动架构分析

    操作系统课程设计—linux字符设备驱动程序

    这是linux下的字符设备驱动程序,对于初学驱动程序的人有很不错的参考价值。

    linux 字符设备驱动程序 示例代码

    linux字符设备驱动程序,示例代码。 共8个文件。包括内核态的驱动程序和用户态的测试例程。

Global site tag (gtag.js) - Google Analytics