ioctl使用方法
ioctl简介
kernel3.0之前,叫ioctl,之后改名为unlocked_ioctl。功能和接口基本相同,名字发生了变化
ioctl既可以往内核读也可以写,read/write在执行大数据量读/写时比较有优势。
在应用层调用ioctl函数时,内核会调用对应驱动中的ublocked_ioctl函数,向内核读写数据。
驱动内的unlocked_ioctl函数
unlocked_ioctl函数属于file_operations文件操作集的一个成员,结构体内函数的定义为:
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
//参数:句柄;接口命令;从应用层传入的据
//返回值:返回给应用层的数据
应用层的ioctl函数
定义在头文件<sys/ioctl.h>中,是个可变参数的函数
int ioctl(int fd, ind cmd, …);
//参数和返回值,和文件操作集里的unlocked_ioctl函数一致
//传给内核的参数可以省略
unlocked_ioctl接口命令规则
命令是一个整型参数(32位)
第一个分区:0-7,命令的编号,范围是0-255
第二个分区:8-15,命令的幻数
第三个分区:16-29,表示传递的数据的大小
第四分区:30-31,代表读写的方向
第一和第二分区,主要用来区分命令,不能有两个完全一样的“一+二”
第四分区:00:没有数据传递;10:用户从驱动读数据;01:用户向驱动写数据;11:先写数据到驱动再把数据读出来
接口命令相关的宏
合成宏,返回一个接口命令,可传入ioctl函数
_IO(type,nr) 没有数据传递的命令
_IOR(type, nr, size) 从驱动中读取数据的命令
_IOW(type, nr, size) 向驱动中写入数据的命令
_IOWR(type, nr, size) 交换数据的命令
//type表示数据的幻数,8-15位
//nr命令的编号,0-7位
//size参数传递的大小,传递的是数据类型:如果传递4字节,可以写成int
分解宏,将接口命令解析出需要的部分
_IOC_DIR(nr) 方向
_IOC_TYPE(nr) 幻数
_IOC_NR(nr) 编号
_IOC_SIZE(nr) 大小
//nr要分解的命令
示例代码
以杂项设备为例
驱动部分
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define CMD_TEST_0 _IO('A', 0) //不需要读写的命令
#define CMD_TEST_1 _IOR('A', 1, int) //从内核读取一个int的命令
#define CMD_TEST_2 _IOW('A', 2, int) //向内核写入一个int的命令
#define CMD_TEST_3 _IOWR('A', 3, int) //读写一个int的命令
int misc_open(struct inode *a,struct file *b){
printk("misc open \n");
return 0;
}
int misc_release (struct inode * a, struct file * b){
printk("misc file release\n");
return 0;
}
long misc_ioctl(struct file *fd, unsigned int cmd, unsigned long b){
/*将命令按内容分解,打印出来*/
printk("cmd type=%c\t nr=%d\t dir=%d\t size=%d\n", _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_DIR(cmd), _IOC_SIZE(cmd));
switch(cmd){
case CMD_TEST_0:
printk("CMD_TEST_0\n");
break;
case CMD_TEST_1:
printk("CMD_TEST_1\n");
return 1;
break;
case CMD_TEST_2:
printk("CMD_TEST_2 date=%d\n",b);
break;
case CMD_TEST_3:
printk("CMD_TEST_3 date=%d\n",b);
return b+1;
break;
}
return 0;
}
//文件操作集
struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.unlocked_ioctl = misc_ioctl
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "test_ioctrl", //设备节点名
.fops = &misc_fops
};
static int hello_init(void){
int ret;
ret = misc_register(&misc_dev); //注册杂项设备
if(ret < 0){
printk("misc regist failed\n");
return -1;
}
printk("misc regist succeed\n");
return 0;
}
static void hello_exit(void){
misc_deregister(&misc_dev);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TAXUE");
module_init(hello_init);
module_exit(hello_exit);
应用层部分
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<sys/ioctl.h>
#define CMD_TEST_0 _IO('A', 0)
#define CMD_TEST_1 _IOR('A', 1, int)
#define CMD_TEST_2 _IOW('A', 2, int)
#define CMD_TEST_3 _IOWR('A', 3, int)
int main(int argc, char *argv[]){
int fd=0;
int revData=0;
fd = open("/dev/test_ioctrl", O_RDWR);
if(fd < 0){
printf("open failed\n");
exit(1);
}
printf("open success\n");
/*依次调用四个命令*/
ioctl( fd, CMD_TEST_0);
revData = ioctl( fd, CMD_TEST_1);
printf("receive 1 data=%d\n", revData);
ioctl( fd, CMD_TEST_2, 99);
revData = ioctl( fd, CMD_TEST_3, 101);
printf("receive 3 data=%d\n", revData);
close(fd);
return 0;
}