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?

  1. VIDIOC_QUERYCAP     /* 获取设备支持的操作 */  
  2. VIDIOC_G_FMT        /* 获取设置支持的视频格式 */  
  3. VIDIOC_S_FMT        /* 设置捕获视频的格式 */  
  4. VIDIOC_REQBUFS      /* 向驱动提出申请内存的请求 */  
  5. VIDIOC_QUERYBUF     /* 向驱动查询申请到的内存 */  
  6. VIDIOC_QBUF         /* 将空闲的内存加入可捕获视频的队列 */  
  7. VIDIOC_DQBUF        /* 将已经捕获好视频的内存拉出已捕获视频的队列 */  
  8. VIDIOC_STREAMON     /* 打开视频流 */  
  9. VIDIOC_STREAMOFF    /* 关闭视频流 */  
  10. VIDIOC_QUERYCTRL    /* 查询驱动是否支持该命令 */  
  11. VIDIOC_G_CTRL       /* 获取当前命令值 */  
  12. VIDIOC_S_CTRL       /* 设置新的命令值 */  
  13. VIDIOC_G_TUNER      /* 获取调谐器信息 */  
  14. VIDIOC_S_TUNER      /* 设置调谐器信息 */  
  15. VIDIOC_G_FREQUENCY  /* 获取调谐器频率 */  
  16. 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?

  1. struct v4l2_capability {  
  2.     __u8    driver[16];     /* i.e. "bttv" */  
  3.     __u8    card[32];       /* i.e. "Hauppauge WinTV" */  
  4.     __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */  
  5.     __u32   version;        /* should use KERNEL_VERSION() */  
  6.     __u32   capabilities;   /* Device capabilities */  
  7.     __u32   reserved[4];  
  8. };  
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?

  1. struct v4l2_format {  
  2.     enum v4l2_buf_type type;  
  3.     union {  
  4.         struct v4l2_pix_format         pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */  
  5.         struct v4l2_window             win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */  
  6.         struct v4l2_vbi_format         vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */  
  7.         struct v4l2_sliced_vbi_format  sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */  
  8.         __u8   raw_data[200];                   /* user-defined */  
  9.     } fmt;  
  10. };  
  11. 其中  
  12. enum v4l2_buf_type {  
  13.     V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,  
  14.     V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,  
  15.     V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,  
  16.     ...  
  17.     V4L2_BUF_TYPE_PRIVATE              = 0x80,  
  18. };  
  19.   
  20. struct v4l2_pix_format {  
  21.     __u32                   width;  
  22.     __u32                   height;  
  23.     __u32                   pixelformat;  
  24.     enum v4l2_field         field;  
  25.     __u32                   bytesperline;   /* for padding, zero if unused */  
  26.     __u32                   sizeimage;  
  27.     enum v4l2_colorspace    colorspace;  
  28.     __u32                   priv;           /* private data, depends on pixelformat */  
  29. };  
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?

  1. struct v4l2_requestbuffers {  
  2.     __u32                   count;  
  3.     enum v4l2_buf_type      type;  
  4.     enum v4l2_memory        memory;  
  5.     __u32                   reserved[2];  
  6. };  
  7. 其中  
  8. enum v4l2_memory {  
  9.     V4L2_MEMORY_MMAP             = 1,  
  10.     V4L2_MEMORY_USERPTR          = 2,  
  11.     V4L2_MEMORY_OVERLAY          = 3,  
  12. };  
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?

  1. struct v4l2_buffer {  
  2.     __u32                   index;  
  3.     enum v4l2_buf_type      type;  
  4.     __u32                   bytesused;  
  5.     __u32                   flags;  
  6.     enum v4l2_field         field;  
  7.     struct timeval          timestamp;  
  8.     struct v4l2_timecode    timecode;  
  9.     __u32                   sequence;  
  10.   
  11.     /* memory location */  
  12.     enum v4l2_memory        memory;  
  13.     union {  
  14.             __u32           offset;  
  15.             unsigned long   userptr;  
  16.     } m;  
  17.     __u32                   length;  
  18.     __u32                   input;  
  19.     __u32                   reserved;  
  20. };  
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?

  1. struct v4l2_queryctrl {  
  2.     __u32                id;            /* 命令编号 */  
  3.     enum v4l2_ctrl_type  type;          /* 命令值的类型 */  
  4.     __u8                 name[32];      /* 命令名称*/  
  5.     __s32                minimum;       /* 最小的命令值 */  
  6.     __s32                maximum;       /* 最大的命令值 */  
  7.     __s32                step;          /* 命令值变化的步长 */  
  8.     __s32                default_value; /* 默认的命令值 */  
  9.     __u32                flags;         /* 命令的标志 */  
  10.     __u32                reserved[2];   /* 命令值的位图表示 */  
  11. };  
  12. 其中  
  13. enum v4l2_ctrl_type {  
  14.     V4L2_CTRL_TYPE_INTEGER       = 1,   /* 整形 */  
  15.     V4L2_CTRL_TYPE_BOOLEAN       = 2,   /* 真值 */  
  16.     V4L2_CTRL_TYPE_MENU          = 3,   /* 菜单 */  
  17.     V4L2_CTRL_TYPE_BUTTON        = 4,   /* 无值 */  
  18.     V4L2_CTRL_TYPE_INTEGER64     = 5,   /* 后面三种不常用 */  
  19.     V4L2_CTRL_TYPE_CTRL_CLASS    = 6,  
  20.     V4L2_CTRL_TYPE_STRING        = 7,  
  21. };  
  22. 命令的标志取值如下:  
  23. /*  Control flags  */  
  24. #define V4L2_CTRL_FLAG_DISABLED     0x0001   
  25. #define V4L2_CTRL_FLAG_GRABBED      0x0002   
  26. #define V4L2_CTRL_FLAG_READ_ONLY    0x0004   
  27. #define V4L2_CTRL_FLAG_UPDATE       0x0008   
  28. #define V4L2_CTRL_FLAG_INACTIVE     0x0010   
  29. #define V4L2_CTRL_FLAG_SLIDER       0x0020   
  30. #define V4L2_CTRL_FLAG_WRITE_ONLY   0x0040   
  31.   
  32. /*  Query flag, to be ORed with the control ID */  
  33. #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?

  1. V4L2_CID_CONTRAST               (V4L2_CID_BASE+1)            /* 对比度调节 */  
  2. V4L2_CID_SATURATION             (V4L2_CID_BASE+2)            /* 饱和度调节 */  
  3. V4L2_CID_AUDIO_VOLUME           (V4L2_CID_BASE+5)            /* 音量调节 */  
  4. V4L2_CID_AUDIO_MUTE             (V4L2_CID_BASE+9)            /* 静音设置 */  
  5. V4L2_CID_DO_WHITE_BALANCE       (V4L2_CID_BASE+13)           /* 白平衡调节 */  
  6. V4L2_CID_GAMMA                  (V4L2_CID_BASE+16)           /* 伽马值调节 */  
  7. V4L2_CID_EXPOSURE               (V4L2_CID_BASE+17)           /* 曝光度调节 */  
  8.   
  9. V4L2_CID_PRIVATE_ATXX_FLASH     (V4L2_CID_PRIVATE_BASE + 2)  /* 闪光灯控制 */  
  10. 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?

  1. struct v4l2_control {  
  2.     __u32            id;  
  3.     __s32            value;  
  4. };  
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?

  1. struct v4l2_tuner {  
  2.     __u32                   index;           /* 调谐器编号,由应用程序设置 */  
  3.     __u8                    name[32];        /* 调谐器名称 */  
  4.     enum v4l2_tuner_type    type;            /* 调谐器类型 */  
  5.     __u32                   capability;      /* 调谐器支持的操作 */  
  6.     __u32                   rangelow;        /* 最低频率值,单位为62.5Hz或者62.5KHz */  
  7.     __u32                   rangehigh;       /* 最高频率值 */  
  8.     __u32                   rxsubchans;      /* 接收的音频信号类型 */  
  9.     __u32                   audmode;         /* 当前音频播放形式 */  
  10.     __s32                   signal;          /* 信号强度 */  
  11.     __s32                   afc;             /* 自动频率控制 */  
  12.     __u32                   reserved[4];     /* 保留备用 */  
  13. };  
  14. 其中  
  15. enum v4l2_tuner_type {  
  16.     V4L2_TUNER_RADIO             = 1,        /* 调频收音机 */  
  17.     V4L2_TUNER_ANALOG_TV         = 2,        /* 模拟电视高频头 */  
  18.     V4L2_TUNER_DIGITAL_TV        = 3,        /* 数字电视高频头 */  
  19. };  
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?

  1. struct v4l2_frequency {  
  2.     __u32                 tuner;          /* 调谐器编号 */  
  3.     enum v4l2_tuner_type  type;           /* 调谐器类型 */  
  4.     __u32                 frequency;      /* 调谐器频率 */  
  5.     __u32                 reserved[8];  
  6. };  
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?

  1. /* 
  2.  * Our DIR and SIZE overlap in order to simulteneously provide 
  3.  * a non-zero _IOC_NONE (for binary compatibility) and 
  4.  * 14 bits of size as on i386. Here's the layout: 
  5.  * 
  6.  *   0xE0000000   DIR            3bit 
  7.  *   0x80000000   DIR = WRITE    bit31 
  8.  *   0x40000000   DIR = READ     bit30 
  9.  *   0x20000000   DIR = NONE     bit29 
  10.  *   0x3FFF0000   SIZE (overlaps NONE bit)  13bit 
  11.  *   0x0000FF00   TYPE           8bit 
  12.  *   0x000000FF   NR (CMD)       8bit 
  13.  */  
  14. /* 各个域的长度 */  
  15. #define _IOC_NRBITS      8   
  16. #define _IOC_TYPEBITS    8   
  17. #define _IOC_SIZEBITS   13  /* Actually 14, see below. */   
  18. #define _IOC_DIRBITS     3   
  19. /* 各个域的掩码 */  
  20. #define _IOC_NRMASK      ((1   
  21. #define _IOC_TYPEMASK    ((1   
  22. #define _IOC_SIZEMASK    ((1   
  23. #define _IOC_XSIZEMASK   ((1   
  24. #define _IOC_DIRMASK     ((1   
  25. /* 各个域的偏移 */  
  26. #define _IOC_NRSHIFT     0   
  27. #define _IOC_TYPESHIFT   (_IOC_NRSHIFT + _IOC_NRBITS)       /* 8 */   
  28. #define _IOC_SIZESHIFT   (_IOC_TYPESHIFT + _IOC_TYPEBITS)   /* 16 */   
  29. #define _IOC_DIRSHIFT    (_IOC_SIZESHIFT + _IOC_SIZEBITS)   /* 29 */   
  30. /* 读写域的值 */  
  31. #define _IOC_NONE        1U   
  32. #define _IOC_READ        2U   
  33. #define _IOC_WRITE       4U   
  34.   
  35. #define _IOC(dir,type,nr,size) \   
  36.         (((dir)  /* 读写方向左移 29bit */  
  37.          ((type) /* 幻数左移 8bit */  
  38.          ((nr)   /* 命令序号 */  
  39.          ((size) /* 参数大小左移 16bit */  
  40. /* 宏原型,这里将会根据传递的数据类型取其长度 */  
  41. #define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)   
  42. #define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))   
  43. #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))   
  44. #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))   
  45. /* 获取各个域的值 */  
  46. #define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)   
  47. #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)   
  48. #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)   
  49. #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?

  1. #define VIDIOC_QUERYCAP      _IOR('V',  0, struct v4l2_capability)   
  2. #define VIDIOC_RESERVED       _IO('V',  1)   
  3. #define VIDIOC_S_FMT        _IOWR('V',  5, struct v4l2_format)   
  4. #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?

  1. static unsigned long cmd_input_size(unsigned int cmd)  
  2. {  
  3. #define CMDINSIZE(cmd, type, field)                 \   
  4.     case VIDIOC_##cmd:                  \  
  5.         return offsetof(struct v4l2_##type, field) +    \  /* 域的偏移 */  
  6.             sizeof(((struct v4l2_##type *)0)->field);      /* 域的长度 */  
  7.   
  8.     switch (cmd) {  
  9.         CMDINSIZE(ENUM_FMT,     fmtdesc,    type);  
  10.         CMDINSIZE(G_FMT,        format,     type);  
  11.         ...  
  12.         CMDINSIZE(ENUM_FRAMESIZES,  frmsizeenum,    pixel_format);  
  13.         CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);  
  14.     default:  
  15.         return _IOC_SIZE(cmd);  /* 剩下的是需要全部拷贝的命令 */  
  16.     }  
  17. }  
  18.   
  19. long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)  
  20. {  
  21.     char    sbuf[128];          /* 在栈中分配128个字节空间用来储存命令的参数 */  
  22.     void    *mbuf = NULL;  
  23.     void    *parg = NULL;       /* 参数存放的首地址 */  
  24.     long    err  = -EINVAL;  
  25.     int     is_ext_ctrl;  
  26.     size_t  ctrls_size = 0;  
  27.     void __user *user_ptr = NULL;  
  28.   
  29.     ...  
  30.     /* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */  
  31.     if (_IOC_DIR(cmd) != _IOC_NONE) {  
  32.         /* 判断参数大小是否超过128字节 */  
  33.         if (_IOC_SIZE(cmd) sizeof(sbuf)) {  
  34.             parg = sbuf;  
  35.         } else {  
  36.             /* 如果超过128字节则从堆中申请 */  
  37.             mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);  
  38.             if (NULL == mbuf)  
  39.                 return -ENOMEM;  
  40.             parg = mbuf;  
  41.         }  
  42.   
  43.         err = -EFAULT;  
  44.         /* 如果包含写命令 */  
  45.         if (_IOC_DIR(cmd) & _IOC_WRITE) {  
  46.             /* 计算需要拷贝的有效数据长度,有的命令不需要全部拷贝 */  
  47.             unsigned long n = cmd_input_size(cmd);  
  48.             /* 从用户空间拷贝参数值 */  
  49.             if (copy_from_user(parg, (void __user *)arg, n))  
  50.                 goto out;  
  51.   
  52.             /* 将剩下的空间清零 */  
  53.             if (n 
  54.                 memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);  
  55.         } else {  
  56.             /* 如果是只读命令则将整个buffer清零 */  
  57.             memset(parg, 0, _IOC_SIZE(cmd));  
  58.         }  
  59.     }  
  60.   
  61.     ...  
  62.     /* 调用 v4l2_ioctl_ops 的成员函数处理命令 */  
  63.     err = __video_do_ioctl(file, cmd, parg);  
  64.     if (err == -ENOIOCTLCMD)  
  65.         err = -EINVAL;  
  66.     ...  
  67.     if (err 
  68.         goto out;  
  69.   
  70. out_ext_ctrl:  
  71.     /* 如果包含读命令则将参数值拷贝到用户空间 */  
  72.     switch (_IOC_DIR(cmd)) {  
  73.     case _IOC_READ:  
  74.     case (_IOC_WRITE | _IOC_READ):  
  75.         if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))  
  76.             err = -EFAULT;  
  77.         break;  
  78.     }  
  79.   
  80. out:  
  81.     kfree(mbuf);  
  82.     return err;  
  83. }  
  84. 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) 
ログイン後にコピー
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

ShazamアプリがiPhoneで動作しない:修正 ShazamアプリがiPhoneで動作しない:修正 Jun 08, 2024 pm 12:36 PM

iPhone の Shazam アプリに問題がありますか? Shazam は、曲を聞いて曲を見つけるのに役立ちます。ただし、Shazam が正常に動作しない場合、または曲が認識されない場合は、手動でトラブルシューティングを行う必要があります。 Shazam アプリの修復にはそれほど時間はかかりません。したがって、これ以上時間を無駄にすることなく、以下の手順に従って Shazam アプリの問題を解決してください。解決策 1 – 太字テキスト機能を無効にする iPhone の太字テキストが、Shazam が正しく動作しない原因である可能性があります。ステップ 1 – これは iPhone の設定からのみ実行できます。それで、開けてください。ステップ 2 – 次に、そこにある「ディスプレイと明るさ」設定を開きます。ステップ 3 – 「太字テキスト」が有効になっている場合

iPhoneのセルラーデータインターネット速度が遅い:修正 iPhoneのセルラーデータインターネット速度が遅い:修正 May 03, 2024 pm 09:01 PM

iPhone のモバイル データ接続に遅延や遅い問題が発生していませんか?通常、携帯電話の携帯インターネットの強度は、地域、携帯ネットワークの種類、ローミングの種類などのいくつかの要因によって異なります。より高速で信頼性の高いセルラー インターネット接続を実現するためにできることがいくつかあります。解決策 1 – iPhone を強制的に再起動する 場合によっては、デバイスを強制的に再起動すると、携帯電話接続を含む多くの機能がリセットされるだけです。ステップ 1 – 音量を上げるキーを 1 回押して放します。次に、音量小キーを押して、もう一度放します。ステップ 2 – プロセスの次の部分は、右側のボタンを押し続けることです。 iPhone の再起動が完了するまで待ちます。セルラーデータを有効にし、ネットワーク速度を確認します。もう一度確認してください 修正 2 – データ モードを変更する 5G はより優れたネットワーク速度を提供しますが、信号が弱い場合はより適切に機能します

アメリカ空軍が初のAI戦闘機を公開し注目を集める!大臣はプロセス全体を通じて干渉することなく個人的にテストを実施し、10万行のコードが21回にわたってテストされました。 アメリカ空軍が初のAI戦闘機を公開し注目を集める!大臣はプロセス全体を通じて干渉することなく個人的にテストを実施し、10万行のコードが21回にわたってテストされました。 May 07, 2024 pm 05:00 PM

最近、軍事界は、米軍戦闘機が AI を使用して完全自動空戦を完了できるようになったというニュースに圧倒されました。そう、つい最近、米軍のAI戦闘機が初めて公開され、その謎が明らかになりました。この戦闘機の正式名称は可変安定性飛行シミュレーター試験機(VISTA)で、アメリカ空軍長官が自ら飛行させ、一対一の空戦をシミュレートした。 5 月 2 日、フランク ケンダル米国空軍長官は X-62AVISTA でエドワーズ空軍基地を離陸しました。1 時間の飛行中、すべての飛行動作が AI によって自律的に完了されたことに注目してください。ケンダル氏は「過去数十年にわたり、私たちは自律型空対空戦闘の無限の可能性について考えてきたが、それは常に手の届かないものだと思われてきた」と語った。しかし今では、

テスラのロボットは工場で働く、マスク氏:手の自由度は今年22に達する! テスラのロボットは工場で働く、マスク氏:手の自由度は今年22に達する! May 06, 2024 pm 04:13 PM

テスラのロボット「オプティマス」の最新映像が公開され、すでに工場内で稼働可能となっている。通常の速度では、バッテリー(テスラの4680バッテリー)を次のように分類します:公式は、20倍の速度でどのように見えるかも公開しました - 小さな「ワークステーション」上で、ピッキング、ピッキング、ピッキング:今回は、それがリリースされたハイライトの1つビデオの内容は、オプティマスが工場内でこの作業を完全に自律的に行​​い、プロセス全体を通じて人間の介入なしに完了するというものです。そして、オプティマスの観点から見ると、自動エラー修正に重点を置いて、曲がったバッテリーを拾い上げたり配置したりすることもできます。オプティマスのハンドについては、NVIDIA の科学者ジム ファン氏が高く評価しました。オプティマスのハンドは、世界の 5 本指ロボットの 1 つです。最も器用。その手は触覚だけではありません

AI スタートアップ企業は一斉に OpenAI に転職し、イリヤが去った後にセキュリティ チームが再編成されました。 AI スタートアップ企業は一斉に OpenAI に転職し、イリヤが去った後にセキュリティ チームが再編成されました。 Jun 08, 2024 pm 01:00 PM

先週、社内の辞任と社外からの批判が相次ぐ中、OpenAIは内外のトラブルに見舞われた。 - 未亡人姉妹への侵害が世界中で白熱した議論を巻き起こした - 「覇権条項」に署名した従業員が次々と暴露 - ネットユーザーがウルトラマンの「」をリストアップ噂の払拭: Vox が入手した漏洩情報と文書によると、アルトマンを含む OpenAI の上級幹部はこれらの株式回収条項をよく認識しており、承認しました。さらに、OpenAI には、AI セキュリティという深刻かつ緊急の課題が直面しています。最近、最も著名な従業員2名を含むセキュリティ関連従業員5名が退職し、「Super Alignment」チームが解散したことで、OpenAIのセキュリティ問題が再び注目を集めている。フォーチュン誌は OpenA を報じた。

70B モデルは数秒で 1,000 トークンを生成、コード書き換えは GPT-4o を超える、OpenAI が投資したコード成果物である Cursor チームによる 70B モデルは数秒で 1,000 トークンを生成、コード書き換えは GPT-4o を超える、OpenAI が投資したコード成果物である Cursor チームによる Jun 13, 2024 pm 03:47 PM

70B モデルでは、数秒で 1,000 個のトークンを生成でき、これはほぼ 4,000 文字に相当します。研究者らは Llama3 を微調整し、高速化アルゴリズムを導入しました。ネイティブ バージョンと比較して、速度は 13 倍高速になりました。速いだけでなく、コード書き換えタスクのパフォーマンスは GPT-4o をも上回ります。この成果は、人気の AI プログラミング成果物 Cursor を開発したチーム、anysphere によるもので、OpenAI も投資に参加しました。有名な高速推論アクセラレーション フレームワークである Groq では、70BLlama3 の推論速度は 1 秒あたり 300 トークンを超える程度であることを知っておく必要があります。 Cursor の速度により、ほぼ瞬時に完全なコード ファイル編集を実現すると言えます。カースと言うと良い奴だと言う人もいる

58 行のコードは Llama 3 から 100 万コンテキストまで拡張可能、あらゆる微調整バージョンが適用可能 58 行のコードは Llama 3 から 100 万コンテキストまで拡張可能、あらゆる微調整バージョンが適用可能 May 06, 2024 pm 06:10 PM

Llama3 はオープンソースの堂々たる王様ですが、オリジナルのコンテキスト ウィンドウはわずか... 8k で、「とても良い匂いがする」という言葉を飲み込みました。現在、32k が開始点であり、100k が一般的ですが、これはオープンソース コミュニティへの貢献の余地を残す意図があるのでしょうか?オープンソース コミュニティは確かにこの機会を逃しませんでした。わずか 58 行のコードで、Llama370b の微調整されたバージョンは自動的に 1048k (100 万) コンテキストに拡張できるようになりました。舞台裏には、適切なコンテキストを拡張する Llama370BInstruct の微調整バージョンから抽出された LoRA があり、ファイルはわずか 800 MB です。次に、Mergekit を使用すると、同じアーキテクチャの他のモデルで実行したり、モデルに直接マージしたりできます。 1048k コンテキストが使用される

チャイナモバイル:人類は第4次産業革命を迎え、「3つの計画」を正式発表 チャイナモバイル:人類は第4次産業革命を迎え、「3つの計画」を正式発表 Jun 27, 2024 am 10:29 AM

6月26日のニュースによると、2024年世界移動通信会議上海(MWC上海)の開会式で、チャイナモバイル会長の楊潔氏がスピーチを行った。現在、人類社会は情報が支配し、情報とエネルギーが深く融合する第4次産業革命、すなわち「デジタルインテリジェンス革命」を迎えており、新たな生産力の形成が加速していると述べた。楊潔氏は、蒸気機関による「機械化革命」から、電気や内燃機関による「電化革命」、コンピューターやインターネットによる「情報革命」に至るまで、各段階の産業革命は、 「情報」と「エネルギー」が生産性向上をもたらす幹線

See all articles