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. python 对位运算

  2. SurfaceFlinger与Surface概述

    基本原理: SF一个Client对应一个app中的SurfaceComposerClient, 分别是Binder的n端和b端,主要用来CreateSurface 一个app中有多个Activity, ...

  3. 公司mysql问题二

    这个问题解决:

  4. 转:国内从事CV相关的企业

    http://blog.csdn.net/carson2005/article/details/7356225 经常碰到朋友问我国内从事计算机视觉(CV)领域的公司的发展情况,产品情况,甚至找工作等问 ...

  5. PHPCMS快速建站系列之常用标签

    <span class="Nmore"><a href="/index.php?m=content&c=index&a=lists&am ...

  6. hdu1527 威佐夫博奕

    有2堆石子,有2个人,每个人可以从一堆取或从2堆取一样的个数的石子,至少取1个.问先手的是胜或输.设(ak,bk)我么成为局势. (0,0)(1,2)(3,5)(4,7)..这种先手必输的叫奇异局势. ...

  7. oracle 创建新表,并复制旧表数据

    需求 备份数据,用于恢复. 语法规则 CREATE TABLE NEW_TAB AS SELECT * FROM OLD_TAB WHERE 1=1; 或者 CREATE TABLE NEW_TAB ...

  8. TIJ——Chapter Thirteen:Strings

    String 对象是不可修改的,对于被String 重载的'+' 和'+=' 运算符来说,当你用它们来连接两个String 对象的时候,它在底层并不会对于每一次连接均生成一个String 对象,取而代 ...

  9. 《DL/T 1476-2015 电力安全工器具预防性试验规程》中的样品名称及试验项目

  10. jQuery简介,安装

    什么是 jQuery ? jQuery是一个JavaScript函数库. jQuery是一个轻量级的"写的少,做的多"的JavaScript库. jQuery库包含以下功能: HT ...