我们开始在真实的 scull 函数中使用它们.

open 方法

 

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 特性的代码时将看到一个真实的初始化如何起作用的.

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 系统调用.

open 和 release的更多相关文章

  1. ASP.NET Core 1.1.0 Release Notes

    ASP.NET Core 1.1.0 Release Notes We are pleased to announce the release of ASP.NET Core 1.1.0! Antif ...

  2. maven 中snapshot版本和release版本的区别

    maven中的仓库分为两种,snapshot快照仓库和release发布仓库.snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本.定义一个组件/模 ...

  3. VS2010 release编译下进行调试,“当前不会命中任何断点,还没有为文档加载”问题解决方案

    在release模式下调试程序,经常出现"当前不会命中任何断点,还没有为文档加载"的问题,可尝试以下方法: 1. 属性 → 配置属性 → C/C++ → 常规 → 调试信息格式:选 ...

  4. 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理

    Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...

  5. maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令

    maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令 在日常的工作中由于各种原因,会出现这样一种情况,某些项目并没有打包至mvnrepository. ...

  6. Oracle Database 12c Release 1下载安装(自身经历)

    1.访问Oracle官网:https://www.oracle.com/index.html,下载Oracle Database 12c Release 1 (注意:File1和File2都要下载!! ...

  7. android系统release签名

    转自:http://blog.csdn.net/yangkai6121/article/details/38682321 为什么需要给Android系统签个名才能进行CTS认证呢?原来我们通过make ...

  8. .NET 的 Debug 和 Release build 对执行速度的影响

    这篇文章发布于我的 github 博客:原文 在真正开始讨论之前先定义一下 Scope. 本文讨论的范围限于执行速度,内存占用什么的不在评估的范围之内. 本文不讨论算法:编译器带来的优化基本上属于底层 ...

  9. VS2008 Debug与Release的本质区别(转)

    如何设置:工具栏“生成”→“配置管理器”→“活动解决方案配置” 对于VS2008的初次使用者来说,常会遇到的编译问题时,Debug版本运行正常,但在Release版本则不稳定或无法运行.以下是对Deb ...

  10. Oracle Database 11g Release 2(11.2.0.3.0) RAC On Redhat Linux 5.8 Using Vmware Workstation 9.0

    一,简介 二,配置虚拟机 1,创建虚拟机 (1)添加三块儿网卡:   主节点 二节点 eth0:    公网  192.168.1.20/24   NAT eth0:    公网  192.168.1 ...

随机推荐

  1. NX二次开发-UFUN创建倒圆UF_MODL_create_blend

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> UF_initialize(); //创建块 UF_FEATURE_SIGN S ...

  2. phpstorm激活 破解 方法

    1.license server 在线激活方式 不是很推荐,自己有服务器的话可以考虑搭建 所以就不说了. 不过我在网上找了一些地址,可以用一下,不保证长期有效 http://idea.goxz.gq  ...

  3. IOS自动化打包介绍

    IOS自动化打包介绍  标签: app打包 , Ios打包 , iphone打包 , iphone自动化打渠道包    分类:无线客户端技术, 贴吧技术 摘要 随着苹果手持设备用户的不断增加,ios应 ...

  4. Linux服务器上监控网络带宽的18个常用命令nload, iftop,iptraf-ng, nethogs, vnstat. nagios,运用Ntop监控网络流量

    Linux服务器上监控网络带宽的18个常用命令 本文介绍了一些可以用来监控网络使用情况的Linux命令行工具.这些工具可以监控通过网络接口传输的数据,并测量目前哪些数据所传输的速度.入站流量和出站流量 ...

  5. Linux date命令 crontab每个月最后一天

    ###使用date获取日期时间等 # 当前日期 openstack@ubuntu:~$ date 2019年 01月 15日 星期二 15:10:49 CST # 明天 openstack@ubunt ...

  6. 三极管NPN和PNP开关电路

    0. 总结 NPN适合做低端驱动,即PN结在下面(低端),发射极E接地. PNP适合做高端驱动,即PN结在上面(高端),发射极E接VCC. Tips:标箭头的PN结,中间的是基极B,外头是E极. 1. ...

  7. PAT_A1020#Tree Traversals

    Source: PAT A1020 Tree Traversals (25 分) Description: Suppose that all the keys in a binary tree are ...

  8. Ant属性文件

    直接在构建文件中设置属性是好的,如果你使用的是少数属性.然而,对于一个大型项目,是要存储在一个单独的属性文件中. 存储在一个单独的文件中的属性可以让你重复使用相同的编译文件,针对不同的执行环境不同的属 ...

  9. HDU 3308 线段树求区间最长连续上升子序列长度

    题意:两种操作,Q L R查询L - R 的最长连续上升子序列长度,U pos val 单点修改值 #include <bits/stdc++.h> #define N 100005 us ...

  10. Reverses CodeForces - 906E (最小回文分解)

    题意: 给你两个串s和t,其中t是由s中选择若干个不相交的区间翻转得到的,现在要求求出最少的翻转次数以及给出方案. 1≤|s|=|t|≤500000 题解: 我们将两个字符串合成成T=s1t1s2t2 ...