1、重要的数据结构
注册设备编号仅仅是驱动代码需要完成的任务之一,还有很多基础性的驱动操作需要驱动代码来完成,这里有3个重要的内核数据结构需要了解一下分别是:file_operations、file、inode。
1.1、文件操作
File_operation结构的功能是建立一个字符驱动与设备编号的连接。通常结构中的每个成员必须指向驱动中的函数,这些函数实现一个特别的操作,对于不支持的操作置为NULL。
__user这种注解是一种文档形式,表明一个指针是一个不能被直接解除引用的用户空间地址,对于正常的编译没有效果。
Structmodule*owner
指向拥有这个结构的模块的指针。
Loff_t(*llseek)(structfile*,loff_t,int);
Llseek用来改变文件中当前读/写位置,并且新位置作为返回值,错误返回负值。
Ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);
用来从设备中获取数据,如果这个方法是NULL,将导致系统调用-EINVAL失败,返回非负值代笔成功读取的字节数(返回值是一个signedsize类型,通常是目标平台本地的整数类型)。
Ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t);
初始化一个异步读,肯恩在函数返回前不结束的读操作,如果这个方法是NULL,所有的操作将会由read代替进行(同步读)。
Ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);
发送数据给设备,如果这个方法NULL,将返回-EINVAL给调用这个方法的程序,如果非负,返回值代表成功写的字节数。
Ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,loff_f*);
初始化设备上的一个异步写。
Int(*readdir)(structfile*,void*,filldir_t);
对于设备文件这个成员应当为NULL,它用来读取目录,并且仅对文件系统有用。
Unsignedint(*poll)(structfile*,structpoll_table_struct*);
Poll方法为3个系统调用的后端:pollepollselect,它们都用作查询一个或多个文件描述符的读和写是否会拥塞。Poll应当方法返回一个位掩码指示读或写是否拥塞,并提供给内核信息,使调用进程睡眠直到I/O变为可能,如果一个驱动的poll方法为NULL,则设备被假定为不阻塞可读可写。
Int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);
Ioctl系统调用提供了发出设备特定命令的方法,如果设备不提供ioctl,对于任何事先未定义的请求,系统调用都会返回一个错误。
Int(*mmap)(structfile*,structvm_area_struct*);
Mmap用来请求将设备内存映射到进程的地址空间。如果这个方法是NULL,mmap系统调用返回-ENODEY。
Int(*open)(structinode*,structfile*);
这常常是对设备文件进行的第一个操作,不要求驱动声明一个对应的方法,如果这个方法是NULL,设备打开一只成功,但是你的驱动不会得到通知。
Int(*flush)(structfile*);
Flush操作在进程关闭它的设备文件描述符的拷贝时调用,它应当执行设备的任何未完成的操作。
Int(*release)(structinode*,structfile*);
在文件结构被释放时引用这个操作,如同open,release可以为NULL。
Int(*fsync)(structfile*,structdentry*,int);
这个方法是fsync系统调用的后端,用户调用来刷新任何挂着的数据,如果这个指针是NULL,系统返回-EINVAL。
Int(*aio_fsync)(structkiocb*,int);
Fsync方法的异步版本。
Int(*fasync)(int,structfile*,int);
这个操作用来通知设备它的FASYNC标志发生改变,如果驱动不支持异步通知,这个成员可以使NULL。
Int(*lock)(structfile*,int,structfile_lock*);
Lock发放用来实现文件加锁,加锁对常规文件时必不可少的特性,但是设备驱动几乎从不实现它。
Ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_f*);
Ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);
这个方法实现发散/汇聚读和写操作,应用程序偶尔需要做一个包含多个内存区的单个读或写操作,这个系统调用允许他们这样做而不必对数据进行额外拷贝,如果这些函数指针为NULL,read和write方法被调用(可能多于一次)。
Ssize_t(*sendfile)(structfile*,loff_t*,size_t,read_actor_t,void*);
这个方法实现sendfile系统调用的读,使用最少的拷贝从一个文件描述符搬移数据到另一个,设备驱动常常使sendfile为NULL。
Ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);
Sendpage是sendfile的另一半,它由内核调用来发送数据,一次一页,到对应的文件,设备驱动通常不实现sendpage。
Unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong);
这个方法的目的是在进程的地址空间找一个合适的位置来映射在底层设备上的内存段中,大部分驱动可以置这个方法为NULL。
Int(*check_flags)(int);
这个方法允许模块检查传递给fnctl(F_SETEL...)调用的标志。
Int(*dir_notify)(structfile*,unsignedlong);
这个方法在应用程序使用fnctl来请求目录改变通知时调用,只对文件系统有用,驱动不需要实现dir_notify。
Scull设备驱动只实现最重要的设备方法,它的file_operations结构是如下初始化的:
Structfile_operationsscull_fops={.owner=THIS_MODULE,
.llseek=scull_llseek,
.read=scull_read,
.write=scull_write,
.ioctl=scull_ioctl,
.open=scull_open,
,release=scull_release,
};
1.2、文件结构
Structfile是设备驱动中第二个重要的数据结构,注意file与用户空间程序的FILE指针没有任何关系,一个FILE定义在C库中,从不出现在内核代码中,一个structfile是内核结构,从不出现在用户程序中。
Structfile代表一个打开的文件,在内核空间,系统中每个打开的文件都有一个关联的structfile,在内核open时创建,并传递给操作文件的函数,直到最后关闭,然后内核释放这个数据结构。
在内核源码中,structfile的指针常常称为file或者filp(filepointer),为避免混淆,以后file指结构,filp指结构指针。下面是file结构的一些重要成员:
Mode_tf_mode:文件模式
确定文件时可读或是可写,通过位FMODE_READ和FMODE_WRITE确定。
Loff_tf_pos:当前读写位置
Loff_t在所有平台都是64位的,驱动如果需要知道文件的当前位置,可以读这个值。
Unsignedintf_flags:文件标志
如O_RDONLYO_NONBLOCKO_SYNC,驱动应该检查O_NONBLOCK标志来查看是否是请求非阻塞操作,其他的很少使用。
Structfile_operations*f_op:和文件关联的操作
Void*private_data:open系统调用设置这个指针为NULL,在为驱动调用open方法之前,你可自由使用这个成员或者忽略它。
Structdentry*f_dentry:关联到文件的目录入口结构。
1.3、inode结构
Inode结构由内核在内部用来表示文件。
有用的成员:
Dev_ti_rdev:对于代表设备文件的节点,这个成员包含实际的设备编号。
Structcdev*i_cdev:
Structcdev是内核的内部结构,代表字符设备。
从一个inode中获取主次编号的宏:
Unsignedintiminor(structinode*inode);
Unsignedintimajor(structinode*inode);
相关推荐
LDD2+LDD3 linux设备驱动
LDD3学习笔记设备模型之底层实现(kobject,kset)[汇编].pdf
经典 LDD3,linux驱动开发 linux驱动开发
ldd code ldd3驱动源代码 ldd code ldd3驱动源代码
LDD3是linux驱动开发的基础入门级图书,适合刚接触linux驱动的新手学习。
本资源为ldd3详解,该书中详细介绍了ldd3的使用以及各种驱动的设置
包含linux设备驱动 第三版(ldd3)书中所有源码。
Linux 设备驱动 Edition 3 - LDD3中文版,学习linux必备之书,pdf格式
LDD-LinuxDeviceDrivers#1书籍-一些书中的原始码和范例目录书籍#2 study--本人的linux学习以及驱动代码目录书籍学习Linux内核的设计与实现,包括文档和示例代码,文档与同步更新自己实现的一些linux内核的驱动代码...
高清PDF,全英文版
这是《linux设备驱动程序》的全部源代码 学习linux设备驱动的时候可以参考一下
Linux_设备驱动_Edition_3_-_LDD3中文版.pdf
Linux设备驱动程序(中文版第三版) 例子
LDD-3(Linux驱动)中文版,绝对好东西
ldd3-examples-3.x, 在 linux 3.x 之后,端口LDD3源代码示例 ldd3-examples-3.xlinux 3 。x 之后LDD3源代码示例的端口背景LDD3是Linux设备驱动程序,第三版。 这是一本关于如何编写linux设备驱动程序的。 你可以从 ...
ldd3中文版、chmldd3中文版chm
LDD3配套源码,配合我的百度云分享的虚拟机可以直接编译运行(虚拟机另行在我上传的资源里下载,相关可以参考我的LDD3系列博客)
一个最简单的字符设备驱动程序,包括LDD第三版前三章的内容。 关键是书中并未讲的太细,关于mknod以及如何自己写一个程序使用自己的驱动,我的代码中有详细的过程,也在blog中写明了驱动模块的思路以及常见问题的...
由于对Linux设备驱动程序设计的需求,所以前段时间在网上下载了LDD3的HTML格式文档,在看的时候感觉不太好看,同时为了打印方便,把它转化为PDF格式,所以在此与大家一起分享。 由于本资料不是本人自创,也是来自于...
Linux内核与设备驱动程序学习笔记