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. PHPCMS V9双语站建设切换

    PHPCMS V9要做双语,很多同学都是迷茫的,在此特地分享我的双语制作步辶 我这种模式是把两个站点都改为HTML静态模式才可以实现 双语切换可分为两种模式: 1.解析二级域名来切换双语 解析二级域名 ...

  2. HTML5拖放API实现拖放排序的实例代码

    想要拖放某个元素,必须设置该元素的 draggable 属性为 true,当该属性为 false 时,将不允许拖放.而 img 元素和 a 元素都默认设置了 draggable 属性为 true,可直 ...

  3. Future Maker | 领跑亚太 进击的阿里云数据库

    7月31日,阿里云马来西亚峰会在吉隆坡召开,阿里巴巴集团副总裁.阿里云智能数据库事业部总裁李飞飞在演讲中表示:“作为亚太地区第一的云服务提供商,阿里云数据库已为多家马来西亚知名企业提供技术支持,助力企 ...

  4. mysql存储过程小解

    mysql 存储过程 1.创建语法 delimiter $$ --$$表示改变默认的分隔符,代表以下为存储过程,不然会以SQL的方式执行 drop procedure if exists pro_na ...

  5. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十九章:法线贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十九章:法线贴图 学习目标 理解为什么需要法线贴图: 学习法线贴图如 ...

  6. 【JZOJ4868】【NOIP2016提高A组集训第9场11.7】Simple

    题目描述 数据范围 解法 在暴力枚举的基础上,当n的系数在[0,m/gcd(n,m))时,得到的c是不重复不遗漏的. 设n的系数为x,m的系数为y. 不重复不遗漏性 设x=m/gcd(n,m)+i,那 ...

  7. 【JZOJ2224】【NOI2006】最大获利

    题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成 ...

  8. 批量或者选择导出datagrid列表数据到表格

    //导出项目信息 function exportXmxx(){ //判断是否选择站址 var index = $("#dgObj").datagrid('getChecked'); ...

  9. UVA_694:The Collatz Sequence

    Language: C++ 4.8.2 #include<stdio.h> int main(void) { long long int m, n, copy_m; ; ; ) { sca ...

  10. UVA_414:Machined Surfaces

    Language : C++ 4.8.2 #include<stdio.h> #include<string.h> int main(void) { int n; int su ...