linux 选择 ioctl 命令
在为 ioctl 编写代码之前, 你需要选择对应命令的数字. 许多程序员的第一个本能的反 应是选择一组小数从0或1 开始, 并且从此开始向上. 但是, 有充分的理由不这样做. ioctl 命令数字应当在这个系统是唯一的, 为了阻止向错误的设备发出正确的命令而引起 的错误. 这样的不匹配不会不可能发生, 并且一个程序可能发现它自己试图改变一个非串 口输入系统的波特率, 例如一个 FIFO 或者一个音频设备. 如果这样的 ioctl 号是唯一 的, 这个应用程序得到一个 EINVAL 错误而不是继续做不应当做的事情.
为帮助程序员创建唯一的 ioctl 命令代码, 这些编码已被划分为几个位段. Linux 的第 一个版本使用 16-位数: 高 8 位是关联这个设备的"魔"数, 低 8 位是一个顺序号, 在设 备内唯一. 这样做是因为 Linus 是"无能"的(他自己的话); 一个更好的位段划分仅在后 来被设想. 不幸的是, 许多驱动仍然使用老传统. 它们不得不: 改变命令编码会破坏大量 的二进制程序,并且这不是内核开发者愿意见到的.
根据 Linux 内核惯例来为你的驱动选择 ioctl 号, 你应当首先检查 include/asm/ioctl.h 和 Documentation/ioctl-number.txt. 这个头文件定义你将使用 的位段: type(魔数), 序号, 传输方向, 和参数大小. ioctl-number.txt 文件列举了在 内核中使用的魔数,[20]20 因此你将可选择你自己的魔数并且避免交叠. 这个文本文件也列 举了为什么应当使用惯例的原因.
定义 ioctl 命令号的正确方法使用 4 个位段, 它们有下列的含义. 这个列表中介绍的新 符号定义在 <linux/ioctl.h>.
但是, 这个文件的维护在后来有些少见了.
魔数. 只是选择一个数(在参考了 ioctl-number.txt 之后)并且使用它在整个驱动 中. 这个成员是 8 位宽(_IOC_TYPEBITS).
number
序(顺序)号. 它是 8 位(_IOC_NRBITS)宽. direction
数据传送的方向,如果这个特殊的命令涉及数据传送.
可能的值是 _IOC_NONE(没有 数据传输), _IOC_READ, _IOC_WRITE, 和 _IOC_READ|_IOC_WRITE (数据在 2 个方
向被传送). 数据传送是从应用程序的观点来看待的; _IOC_READ 意思是从设备读, 因此设备必须写到用户空间. 注意这个成员是一个位掩码, 因此
_IOC_READ 和
_IOC_WRITE 可使用一个逻辑 AND 操作来抽取.
size
涉及到的用户数据的大小. 这个成员的宽度是依赖体系的, 但是常常是 13 或者 14 位. 你可为你的特定体系在宏 _IOC_SIZEBITS 中找到它的值. 你使用这个 size 成员不是强制的
- 内核不检查它 -- 但是它是一个好主意. 正确使用这个成
员可帮助检测用户空间程序的错误并使你实现向后兼容, 如果你曾需要改变相关数 据项的大小. 如果你需要更大的数据结构, 但是, 你可忽略这个 size 成员. 我们 很快见到如何使用这个成员.
头文件
<asm/ioctl.h>, 它包含在 <linux/ioctl.h> 中, 定义宏来帮助建立命令号, 如 下:
_IO(type,nr)(给没有参数的命令), _IOR(type, nre, datatype)(给从驱动中读数据 的),
_IOW(type,nr,datatype)(给写数据), 和 _IOWR(type,nr,datatype)(给双向传送). type 和 number 成员作为参数被传递,
并且 size 成员通过应用 sizeof 到 datatype 参数而得到.
这个头文件还定义宏, 可被用在你的驱动中来解码这个号: _IOC_DIR(nr),
_IOC_TYPE(nr), _IOC_NR(nr), 和 _IOC_SIZE(nr). 我们不进入任何这些宏的细节,
因为 头文件是清楚的, 并且在本节稍后有例子代码展示.
这里是一些 ioctl 命令如何在 scull 被定义的. 特别地, 这些命令设置和获得驱动的可 配置参数.
/* Use 'k' as magic number */
#define SCULL_IOC_MAGIC 'k'
/* Please use a different 8-bit number in your code */
#define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)
/*
* S means
"Set" through a ptr,
* T means
"Tell" directly with the argument value
* G means
"Get": reply by setting through a pointer
* Q means
"Query": response is on the return value
* X means
"eXchange": switch G and S atomically
* H means
"sHift": switch T and Q atomically
*/
#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1,
int)
#define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)
#define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)
#define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)
#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5,
int)
#define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)
#define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)
#define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)
#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9,
int)
#define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int)
#define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)
#define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)
#define SCULL_IOC_MAXNR 14 真正的源文件定义几个额外的这里没有出现的命令.
我们选择实现 2 种方法传递整数参数: 通过指针和通过明确的值(尽管, 由于一个已存在
的惯例, ioclt 应当通过指针交换值). 类似地, 2 种方法被用来返回一个整数值:通过指 针和通过设置返回值. 这个有效只要返回值是一个正的整数; 如同你现在所知道的, 在从 任何系统调用返回时, 一个正值被保留(如同我们在 read 和 write 中见到的), 而一个 负值被看作一个错误并且被用来在用户空间设置 errno.[21] 21
"exchange"和"shift"操作对于 scull 没有特别的用处. 我们实现"exchange"来显示驱动
如何结合独立的操作到单个的原子的操作, 并且"shift"来连接"tell"和"query". 有时需
要象这样的原子的测试-和-设置操作, 特别地, 当应用程序需要设置和释放锁.
命令的明确的序号没有特别的含义. 它只用来区分命令. 实际上, 你甚至可使用相同的序 号给一个读命令和一个写命令, 因为实际的 ioctl 号在"方向"位是不同的, 但是你没有 理由这样做. 我们选择在任何地方不使用命令的序号除了声明中, 因此我们不分配一个返 回值给它. 这就是为什么明确的号出现在之前给定的定义中. 这个例子展示了一个使用命
令号的方法, 但是你有自由不这样做.
除了少数几个预定义的命令(马上就讨论), ioctl 的 cmd 参数的值当前不被内核使用, 并且在将来也很不可能. 因此, 你可以, 如果你觉得懒, 避免前面展示的复杂的声明并明 确声明一组调整数字. 另一方面, 如果你做了, 你不会从使用这些位段中获益, 并且你会 遇到困难如果你曾提交你的代码来包含在主线内核中. 头文件<linux/kd.h> 是这个老式 方法的例子, 使用 16-位的调整值来定义 ioctl 命令. 那个源代码依靠调整数因为使用 那个时候遵循的惯例, 不是由于懒惰. 现在改变它可能导致无理由的不兼容.
linux 选择 ioctl 命令的更多相关文章
- 使用Linux的alternatives命令替换选择软件的版本
上周在安装搜索引擎Elasticsearch时,要求安装比较新的java 版本,我选择了java 1.8.0,安装java 成功后使用java -version 发现使用的版本仍旧是1.6.0, 查询 ...
- 关于构造IOCTL命令的学习心得
在编写ioctl代码之前,需要选择对应不同命令的编号.为了防止对错误的设备使用正确的命令,命令号应该在系统范围内唯一,这种错误匹配并不是不会发生,程序可能发现自己正在试图对FIFO和audio等这类非 ...
- 构造IOCTL命令的学习心得-----_IO,…
在编写ioctl代码之前,需要选择对应不同命令的编号.为了防止对错误的设备使用正确的命令,命令号应该在系统范围内唯一,这种错误匹配并不是不会发生,程序可能发现自己正在试图对FIFO和audio等这类非 ...
- 例解 Linux 下 Make 命令
Linux 下 make 命令是系统管理员和程序员用的最频繁的命令之一.管理员用它通过命令行来编译和安装很多开源的工具,程序员用它来管理他们大型复杂的项目编译问题.本文我们将用一些实例来讨论 make ...
- 12个Linux进程管理命令介绍(转)
12个Linux进程管理命令介绍 [日期:2015-06-02] 来源:Linux中国 作者:Linux [字体:大 中 小] 执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的 ...
- Linux下rz命令使用的实例详解
Linux中rz命令和sz命令都可用于文件传输,而rz命令主要用于文件的上传,下面将通过几个实例来给大家详细介绍下Linux下rz命令的用法,一起来学习下吧. rz命令可以批量上传文件,当然也可上传单 ...
- linux 的 scp 命令 可以 在 linux 之间复制 文件 和 目录
转自:http://blog.csdn.net/snlying/article/details/6184102 Linux系统中scp命令的用法. scp就是secure copy的简写,用于在lin ...
- 从零单排Linux – 1 – 简单命令
从零单排Linux – 1 – 简单命令 Posted in: Linux 从零单排Linux – 1 一.Linux的简单命令: 1.忘记root密码: 读秒时按任意键进入 – e – ↓选择第二个 ...
- linux中screen命令的用法
http://www.9usb.net/201002/linux-screen-mingling.html 作为linux服务器管理员,经常要使用ssh登陆到远程linux机器上做一些耗时的操作.也许 ...
随机推荐
- UCloud-201809-001:Redis服务未授权访问漏洞安全预警
UCloud-201809-001:Redis服务未授权访问漏洞安全预警 尊敬的UCloud用户,您好! 发布时间 2018-09-11更新时间 2018-09-11漏洞等级 HighCVE编号 ...
- 类似淘宝五星点评 ,Jquery实现代码
<!--默认五星,根据鼠标点击判断--> <!DOCTYPE html><html lang="en"><head> <met ...
- PyCharm2019 永久激活
<!-- 2019激活码 2019-06-21新更新 --> D00F1BDTGF-eyJsaWNlbnNlSWQiOiJEMDBGMUJEVEdGIiwibGljZW5zZWVOYW1l ...
- PLAY2.6-SCALA(八) comet
Comet是指基于 HTTP 长连接的“服务器推”技术,是一种不需要客户端主动请求,服务端可以主动给客户端推送消息的技术. 1.使用chunked response来实现Comet chunked r ...
- 在一台机器上搭建多个redis实例
默认Redis程序安装在/usr/local/redis目录下: 配置文件:/usr/local/redis/redis.conf,该配置文件中配置的端口为默认端口:6379: Redis的启动命令路 ...
- oracle显示和设置环境变量
概述:可以用来控制输出的各种格式. (1)linesize 用于控制每行显示多少个字符,默认80个字符. 基本用法:set linesize 字符数 aql>show linesize sql ...
- HTTP请求模型
HTTP请求模型 HTTP请求模型 一.连接至Web服务器一个客户端应用(如Web浏览器)打开到Web服务器的HTTP端口的一个套接字(缺省为80). 例如:http://www.myweb.com: ...
- ADT上跑java application
Invalid layout of java.lang.String at value## A fatal error has been detected by the Java Runtime En ...
- 【vb.net机房收费系统】之sqlhelper 标签: 数据库 2015-05-17 10:47 819人阅读 评论(15)
在敲机房收费重构版的时候,用到了sqlhelper,当时不知道怎么开始,各种听别人说,张晗说,一定要用sqlhelper,特别好用,我当时没有用balabala~当时一听,哎哎哎,这个高级,要搞一搞, ...
- 归并排序及应用 (nyoj 117 求逆序数)
求逆序数 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...