ioctl接口
struct file_operations {
......
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
......
};
1.什么是unlocked_ioctl接口?
unlocked_ioctl就是ioctl接口,但是功能和对应的系统调用均没有发生变化。
2.unlocked_ioctl和read/write函数有什么相同点和不同点?
相同点:都可以往内核写数据。
不同点:read函数只能完成读的功能,write只能完成写的功能。读取大数据的时候效率高。
ioctl既可以读也可以写。读取大数据的时候效率不高。
所以: read/write专注于读写大量数据,因为效率很高, ioctl用来设置设备的配置和数据
3.unlocked_ioctl接口命令规则。
第一个分区:0-7,命令的编号,范围是0-255.
第二个分区:8-15,命令的幻数。
第一个分区和第二个分区主要作用是用来区分命令的。
第三个分区:16-29表示传递的数据大小。
第四个分区:30-31 代表读写的方向。
00:表示用户程序和驱动程序没有数据传递
10:表示用户程序从驱动里面读数据
01:表示用户程序向驱动里面写数据
11:先写数据到驱动里面然后在从驱动里面把数据读出来。
4.命令的合成宏与分解宏
头文件
#include <sys/ioctl.h>
合成宏:
_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(nr) 分解命令的魔数,也就是上面说8~15位的值
_IOC_NR(nr) 分解命令的编号,也就是上面说0~7位
_IOC_SIZE(nr) 分解命令的复制数据大小,也就是上面说的16~29位
参数说明:
nr :要分解的命令
ioctl函数
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。
它的调用函数如下:
int ioctl(int fd, unsigned long request, ...);
其中fd是用户程序打开设备时使用open函数返回的文件标示符,request是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,比如要传输的数据
返回值: 成功 返回0 失败 返回 -1 并置位错误码
_IO没有数据传递示例
ioctl.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CMD_TEST0 _IO('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
int main(int argc, const char *argv[])
{
int fd;
fd = open("/dev/hello_mise", O_RDWR);
if (fd < 0)
{
printf("open is error\n");
return -1;
}
while(1)
{
ioctl(fd, CMD_TEST0); //触发驱动中ioctl函数
sleep(2);
ioctl(fd, CMD_TEST1);
sleep(2);
}
return 0;
}
beep.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('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
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("hello mise_release bye bye\n");
return 0;
}
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
switch (cmd)
{
case CMD_TEST0:
printk("LED ON!!\n");
break;
case CMD_TEST1:
printk("LED OFF!!\n");
break;
default:
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 = "hello_mise", // 设备节点的名字
.fops = &misc_fops, // 文件操作集
};
static int mise_init(void)
{
int ret;
ret = misc_register(&misc_dev); // 注册杂项设备
if (ret < 0)
{
printk("misc register is error!\n");
return -1;
}
printk("mise register is ok!\n");
return 0;
}
static void mise_exit(void)
{
misc_deregister(&misc_dev); // 注销杂项设备
printk("misc gooodbye!\n");
}
module_init(mise_init);
module_exit(mise_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m +=beep.o
KDIR:=/home/mzx/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
运行结果
_IOW向驱动写入数据示例
ioctl.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CMD_TEST0 _IO('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
#define CMD_TEST2 _IOW('L', 2, int) //用来定义向驱动写入数据的命令
#define CMD_TEST3 _IOW('L', 3, int) //用来定义向驱动写入数据的命令
int main(int argc, const char *argv[])
{
int fd;
fd = open("/dev/hello_mise", O_RDWR);
if (fd < 0)
{
printf("open is error\n");
return -1;
}
while(1)
{
ioctl(fd, CMD_TEST2, 0); //触发驱动中ioctl函数
sleep(2);
ioctl(fd, CMD_TEST3, 1);
sleep(2);
}
return 0;
}
beep.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('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
#define CMD_TEST2 _IOW('L', 2, int) // 用来定义向驱动写入数据的命令
#define CMD_TEST3 _IOW('L', 3, 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("hello mise_release bye bye\n");
return 0;
}
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
switch (cmd)
{
case CMD_TEST0:
printk("LED ON!!\n");
break;
case CMD_TEST1:
printk("LED OFF!!\n");
break;
case CMD_TEST2:
printk("LED ON!!\n");
printk("value is %lu\n", value);
break;
case CMD_TEST3:
printk("LED OFF!!\n");
printk("value is %lu\n", value);
break;
default:
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 = "hello_mise", // 设备节点的名字
.fops = &misc_fops, // 文件操作集
};
static int mise_init(void)
{
int ret;
ret = misc_register(&misc_dev); // 注册杂项设备
if (ret < 0)
{
printk("misc register is error!\n");
return -1;
}
printk("mise register is ok!\n");
return 0;
}
static void mise_exit(void)
{
misc_deregister(&misc_dev); // 注销杂项设备
printk("misc gooodbye!\n");
}
module_init(mise_init);
module_exit(mise_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m +=beep.o
KDIR:=/home/mzx/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
运行结果
_IOR从驱动中读取数据示例
ioctl.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CMD_TEST0 _IO('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
#define CMD_TEST2 _IOW('L', 2, int) //用来定义向驱动写入数据的命令
#define CMD_TEST3 _IOW('L', 3, int) //用来定义向驱动写入数据的命令
#define CMD_TEST4 _IOR('L', 4, int) //用来定义从驱动中读取数据的命令
int main(int argc, const char *argv[])
{
int fd;
int value;
fd = open("/dev/hello_mise", O_RDWR);
if (fd < 0)
{
printf("open is error\n");
return -1;
}
while(1)
{
ioctl(fd, CMD_TEST4, &value); //触发驱动中ioctl函数
printf("value is %d\n", value);
sleep(2);
}
return 0;
}
beep.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('L', 0) // 用来定义没有数据传递的命令
#define CMD_TEST1 _IO('L', 1) // 用来定义没有数据传递的命令
#define CMD_TEST2 _IOW('L', 2, int) // 用来定义向驱动写入数据的命令
#define CMD_TEST3 _IOW('L', 3, int) // 用来定义向驱动写入数据的命令
#define CMD_TEST4 _IOR('L', 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("hello mise_release bye bye\n");
return 0;
}
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
int val;
switch (cmd)
{
case CMD_TEST0:
printk("LED ON!!\n");
break;
case CMD_TEST1:
printk("LED OFF!!\n");
break;
case CMD_TEST2:
printk("LED ON!!\n");
printk("value is %lu\n", value);
break;
case CMD_TEST3:
printk("LED OFF!!\n");
printk("value is %lu\n", value);
break;
case CMD_TEST4:
val = 12;
if(copy_to_user((int *)value, &val, sizeof(val)) != 0)
{
printk("copy_to_user is error\n");
return -1;
}
break;
default:
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 = "hello_mise", // 设备节点的名字
.fops = &misc_fops, // 文件操作集
};
static int mise_init(void)
{
int ret;
ret = misc_register(&misc_dev); // 注册杂项设备
if (ret < 0)
{
printk("misc register is error!\n");
return -1;
}
printk("mise register is ok!\n");
return 0;
}
static void mise_exit(void)
{
misc_deregister(&misc_dev); // 注销杂项设备
printk("misc gooodbye!\n");
}
module_init(mise_init);
module_exit(mise_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m +=beep.o
KDIR:=/home/mzx/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules