Linux驱动学习—ioctl接口

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器监控软件夜莺部署(一)

文章目录 一、夜莺介绍1. 简介2. 相关网站 二、夜莺部署1. 部署架构2. Docker启动3. 配置数据源4. 内置仪表盘效果5. 时序指标效果 一、夜莺介绍 1. 简介 夜莺监控系统是一款专业的服务器监控软件&#xff0c;它可以帮助用户实时监测服务器的CPU、内存、磁盘利用率等。 夜莺监…

0101包冲突导致安装docker失败-docker-云原生

文章目录 1 前言2 报错3 解决结语 1 前言 最近在学习k8s&#xff0c;前置条件就是要安装指定版本的docker&#xff0c;命令如下 yum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io-1.4.62 报错 file /usr/libexec/docker/cli-plugins/docker-buildx fr…

动态内存管理篇

为什么要动态内存分配&#xff1f; 之前&#xff0c;我们向内存申请空间&#xff0c;有两种方式&#xff0c;一种是定义变量&#xff0c;一种是建立数组&#xff1b;但是&#xff0c;这两种方式都有缺陷&#xff0c;创建的空间大小是固定的&#xff0c;在程序的运行过程中&…

听GPT 讲Rust源代码--library/alloc(2)

File: rust/library/alloc/src/vec/mod.rs 在Rust源代码中&#xff0c;rust/library/alloc/src/vec/mod.rs这个文件是Rust标准库中的Vec类型的实现文件。Vec是一个动态大小的数组类型&#xff0c;在内存中以连续的方式存储其元素。 具体来说&#xff0c;mod.rs文件中定义了以下…

我的512天创作者纪念日总结:高效、高现

文章目录 512天创作者纪念日&#xff1a;2023年的12月31日CSDN的512天消息提醒第一篇文章&#xff0c;最后一篇文章总计847篇文章&#xff0c;每月发文分布512天&#xff0c;各专栏文章统计512天&#xff0c;互动总成绩 512天创作者纪念日&#xff1a;2023年的12月31日 2023年…

【Linux C | 文件I/O】fcntl函数详解 | 设置描述符非阻塞、文件(记录)锁

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

什么情况下不应该使用 LockWindowUpdate ?

在之前的文章中&#xff0c;我们将了解了 LockWindowUpdate 应该在什么场景下使用&#xff0c;也就是拖动的场景。 今天&#xff0c;我们来看看 LockWindowUpdate 被误用的一些场景。 人们看到 LockWindowUpdate 的“您锁定的窗口将无法重新绘制自身”行为&#xff0c;并将其…

ToDesk Linux 客户端安装(欧拉系统)

下载链接 下载链接 https://newdl.todesk.com/linux/todesk-v4.3.1.0-x86_64.rpm &#xff08;使用4.3.1.0覆盖安装后&#xff0c;临时密码将会变更&#xff09; 安装命令&#xff1a; sudo rpm -Uvh todesk-v4.3.1.0-x86_64.rpm启动命令&#xff1a; todesk启动命令只能在桌…

Spring通信传参的方法

Spring通信传参的方法 目录概述需求&#xff1a; 设计思路实现思路分析1.简单参数传递2.复合参数3.动态参数 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better resul…

typescript,eslint,prettier的引入

typescript 首先用npm安装typescript&#xff0c;cnpm i typescript 然后再tsc --init生成tsconfig.json配置文件&#xff0c;这个文件在package.json同级目录下 最后在tsconfig.json添加includes配置项&#xff0c;在该配置项中的目录下&#xff0c;所有的d.ts中的类型可以在…

[新版Hi3531DV200 性能强悍]

新版Hi3531DV200 性能强悍 Hi3531DV200是针对多路高清/超高清&#xff08;1080p/4M/5M/4K&#xff09;DVR产品应用开发的新一代专业SoC芯片。Hi3531DV200集成了ARM A53四核处理器和性能强大的神经网络推理引擎&#xff0c;支持多种智能算法应用。同时&#xff0c;Hi3531DV200还…

听GPT 讲Rust源代码--library/alloc

File: rust/library/alloc/benches/slice.rs 在Rust源代码中&#xff0c;rust/library/alloc/benches/slice.rs文件的作用是对&[T]类型&#xff08;切片类型&#xff09;进行性能基准测试。该文件包含了对切片类型的一系列操作的基准测试&#xff0c;例如切片迭代、切片排序…

面试高频算法专题:数组的双指针思想及应用(算法村第三关白银挑战)

所谓的双指针其实就是两个变量&#xff0c;不一定真的是指针。 快慢指针&#xff1a;一起向前走对撞指针、相向指针&#xff1a;从两头向中间走背向指针&#xff1a;从中间向两头走 移除值为val的元素 题目描述 27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 给你…

Spring Boot案例-员工分页查询

准备工作: 数据库的连接: #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://localhost:3306/tlias #连接数据库的用户名 spring.datasource.usernameroot #连接数据库的密码 spring.datasource.p…

SpringBoot 医药咨询系统

概述 智慧医药系统&#xff08;smart-medicine&#xff09;是一个基于 SpringBoot 开发的Web 项目。整体页面简约大气&#xff0c;增加了AI医生问诊功能&#xff0c;功能设计的较为简单。 开源地址 https://gitcode.net/NVG_Haru/Java_04 界面预览 功能介绍 游客功能介绍 …

Java多线程之线程池,volatile,悲观锁,乐观锁,并发工具类

目录 1.线程池核心原理1.创建线程池2.任务拒绝策略3.自定义线程池 2.线程池的大小1.最大并行数2.影响线程池大小的因素 3.多线程常见考点&#xff08;volatile&#xff0c;悲观锁&#xff0c;乐观锁&#xff09;4.并发工具类 1.线程池核心原理 ①创建一个空的池子 ②提交任务时…

c++写入数据到文件中

假设你想编写一个C程序&#xff1a;当你在调试控制台输入一些数据时&#xff0c;系统会自动存入到指定的文件中&#xff0c;该如何操作呢&#xff1f; 具体操作代码如下&#xff1a; #include<iostream> #include<string> #include<fstream> using namespa…

Spring Boot日志:从Logger到@Slf4j的探秘

写在前面 Hello大家好&#xff0c;今日是2024年的第一天&#xff0c;祝大家元旦快乐&#x1f389; 2024第一篇文章从SpringBoot日志开始 文章目录 一、前言二、日志有什么用&#xff1f;三、日志怎么用&#xff1f;四、自定义日志打印&#x1f4ac; 常见日志框架说明4.1 在程序…

【教3妹学编程-算法题】一年中的第几天

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开森。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;经过了一周多的寒潮&#xff0c;天气总算暖和些了。 2哥&#xff…

VUE——IDEA 启动前端工程VS文件启动前端工程

IDEA 启动前端 目录 前言一、打开控制台二、输入npm install三、依赖下载完之后&#xff0c;输入npm run dev&#xff0c;运行前端项目1、IDEA启动前端工程2、文件目录启动前端工程 四、点击http://localhost:8080后续敬请期待 前言 启动已有的vue前端项目 一、打开控制台 选…