《Linux设备驱动程序》ioctl详解
除了读取和写入设备之外,大部分驱动程序还需要通过设备驱动程序实行各种类型的硬件控制。简单的数据传输之外,大部分设备还可以执行其他一些操作,比如,用户空间经常会请求设备锁门,弹出介质,报告错误信息,改变波特率或者执行子破坏,等等。这些操作通常通过ioctl方法来支持。
ioctl在用户空间的原型:
int ioctl(int fd, unsigned long cmd, ...)
这里的...代表可变参数,他并不是代表任意数量的一组可变参数,通常,更具cmd来定,如果cmd不需要参数,那么...就不会被使用,如果cmd需要参数,则就会使用...所以,它只是代表一个可变参数。习惯上使用 char *argp来定义。这里使用...就是为了编译时防止编译器进行类型检查。
ioctl命令
每个驱动,都会有自己的ictol命令,那么在不同的驱动,不同类型设备的驱动之间,这些命令必须唯一标示出来,例如,我们对非串口设备使用设置波特率的命令,如果按照通常意义上将,对ioctl命令从0或者1开始编号,假设1在串口驱动中代表设置波特率,由于其他原因,我们错误的在非串口设备中使用1的时候,可能并没有发生错误,只是进行了其他的操作而已,那么这是在驱动程序中不允许的。但是如果ioctl命令编号是唯一的,那么就不会出现这种无意间成功的完成了意想不到的操作。
为了方便程序员唯一的创建ioctl命令编号,内核中作了如下规定:
每一个命令号被分为多个字段。新的内核(2.6)中,定义号码的新方法中使用4个字段来唯一标示一个命令。
中对个字段的位数做出了定义
type
幻数。选择一个号码,并在整个驱动程序中使用这个号码。
number
序数
direction
传输方向。_IOC_NONE(没有数据传输),_IOC_READ,_IOC_WRITE以及_IOC_READ|_IOC_WRITE(双向)这些方向。传输方向是站在应用程序的角度来看的。如果应用程序需要从驱动中读取数据,则方向应该是_IOC_READ。
size
所涉及的用户数据大小。对于大量数据传输可以忽略该字段。
以下是中对各个字段所占的位数做出了说明
#define _IOC_NRBITS 8 //序数占8位
#define _IOC_TYPEBITS 8 //幻数占8位
/*
* Let any architecture override either of the following before
* including this file.
*/
#ifndef _IOC_SIZEBITS //size字段
# define _IOC_SIZEBITS 14
#endif
#ifndef _IOC_DIRBITS
# define _IOC_DIRBITS 2 //direction 字段
#endif
对于自己的驱动,如果需要使用特定的ioctl命令,则必须创建ioctl命令以及编号。内核中给出了创建ioctl命令的宏
/* used to create numbers */
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))