在应用程序获取视频数据的流程中,都是通过 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 /* 设置调谐器频率 */1、struct v4l2_capability 与 VIDIOC_QUERYCAP
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]; };其中域 capabilities 代表设备支持的操作模式,常见的值有 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 表示是一个视频捕捉设备并且具有数据流控制模式;另外 driver 域需要和 struct video_device 中的 name 匹配。
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 */ };常见的捕获模式为 V4L2_BUF_TYPE_VIDEO_CAPTURE 即视频捕捉模式,在此模式下 fmt 联合体采用域 v4l2_pix_format:其中 width 为视频的宽、height 为视频的高、pixelformat 为视频数据格式(常见的值有 V4L2_PIX_FMT_YUV422P | V4L2_PIX_FMT_RGB565)、bytesperline 为一行图像占用的字节数、sizeimage 则为图像占用的总字节数、colorspace 指定设备的颜色空间。
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, };count 指定根据图像占用空间大小申请的缓存区个数,type 为视频捕获模式,memory 为内存区的使用方式。
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; };index 为缓存编号,type 为视频捕获模式,bytesused 为缓存已使用空间大小,flags 为缓存当前状态(常见值有 V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE,分别代表当前缓存已经映射、缓存可以采集数据、缓存可以提取数据),timestamp 为时间戳,sequence为缓存序号,memory 为缓存使用方式,offset 为当前缓存与内存区起始地址的偏移,length 为缓存大小,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, /* 数字电视高频头 */ };其中域 type 有三种类型;capability 域一般为 V4L2_TUNER_CAP_LOW,表明频率调节的步长是62.5Hz,如果没有这个标志位则步长为62.5KHz;rangelow 与 rangehigh 是调谐器可以调频率的最高值和最低值,但都以步长为单位表示;rxsubchans 表示调谐器接收的音频信号类型,常见值有 V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO 即单声道与立体声;audmode 表示以何种方式播放声音,常见值有 V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO,即以单声道还是立体声的方式播放;signal 为当前信号强度,一般取值范围为 0 - 65535。
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]; };注意:frequency 的值是以62.5Hz 或者 62.5KHZ 为单位的。
附:_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)这里特别说明一下 _IO 宏,该宏没有可传递的变量,只用于发送命令。这是因为变量需要可变数据,只作为命令(比如 reset)使用时,没有必要判断设备上的数据,因此设备驱动程序没有必要执行文件相关的处理。在 v4l2 中使用示例如下:
[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)v4l2 中对上述宏命令的处理在 video_ioctl2 函数中:
[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)

MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템으로, 주로 데이터를 신속하고 안정적으로 저장하고 검색하는 데 사용됩니다. 작업 원칙에는 클라이언트 요청, 쿼리 해상도, 쿼리 실행 및 반환 결과가 포함됩니다. 사용의 예로는 테이블 작성, 데이터 삽입 및 쿼리 및 조인 작업과 같은 고급 기능이 포함됩니다. 일반적인 오류에는 SQL 구문, 데이터 유형 및 권한이 포함되며 최적화 제안에는 인덱스 사용, 최적화 된 쿼리 및 테이블 분할이 포함됩니다.

MySQL은 데이터 저장, 관리, 쿼리 및 보안에 적합한 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1. 다양한 운영 체제를 지원하며 웹 응용 프로그램 및 기타 필드에서 널리 사용됩니다. 2. 클라이언트-서버 아키텍처 및 다양한 스토리지 엔진을 통해 MySQL은 데이터를 효율적으로 처리합니다. 3. 기본 사용에는 데이터베이스 및 테이블 작성, 데이터 삽입, 쿼리 및 업데이트가 포함됩니다. 4. 고급 사용에는 복잡한 쿼리 및 저장 프로 시저가 포함됩니다. 5. 설명 진술을 통해 일반적인 오류를 디버깅 할 수 있습니다. 6. 성능 최적화에는 인덱스의 합리적인 사용 및 최적화 된 쿼리 문이 포함됩니다.

MySQL은 성능, 신뢰성, 사용 편의성 및 커뮤니티 지원을 위해 선택됩니다. 1.MYSQL은 효율적인 데이터 저장 및 검색 기능을 제공하여 여러 데이터 유형 및 고급 쿼리 작업을 지원합니다. 2. 고객-서버 아키텍처 및 다중 스토리지 엔진을 채택하여 트랜잭션 및 쿼리 최적화를 지원합니다. 3. 사용하기 쉽고 다양한 운영 체제 및 프로그래밍 언어를 지원합니다. 4. 강력한 지역 사회 지원을 받고 풍부한 자원과 솔루션을 제공합니다.

InnoDB의 잠금 장치에는 공유 잠금 장치, 독점 잠금, 의도 잠금 장치, 레코드 잠금, 갭 잠금 및 다음 키 잠금 장치가 포함됩니다. 1. 공유 잠금을 사용하면 다른 트랜잭션을 읽지 않고 트랜잭션이 데이터를 읽을 수 있습니다. 2. 독점 잠금은 다른 트랜잭션이 데이터를 읽고 수정하는 것을 방지합니다. 3. 의도 잠금은 잠금 효율을 최적화합니다. 4. 레코드 잠금 잠금 인덱스 레코드. 5. 갭 잠금 잠금 장치 색인 기록 간격. 6. 다음 키 잠금은 데이터 일관성을 보장하기 위해 레코드 잠금과 갭 잠금의 조합입니다.

MySQL 쿼리 성능이 좋지 않은 주된 이유는 인덱스 사용, 쿼리 최적화에 의한 잘못된 실행 계획 선택, 불합리한 테이블 디자인, 과도한 데이터 볼륨 및 잠금 경쟁이 포함됩니다. 1. 색인이 느리게 쿼리를 일으키지 않으며 인덱스를 추가하면 성능이 크게 향상 될 수 있습니다. 2. 설명 명령을 사용하여 쿼리 계획을 분석하고 Optimizer 오류를 찾으십시오. 3. 테이블 구조를 재구성하고 결합 조건을 최적화하면 테이블 설계 문제가 향상 될 수 있습니다. 4. 데이터 볼륨이 크면 분할 및 테이블 디비전 전략이 채택됩니다. 5. 높은 동시성 환경에서 거래 및 잠금 전략을 최적화하면 잠금 경쟁이 줄어들 수 있습니다.

데이터베이스 최적화에서 쿼리 요구 사항에 따라 인덱싱 전략을 선택해야합니다. 1. 쿼리에 여러 열이 포함되고 조건 순서가 수정되면 복합 인덱스를 사용하십시오. 2. 쿼리에 여러 열이 포함되어 있지만 조건 순서가 고정되지 않은 경우 여러 단일 열 인덱스를 사용하십시오. 복합 인덱스는 다중 열 쿼리를 최적화하는 데 적합한 반면 단일 열 인덱스는 단일 열 쿼리에 적합합니다.

MySQL 느린 쿼리를 최적화하려면 SlowQueryLog 및 Performance_Schema를 사용해야합니다. 1. SlowQueryLog 및 Set Stresholds를 사용하여 느린 쿼리를 기록합니다. 2. Performance_schema를 사용하여 쿼리 실행 세부 정보를 분석하고 성능 병목 현상을 찾고 최적화하십시오.

MySQL 및 SQL은 개발자에게 필수적인 기술입니다. 1.MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템이며 SQL은 데이터베이스를 관리하고 작동하는 데 사용되는 표준 언어입니다. 2.MYSQL은 효율적인 데이터 저장 및 검색 기능을 통해 여러 스토리지 엔진을 지원하며 SQL은 간단한 문을 통해 복잡한 데이터 작업을 완료합니다. 3. 사용의 예에는 기본 쿼리 및 조건 별 필터링 및 정렬과 같은 고급 쿼리가 포함됩니다. 4. 일반적인 오류에는 구문 오류 및 성능 문제가 포함되며 SQL 문을 확인하고 설명 명령을 사용하여 최적화 할 수 있습니다. 5. 성능 최적화 기술에는 인덱스 사용, 전체 테이블 스캔 피하기, 조인 작업 최적화 및 코드 가독성 향상이 포함됩니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

SecList
SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.
