LDD3学习笔记(4):字符驱动2

简介: 1、重要的数据结构注册设备编号仅仅是驱动代码需要完成的任务之一,还有很多基础性的驱动操作需要驱动代码来完成,这里有3个重要的内核数据结构需要了解一下分别是:file_operations、file、inode。

1、重要的数据结构

注册设备编号仅仅是驱动代码需要完成的任务之一,还有很多基础性的驱动操作需要驱动代码来完成,这里有3个重要的内核数据结构需要了解一下分别是:file_operationsfileinode

1.1、文件操作

File_operation结构的功能是建立一个字符驱动与设备编号的连接。通常结构中的每个成员必须指向驱动中的函数,这些函数实现一个特别的操作,对于不支持的操作置为NULL

__user这种注解是一种文档形式,表明一个指针是一个不能被直接解除引用的用户空间地址,对于正常的编译没有效果。

Struct module* owner

指向拥有这个结构的模块的指针。

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

Llseek用来改变文件中当前读/写位置,并且新位置作为返回值,错误返回负值。

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

用来从设备中获取数据,如果这个方法是NULL,将导致系统调用-EINVAL失败,返回非负值代笔成功读取的字节数(返回值是一个signed size 类型,通常是目标平台本地的整数类型)。

Ssize_t *aio_read) (struct kiocb * , char __user* , size_t , loff_t);

初始化一个异步读,肯恩在函数返回前不结束的读操作,如果这个方法是NULL,所有的操作将会由read代替进行(同步读)。

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

发送数据给设备,如果这个方法NULL,将返回-EINVAL给调用这个方法的程序,如果非负,返回值代表成功写的字节数。

Ssize_t*aio_write(struct kiocb* , const char __user* , size_t , loff_f *);

初始化设备上的一个异步写。

Int *readdir(struct file * , void * , filldir_t);

对于设备文件这个成员应当为NULL,它用来读取目录,并且仅对文件系统有用。

Unsigned int *poll(struct file* , struct poll_table_struct *);

Poll方法为3个系统调用的后端:poll epoll select,它们都用作查询一个或多个文件描述符的读和写是否会拥塞。Poll应当方法返回一个位掩码指示读或写是否拥塞,并提供给内核信息,使调用进程睡眠直到I/O变为可能,如果一个驱动的poll方法为NULL,则设备被假定为不阻塞可读可写。

Int *ioctl)(struct inode* struct file * unsigned int unsigned long;

Ioctl系统调用提供了发出设备特定命令的方法,如果设备不提供ioctl,对于任何事先未定义的请求,系统调用都会返回一个错误。

Int *mmap(struct file * , struct vm_area_struct *);

Mmap用来请求将设备内存映射到进程的地址空间。如果这个方法是NULLmmap系统调用返回-ENODEY

Int *open)(struct inode* struct file*);

这常常是对设备文件进行的第一个操作,不要求驱动声明一个对应的方法,如果这个方法是NULL,设备打开一只成功,但是你的驱动不会得到通知。

Int *flush(struct file *);

Flush操作在进程关闭它的设备文件描述符的拷贝时调用,它应当执行设备的任何未完成的操作。

Int *release)(struct inode * , struct file*);

在文件结构被释放时引用这个操作,如同openrelease可以为NULL

Int (*fsync)(struct file* , struct dentry * , int );

这个方法是fsync系统调用的后端,用户调用来刷新任何挂着的数据,如果这个指针是NULL,系统返回-EINVAL

Int *aio_fsync) (struct kiocb* , int);

Fsync方法的异步版本。

Int *fasync)(int , struct file* , int );

这个操作用来通知设备它的FASYNC标志发生改变,如果驱动不支持异步通知,这个成员可以使NULL

Int*lock)(struct file * , int , struct file_lock*;

Lock发放用来实现文件加锁,加锁对常规文件时必不可少的特性,但是设备驱动几乎从不实现它。

Ssize_t(*readv)(struct file* , const struct iovec* , unsigned long , loff_f*);

Ssize_t(*writev)(struct file* , const struct iovec* , unsigned long , loff_t*);

这个方法实现发散/汇聚读和写操作,应用程序偶尔需要做一个包含多个内存区的单个读或写操作,这个系统调用允许他们这样做而不必对数据进行额外拷贝,如果这些函数指针为NULLreadwrite方法被调用(可能多于一次)。

Ssize_t*sendfile)(struct file* , loff_t* , size_tread_actor_t,void *);

这个方法实现sendfile系统调用的读,使用最少的拷贝从一个文件描述符搬移数据到另一个,设备驱动常常使sendfileNULL

Ssize_t*sendpage)(struct file* , struct page* , int ,size_t ,loff_t* , int);

Sendpagesendfile的另一半,它由内核调用来发送数据,一次一页,到对应的文件,设备驱动通常不实现sendpage

Unsigned long*get_unmapped_area)(struct file * , unsigned long ,unsigned long ,unsigned long);

这个方法的目的是在进程的地址空间找一个合适的位置来映射在底层设备上的内存段中,大部分驱动可以置这个方法为NULL

Int *check_flags)(int);

这个方法允许模块检查传递给fnctlF_SETEL...)调用的标志。

Int*dir_notify)(struct file* , unsigned long);

这个方法在应用程序使用fnctl来请求目录改变通知时调用,只对文件系统有用,驱动不需要实现dir_notify

Scull设备驱动只实现最重要的设备方法,它的file_operations结构是如下初始化的:

Struct file_operations scull_fops={.owner = THIS_MODULE,

.llseek = scull_llseek,

.read = scull_read,

.write = scull_write,

.ioctl = scull_ioctl,

.open = scull_open,

,release = scull_release,

};

1.2、文件结构

Struct file是设备驱动中第二个重要的数据结构,注意file与用户空间程序的FILE指针没有任何关系,一个FILE定义在C库中,从不出现在内核代码中,一个struct file是内核结构,从不出现在用户程序中。

Struct file代表一个打开的文件,在内核空间,系统中每个打开的文件都有一个关联的struct file ,在内核open时创建,并传递给操作文件的函数,直到最后关闭,然后内核释放这个数据结构。

在内核源码中,struct file的指针常常称为file或者filpfile pointer,为避免混淆,以后file指结构,filp指结构指针。下面是file结构的一些重要成员:

Mode_t f_mode:文件模式

确定文件时可读或是可写,通过位FMODE_READFMODE_WRITE确定。

Loff_t f_pos:当前读写位置

Loff_t在所有平台都是64位的,驱动如果需要知道文件的当前位置,可以读这个值。

Unsigned int f_flags:文件标志

O_RDONLY O_NONBLOCK O_SYNC,驱动应该检查O_NONBLOCK标志来查看是否是请求非阻塞操作,其他的很少使用。

Struct file_operations *f_op:和文件关联的操作

Void *private_data:open系统调用设置这个指针为NULL,在为驱动调用open方法之前,你可自由使用这个成员或者忽略它。

Struct dentry* f_dentry:关联到文件的目录入口结构。

1.3inode结构

Inode结构由内核在内部用来表示文件。

有用的成员:

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

Struct cdev* i_cdev:

Struct cdev是内核的内部结构,代表字符设备。

从一个inode中获取主次编号的宏:

Unsigned int iminor(struct inode * inode);

Unsigned int imajor(struct inode* inode);

目录
相关文章
|
iOS开发 MacOS Python
在Mac 上搭建Pygame开发环境(含安装错误的解决办法)
在Mac 上搭建Pygame开发环境(含安装错误的解决办法)
1364 0
|
前端开发 Java 数据安全/隐私保护
聊聊 OAuth 2.0 的 Token 续期处理
Token 校验逻辑 // CheckTokenEndpoint.checkToken @RequestMapping(value = "/oauth/check_token") @ResponseBody public Map checkToken(@RequestPara.
2322 0
|
敏捷开发 弹性计算 运维
微服务架构的优点有哪些?
微服务架构的优点有哪些?
826 61
|
存储 测试技术 Python
Python 中别再用 ‘+‘ 拼接字符串了!
通过选择合适的字符串拼接方法,可以显著提升 Python 代码的效率和可读性。在实际开发中,根据具体需求和场景选择最佳的方法,避免不必要的性能损失。
246 5
|
机器学习/深度学习 算法 PyTorch
Python实现替换照片人物背景,精细到头发丝(附上代码) | 机器学习(1)
Python实现替换照片人物背景,精细到头发丝(附上代码) | 机器学习
Python实现替换照片人物背景,精细到头发丝(附上代码) | 机器学习(1)
|
监控 安全 网络安全
网络安全的基本原则与策略
【8月更文挑战第19天】网络安全的基本原则与策略是保障网络系统安全性的重要基石。通过遵循网络空间主权原则、网络安全与信息化发展并重原则以及共同治理原则等基本原则,制定并实施科学合理的安全策略和实施措施,可以有效提升网络系统的安全性、完整性、可用性和保密性。同时,随着网络技术的不断发展和变化,我们需要持续关注网络安全的新趋势和新挑战,不断调整和完善安全策略和实施措施,确保网络系统的持续安全和稳定运行。
|
缓存 Java Apache
Spring一行代码搞定图片url地址转换为Base64,超简单!!!!
这段内容讲述了如何将URL指向的图片转换为Base64字符串。首先通过`org.apache.commons.io.IOUtils`或Java标准库读取URL的字节流,然后用Java 8的`Base64`类编码。示例代码提供了两种实现方式:一种依赖Apache Commons IO,另一种仅使用Java内置类。在第二种方式中,自定义了`toByteArray()`方法处理输入流并转换为字节数组,最后关闭输入流释放资源。
|
存储 安全 算法
静态路由与动态路由的区别及应用场景
【8月更文挑战第25天】
862 0
|
弹性计算 大数据 测试技术
阿里云服务器多少钱一年?2024年阿里云优惠云服务器新版租用价格表出炉!
在当下云计算的浪潮中,阿里云作为国内领先的云服务提供商,一直备受关注。许多用户都想知道,租用阿里云服务器一年需要多少钱?今天,就为大家带来了一份详细的优惠云服务器新版租用价格表。对于轻量级应用,阿里云2核2G3M轻量应用服务器一年仅需62元,无疑是性价比之选。而如果是稍微复杂一些的应用场景,阿里云2核2G3M经济型e实例云服务器ECS一年价格为99元,也非常实惠。