Unix编程之ioctl函数详解

我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围。写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑。

一、 什么是ioctl

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:

int ioctl(int fd, ind cmd, …);

其中fd是用户程序打开设备时使用open函数返回的文件标示符,cmd是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,这个参数的有无和cmd的意义相关。

ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数来控制设备的I/O通道。

二、 ioctl的必要性

如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那是蛮拧了。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。要记住,用户程序所作的只是通过命令码(cmd)告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

三、 ioctl如何实现

这是一个很麻烦的问题,我是能省则省。要说清楚它,没有四五千字是不行的,所以我这里是不可能把它说得非常清楚了,不过如果读者对用户程序是怎么和驱动程序联系起来感兴趣的话,可以看我前一阵子写的《write的奥秘》。读者只要把write换成ioctl,就知道用户程序的ioctl是怎么和驱动程序中的ioctl实现联系在一起的了。我这里说一个大概思路,因为我觉得《Linux设备驱动程序》这本书已经说的非常清楚了,但是得花一些时间来看。

在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作。怎么实现这些操作,这是每一个程序员自己的事情。因为设备都是特定的,这里也没法说。关键在于怎样组织命令码,因为在ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径。命令码的组织是有一些讲究的,因为我们一定要做到命令和设备是一一对应的,这样才不会将正确的命令发给错误的设备,或者是把错误的命令发给正确的设备,或者是把错误的命令发给错误的设备。这些错误都会导致不可预料的事情发生,而当程序员发现了这些奇怪的事情的时候,再来调试程序查找错误,那将是非常困难的事情。所以在Linux核心中是这样定义一个命令码的:

____________________________________

| 设备类型 | 序列号 | 方向 |数据尺寸|

|----------|--------|------|--------|

| 8 bit      | 8 bit    |  2 bit |8~14 bit|

|----------|--------|------|--------|

这样一来,一个命令就变成了一个整数形式的命令码;但是命令码非常的不直观,所以Linux Kernel中提供了一些宏。这些宏可根据便于理解的字符串生成命令码,或者是从命令码得到一些用户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送方向和数据传输尺寸。

这些宏我就不在这里解释了,具体的形式请读者察看Linux核心源代码中的宏,文件里给这些宏做了完整的定义。这里我只多说一个地方,那就是"幻数"。 "幻数"是一个字母,数据长度也是8,用一个特定的字母来标明设备类型,这和用一个数字是一样的,只是更加利于记忆和理解。就是这样,再没有更复杂的了。 更多的说了也没用,读者还是看一看源代码吧,推荐各位阅读《Linux 设备驱动程序》所带源代码中的short一例,因为它比较短小,功能比较简单,可以看明白ioctl的功能和细节。

时间: 2024-08-01 22:08:47

Unix编程之ioctl函数详解的相关文章

Unix编程之alarm函数详解

Unix下编程很容易遇到这个函数,我们可以先看下这个函数的介绍,用man工具,man alarm. 对于Unix系统的联机帮助中关于alarm函数的介绍如下: #include <unistd.h> unsigned int alarm(unsigned int seconds); 它的主要功能是设置信号传送闹钟.其主要功能用来设置信号SIGALRM在经过seconds指定的秒数后传送给目前的进程,如果在定时未完成的时间内再次调用了alarm函数,则后一次定时器设置将覆盖前面的设置,当seco

linux编程之pipe()函数详解_Linux

管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道.其中一个对管道进行写操作,另一个对管道进行读操作.对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据. #include<unistd.h> int pipe(int filedes[2]); 返回值:成功,返回0,否则返回-1.参数数组包含pipe使用的两个文件的描述符.fd[0]:读管道,fd[

Android编程之SurfaceView实例详解_Android

本文实例讲述了Android编程之SurfaceView用法.分享给大家供大家参考,具体如下: 关于surfaceView相关知识: View和SurfaceView主要区别: 1. View只能在UI线程中刷新,而SurfaceView可以在子线程中刷新 2. SurfaceView可以控制刷新频率 SurfaceView几个重要的方法: 1. 继承SurfaceView 后调用getHolder()方法可以获取到mSurfaceHolder对象这个对于可以控制SurfaceView的绘制 2

Android编程之Animation动画详解_Android

本文实例讲述了Android编程之Animation动画用法.分享给大家供大家参考,具体如下: Animations 一.Animations介绍 Animations是一个实现android UI界面动画效果的API,Animations提供了一系列的动画效果,可以进行旋转.缩放.淡入淡出等,这些效果可以应用在绝大多数的控件中. 二.Animations的分类 Animations从总体上可以分为两大类: 1.Tweened Animations:该类Animations提供了旋转.移动.伸展

java多线程编程之Synchronized关键字详解_java

本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章  一.分析 synchronized可以修饰实例方法,如下形式: public class MyObject { synchronized public void methodA() { //do something.... } 这里,synchronized 关键字锁住的是当前对象.这也是称为对象锁的原因. 为啥锁住当

Android编程之Animation动画详解

本文实例讲述了Android编程之Animation动画用法.分享给大家供大家参考,具体如下: Animations 一.Animations介绍 Animations是一个实现android UI界面动画效果的API,Animations提供了一系列的动画效果,可以进行旋转.缩放.淡入淡出等,这些效果可以应用在绝大多数的控件中. 二.Animations的分类 Animations从总体上可以分为两大类: 1.Tweened Animations:该类Animations提供了旋转.移动.伸展

linux时间函数详解

我们在编程中可能会经常用到时间,比如取得系统的时间(获取系统的年.月.日.时.分.秒,星期等 ),或者是隔一段时间去做某事,那么我们就用到一些时间函数. linux下存储时间常见的有两种存储 方式,一个是从1970年到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的. time_t 这种类型就是用来存储从1970年到现在经过了多少秒,要想更精确一点,可以用结构struct timeval,它精确 到微妙. struct timeval { long tv_sec ; /*秒*/ lon

PHP实现时间轴函数详解

本文将介绍如何实现基于时间轴的时间的转换. 首先我们要明白时间的几个函数: time():返回当前的 Unix 时间戳 date():格式化一个本地时间/日期. 应用举例: 格式化当前时间,输出:2010-10-11 05:27:35 strtotime():将任何英文文本的日期时间描述解析为 Unix 时间戳. 应用举例: 输出1天前的时间戳:1286861475 date_default_timezone_set():设定要用的默认时区. 一般我们设置北京时间:date_default_ti

Linux 内存映射函数 mmap()函数详解

一.概述 内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间.那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的. 以下是一个把普遍文件映射到用户空间的内存区域的示意图. 图一: 二.基本函数 mmap函数是unix/linux下的系统调用,详细内容可参考<Unix Netword programming>卷二12.2节. mma