ioctrl
用户层ioctl 函数原型:
#include <sys/ioctl.h>
int ioctl(int fd, int cmd, ...) ;
这是一个可选参数函数,第3个参数为args。
fd: 文件描述符。
cmd: 控制命令。
arg: 参数。比如说控制定时器延时500ms,500ms 就是参数。
在 file_operations
中有以下两个函数:
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
除了struct file 以外后面连个参数都与应用层相同。
cmd 构建
cmd 参数是一个 无符号32 位数据,我们通常会定义成宏的形式,但是这个数据构建的规则由内核决定。
cmd 主要分为以下4个字段,每个字段都有不同的意义:
幻数 | 序列号 | 方向 | 数据尺寸 |
---|---|---|---|
8 bit | 8 bit | 2 bit | 8~14 bit |
---------- | -------- | ------- | ----------- |
幻数 : 实际上就是一个0~ 0xff 的数,,占8bit (_IOC_TYPEBITS) 。这个数是用来区分不同的驱动的。
序列号: 序数:用这个数来给自己的命令编号,占8bit (_IOC_NRBITS) ,我的程序从1开始排序。
数据传输方向: 占2bit(_IOC_DIRBITS)。如果涉及到要传参,内核要求描述一下传输的方向,传输的方向是以应用层的角度来描述的。
- _IOC_NONE:值为0,无数据传输。
- _IOC_READ:值为1,从设备驱动读取数据。
- _IOC_WRITE:值为2,往设备驱动写入数据。
- _IOC_READ | _IOC_WRITE:双向数据传输。
数据大小: 所传参数的长度。与体系结构相关,ARM下占14bit(_IOC_SIZEBITS),如果数据是int,内核给这个赋的值就是sizeof(int)。
内核提供了一些宏定义,让我们更方便构建cmd:
//type:类型 //nr:序号 //size:参数长度
_IO(type,nr) //没有参数的命令
_IOR(type,nr,size) //该命令是从驱动读取数据
_IOW(type,nr,size) //该命令是从驱动写入数据
_IOWR(type,nr,size) //双向数据传输
arg 参数类型
参数的类型是一个 无符号32字节的数据,虽然是这样,但是我们可以灵活多用,完全可以传一个地址过去(指针也是4字节),这样就很方便了,传的时候转型,使用的时候在转回来。