简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻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_user
和copy_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具有相同的编号,但这可能是因为它们属于不同的设备或驱动,或者它们可能在不同的上下文中使用。
- 通常,为了防止命令之间的冲突,应该为每个命令分配一个唯一的编号。