open()往往是一个设备操作的发起者,而release()往往是一个设备操作的终结者.
1.open():
当我们要操作一个设备时,往往第一个动作就是open().其原型如下:
int (*open)(struct inode *inode,struct file *filp);
其中,两个参数inode和filp由内核根据我们打开的设备节点信息(如主次设备号,字符设备等)来填充,这样我们可以通过这两个参数来找到我们要操作的目标设备.这对于一个驱动对应多个设备的情况非常实用.一般来说,根据函数open()的作用编程规则如下:1).检查设备特定的错误(如设备未就绪);
2).对设备实现初始化;
3).更新f_op指针.这一点很实用,比如带有子系统的驱动模型,一般有系统默认的操作集,如果系统默认的操作集满足不了我们的需求时,我们可以通过更新f_op指针指向我们具体的操作集,实现了操作集的重载.其中LCD子系统就是这么干的;
4).有必要时更新filp->private_data.当多个设备共享一套驱动时,为后续读写数据交互,可以借助这个"桥梁".
其中,LDD3中P63是一个比较经典的用法:
int scull_open(struct inode *inode,struct file *filp)
{
struct scull_dev *dev;
dev = container_of(inode->i_cdev,struct scull_dev,cdev);
filp->private_data = dev;
do something;
return 0;
}
2.release():
release()完成与open()相反的工作.释放open()向内核申请的所有资源.实际使用过程中主要注意两点:
2-1.close()并不完全是release():
内核对每个file结构维护其被使用的计数,无论是fork还是dup,都不会创建新的数据结构,如fork和dup,它们只是增加已有(由open生成)结构中的计数.只有在file结构的计数为0时,close才会实质地调用release.因此,并不是每个close系统调用都会引起对release方法的调用;
2-2.内核自动关闭:
内核在进程退出时,会在内部使用close系统调用自动关闭所有相关文件.