什么是IOCTL
IOCTL是设备驱动程序中对设备的I/O通道进行管理的函数。所谓的I/O通道管理即设备参数读写、设备状态读、以及控制设备。
例如:控制串口传输的波特率、马达的转速等等。
功能:控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。用于向设备发控制和配置命令 ,有些命令需要控制参数,这些数据是不能用read / write 读写的,称为Out-of-band数据。也就是说,read / write 读写的数据是in-band数据,是I/O操作的主体,而ioctl 命令传送的是控制信息,其中的数据是辅助的数据。
IOCTL参数命令
long (*unlocked_ioctl)(struct file *filp, unsigned int cmd, unsigned long arg)
struct file *filp
由fd得到的file结构体
unsigned int cmd
命令码,设备驱动定义的,区分具体工作的编号
unsigned long arg
输入/出参数(可能是值,也可能是地址;如果要输出,必须是地址)
命令码的格式(即cmd的格式)
|type|nr|dir|size|
设备类型 | 序列号 | 方向 | 数据尺寸 |
---|---|---|---|
8bit | 8bit | 2bit | 13/14bit |
type:类型
nr:命令编号
dir:方向,读/写
size:参数大小
如何得到上面的命令码呢?
内核定义了 _IO() _OR() _IOW() _IOWR()几个宏命令来帮助生成命令,这几个宏如下:
函数定义在:/linux/asm/ioctl.h
_IO(type,nr) 定制控制命令码
_IOR(type,nr,size ) 定制读参数命令
_IOW(type,nr,size ) 定制写参数命令
_IOWR(type,nr,size ) 定制读写参数命令
还可以通过命令来提取相对应的参数
IOC_DIR(cmd) 提取读写方向
IOC_TYPE(cmd) 提取类型
IOC_NR(cmd) 提取命令码编号
IOC_SIZE(cmd) 提取读写参数的大小
工程实例
头文件
#ifndef MYCMD_H
#define MYCMD_H
#include <asm/ioctl.h>
#define CMDT 'A'
#define KARGL 36
struct karg{
int kval;
char kbuf[KARGL];
};
#define CMDOFF _IO(CMDT,0)
#define CMDON _IO(CMDT,1)
#define CMDR _IOR(CMDT,2,struct karg)
#define CMDW _IOW(CMDT,3,struct karg)
#endif
内核模块代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/device.h>
static struct class *cls = NULL;
#include "mycmd.h"
static int major = 0;
static int minor = 0;
const