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

Linux内核之宏_IOWR:如何生成ioctl控制命令(六十)本篇目的 Linux 内核之宏 IOWR 如何生成 ioctl 控制命令在 Linux 内核中 IOWR 是一个宏 用于生成系统调用中 ioctl 命令代码的一部分

大家好,欢迎来到IT知识分享网。

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

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

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


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

欢迎关注Android系统攻城狮

🌻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 = 0xc
BINDER_CTL_DEL = 0xc

🐓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具有相同的编号,但这可能是因为它们属于不同的设备或驱动,或者它们可能在不同的上下文中使用。
  • 通常,为了防止命令之间的冲突,应该为每个命令分配一个唯一的编号。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/155145.html

(0)
上一篇 2025-02-21 15:26
下一篇 2025-02-21 15:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信