首页 > 其他分享 >16_ioctl接口

16_ioctl接口

时间:2024-04-30 15:33:06浏览次数:21  
标签:16 int CMD misc 接口 ioctl printk include

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

运行结果

image-20240425205129990

_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

运行结果

image-20240425205911582

_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

运行结果

image-20240425211622757

标签:16,int,CMD,misc,接口,ioctl,printk,include
From: https://www.cnblogs.com/mzx233/p/18168107

相关文章

  • TypeScript入门3:接口、多态
    //接口:通常情况下,接⼝中只会包含属性和⽅法的声明,⽽不包含具体的实现细节,具体的细节由其实现类完成interfacePerson9{id:number;name:string;age:number;introduce():void;}//实现类中,需要包含接⼝属性的赋值逻辑,以及接⼝⽅法的实现逻辑classStudent9im......
  • Go语言系列——数组和切片、可变参数函数、Maps、字符串、指针、结构体、方法、接口(一
    文章目录11-数组和切片数组数组的声明数组是值类型数组的长度使用range迭代数组多维数组切片创建一个切片切片的修改切片的长度和容量使用make创建一个切片追加切片元素切片的函数传递多维切片内存优化12-可变参数函数什么是可变参数函数语法通过一些例子理解可变参......
  • fiddler 修改请求接口的返回结果
    修改返回结果Response结果有两种方式,一种把结果写在文件中,一种直接修改接口返回的结果第一种:把response结果放在txt文件中让其访问txt的内容response.txt文件中内容如下:{"code":0,"msg":"查询成功!","count":0,"data":[]}操作步骤:1、点击需要修改response的url2、......
  • 【LeetCode 1648】销售价值减少的颜色球
    题目描述原题链接:LeetCode.1648销售价值减少的颜色球解题思路题意很容易理解,就是每次挑剩余同色球数量最大的颜色卖得到最大价值,总共卖orders个球的最大总价值;最快速直观暴力的解法是按照同色球数量排序,每次取数量最大值累加到总价值中并且将数量减一后重新排序,重复or......
  • C#接口的主要特点
    C#接口(Interface)是一种引用类型,它定义了一组契约或规范,这些契约或规范由方法、属性、事件或索引器组成。接口本身不实现任何成员,而是由实现它的类或结构来提供具体实现。C#接口的主要特点:不能包含访问修饰符:接口中的成员不能包含访问修饰符,默认为public。不能包含字段、常量或......
  • C#接口、抽象类、普通类和继承(子类与父类)都有其特定的用途和场景
    在C#(以及许多其他面向对象的编程语言中),接口、抽象类、普通类和继承(子类与父类)都有其特定的用途和场景。选择使用哪种机制通常取决于你的具体需求和设计目标。不过,关于“能使用接口就不用抽象类,能使用抽象类就不用类,能用父类就不用子类”的说法,这并不完全准确,因为每种机制都有其独......
  • BST二叉查找树的接口设计
    /***********************************************************************************************************设计BST二叉查找树的接口,为了方便对二叉树进行节点的增删,所以采用双向不循环链表实现,每个节点内部都需要*有2个指针,分别指向该节点的左子树(lchild)和右子树......
  • 接口测试框架选择
    接口测试是现在比较有性价比的自动化测试方法目前常见的接口测试框架是1.Python+unittest+HtmlTestRunner;2.Python+Pytest+allure。下面描述一下2种框架的大概区别,可以自行判断使用的框架1、准备工作unittest是python自带的库,不用安装。可直接使用,该框架下需要仅需安......
  • MURF1640CT-ASEMI逆变器专用MURF1640CT
    编辑:llMURF1640CT-ASEMI逆变器专用MURF1640CT型号:MURF1640CT品牌:ASEMI封装:TO-220F正向电流(IF):16A反向电压(VRRM):400V正向电压(VF):0.95V工作温度:-55°C~150°C反向恢复时间:35ns芯片个数:2芯片尺寸:86mil引脚数量:3浪涌电流(IFMS):175A包装方式:50/管1000/盘3000/箱MURF1640CT......
  • 接口自动化要准备哪些内容?
    接口自动化测试是通过编写脚本来模拟用户操作和验证接口功能的自动化测试过程。为了进行接口自动化测试,你需要准备以下内容:接口文档:获取准确的接口文档,包括API端点、请求方法、参数、返回数据结构等信息。这些文档通常由后端开发人员提供。自动化测试工具:选择适合的自动化测......