Linux建议如下表所示的方式定义ioctl() 的命令。
设备类型 | 序列号 | 方向 | 数据尺寸 |
---|---|---|---|
8位 | 8位 | 2位 | 13/14位 |
1、设备类型字段(8位)
命令码的设备类型字段为一个“幻数”,可以是0 ~ 0xff的值,内核中的ioctl-number.txt给出了一些推荐的和已经被使用的“幻数”,新设备驱动定义“幻数”的时候要避免与其冲突。
ioctl-number.txt文档中指出如下建议:
Some devices use their major number as the identifier; this is OK, as long as it is unique.
2、序列号(8位)
3、方向字段(2位)
该字段表示数据传送的方向,可能的值是_IOC_NONE(无数据传输)、_IOC_READ(读)、_IOC_WRITE(写)、_IOC_READ|_IOC_WRITE(双向)。数据传送的方向是从应用程序的角度来看的。
4、数据长度字段
该字段表示涉及的用户数据的大小,这个成员的宽度依赖于体系结构,通常是13或者14位。
内核定义了_IO()、_IOR()、_IOW()、_IOWR()这4个宏来辅助生成命令,其通用定义代码如下所示(来自/linux/ioctl.h):
#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)))
/* _IOC宏定义如下 */
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
/* _IOC_xxxSHIFT定义如下 */
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
/* 各字段占用bit位如下定义 */
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
# define _IOC_SIZEBITS 14 /* 有条件宏,故可自己定义 */
# define _IOC_DIRBITS 2 /* 有条件宏,故可自己定义 */
由_IOC_xxxSHIFT宏定义,命令码的高低位排列应如下:(左高右低)
方向 | 数据尺寸 | 设备类型 | 序列号 |
---|---|---|---|
2位 | 13/14位 | 8位 | 8位 |
5、以下是内核针对上述的命令码进行解码的宏:
/* 掩码宏 */
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)