如果将《linux程序设计》中的系统调用open函数和《linux设备驱动程序》中的设备驱动open函数对比,我们
可以发现这两个函数有很大的区别,至少参数就不一样。
在linux程序设计中,对于系统调用open函数定义如下:
为了创建一个新的文件描述符,需要使用系统调用open函数
包含的头文件
#include fcntl.h
//可能需要下面两个头文件
#include sys/stat.h
#include sys/types.h
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);
这里,open建立了一条文件或设备的访问路径。调用成功返回新的文件描述符,调用失败返回-1
第一个参数(path)为准备打开的文件或设备的名字,第二个参数(oflags)用来指定打开文件采用的动作(只读,只写,读写 ...)
第三个参数(为配和的模式)
如下例:
in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
对于《linux设备驱动程序》中的设备驱动open函数,定义如下:
open方法提供给驱动程序以初始化的能力,从而为以后的操作完成初始化做准备。
大部分驱动程序中,open完成如下工作:
-
检查设备特定错误
-
如果设备是首次打开,则对其进行初始化
-
如有必要,更新f_op指针
-
分配并填写置于filp->private_data里的数据结构
首先要做的是确定要打开的具体设备,open原型如下:
int (*open)(struct inode *inode, struct file *filp)
一个简单的字符设备open函数:
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; //设备信息
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
//内核用inode结构在内部表示文件,而对于字符设备,inode结构中包含有 struct cdev结构,
这个结构同样被包含在scull_dev结构中,而这个结构(scull_dev)是一个表示字符设备的结构
filp->private_data = dev;
//private_data属于struct file结构,这个结构表示一个打开的文件,字符设备的信息通过这种方法
传给struct file结构
if ((filp->fLflags & O_ACCMODE) = = O_WRDNLY)
scull_trim(dev);
return 0;
}
显然设备驱动程序的open函数与系统调用open函数是不一样的。
当应用程序通过fopen调用库函数来访问文件时,应用程序同库就联系起来了,而fopen不能进入内核空间,
所以只能通过open系统调用,实现库与内核的联系。
接下来的任务就交给内核了,内核又是如何访问字符设备文件的?驱动程序。
驱动程序的作用是让内核能够访问设备,字符设备成功驱动之后,内核就将会使用驱动程序提供的open函数,来打开
字符设备,这里的open函数所做的工作主要是将表示字符设备的结构传给file结构(传给了private_data指针),而file
结构刚好就是一个被打开了的 文件描述符。file结构中,不仅包含了 *private_data指针,还还包含了file_operations 结构,
而file_operations结构中,又恰好的包含了一组驱动程序提供的接口函数(open read write llseek ...)
此外,file结构中还包含了系统调用时的参数,如文件模式 mode_t,表示文件可读,可写等; 文件标志 f_flags等。这些
参数就是系统调用open函数中的参数。
因此,当用open实现系统调用时,系统调用的open函数会将所调用的文件路径传给内核,内核识别该字符设备文件后,
会去调用该字符设备的驱动程序,驱动程序中的open函数将会返回包含字符设备信息的结构dev给file结构,file结构将系统调用open函数传来的参数一并打包,返回的文件描述符包含了这些所有信息。
阅读(3301) | 评论(0) | 转发(0) |