Linux驱动学习—ioctl接口

news2024/11/26 15:29:06

1、unlock_ioctl和ioctl有什么区别?

kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针,取而代之的是unlocked_ioctl 。ioctl是老的内核版本中的驱动API,unlock_ioctl是当下常用的驱动API。unlocked_ioctl 实际上取代了用了很久的ioctl,主要的改进就是不再需要上大内核锁(BKL) (调用之前不再先调用lock_kernel()然后再unlock_kernel())。

2、unlock_ioctl和read/write函数有什么相同点和不同点

相同点:都可以往内核里面写数据。

不同点:read函数只能完成读的功能,write只能完成写的功能。读取大数据的时候效率高。ioctrl既可以读也可以写。读取大数据的时候效率不高。

3、unlock_ioctl接口命令规则

第一个分区:0-7位,命令的编号,范围是0-255。

第二个分区:8-15位,命令的幻数。

注意:第一个分区个第二个分布主要作用是用来区分命令的。

第三个分区:16-29位表示传递的数据大小。

第四个分区:30-31位代表读写的方向。

00:表示用户程序和驱动程序没有数据传递。
10:表示用户程序从驱动里面读数据。
01:表示用户程序向驱动里面写数据。
11:表示先写数据到驱动里面,然后在从驱动里面把数据读出来。

这四个分区的示例图如下:

img

4、命令的合成宏与分解宏

4.1 合成宏

在include\uapi\asm-generic\ioctl.h

#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
注释如下:
_IO(type,nr)用来定义没有数据传递的命令
_IOR(type,nr,size)用来定义从驱动中读取数据的命令
IOW(type,nr,size)用来定义从驱动中写入数据的命令
_IOWR(type,nr,size)用来定义输一局交换类型的命令,先写入数据,在读取数据这类命令。
参数:
type:表示命令的组成的魔数,也就是8-15位。
nr:表示命令组成的编号,也就是0-7位。
size:表示命令组成的参数传递大小,注意这里不是传递数字,而是传递数据类型,如要传递4字节,就可以写成int.

4.2 分解宏

#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)     (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
注释如下:
_IOC_DIR(nr)是分解命令的方向,也就是上面说30-31位的值。
_IOC_TYPE(nr)分解命令的魔数,也就是上面说的8-15位的值。
_IOC_NR(nr)分解命令的编号,也就是上面说的0-7位。
_IOC_SIZE(nr)分解命令的复制数据大小,也就是上面说的16-29位。
参数说明:
nr:要分解的命令

5、实验:在应用层使用命令合成宏和命令分解宏

值得注意的是,内核中使用的合成宏和分解宏与应用层使用的是一样的。其实可以用户和内核空间共用的头文件,里面是ioctl命令的构成和头文件。但本实例在应用层演示其使用,所以就不定义共用的头文件了。

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOR("L",3,int)
​
int main(int argc, char *argv[])
{
    printf("30-31 is %d\n",_IOC_DIR(CMD_TEST0));
    printf("30-31 is %d\n",_IOC_DIR(CMD_TEST3));
    
    printf("8-15 is %d\n",_IOC_TYPE(CMD_TEST0));
    printf("8-15 is %d\n",_IOC_TYPE(CMD_TEST1));
    
    printf("0-7 is %d\n",_IOC_NR(CMD_TEST2));
}

6、实验:驱动层和应用层使用ioctl

6.1 驱动层代码

#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("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOW("L",3,int)
#define CMD_TEST4 _IOR("L",4,int)
​
ssize_t misc_read(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = "heheh";
    
    if(copy_to_user(ubuf, kbuf, strlen(kbuf)) != 0) {
        printk("copy_to_user error\n");
        return -1;
    }
    return 0;
}
​
ssize_t misc_wirie(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{
    char kbuf[64] = {0};
    
    if(copy_form_user(kbuf, ubuf, strlen(kbuf)) != 0) {
        printk("copy_form_user error\n");
        return -1;
    }
    printk("kbuf is %s\n",kbuf);
    return 0;
}
​
int misc_open(struct inode *inode, struct file *file)
{
    printk("misc_open \n");
    return 0;
}
​
int misc_release(struct inode *inode, struct file *file)
{
    printk("misc_release \n");
    return 0;
}
​
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
    int val = 0;
    
    switch(cmd)
    {
        case CMD_TEST2:
            printk("LEN ON!\n");
            printk("value is %d!!\n",value);
        break;
        case CMD_TEST3:
            printk("LEN OFF!\n");
            printk("value is %d!!\n",value);
        break;
        case CMD_TEST4:
            val = 12;
            if(copy_to_user((int *)value, &val, sizeof(val)) != 0) {
                printk("copy_to_user error\n");
                 return -1;
             }
        break;  
    }
}
struct file_operations misc_fops={
    .owner = THIS_MODULE,//owner 指针指向的就是你的模块
    .open  = misc_open,
    .release = misc_release,
    .read   = misc_read,
    .write  = misc_write,
    .unlocked_ioctrl = misc_ioctl 
};
    
struct miscdevice misc_dev={
    .minor=MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR动态分配次设备号
    .name = "hello_misc",
    .fops = &misc_fops,
};
​
static int misc_init(void)
{
    int ret;
    ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("misc register is error \n");
        return ret;
    }
    printk("misc register is succeed \n");
    return 0;
}
​
static void misc_exit(void)
{
    misc_deregister(&misc_dev);
    printk("misc_exit \n");
}
​
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

6.2应用层ioctl函数

和open read write函数同理,当在应用层代码中调用ioctl接口的时候,其实调用的内核file_operations的unlocked_ioctl结构体成员。

#include <sys/ioctl.h> 
int ioctl(int fd, int cmd, ...) ;
参数1:设备描述符
参数2:指令,如某一个命令对应驱动层的某一个功能
参数3:可变参数,跟命令有关,传递进入驱动层的参数或者是接收数据的缓存
返回值:成功:返回 0,失败:返回 -1,并设置全局变量 errorno 值

6.3应用层代码

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",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, char *argv[])
{
    int fd; 
    fd = open("/dev/hello_misc",O_RDWR);
    if (fd < 0) {
        perror("open error");
        return fd;
    }
    while (1) {
        ioctl(fd,CMD_TEST2,0);
        sleep(2);
        ioctl(fd,CMD_TEST3,1);
        sleep(2);
    }
    return 0;
}

6.4 修改应用层代码,使得用到宏IOR

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",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, char *argv[])
{
    int fd; 
    fd = open("/dev/hello_misc",O_RDWR);
    if (fd < 0) {
        perror("open error");
        return fd;
    }
    while (1) {
        ioctl(fd,CMD_TEST4,&value);
        printf("value is %d\n",value);
        sleep(2);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1349655.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

易舟云财务软件使用教程【文章目录】

易舟云财务软件使用教程【文章目录】 1、财务软件导论2、易舟云财务软件3、财务软件原理4、账套5、会计凭证6、资金日记账7、发票8、员工工资9、固定资产10、期末处理(结转与结账)11、会计账簿12、财务报表13、财务软件设置 1、财务软件导论 财务软件导论 2、易舟云财务软件 …

STM32与TB6612电机驱动器的基础入门教程

TB6612是一款常用的双路直流电机驱动芯片&#xff0c;适用于小型机器人以及其他需要控制电机方向和转速的应用。在STM32微控制器的配合下&#xff0c;可以实现对TB6612电机驱动器的控制&#xff0c;进而实现电机的控制。本文将带领读者一步步了解如何搭建基于STM32与TB6612的电…

Android 13 - Media框架(29)- MediaCodec(四)

上一节我们了解了如何通过 onInputBufferAvailable 和 getInputBuffer 获取到 input buffer index&#xff0c;接下来我们一起学习上层如何拿到buffer并且向下写数据的。 1、获取 input Buffer 获取 MediaCodec 中的 buffer 有两种方式&#xff0c;一种是调用 getInputBuffers…

Linux:/proc/sys/vm/目录各文件详解

目录 前言一、/proc/sys/vm/目录各文件二、相关功能的API函数 前言 /proc/sys/vm/ 目录是 Linux 系统中的一个特殊目录&#xff0c;它包含了与虚拟内存子系统相关的系统内核参数。这些参数可以用来配置系统的虚拟内存管理策略&#xff0c;包括内存分配、页面置换、内存压缩、NU…

【软件工程】航行敏捷之路:深度解析Scrum框架的精髓

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 Scrum&#xff08;敏捷开发框架之一&#xff09; 详细介绍和解释&#xff1a; 优缺点&#xff1a; 优点&#xff1a; 缺点&…

2.3 设计FMEA步骤三:功能分析

2.3.1 目的 设计功能分析确保要求/规范中的功能适当分配给系统要素。分析必须使用功能术语进行编写。 功能分析地主要目标是: 产品或过程功能可视化。制作功能树/网或功能分析表格和参数图(P图)。展开与顾客(内部和外部)功能相关的要求。将要求或特性与功能关联。促进工…

cocos creator + vscode debug

安装插件 安装插件&#xff1a;JavaScript Debugger 配置 7456 为本地cocos creator的启动端口 启动debug调试 选择对应的启动方式

计算机网络第一课

先了解层级&#xff1a; 传输的信息称为协议数据单元&#xff08;PDU&#xff09;&#xff0c;PDU在每个层次的称呼都不同&#xff0c;见下图&#xff1a;

关于MySQL Cluster

目录 1.MySQL Cluster2.MySQL Cluster架构3.MySQL Cluster 与 MySQL 主从架构有什么区别4.参考 MySQL Cluster是MySQL的一个高可用性&#xff0c;高性能的分布式数据库解决方案。它结合了内存数据库和共享无状态架构的技术&#xff0c;提供了99.999%的可用性&#xff0c;满足严…

三、C语言中的分支与循环—循环嵌套 (9)

嵌套循环指的是一个循环内部包含另一个循环。外层循环每执行一次&#xff0c;内层循环会执行完其所有的迭代。嵌套循环经常被用来处理多维数据结构&#xff0c;如多维数组&#xff0c;或者在进行复杂的算法操作时&#xff0c;如排序和搜索算法。 嵌套循环可以是任意类型的循环…

excel统计分析——单因素方差分析

参考资料&#xff1a;生物统计学 方差分析是将总变异分解为组间变异的方差和组内变异的方差&#xff0c;并通过F检验推断处理效应是否显著的过程&#xff0c;而方差是通过平方和与自由度计算出来的&#xff0c;所以方差分析首先需要进行平方和与自由度的分解。具体步骤如下&…

RedisTemplate序列化

SpringBoot整合Redis&#xff0c;配置RedisTemplate序列化。如果使用StringRedisTemplate&#xff0c;那么不需要配置序列化&#xff0c;但是StringRedisTemplate只能存储简单的String类型数据&#xff0c;如图&#xff1a; 如果使用StringRedisTemplate存储一个常规对象&#…

【Unity入门】MenuItem 和 ContextMenu 的使用方法

目录 一、ContextMenu描述使用示例ContextMenuItem使用示例 二、MenuItem描述使用示例 三、MenuItem 和 ContextMenu 的区别 一、ContextMenu 描述 ContextMenu 属性用于向上下文菜单添加命令。 在该附加脚本的 Inspector 中&#xff0c;当用户选择该上下文菜单时&#xff0c…

RO-NeRF论文笔记

RO-NeRF论文笔记 文章目录 RO-NeRF论文笔记论文概述Abstract1 Introduction2 Related Work3 Method3.1 RGB and depth inpainting network3.2 Background on NeRFs3.3 Confidence-based view selection3.4 Implementation details 4 Experiments4.1 DatasetsReal ObjectsSynthe…

中科亿海微UART协议

引言 在现代数字系统设计中&#xff0c;通信是一个至关重要的方面。而UART&#xff08;通用异步接收器/发送器&#xff09;协议作为一种常见的串行通信协议&#xff0c;被广泛应用于各种数字系统中。FPGA&#xff08;现场可编程门阵列&#xff09;作为一种灵活可编程的硬件平台…

数据结构-十大排序算法

数据结构十大排序算法 十大排序算法分别是直接插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序、基数排序、外部排序。 其中插入排序包括直接插入排序、折半插入排序、希尔排序&#xff1b;交换排序包括冒泡排序、快速排序&#xff1…

c++ / day03

1. 定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xf…

经典卷积神经网络-ResNet

经典卷积神经网络-ResNet 一、背景介绍 残差神经网络(ResNet)是由微软研究院的何恺明、张祥雨、任少卿、孙剑等人提出的。ResNet 在2015 年的ILSVRC&#xff08;ImageNet Large Scale Visual Recognition Challenge&#xff09;中取得了冠军。残差神经网络的主要贡献是发现了…

萨姆·奥尔特曼的预言

Sam Altman&#xff08;萨姆奥尔特曼&#xff09;是 OpenAI 的首席执行官&#xff0c;这家初创公司开发了众所周知的 ChatGPT。2023年11月&#xff0c;他突然被董事会解雇&#xff0c;并短暂调往微软。在 OpenAI 的每个人都威胁要辞职后&#xff0c;他又回来了。 新的商业模式…

2024年Mac专用投屏工具AirServer 7 .27 for Mac中文版

AirServer 7 .27 for Mac中文免费激活版是一款Mac专用投屏工具&#xff0c;能够通过本地网络将音频、照片、视频以及支持AirPlay功能的第三方App&#xff0c;从 iOS 设备无线传送到 Mac 电脑的屏幕上&#xff0c;把Mac变成一个AirPlay终端的实用工具。 目前最新的AirServer 7.2…