要 按 Linux 内核的约定方法为驱动程序选择 ioctl 编 号,应该首先看看 include/asm/ioctl.h (我在网上下载的是2.6.29内核,在asm下没用找到ioctl.h文件,相应的变换到了目录asm-generic下)和 Doucumention/ioctl-number.txt 这 两个文件。头文件定义了要使用的位字段:类型(幻数)、序数、传送方向以及参数大小等。 ioctl-number.txt 文 件中罗列了内核所使用的幻数,选择自己的幻数要避免和内核冲突。以下是对 include/asm/ioctl.h 中 定义的宏的注释:
#define _IOC_NRBITS 8 // 序数( number )字段的字位宽度, 8bits
#define _IOC_TYPEBITS 8 // 幻数( type )字段的字位宽度, 8bits
#define _IOC_SIZEBITS 14 // 大小( size )字段的字位宽度, 14bits
#define _IOC_DIRBITS 2 // 方向( direction )字段的字位宽 度, 2bits
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) // 序数字段的掩 码, 0x000000FF
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) // 幻数字段的掩 码, 0x000000FF
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) // 大小字段的掩 码, 0x00003FFF
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) // 方向字段的掩 码, 0x00000003
#define _IOC_NRSHIFT 0 // 序数字段在整个 字段中的位移, 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) // 幻数字段的位 移, 8
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) // 大小字段的位 移, 16
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) // 方向字段的位 移, 30
/*
* Direction bits.
*/
#define _IOC_NONE 0U // 没有数据传输
#define _IOC_WRITE 1U // 向设备写入数 据,驱动程序必须从用户空间读入数据
#define _IOC_READ 2U // 从设备中读取数 据,驱动程序必须向用户空间写入数据
/*
*_IOC 宏将 dir , type , nr , size 四个参数组合成一个 cmd 参数,如下图:
*
*/

#define _IOC (dir ,type ,nr ,size ) /
(((dir ) << _IOC_DIRSHIFT) | /
((type ) << _IOC_TYPESHIFT) | /
((nr ) << _IOC_NRSHIFT) | /
((size ) << _IOC_SIZESHIFT))
/*
* used to create numbers
*/
// 构造无参数的命令编号
#define _IO (type ,nr ) _IOC(_IOC_NONE,(type ),(nr ),0)
// 构造从驱动程序中读取数据的命令编号
#define _IOR (type ,nr ,size ) _IOC(_IOC_READ,(type ),(nr ),sizeof(size ))
// 用 于向驱动程序写入数据命令
#define _IOW (type ,nr ,size ) _IOC(_IOC_WRITE,(type ),(nr ),sizeof(size ))
// 用 于双向传输
#define _IOWR (type ,nr ,size ) _IOC(_IOC_READ|_IOC_WRITE,(type ),(nr ),sizeof(size ))
/*
*used to decode ioctl numbers..
*/
// 从命令参数中解析出数据方向,即写进还是读出
#define _IOC_DIR (nr ) (((nr ) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
// 从命令参数中解析出幻数 type
#define _IOC_TYPE (nr ) (((nr ) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
// 从命令参数中解析出序数 number
#define _IOC_NR (nr ) (((nr ) >> _IOC_NRSHIFT) & _IOC_NRMASK)
// 从命令参数中解析出用户数据大小
#define _IOC_SIZE (nr ) (((nr ) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
/* ...and for the drivers/sound files... */
#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)