v4l2 编程接口(一) — ioctl
Jun 07, 2016 pm 03:32 PM在应用程序获取视频数据的流程中,都是通过 ioctl 命令与驱动程序进行交互,常见的 ioctl 命令有: [cpp] view plaincopyprint? VIDIOC_QUERYCAP /*获取设备支持的操作*/ VIDIOC_G_FMT /*获取设置支持的视频式*/ VIDIOC_S_FMT /*设置捕获视频的式*/ VIDIOC_R
在应用程序获取视频数据的流程中,都是通过 ioctl 命令与驱动程序进行交互,常见的 ioctl 命令有:
[cpp] view plaincopyprint?
- VIDIOC_QUERYCAP /* 获取设备支持的操作 */
- VIDIOC_G_FMT /* 获取设置支持的视频格式 */
- VIDIOC_S_FMT /* 设置捕获视频的格式 */
- VIDIOC_REQBUFS /* 向驱动提出申请内存的请求 */
- VIDIOC_QUERYBUF /* 向驱动查询申请到的内存 */
- VIDIOC_QBUF /* 将空闲的内存加入可捕获视频的队列 */
- VIDIOC_DQBUF /* 将已经捕获好视频的内存拉出已捕获视频的队列 */
- VIDIOC_STREAMON /* 打开视频流 */
- VIDIOC_STREAMOFF /* 关闭视频流 */
- VIDIOC_QUERYCTRL /* 查询驱动是否支持该命令 */
- VIDIOC_G_CTRL /* 获取当前命令值 */
- VIDIOC_S_CTRL /* 设置新的命令值 */
- VIDIOC_G_TUNER /* 获取调谐器信息 */
- VIDIOC_S_TUNER /* 设置调谐器信息 */
- VIDIOC_G_FREQUENCY /* 获取调谐器频率 */
- VIDIOC_S_FREQUENCY /* 设置调谐器频率 */
VIDIOC_QUERYCAP /* 获取设备支持的操作 */ VIDIOC_G_FMT /* 获取设置支持的视频格式 */ VIDIOC_S_FMT /* 设置捕获视频的格式 */ VIDIOC_REQBUFS /* 向驱动提出申请内存的请求 */ VIDIOC_QUERYBUF /* 向驱动查询申请到的内存 */ VIDIOC_QBUF /* 将空闲的内存加入可捕获视频的队列 */ VIDIOC_DQBUF /* 将已经捕获好视频的内存拉出已捕获视频的队列 */ VIDIOC_STREAMON /* 打开视频流 */ VIDIOC_STREAMOFF /* 关闭视频流 */ VIDIOC_QUERYCTRL /* 查询驱动是否支持该命令 */ VIDIOC_G_CTRL /* 获取当前命令值 */ VIDIOC_S_CTRL /* 设置新的命令值 */ VIDIOC_G_TUNER /* 获取调谐器信息 */ VIDIOC_S_TUNER /* 设置调谐器信息 */ VIDIOC_G_FREQUENCY /* 获取调谐器频率 */ VIDIOC_S_FREQUENCY /* 设置调谐器频率 */
VIDIOC_QUERYCAP 命令通过结构 v4l2_capability 获取设备支持的操作模式:
[cpp] view plaincopyprint?
- struct v4l2_capability {
- __u8 driver[16]; /* i.e. "bttv" */
- __u8 card[32]; /* i.e. "Hauppauge WinTV" */
- __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
- __u32 version; /* should use KERNEL_VERSION() */
- __u32 capabilities; /* Device capabilities */
- __u32 reserved[4];
- };
struct v4l2_capability { __u8 driver[16]; /* i.e. "bttv" */ __u8 card[32]; /* i.e. "Hauppauge WinTV" */ __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ __u32 reserved[4]; };
2、struct v4l2_format 与 VIDIOC_G_FMT、VIDIOC_S_FMT、VIDIOC_TRY_FMT
通常用 VIDIOC_S_FMT 命令通过结构 v4l2_format 初始化捕获视频的格式,如果要改变格式则用 VIDIOC_TRY_FMT 命令:
[cpp] view plaincopyprint?
- struct v4l2_format {
- enum v4l2_buf_type type;
- union {
- struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
- struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
- struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
- struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
- __u8 raw_data[200]; /* user-defined */
- } fmt;
- };
- 其中
- enum v4l2_buf_type {
- V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
- V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
- V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
- ...
- V4L2_BUF_TYPE_PRIVATE = 0x80,
- };
- struct v4l2_pix_format {
- __u32 width;
- __u32 height;
- __u32 pixelformat;
- enum v4l2_field field;
- __u32 bytesperline; /* for padding, zero if unused */
- __u32 sizeimage;
- enum v4l2_colorspace colorspace;
- __u32 priv; /* private data, depends on pixelformat */
- };
struct v4l2_format { enum v4l2_buf_type type; union { struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ __u8 raw_data[200]; /* user-defined */ } fmt; }; 其中 enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, ... V4L2_BUF_TYPE_PRIVATE = 0x80, }; struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; enum v4l2_field field; __u32 bytesperline; /* for padding, zero if unused */ __u32 sizeimage; enum v4l2_colorspace colorspace; __u32 priv; /* private data, depends on pixelformat */ };
3、struct v4l2_requestbuffers 与 VIDIOC_REQBUFS
VIDIOC_REQBUFS 命令通过结构 v4l2_requestbuffers 请求驱动申请一片连续的内存用于缓存视频信息:
[cpp] view plaincopyprint?
- struct v4l2_requestbuffers {
- __u32 count;
- enum v4l2_buf_type type;
- enum v4l2_memory memory;
- __u32 reserved[2];
- };
- 其中
- enum v4l2_memory {
- V4L2_MEMORY_MMAP = 1,
- V4L2_MEMORY_USERPTR = 2,
- V4L2_MEMORY_OVERLAY = 3,
- };
struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; __u32 reserved[2]; }; 其中 enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, };
4、struct v4l2_buffer与 VIDIOC_QUERYBUF
VIDIOC_QUERYBUF 命令通过结构 v4l2_buffer 查询驱动申请的内存区信息:
[cpp] view plaincopyprint?
- struct v4l2_buffer {
- __u32 index;
- enum v4l2_buf_type type;
- __u32 bytesused;
- __u32 flags;
- enum v4l2_field field;
- struct timeval timestamp;
- struct v4l2_timecode timecode;
- __u32 sequence;
- /* memory location */
- enum v4l2_memory memory;
- union {
- __u32 offset;
- unsigned long userptr;
- } m;
- __u32 length;
- __u32 input;
- __u32 reserved;
- };
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
另外 VIDIOC_QBUF 和 VIDIOC_DQBUF 命令都采用结构 v4l2_buffer 与驱动通信:VIDIOC_QBUF 命令向驱动传递应用程序已经处理完的缓存,即将缓存加入空闲可捕获视频的队列,传递的主要参数为 index;VIDIOC_DQBUF 命令向驱动获取已经存放有视频数据的缓存,v4l2_buffer 的各个域几乎都会被更新,但主要的参数也是 index,应用程序会根据 index 确定可用数据的起始地址和范围。
5、enum v4l2_buf_type 与 VIDIOC_STREAMON、VIDIOC_STREAMOFF
这两个命令使用的只是一个整形数据,即 v4l2_buf_type,一般只要指定其值为 V4L2_BUF_TYPE_VIDEO_CAPTURE 即可。
6、struct v4l2_queryctrl 与 VIDIOC_QUERYCTRL
VIDIOC_QUERYCTRL 命令通过结构 v4l2_queryctrl 查询驱动是否支持该 id 代表的命令,并返回该命令的各种参数:
[cpp] view plaincopyprint?
- struct v4l2_queryctrl {
- __u32 id; /* 命令编号 */
- enum v4l2_ctrl_type type; /* 命令值的类型 */
- __u8 name[32]; /* 命令名称*/
- __s32 minimum; /* 最小的命令值 */
- __s32 maximum; /* 最大的命令值 */
- __s32 step; /* 命令值变化的步长 */
- __s32 default_value; /* 默认的命令值 */
- __u32 flags; /* 命令的标志 */
- __u32 reserved[2]; /* 命令值的位图表示 */
- };
- 其中
- enum v4l2_ctrl_type {
- V4L2_CTRL_TYPE_INTEGER = 1, /* 整形 */
- V4L2_CTRL_TYPE_BOOLEAN = 2, /* 真值 */
- V4L2_CTRL_TYPE_MENU = 3, /* 菜单 */
- V4L2_CTRL_TYPE_BUTTON = 4, /* 无值 */
- V4L2_CTRL_TYPE_INTEGER64 = 5, /* 后面三种不常用 */
- V4L2_CTRL_TYPE_CTRL_CLASS = 6,
- V4L2_CTRL_TYPE_STRING = 7,
- };
- 命令的标志取值如下:
- /* Control flags */
- #define V4L2_CTRL_FLAG_DISABLED 0x0001
- #define V4L2_CTRL_FLAG_GRABBED 0x0002
- #define V4L2_CTRL_FLAG_READ_ONLY 0x0004
- #define V4L2_CTRL_FLAG_UPDATE 0x0008
- #define V4L2_CTRL_FLAG_INACTIVE 0x0010
- #define V4L2_CTRL_FLAG_SLIDER 0x0020
- #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040
- /* Query flag, to be ORed with the control ID */
- #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
struct v4l2_queryctrl { __u32 id; /* 命令编号 */ enum v4l2_ctrl_type type; /* 命令值的类型 */ __u8 name[32]; /* 命令名称*/ __s32 minimum; /* 最小的命令值 */ __s32 maximum; /* 最大的命令值 */ __s32 step; /* 命令值变化的步长 */ __s32 default_value; /* 默认的命令值 */ __u32 flags; /* 命令的标志 */ __u32 reserved[2]; /* 命令值的位图表示 */ }; 其中 enum v4l2_ctrl_type { V4L2_CTRL_TYPE_INTEGER = 1, /* 整形 */ V4L2_CTRL_TYPE_BOOLEAN = 2, /* 真值 */ V4L2_CTRL_TYPE_MENU = 3, /* 菜单 */ V4L2_CTRL_TYPE_BUTTON = 4, /* 无值 */ V4L2_CTRL_TYPE_INTEGER64 = 5, /* 后面三种不常用 */ V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_STRING = 7, }; 命令的标志取值如下: /* Control flags */ #define V4L2_CTRL_FLAG_DISABLED 0x0001 #define V4L2_CTRL_FLAG_GRABBED 0x0002 #define V4L2_CTRL_FLAG_READ_ONLY 0x0004 #define V4L2_CTRL_FLAG_UPDATE 0x0008 #define V4L2_CTRL_FLAG_INACTIVE 0x0010 #define V4L2_CTRL_FLAG_SLIDER 0x0020 #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 /* Query flag, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
id 是命令的编号,常见的命令有两种:一种以 V4L2_CID_BASE 为起始值,是公用命令;一种以 V4L2_CID_PRIVATE_BASE 为起始值,是私有命令。在一般的应用中命令值可见如下:
[cpp] view plaincopyprint?
- V4L2_CID_CONTRAST (V4L2_CID_BASE+1) /* 对比度调节 */
- V4L2_CID_SATURATION (V4L2_CID_BASE+2) /* 饱和度调节 */
- V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) /* 音量调节 */
- V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) /* 静音设置 */
- V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) /* 白平衡调节 */
- V4L2_CID_GAMMA (V4L2_CID_BASE+16) /* 伽马值调节 */
- V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) /* 曝光度调节 */
- V4L2_CID_PRIVATE_ATXX_FLASH (V4L2_CID_PRIVATE_BASE + 2) /* 闪光灯控制 */
- V4L2_CID_PRIVATE_ATXX_FRAME (V4L2_CID_PRIVATE_BASE + 12) /* 帧率调节 */
V4L2_CID_CONTRAST (V4L2_CID_BASE+1) /* 对比度调节 */ V4L2_CID_SATURATION (V4L2_CID_BASE+2) /* 饱和度调节 */ V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) /* 音量调节 */ V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) /* 静音设置 */ V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) /* 白平衡调节 */ V4L2_CID_GAMMA (V4L2_CID_BASE+16) /* 伽马值调节 */ V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) /* 曝光度调节 */ V4L2_CID_PRIVATE_ATXX_FLASH (V4L2_CID_PRIVATE_BASE + 2) /* 闪光灯控制 */ V4L2_CID_PRIVATE_ATXX_FRAME (V4L2_CID_PRIVATE_BASE + 12) /* 帧率调节 */
type 为命令值的类型(总共有7中类型的值),name 是命令的名称,reserved 则是命令值的位图表示,驱动会将所有的命令值都以 bit 的形式写到 64 位的域中,上层应用查询时可以根据位图判断命令支持的值。
7、struct v4l2_control 与 VIDIOC_G_CTRL、VIDIOC_S_CTRL
VIDIOC_S_CTRL 或 VIDIOC_G_CTRL 命令通过结构 v4l2_control 设置或者获取 id 命令的值:
[cpp] view plaincopyprint?
- struct v4l2_control {
- __u32 id;
- __s32 value;
- };
struct v4l2_control { __u32 id; __s32 value; };
这个结构只有 2 个域,id 是命令编号,value 则是命令的值。
8、struct v4l2_tuner 与 VIDIOC_G_TUNER、VIDIOC_S_TUNER
VIDIOC_S_TUNER 或 VIDIOC_G_TUNER 命令通过结构 v4l2_tuner 设置调谐器的信息:
[cpp] view plaincopyprint?
- struct v4l2_tuner {
- __u32 index; /* 调谐器编号,由应用程序设置 */
- __u8 name[32]; /* 调谐器名称 */
- enum v4l2_tuner_type type; /* 调谐器类型 */
- __u32 capability; /* 调谐器支持的操作 */
- __u32 rangelow; /* 最低频率值,单位为62.5Hz或者62.5KHz */
- __u32 rangehigh; /* 最高频率值 */
- __u32 rxsubchans; /* 接收的音频信号类型 */
- __u32 audmode; /* 当前音频播放形式 */
- __s32 signal; /* 信号强度 */
- __s32 afc; /* 自动频率控制 */
- __u32 reserved[4]; /* 保留备用 */
- };
- 其中
- enum v4l2_tuner_type {
- V4L2_TUNER_RADIO = 1, /* 调频收音机 */
- V4L2_TUNER_ANALOG_TV = 2, /* 模拟电视高频头 */
- V4L2_TUNER_DIGITAL_TV = 3, /* 数字电视高频头 */
- };
struct v4l2_tuner { __u32 index; /* 调谐器编号,由应用程序设置 */ __u8 name[32]; /* 调谐器名称 */ enum v4l2_tuner_type type; /* 调谐器类型 */ __u32 capability; /* 调谐器支持的操作 */ __u32 rangelow; /* 最低频率值,单位为62.5Hz或者62.5KHz */ __u32 rangehigh; /* 最高频率值 */ __u32 rxsubchans; /* 接收的音频信号类型 */ __u32 audmode; /* 当前音频播放形式 */ __s32 signal; /* 信号强度 */ __s32 afc; /* 自动频率控制 */ __u32 reserved[4]; /* 保留备用 */ }; 其中 enum v4l2_tuner_type { V4L2_TUNER_RADIO = 1, /* 调频收音机 */ V4L2_TUNER_ANALOG_TV = 2, /* 模拟电视高频头 */ V4L2_TUNER_DIGITAL_TV = 3, /* 数字电视高频头 */ };
9、struct v4l2_frequency 与 VIDIOC_G_FREQUENCY、VIDIOC_S_FREQUENCY
VIDIOC_S_FREQUENCY 或 VIDIOC_G_FREQUENCY 命令通过结构 v4l2_frequency 设置或获取当前频率值:
[cpp] view plaincopyprint?
- struct v4l2_frequency {
- __u32 tuner; /* 调谐器编号 */
- enum v4l2_tuner_type type; /* 调谐器类型 */
- __u32 frequency; /* 调谐器频率 */
- __u32 reserved[8];
- };
struct v4l2_frequency { __u32 tuner; /* 调谐器编号 */ enum v4l2_tuner_type type; /* 调谐器类型 */ __u32 frequency; /* 调谐器频率 */ __u32 reserved[8]; };
附:_IO、_IOR、_IOW、_IOWR 宏的使用说明
驱动程序中 ioctl 函数传递的变量 cmd 是应用程序向驱动程序请求处理的命令。cmd 除了用于区别不同命令的数值,还可包含有助于处理的几种信息。cmd 的大小为 32 bit,共分 4 个域:
bit29 ~ bit31: 3bit 为 “读写” 区,作用是区分是读命令还是写命令。
bit16 ~ bit28:13bit 为 "数据大小" 区,表示 ioctl 中的 arg 变量传递的数据大小;有时候为 14bit 即将 bit29 覆盖。
bit8 ~ bit15: 8bit 为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
bit0 ~ bit7: 8bit 为 "序号" 区,是区分命令的命令顺序序号。
魔数(magic number)
魔数范围为 0~255 。通常,用英文字符 'A' ~ 'Z' 或者 'a' ~ 'z' 来表示。设备驱动程序从传递进来的命令获取魔数,然后与自身处理的魔数想比较,如果相同则处理,不同则不处理。魔数是拒绝误使用的初步辅助参数。设备驱动程序可以通过宏 _IOC_TYPE (cmd) 来获取魔数。不同的设备驱动程序最好设置不同的魔数,但并不是要求绝对,也是可以使用其他设备驱动程序已用过的魔数。
基数(序号)
基数用于区别各种命令。通常,从 0开始递增,相同设备驱动程序上可以重复使用该值。例如,读和写命令中使用了相同的基数,设备驱动程序也能分辨出来,原因在于设备驱动程序区分命令时使用 switch ,且直接使用命令变量 cmd 值。创建命令的宏生成的值由多个域组合而成,所以即使是相同的基数,也会判断为不同的命令。设备驱动程序想要从命令中获取该基数,就使用宏 _IOC_NR (cmd)。
下面我们看一下上述宏在内核中的原型:
[cpp] view plaincopyprint?
- /*
- * Our DIR and SIZE overlap in order to simulteneously provide
- * a non-zero _IOC_NONE (for binary compatibility) and
- * 14 bits of size as on i386. Here's the layout:
- *
- * 0xE0000000 DIR 3bit
- * 0x80000000 DIR = WRITE bit31
- * 0x40000000 DIR = READ bit30
- * 0x20000000 DIR = NONE bit29
- * 0x3FFF0000 SIZE (overlaps NONE bit) 13bit
- * 0x0000FF00 TYPE 8bit
- * 0x000000FF NR (CMD) 8bit
- */
- /* 各个域的长度 */
- #define _IOC_NRBITS 8
- #define _IOC_TYPEBITS 8
- #define _IOC_SIZEBITS 13 /* Actually 14, see below. */
- #define _IOC_DIRBITS 3
- /* 各个域的掩码 */
- #define _IOC_NRMASK ((1
- #define _IOC_TYPEMASK ((1
- #define _IOC_SIZEMASK ((1
- #define _IOC_XSIZEMASK ((1
- #define _IOC_DIRMASK ((1
- /* 各个域的偏移 */
- #define _IOC_NRSHIFT 0
- #define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) /* 8 */
- #define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) /* 16 */
- #define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) /* 29 */
- /* 读写域的值 */
- #define _IOC_NONE 1U
- #define _IOC_READ 2U
- #define _IOC_WRITE 4U
- #define _IOC(dir,type,nr,size) \
- (((dir) /* 读写方向左移 29bit */
- ((type) /* 幻数左移 8bit */
- ((nr) /* 命令序号 */
- ((size) /* 参数大小左移 16bit */
- /* 宏原型,这里将会根据传递的数据类型取其长度 */
- #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
- #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
- #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
- #define _IOWR(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)
/* * Our DIR and SIZE overlap in order to simulteneously provide * a non-zero _IOC_NONE (for binary compatibility) and * 14 bits of size as on i386. Here's the layout: * * 0xE0000000 DIR 3bit * 0x80000000 DIR = WRITE bit31 * 0x40000000 DIR = READ bit30 * 0x20000000 DIR = NONE bit29 * 0x3FFF0000 SIZE (overlaps NONE bit) 13bit * 0x0000FF00 TYPE 8bit * 0x000000FF NR (CMD) 8bit */ /* 各个域的长度 */ #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 #define _IOC_SIZEBITS 13 /* Actually 14, see below. */ #define _IOC_DIRBITS 3 /* 各个域的掩码 */ #define _IOC_NRMASK ((1 > _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)
[cpp] view plaincopyprint?
- #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
- #define VIDIOC_RESERVED _IO('V', 1)
- #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
- #define VIDIOC_STREAMON _IOW('V', 18, int)
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) #define VIDIOC_RESERVED _IO('V', 1) #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) #define VIDIOC_STREAMON _IOW('V', 18, int)
[cpp] view plaincopyprint?
- static unsigned long cmd_input_size(unsigned int cmd)
- {
- #define CMDINSIZE(cmd, type, field) \
- case VIDIOC_##cmd: \
- return offsetof(struct v4l2_##type, field) + \ /* 域的偏移 */
- sizeof(((struct v4l2_##type *)0)->field); /* 域的长度 */
- switch (cmd) {
- CMDINSIZE(ENUM_FMT, fmtdesc, type);
- CMDINSIZE(G_FMT, format, type);
- ...
- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
- default:
- return _IOC_SIZE(cmd); /* 剩下的是需要全部拷贝的命令 */
- }
- }
- long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)
- {
- char sbuf[128]; /* 在栈中分配128个字节空间用来储存命令的参数 */
- void *mbuf = NULL;
- void *parg = NULL; /* 参数存放的首地址 */
- long err = -EINVAL;
- int is_ext_ctrl;
- size_t ctrls_size = 0;
- void __user *user_ptr = NULL;
- ...
- /* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */
- if (_IOC_DIR(cmd) != _IOC_NONE) {
- /* 判断参数大小是否超过128字节 */
- if (_IOC_SIZE(cmd) sizeof(sbuf)) {
- parg = sbuf;
- } else {
- /* 如果超过128字节则从堆中申请 */
- mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
- if (NULL == mbuf)
- return -ENOMEM;
- parg = mbuf;
- }
- err = -EFAULT;
- /* 如果包含写命令 */
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- /* 计算需要拷贝的有效数据长度,有的命令不需要全部拷贝 */
- unsigned long n = cmd_input_size(cmd);
- /* 从用户空间拷贝参数值 */
- if (copy_from_user(parg, (void __user *)arg, n))
- goto out;
- /* 将剩下的空间清零 */
- if (n
- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
- } else {
- /* 如果是只读命令则将整个buffer清零 */
- memset(parg, 0, _IOC_SIZE(cmd));
- }
- }
- ...
- /* 调用 v4l2_ioctl_ops 的成员函数处理命令 */
- err = __video_do_ioctl(file, cmd, parg);
- if (err == -ENOIOCTLCMD)
- err = -EINVAL;
- ...
- if (err
- goto out;
- out_ext_ctrl:
- /* 如果包含读命令则将参数值拷贝到用户空间 */
- switch (_IOC_DIR(cmd)) {
- case _IOC_READ:
- case (_IOC_WRITE | _IOC_READ):
- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
- err = -EFAULT;
- break;
- }
- out:
- kfree(mbuf);
- return err;
- }
- EXPORT_SYMBOL(video_ioctl2);
static unsigned long cmd_input_size(unsigned int cmd) { #define CMDINSIZE(cmd, type, field) \ case VIDIOC_##cmd: \ return offsetof(struct v4l2_##type, field) + \ /* 域的偏移 */ sizeof(((struct v4l2_##type *)0)->field); /* 域的长度 */ switch (cmd) { CMDINSIZE(ENUM_FMT, fmtdesc, type); CMDINSIZE(G_FMT, format, type); ... CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); default: return _IOC_SIZE(cmd); /* 剩下的是需要全部拷贝的命令 */ } } long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) { char sbuf[128]; /* 在栈中分配128个字节空间用来储存命令的参数 */ void *mbuf = NULL; void *parg = NULL; /* 参数存放的首地址 */ long err = -EINVAL; int is_ext_ctrl; size_t ctrls_size = 0; void __user *user_ptr = NULL; ... /* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */ if (_IOC_DIR(cmd) != _IOC_NONE) { /* 判断参数大小是否超过128字节 */ if (_IOC_SIZE(cmd)

Hot Article

Hot tools Tags

Hot Article

Hot Article Tags

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Shazam app not working in iPhone: Fix

Slow Cellular Data Internet Speeds on iPhone: Fixes

The U.S. Air Force showcases its first AI fighter jet with high profile! The minister personally conducted the test drive without interfering during the whole process, and 100,000 lines of code were tested for 21 times.

Tesla robots work in factories, Musk: The degree of freedom of hands will reach 22 this year!

70B model generates 1,000 tokens in seconds, code rewriting surpasses GPT-4o, from the Cursor team, a code artifact invested by OpenAI

AI startups collectively switched jobs to OpenAI, and the security team regrouped after Ilya left!

58 lines of code scale Llama 3 to 1 million contexts, any fine-tuned version is applicable

iPhone camera flickers/flickers in room lights: fix
