Linux内核之宏_IOWR:如何生成ioctl控制命令(六十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.Linux内核之_IOWR宏介绍
    • 🌻3.代码实例
      • 🐓3.1 _IOWR宏实现
      • 🐓3.2 _IOWR内核中使用
      • 🐓3.3 _IOWR用法实例
        • 🐓3.4 问题一:#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device)的_IOWR中,用法区别是什么?
        • 🐓3.5 问题二:#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device)的_IOWR中,为什么它俩的编号都是1?
        • 🐓3.6 问题三:#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device)的_IOWR中,编号可以随意定义吗?

🌻1.前言

本篇目的:Linux内核之宏_IOWR:如何生成ioctl控制命令

🌻2.Linux内核之_IOWR宏介绍

  • 在Linux内核中,_IOWR是一个宏,用于生成系统调用中ioctl命令代码的一部分。ioctl(“input/output control”)系统调用是Linux中用于与设备文件交互的接口,它允许用户空间程序向设备驱动发送控制命令,并可能传递或接收数据。
  • _IOWR宏用于构造一个ioctl命令,该命令支持双向数据传输,即可以同时从用户空间读取数据和向用户空间写入数据。这个宏通常在内核头文件<linux/ioctl.h>中定义,其定义类似于:
#define _IOWR(type, nr, size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (size))
  • 这里的参数有:
  • type:一个唯一的字母标识符,通常是大写,用于标识设备类型。
  • nr:命令编号,用于区分同一个设备类型的不同命令。
  • size:数据的大小,即用户空间和内核空间之间传递的数据的大小。
  • 使用_IOWR宏,设备驱动程序可以定义一个ioctl命令,如下所示:
#define MYDEV_IOC_MAGIC 'M'
#define MYDEV_IOCI_CMD _IOWR(MYDEV_IOC_MAGIC, 1, sizeof(mydev_ioctl_data))
  • 在这里,MYDEV_IOC_MAGIC是设备特定的魔数,MYDEV_IOCI_CMD是生成的ioctl命令码。mydev_ioctl_data是自定义的数据结构,用于在用户空间和内核空间之间传递数据。
  • 在驱动程序的ioctl函数中,你可以这样处理这个命令:
long mydev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct mydev_ioctl_data data;switch (cmd) {case MYDEV_IOCI_CMD:// 验证数据的复制是否安全if (copy_from_user(&data, (struct mydev_ioctl_data *)arg, sizeof(data)))return -EFAULT;// 处理命令...// 可能会修改data中的值// 将结果复制回用户空间if (copy_to_user((struct mydev_ioctl_data *)arg, &data, sizeof(data)))return -EFAULT;return 0;default:// 处理其他命令或返回错误return -EINVAL;}
}
  • 在使用ioctl时,重要的是要确保用户空间传递的指针是可访问的,并且在内核空间和用户空间之间复制数据时不会出现错误。使用copy_from_usercopy_to_user函数可以实现这一点。

🌻3.代码实例

🐓3.1 _IOWR宏实现

bionic/libc/kernel/uapi/asm-generic/ioctl.h

#ifndef _UAPI_ASM_GENERIC_IOCTL_H
#define _UAPI_ASM_GENERIC_IOCTL_H
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
#ifndef _IOC_SIZEBITS
#define _IOC_SIZEBITS 14
#endif
#ifndef _IOC_DIRBITS
#define _IOC_DIRBITS 2
#endif
#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
#ifndef _IOC_NONE
#define _IOC_NONE 0U
#endif
#ifndef _IOC_WRITE
#define _IOC_WRITE 1U
#endif
#ifndef _IOC_READ
#define _IOC_READ 2U
#endif
#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
#define _IOC_TYPECHECK(t) (sizeof(t))
#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)))
#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ, (type), (nr), sizeof(size))
#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size))
#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size))
#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)
#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
#define IOC_INOUT ((_IOC_WRITE | _IOC_READ) << _IOC_DIRSHIFT)
#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
#endif

🐓3.2 _IOWR内核中使用

#define BINDER_WRITE_READ		_IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT		_IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS		_IOW('b', 5, __u32)
#define BINDER_SET_IDLE_PRIORITY	_IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR		_IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT		_IOW('b', 8, __s32)
#define BINDER_VERSION			_IOWR('b', 9, struct binder_version)
#define BINDER_GET_NODE_DEBUG_INFO	_IOWR('b', 11, struct binder_node_debug_info)
#define BINDER_GET_NODE_INFO_FOR_REF	_IOWR('b', 12, struct binder_node_info_for_ref)
#define BINDER_SET_CONTEXT_MGR_EXT	_IOW('b', 13, struct flat_binder_object)
#define BINDER_FREEZE			_IOW('b', 14, struct binder_freeze_info)
#define BINDER_GET_FROZEN_INFO		_IOWR('b', 15, struct binder_frozen_status_info)

🐓3.3 _IOWR用法实例

#define BINDERFS_MAX_NAME 255
struct binderfs_device {char name[BINDERFS_MAX_NAME + 1];int major;int minor;
};#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
#define _IOC_SIZEBITS 14
#define _IOC_DIRBITS 2
#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
#define _IOC_WRITE 1U
#define _IOC_READ 2U#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))
#define _IOC_TYPECHECK(t) (sizeof(t))
#define _IOWR(type,nr,size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))#define BINDER_CTL_DEL _IOWR('d', 1, struct binderfs_device)
#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device)
#include <iostream>
using namespace std;int main(){printf("BINDER_CTL_ADD = %#lx\n",BINDER_CTL_ADD);printf("BINDER_CTL_DEL = %#lx\n",BINDER_CTL_DEL);
}

打印:
BINDER_CTL_ADD = 0xc1086201
BINDER_CTL_DEL = 0xc1086401

🐓3.4 问题一:#define BINDER_WRITE_READ _IOWR(‘b’, 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR(‘b’, 1, struct binderfs_device)的_IOWR中,用法区别是什么?
  • 在Linux内核中,_IOWR宏用于定义ioctl命令,它包含了读(Read)和写(Write)的操作。你提到的两个宏定义:
#define BINDER_WRITE_READ		_IOWR('b', 1, struct binder_write_read)
#define BINDER_CTL_ADD			_IOWR('b', 1, struct binderfs_device)
  • 这两个宏都是使用_IOWR来定义ioctl命令,但是它们对应不同的操作和数据结构。

  • BINDER_WRITE_READ:这个命令通常用于与Binder通信机制相关的操作,它允许用户空间进程发送数据到Binder驱动,并从Binder驱动接收数据。struct binder_write_read是用于这个命令的数据结构,它包含了要写入Binder驱动和要从Binder驱动读取的数据。

  • BINDER_CTL_ADD:这个命令可能是用于添加一个新的Binder设备到系统中。struct binderfs_device是与这个命令相关的数据结构,它可能包含了添加设备所需的信息。

🐓3.5 问题二:#define BINDER_WRITE_READ _IOWR(‘b’, 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR(‘b’, 1, struct binderfs_device)的_IOWR中,为什么它俩的编号都是1?
  • 尽管这两个命令的编号都是1,但是它们的类型(‘b’)和数据结构不同,因此在ioctl系统中它们被视为不同的命令。
  • 在ioctl机制中,命令是通过一个整数来识别的,这个整数是由_IOWR宏根据类型、编号和数据结构大小生成的。
  • 即使编号相同,由于类型或数据结构的不同,生成的命令整数也会不同。
🐓3.6 问题三:#define BINDER_WRITE_READ _IOWR(‘b’, 1, struct binder_write_read)和#define BINDER_CTL_ADD _IOWR(‘b’, 1, struct binderfs_device)的_IOWR中,编号可以随意定义吗?
  • 编号不能随意定义。
  • 在定义ioctl命令时,编号应该唯一地标识一个特定的操作。
  • 虽然在这里例子中BINDER_WRITE_READ和BINDER_CTL_ADD具有相同的编号,但这可能是因为它们属于不同的设备或驱动,或者它们可能在不同的上下文中使用。
  • 通常,为了防止命令之间的冲突,应该为每个命令分配一个唯一的编号。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装VCenter 7 对硬件资源的需求

安装VMware vCenter Server 7.x 对硬件资源的需求主要包括以下方面&#xff1a; 服务器硬件&#xff1a; 处理器&#xff1a;64位 x86架构&#xff0c;推荐采用多核CPU以支持高并发管理和运行多个虚拟机。具体数量取决于vCenter Server将管理的虚拟机规模及复杂度。内存&#x…

【Flask】Flask中HTTP请求与接收

一、接收http请求与返回响应 在Flask中&#xff0c;可以通过app.route装饰器来定义路由函数。 app.route(/BringGoods,methods [POST, GET]) GET请求&#xff1a;使用request.args.get(key)或者request.values.get(key)来获取URL中的参数。 POST请求&#xff1a; 使用req…

微信小程序实时日志使用,setFilterMsg用法

实时日志 背景 为帮助小程序开发者快捷地排查小程序漏洞、定位问题&#xff0c;我们推出了实时日志功能。开发者可通过提供的接口打印日志&#xff0c;日志汇聚并实时上报到小程序后台。开发者可从We分析“性能质量->实时日志->小程序日志”进入小程序端日志查询页面&am…

python基础知识点(蓝桥杯python科目个人复习计划66)

今日复习内容&#xff1a;算法双周赛 第一题&#xff1a;疯狂星期六 题目描述&#xff1a; 麦肯鸡是一家名声在外的汉堡店&#xff0c;他们最近推出了一份名为vivo50的套餐&#xff0c;只需要在门口大声喊出vivo50&#xff0c;就可以获得这个套餐。 现在&#xff0c;请你打…

【Hadoop】-Hive初体验[13]

Hive体验 预先确保已经完成部署Hive&#xff0c;并启动了Metastore服务 可以执行&#xff1a;bin/hive&#xff0c;进入到Hive Shell环境中&#xff0c;可以直接执行SQL语句。 创建表 create table test(id int,name string,gender string); 插入数据 INSERT INTO test val…

parallels desktop19出来了吗?2024最新版本有哪些新功能

Parallels Desktop 19已经发布。以下是关于Parallels Desktop 19的相关信息&#xff1a; 发布时间&#xff1a;Parallels Desktop 19是在近期发布的一款虚拟机软件&#xff0c;具体发布时间为2023年下半年。 功能特点&#xff1a; 针对搭载苹果芯片的Mac进行了优化&#xff0c…

java:观察者模式

java&#xff1a;观察者模式 1 前言 观察者模式&#xff0c;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;他定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所…

【网络安全】对称加密、非对称加密以及密钥分配

目录 1、对称加密 2、非对称加密 3、如何分配对称密钥&#xff1f; 4、如何分配非对称密钥&#xff1f; 1、对称加密 所谓对称加密&#xff0c;就是指加密密钥与解密密钥都使用相同的密钥。如下图所示&#xff0c;通信双方使用的就是对称加密密钥。//代表&#xff1a;DES和…

通信场景:动态调整对象池大小

通信场景&#xff1a;动态调整对象池大小 文章目录 通信场景&#xff1a;动态调整对象池大小前言历史通信量队列长度系统资源响应时间结语 前言 在做通信相关的开发时&#xff0c;使用对象池管理用于存放接收数据的内存块&#xff0c;是一种常见的优化技术。特别是在需要频繁分…

大模型很厉害,但也有搞不定的事儿

说到大模型&#xff0c;可能大家觉得高深莫测&#xff0c;其实它就是现在AI领域里的“大明星”。为啥这么说呢&#xff1f;因为它确实太牛了&#xff0c;依托大数据、超强的算力和一流的算法&#xff0c;无论是处理自然语言、图像识别&#xff0c;还是语音识别&#xff0c;它都…

6DoF位姿估计深度学习架构---以FFB6D算法为例(复现)

说明 在位姿估计的学习过程中&#xff0c;发现不同算法的代码架构相差非常大&#xff0c;有的算法考虑通用性和可扩展性&#xff0c;进行了大量的模块化设计和继承&#xff0c;这对代码调试和复现工作带来很大麻烦。因此&#xff0c;为了便于算法复现与改进&#xff0c;本人参…

QT中基于TCP的网络通信

QT中基于TCP的网络通信 QTcpServer公共成员函数信号 QTcpSocket公共成员函数信号 通信流程服务器端通信流程代码 客户端通信流程代码 使用Qt提供的类进行基于TCP的套接字通信需要用到两个类&#xff1a; QTcpServer&#xff1a;服务器类&#xff0c;用于监听客户端连接以及和客…