Linux下的ioctl接口介绍及其应用
ioctl接口也叫做unlocked_ioctl接口。unlocked_ioctl和read/write函数的异同点:相同点:都可以往内核中写数据。不同点:read函数只能完成读的功能,write函数只能完成写的功能,ioctl既可以读也可以写,但在读取大数据时,ioctl的效率不及read/write函数。
文章目录
前言
本文的主要内容是Linux下的ioctl接口介绍及其应用,注意在写代码的过程中体会ioctl接口与read和write函数的异同。
一、ioctl接口介绍
ioctl接口也叫做unlocked_ioctl接口。
unlocked_ioctl和read/write函数的异同点:
相同点:都可以往内核中写数据。
不同点:read函数只能完成读的功能,write函数只能完成写的功能,ioctl既可以读也可以写,但在读取大数据时,ioctl的效率不及read/write函数。
unlocked_ioctl接口共有四个分区,分别如下:
第一个分区:0-7位,命令的编号,范围是0-255。
第二个分区:8-15位,命令的魔数(幻数)。
第一个分区和第二个分区的主要作用是用来区分命令。
第三个分区:16-29位,表示传递的数据大小。
第四个分区:30-31位,代表读写的方向。
30-31位的四种情况如下:
00:表示用户程序和驱动程序没有数据的传递;
01:表示用户程序向驱动里面写数据;
10:表示用户程序从驱动里面读数据;
11:表示用户程序先写数据到驱动,然后再从驱动里面把数据读出来。
命令的合成宏与分解宏:
合成宏:
_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) :分解命令的方向,30-31位。
_IOC_TYPE:分解命令的魔数(幻数),8-15位。
_IOC_NR(nr) :分解命令的编号,0-7位。
_IOC_SIZE(nr) :分解命令的复制数据的大小,16-29位。
参数:
nr:要分解的命令。
二、简单打印程序
1.代码文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#define CMD_TEST0 _IO('A',0)
#define CMD_TEST1 _IO('B',1)
#define CMD_TEST2 _IOW('A',2,int)
#define CMD_TEST3 _IOR('A',3,int)
int main(int argv,char *arg[])
{
printf("CMD_TEST0 30-31 bits is %d.\n",_IOC_DIR(CMD_TEST0));
printf("CMD_TEST3 30-31 bits is %d.\n",_IOC_DIR(CMD_TEST3));
printf("CMD_TEST0 7-15 bits is %c.\n",_IOC_TYPE(CMD_TEST0));
printf("CMD_TEST1 7-15 bits is %c.\n",_IOC_TYPE(CMD_TEST1));
printf("CMD_TEST2 0-7 bits is %d.\n",_IOC_NR(CMD_TEST2));
return 0;
}
2.运行结果
使用如下命令编译该文件。
gcc app.c -o app
然后运行该文件,其打印结果如下。
三、ioctl读写程序
1.ioctl.c文件
#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_TEST0 _IO('A',0)
#define CMD_TEST1 _IO('A',1)
#define CMD_TEST2 _IOW('A',2,int)
#define CMD_TEST3 _IOW('A',3,int)
#define CMD_TEST4 _IOR('A',4,int)
int misc_open(struct inode *inode, struct file *file)
{
printk("hello misc_open!\n");
return 0;
}
int misc_release(struct inode *inode, struct file *file)
{
printk("misc_release bye!\n");
return 0;
}
long misc_ioctl (struct file *file, unsigned int cmd, unsigned long value)
{
int val;
switch(cmd){
case CMD_TEST0:
printk("CMD_TEST0 is 0!\n");
break;
case CMD_TEST1:
printk("CMD_TEST1 is 1!\n");
break;
case CMD_TEST2:
printk("The CMD_TEST2's value is %d.\n",value);
break;
case CMD_TEST3:
printk("The CMD_TEST3's value is %d.\n",value);
break;
case CMD_TEST4:
val = 100;
if(copy_to_user((int *)value, &val, sizeof(val))!=0)
{
printk("copy_to_user error!\n");
return -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 = "misc_device", //设备节点的名字
.fops = &misc_fops
};
static int misc_init(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret < 0)
{
printk("miscdevice registered error!\n");
return -1;
}
printk("miscdevice registered ok!\n");
return 0;
}
static int misc_exit(void)
{
misc_deregister(&misc_dev);
printk("misc exit!\n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
2.Makefile文件
obj-m += ioctl.o
KDIR:=/linux/linux-4.1.15
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
3.app.c文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#define CMD_TEST0 _IO('A',0)
#define CMD_TEST1 _IO('A',1)
#define CMD_TEST2 _IOW('A',2,int)
#define CMD_TEST3 _IOW('A',3,int)
#define CMD_TEST4 _IOR('A',4,int)
int main(int argv,char *arg[])
{
int fd;
int value;
fd = open("/dev/misc_device", O_RDWR);
if(fd < 0)
{
perror("open error!\n");
return fd;
}
/*下面的三个while在编译时逐个编译,注释掉另外两个*/
/*1.通过宏直接置数*/
while(1)
{
ioctl(fd, CMD_TEST0); //这里的值就是传向long misc_ioctl (struct file *file, unsigned int cmd, unsigned long value)
sleep(1);
ioctl(fd, CMD_TEST1);
sleep(1);
}
/*2.写数*/
/*while(1)
{
ioctl(fd, CMD_TEST2,0);
sleep(1);
ioctl(fd, CMD_TEST3,1);
sleep(1);
}*/
/*3.读数*/
/*while(1)
{
ioctl(fd,CMD_TEST4,&value);
printf("value is %d.\n",value);
sleep(1);
}*/
return 0;
}
4.运行结果
1>.通过宏直接置数
运行结果如下。
2>.写数
运行结果如下。
3>.读数
运行结果如下。
总结
以上就是Linux下的ioctl接口介绍及其应用的所有内容了,通过这个例子,我们应该对ioctl接口的作用比较熟悉,相对来说,ioctl接口的代码量比read和write函数的要少一些,也更加简单明了。
本文参考视频:https://www.bilibili.com/video/BV1Vy4y1B7ta?p=32和https://www.bilibili.com/video/BV1Vy4y1B7ta?p=33。
更多推荐
所有评论(0)