字符设备驱动之结构体

https://blog.csdn.net/tigerjibo/article/details/6412469
大部分驱动程序操作都涉及到三个重要的内核数据结构,分别是file_operations、file和inode,它们定义在<linux/fs.h>

1、file_operations:是一个函数指针的集合
1>应用程序和VFS之间的接口是系统调用,而VFS与磁盘文件系统以及普通设备之间的接口是file_operations结构体成员函数。file_operations结构体中成员函数是字符设备驱动与内核的接口,是用户空间对linux进行系统调用的最终落实者,这个结构体包含对文件打开,关闭,读写,控制的一系列成员函数
2>由于字符设备的上层没有磁盘文件系统,所以字符设备的file_operations成员函数就直接由设备驱动提供了,file_operations正是字符设备驱动的核心
3>对于块设备而言,ext2,fat,jffs2等文件系统中会实现对VFS的file_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指针
第二个为请求偏移量
第三个为文件定位的起始地址:一般为0或1,0表示文件开头,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 *);关闭文件

  1. struct file:文件结构体
    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:当前读写位置。loft_t在所有平台都是64位(ggc术语是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 中的操作. 这个做法允许实现几种行为, 在同一个主编号下而不必在每个系统调用中引入开销. 替换文件操作的能力是面向对象编程的"方法重载"的内核对等体

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

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

}
4>用下面的代码判断以阻塞还是非阻塞方式打开设备文件
if (file->f_flags & O_NONBLOCK)//非阻塞
{

}
else //阻塞
{

}

3.struct inode 结构

虚拟文件系统中的每个文件都关联到一个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_bdev或者i_cdev指向更多具体的信息。对于代表设备文件的节点,这个成员包含实际的设备编号
5>struct cdev
i_dev: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是一组文件操作,实现了与硬件通信的具体操作

原文地址:https://www.cnblogs.com/Ocean-Star/p/9250446.html

时间: 2024-10-17 18:43:24

字符设备驱动之结构体的相关文章

linux块设备驱动---相关结构体(转)

上回最后面介绍了相关数据结构,下面再详细介绍 块设备对象结构 block_device 内核用结构block_device实例代表一个块设备对象,如:整个硬盘或特定分区.如果该结构代表一个分区,则其成员bd_part指向设备的分区结构.如果该结构代表设备,则其成员bd_disk指向设备的通用硬盘结构gendisk 当用户打开块设备文件时,内核创建结构block_device实例,设备驱动程序还将创建结构gendisk实例,分配请求队列并注册结构block_device实例. 块设备对象结构blo

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备

【转】深入浅出:Linux设备驱动之字符设备驱动

深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称

SylixOS字符设备驱动框架

1.概述 本文档主要介绍SylixOS中字符设备驱动框架,适用于在SylixOS集成开发环境下进行字符设备驱动开发的学习. 注:文中xxx是指具体设备名,编写对应驱动时,自行命名(如RTC.COMPASS等). 2.SylixOS字符设备驱动简介 字符设备是指只能以字节为单位进行读写的设备,读取数据需按照先后顺序,不能随机读取设备内存中某一数据.常见的字符设备如:鼠标.键盘.串口等. 在SylixOS中,每个字符设备都会在/dev目录下对应一个设备文件,用户程序可通过设备文件(或设备节点)来使用

(57)Linux驱动开发之三Linux字符设备驱动

1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是:这种三层的裸机驱动模型是足够满足低耦合.高内聚的特点的. 3.当有操作系统存在时,设备驱动成为了连接硬件和内核的桥梁,这时候的设备驱动对外表现为操作系统的API,与直接裸机开发不同,裸机开发时的设备驱动是应用工程师的API.如果设备驱动都按照操作系统给出的独立于设备的接口而设计,应用程序将可以使用统

从Linux内核LED驱动来理解字符设备驱动开发流程

目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设备号注册卸载 2.1 设备号注册 2.2 设备号注销 3. 字符设备驱动--文件操作 参考资料 示例代码 @(从Linux内核LED驱动来理解字符设备驱动开发流程) 博客说明 撰写日期 2018.12.08 完稿日期 2019.10.06 最近维护 暂无 本文作者 multimicro 联系方式 [

Linux 字符设备驱动结构

1 cdev结构体 struct cdev{ struct kobject kobj; /* 内嵌的kobject对象*/ struct module *owner; /* 所属模块 */ struct file_operations *ops; /* 文件操作结构体 */ struct list_head list; dev_t dev; /* 设备号 */ unsigned int count; } cdev 结构体的dev_t成员定义了设备号, 为32位,其中12位主设备号,20位次设备号

register_chrdev_region/alloc_chrdev_region和cdev注册字符设备驱动

内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region().alloc_chrdev_region() 和 register_chrdev(). (1)register_chrdev  比较老的内核注册的形式   早期的驱动(2)register_chrdev_region/alloc_chrdev_region + cdev  新的驱动形式 (3)register_chrdev()函数是老版本里面的设备号注册函数,可以实现静态和动态注册两种方法

linux字符设备驱动

一.字符设备.字符设备驱动与用户空间访问该设备的程序三者之间的关系. 如图,在Linux内核中使用cdev结构体来描述字符设备,通过其成员dev_t来定义设备号(分为主.次设备号)以确定字符设备的唯一性.通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open().read().write()等. 在Linux字符设备驱动中,模块加载函数通过register_chrdev_region( ) 或alloc_chrdev_region( )来静态或者动态获