对一个打开的文件而言,最常用到的就是对文件的读写操作,在Linux系统中,提供了系统调用函数实现文件的读写操作。读取文件数据时,文件的当前读写位置会向后移。以下几种读取文件数据情况下,返回的字节数会小于count值。......
2025-09-30
用户应用程序调用设备的功能都是在设备驱动程序中定义的,也就是设备驱动程序中所定义的功能入口点函数(或称为功能接口函数)。这些设备的功能接口函数都被定义在<include/linux/fs.h>中的数据结构体里面。
struct file_operations{};
struct inode{};
struct file{};
编写设备驱动程序,很大一部分工作就是“填写”结构体中定义的函数。这是内核结构,不会出现在用户级的程序中。
1.file_operations{}结构体
在内核的内部,通过file_operations{}结构体提供文件系统的入口点函数,也就是访问设备驱动的功能接口函数。
在include//linux/fs.h>中所定义的file_operations{}结构体的结构如下:
在结构体file operations{}里,每一个成员的名字都对应着一个系统调用,对应着设备驱动程序所提供的入口点位置。在用户进程利用系统调用对设备文件进行操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个结构体相应的函数指针,接着把控制权交给该函数,这就是设备驱动程序的工作原理。
设备驱动程序所提供的入口点位置分别有以下几个:
(1)lseek。移动文件指针的位置,显然只能用于可以随机存取的设备。
(2)read进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误,否则返回实际读取的字节数。对于字符型,要求取的字节和返回实际读取字节数都必须是inode_>i_blksize的倍数。
(3)write。进行写操作,与read类似。
(4)readdir。取得目录入口点,只用于与文件系统相关的设备驱动程序。(https://www.chuimin.cn)
(5)select。进行选择操作,如果驱动程序没有提供select人口,select操作将会认为设备已经准备好进行任何的1/O操作。
(6)ioctl。进行读、写以外的其他操作,前面已有详细介绍。
(7)mmap。用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用。
(8)open。打开设备准备进行I/O操作,返回O表示打开成功,返回负数表示失败。如果驱动程序没有提供open入,则只要/dev/driver文件存在就认为打开成功。
(9)release。关闭设备并释放资源。
一般编写设备驱动程序时并不一定要全部定义以上函数,只需定义对设备有意义的接口函数。例如,一个仅有输出功能的设备只要定义一个write()函数,一个仅有输入功能的设备只要定义一个read()函数。在大多数的嵌入式系统的开发中,一般仅仅实现其中几个关键的接口函数,如open、read、write、ioctl、release等。
在编写用gcc编译的设备驱动程序时,经常使用一种更为方便的结构体形式:
当用gcc命令编译上述结构体时,对于没有显式声明的结构体成员都被gcc初始化为NULL。
2.inode{}和file{}结构体
文件系统处理文件所需要的信息在inode(索引节点)数据结构体中。inode中保存了“页”结构,用于进行设备缓冲,当进行读、写操作时,系统首先检查是否有inode存在,然后检查是否已经获得其缓冲内容。若没有则请求,若已经存在,则把被写的“页”作上标记。
inode数据结构体提供了关于特别设备文件/dev/driver(这里假设设备名为driver)的信息。
fie结构主要是与文件系统对应的设备驱动程序使用。当然,其他设备驱动程序也可以使用。
相关文章
对一个打开的文件而言,最常用到的就是对文件的读写操作,在Linux系统中,提供了系统调用函数实现文件的读写操作。读取文件数据时,文件的当前读写位置会向后移。以下几种读取文件数据情况下,返回的字节数会小于count值。......
2025-09-30
文件是Linux系统处理数据的基本单位,实际上,Linux系统所有的数据以及其他实体都是按照文件组织的。shell程序使用文件名通配符可以查询符合指定条件的文件名。......
2025-09-30
每个GPIO端口至少需要两个寄存器,一个是用于控制的“通用I/O端口控制寄存器”,一个是存放数据的“通用I/O端口数据寄存器”。控制和数据寄存器的每一位和GPIO的硬件引脚相对应,由控制寄存器设置每一个引脚的数据流向,数据寄存器设置引脚输出的高低电平或读取引脚上的电平。S5PV210共有237个GPIO端口,分成15组。GPP1:低功率I2S、PCM。GPIO的15组引脚除了作为输入、输出引脚外,一般都还有其他功能,称为引脚复用。图4.6GPIO端口功能框图......
2025-09-30
按照惯例,所有的Makefile变量都应该是大写。如果变量的值发生变化,就只需要在一个地方修改,从而简化了Makefile的维护。现在利用变量把前面的Makefile重写一遍:除用户自定义的变量外,make还允许使用环境变量、自动变量和预定义变量。需要注意的是,如果用户在Makefile中定义了同名的变量,用户自定义变量将覆盖同名的环境变量。此外,Makefile中还有一些预定义变量和自动变量,但是看起来并不像自定义变量那样直观。......
2025-09-30
嵌入式系统目前已在军事装备、工业制造与过程控制、通信、机器人、仪器与仪表、汽车、船舶、交通管理、信息家电及家庭智能管理、消费类产品各领域普及应用,具有广阔的发展前景。在这些设备中,嵌入式系统将大有用武之地。在服务领域,如远程点菜器等已经体现了嵌入式系统的优势。在很多环境恶劣,地况复杂的地区,嵌入式系统将实现无人监测。......
2025-09-30
S5PV210处理器中采用的是异步串行通信方式。异步串行通信通常以字符为单位组成字符帧传送。在串行通信中,数据位的发送和接收分别由发送时钟脉冲和接收时钟脉冲进行定时控制。......
2025-09-30
嵌入式系统设计与开发工作中,软件工作量约占全部工作量的80%,其中测试和验证部分的工作量占软件工作量的70%。图1.6嵌入式系统设计与开发流程1.需求分析分析用户的需求:产品的功能、性能、价格、体积、功耗等。嵌入式系统(实现)编程:选择硬件、操作系统、编程语言以及开发工具,编写程序。......
2025-09-30
网络通信时必须明确通信双方地址,而一个socke地址可以唯一表示一个通信端点,因此在通信前需进行socket地址绑定。图8.3sockaddr_in与sockaddr结构体对比从图8.3看出,sockaddr和sockaddr_in的长度相同,都是16字节,只是在sockaddr结构体中将IP地址和端口号合并到一起,用一个数组成员sa_data表示。要想给sa_data赋值,必须同时指明IP地址和端口号,例如“192.168.0.1:80”,遗憾的是,没有相关函数将这个字符串转换成需要的形式,也就很难给sockaddr类型的变量赋值,因此使用sockaddr_in来代替。......
2025-09-30
相关推荐