关于ioctl幻数构造

      在编写ioctl 代码之前,需要选择对应不同命令的编号。为了防止对错误的设备使用正确的命 令,命令号应该在系统范围内唯一,这种错误匹配并不是不会发生,程序可能发现自己正在试图对 FIFO 和 audio 等 这类非串行设备输入流修改波特率,如果每一个 ioctl 命令都是唯一的,应用程序进行这种操作时就 会得到一个 EINVAL 错误,而不是无意间成功地完成了意想不到的操作。

     要 按 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 参数,如下图:

*

*/

 500)this.width=500;" border=0>

 

#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)

ioctl 幻数一般是通过定义 ioctl 命令时使用的,可以在对应的头文件中查看。在 Linux 中,很多驱动程序都会定义自己的 ioctl 命令,这些命令的幻数一般都会在对应的头文件中定义。比如,在 Linux 内核源码的 include/uapi/linux/fs.h 头文件中,可以找到以下定义: ```c #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 #define _IOC_SIZEBITS 14 #define _IOC_DIRBITS 2 #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) #define _IOC_NONE 0U #define _IOC_WRITE 1U #define _IOC_READ 2U #define _IOC(dir,type,nr,size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ ((size) << _IOC_SIZESHIFT)) #define _IOC_TYPECHECK(t) (sizeof(t)) ``` 其中,_IOC_TYPEBITS 定义了 ioctl 命令的幻数长度,这里是 8 位,即一个字节。在定义具体的 ioctl 命令时,可以使用 _IO(type, nr)、_IOR(type, nr, size)、_IOW(type, nr, size)、_IOWR(type, nr, size) 等宏来定义,其中的 type 就是 ioctl 命令的幻数。比如,可以在驱动程序的头文件中找到类似以下的定义: ```c #define MYDRV_IOC_MAGIC 'm' #define MYDRV_IOC_GET_VERSION _IOR(MYDRV_IOC_MAGIC, 1, int) #define MYDRV_IOC_SET_PARAM _IOW(MYDRV_IOC_MAGIC, 2, mydrv_param_t) ``` 其中,MYDRV_IOC_MAGIC 定义了驱动程序的幻数为 'm',MYDRV_IOC_GET_VERSION 和 MYDRV_IOC_SET_PARAM 就是具体的 ioctl 命令。在用户空间程序中,可以通过 ioctl 函数调用这些命令,例如: ```c int fd = open("/dev/mydrv", O_RDWR); int version; if (ioctl(fd, MYDRV_IOC_GET_VERSION, &version) < 0) { perror("ioctl MYDRV_IOC_GET_VERSION failed"); return -1; } printf("My driver version: %d\n", version); close(fd); ``` 在这个例子中,MYDRV_IOC_GET_VERSION 就是一个 ioctl 命令,MYDRV_IOC_MAGIC 定义了这个命令的幻数。用户空间程序通过 ioctl 函数调用这个命令,并且将 version 作为参数传递给内核空间的驱动程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值