open 方法提供给驱动来做任何的初始化来准备后续的操作. 在大部分驱动中, open 应当 进行下面的工作:

  • 检查设备特定的错误(例如设备没准备好, 或者类似的硬件错误
  • 如果它第一次打开, 初始化设备
  • 如果需要, 更新 f_op 指针.
  • 分配并填充要放进 filp->private_data 的任何数据结构

但是, 事情的第一步常常是确定打开哪个设备. 记住 open 方法的原型是:

int (*open)(struct inode *inode, struct file *filp);

inode 参数有我们需要的信息,以它的 i_cdev 成员的形式, 里面包含我们之前建立的 cdev 结构. 唯一的问题是通常我们不想要 cdev 结构本身, 我们需要的是包含 cdev 结构 的 scull_dev 结构. C 语言使程序员玩弄各种技巧来做这种转换; 但是, 这种技巧编程是 易出错的, 并且导致别人难于阅读和理解代码. 幸运的是, 在这种情况下, 内核 hacker 已经为我们实现了这个技巧, 以 container_of 宏的形式, 在 <linux/kernel.h> 中定义:

container_of(pointer, container_type, container_field);

这个宏使用一个指向 container_field 类型的成员的指针, 它在一个 container_type 类 型的结构中, 并且返回一个指针指向包含结构. 在 scull_open, 这个宏用来找到适当的设 备结构:

struct scull_dev *dev; /* device information */

dev = container_of(inode->i_cdev, struct scull_dev, cdev); filp->private_data = dev; /* for other methods */

一旦它找到 scull_dev 结构, scull 在文件结构的 private_data 成员中存储一个它的指 针, 为以后更易存取.

识别打开的设备的另外的方法是查看存储在 inode 结构的次编号. 如果你使用 register_chrdev 注册你的设备, 你必须使用这个技术. 确认使用 iminor 从 inode 结构 中获取次编号, 并且确定它对应一个你的驱动真正准备好处理的设备.

scull_open 的代码(稍微简化过)是:

int scull_open(struct inode *inode, struct file *filp)

{

struct scull_dev *dev; /* device information */

dev = container_of(inode->i_cdev, struct scull_dev, cdev); filp->private_data = dev; /* for other methods */

/* now trim to 0 the length of the device if open was write-only */ if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)

{

scull_trim(dev); /* ignore errors */

}

return 0; /* success */

}

代码看来相当稀疏, 因为在调用 open 时它没有做任何特别的设备处理. 它不需要, 因为 scull 设备设计为全局的和永久的. 特别地, 没有如"在第一次打开时初始化设备"等动作, 因为我们不为 scull 保持打开计数.

唯一在设备上的真实操作是当设备为写而打开时将它截取为长度为 0. 这样做是因为, 在 设计上, 用一个短的文件覆盖一个 scull 设备导致一个短的设备数据区. 这类似于为写而 打开一个常规文件, 将其截短为 0. 如果设备为读而打开, 这个操作什么都不做.

在我们查看其他 scull 特性的代码时将看到一个真实的初始化如何起作用的.

3.5.1. release 方法

 

release 方法的角色是 open 的反面. 有时你会发现方法的实现称为 device_close, 而不 是 device_release. 任一方式, 设备方法应当进行下面的任务:

  • 释放 open 分配在 filp->private_data 中的任何东西
  • 在最后的 close 关闭设备

scull 的基本形式没有硬件去关闭, 因此需要的代码是最少的:[12]12

int scull_release(struct inode *inode, struct file *filp)

{

return 0;

}

你可能想知道当一个设备文件关闭次数超过它被打开的次数会发生什么. 毕竟, dup 和 fork 系统调用不调用 open 来创建打开文件的拷贝; 每个拷贝接着在程序终止时被关闭. 例如, 大部分程序不打开它们的 stdin 文件(或设备), 但是它们都以关闭它结束. 当一个 打开的设备文件已经真正被关闭时驱动如何知道?

答案简单: 不是每个 close 系统调用引起调用 release 方法. 只有真正释放设备数据结 构的调用会调用这个方法 -- 因此得名. 内核维持一个文件结构被使用多少次的计数. fork 和 dup 都不创建新文件(只有 open 这样); 它们只递增正存在的结构中的计数. close 系统调用仅在文件结构计数掉到 0 时执行 release 方法, 这在结构被销毁时发生. release 方法和 close 系统调用之间的这种关系保证了你的驱动一次 open 只看到一次 release.

注意, flush 方法在每次应用程序调用 close 时都被调用. 但是, 很少驱动实现 flush, 因为常常在 close 时没有什么要做, 除非调用 release.

如你会想到的, 前面的讨论即便是应用程序没有明显地关闭它打开的文件也适用: 内核在 进程 exit 时自动关闭了任何文件, 通过在内部使用 close 系统调用.

linux scull 函数open 方法的更多相关文章

  1. linux scull 代码read 方法

    read 的返回值由调用的应用程序解释: 如果这个值等于传递给 read 系统调用的 count 参数, 请求的字节数已经被传送. 这是最好的情况. 如果是正数, 但是小于 count, 只有部分数据 ...

  2. linux scull 代码write 方法

    write, 象 read, 可以传送少于要求的数据, 根据返回值的下列规则: 如果值等于 count, 要求的字节数已被传送. 如果正值, 但是小于 count, 只有部分数据被传送. 程序最可能重 ...

  3. Linux内核多线程实现方法 —— kthread_create函数【转】

    转自:http://blog.csdn.net/sharecode/article/details/40076951 Linux内核多线程实现方法 —— kthread_create函数 内核经常需要 ...

  4. linux c语言 select函数使用方法

    linux c语言 select函数使用方法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<un ...

  5. 嵌入式linux应用程序移植方法总结

    嵌入式linux应用程序移植方法总结 前段时间一直在做openCapwap的移植和调试工作,现在工作已接近尾声,编写本文档对前段工作进行一个总结,分享下openCapwap移植过程中的经验和感悟.江浩 ...

  6. linux php安装扩展方法 查找配置文件

    如何在linux中查看nginx.apache.php.mysql配置文件路径了,如果你接收一个别人配置过的环境,但没留下相关文档.这时该怎么判断找到正确的加载文件路径了.可以通过以下来判断 1.判断 ...

  7. python基础:os模块中关于文件/目录常用的函数使用方法

    Python是跨平台的语言,也即是说同样的源代码在不同的操作系统不需要修改就可以同样实现 因此Python的作者就倒腾了OS模块这么一个玩意儿出来,有了OS模块,我们不需要关心什么操作系统下使用什么模 ...

  8. os模块中关于文件/目录常用的函数使用方法

    os模块中关于文件/目录常用的函数使用方法 函数名 使用方法 getcwd() 返回当前工作目录 chdir(path) 改变工作目录 listdir(path='.') 列举指定目录中的文件名('. ...

  9. 18 os/os.path模块中关于文件/目录常用的函数使用方法 (转)

    os模块中关于文件/目录常用的函数使用方法 函数名 使用方法 getcwd() 返回当前工作目录 chdir(path) 改变工作目录 listdir(path='.') 列举指定目录中的文件名('. ...

随机推荐

  1. pytest相关资源收集

    pytest官网 https://docs.pytest.org/en/latest/getting-started.html 官网推荐的plugin https://docs.pytest.org/ ...

  2. LeetCode169 Majority Element, LintCode47 Majority Number II, LeetCode229 Majority Element II, LintCode48 Majority Number III

    LeetCode169. Majority Element Given an array of size n, find the majority element. The majority elem ...

  3. LintCode_408 二进制求和

    给定两个二进制字符串,返回他们的和(用二进制表示). 思路 string s = ""; 目标字符串 cp 存储进位;取 0或1 sum = a[i] + b[i] + cp;分为 ...

  4. R语言实现分层抽样(Stratified Sampling)以iris数据集为例

    R语言实现分层抽样(Stratified Sampling)以iris数据集为例 1.观察数据集 head(iris) Sampling)以iris数据集为例">  选取数据集中前6个 ...

  5. 【OI】拓扑排序

    拓扑排序 首先要求图为DAG 算法:首先将度为1的节点加入队列每次取出队首点u,在图中删去和u相邻的边继续将度数为1的点加入队列 到了最后, 如果没有度数为1的点,则图不是DAG 通过拓扑排序可以给D ...

  6. 洛谷 P1342 请柬 最短路+Dijkstra算法

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例 输出样例 说明 思路 AC代码 总结 题面 题目链接 P1342 请柬 题目描述 在电视时代,没有多少人观看戏 ...

  7. 开启远程XUL

    参考:https://developer.mozilla.org/zh-cn/Remote_XUL firefox自4.0起(2011年4月版本,目前最新版为13.0),开始禁用远程XUL,这阻碍了初 ...

  8. MVC设计之从零打造到实际操作(总汇)

    我们为什么要自己搭建一个MVC架构的框架? 1.为了更快的开发效率 2.为了更高的运行效率 3.为了更好的证明自己 在别的框架中,有些方法我们使用起来可能会比较麻烦,我们可以在自己的框架中写一些自己想 ...

  9. TIJ——Chapter Fourteen:Type Information

    Runtime type information(RTTI) allows you to discover and use type information while a program is ru ...

  10. phpexcel使用说明5----ThinkPHP+PHPExcel[导入][导出]实现方法

    转自:http://www.thinkphp.cn/code/403.html实现步骤: 注意:phpexcel必须是1.78版本的,不能用1.8以上的 一:去官网http://phpexcel.co ...