v4l2編程接口——使用ioctl

在應用程序獲取視頻數據的流程中,都是經過 ioctl 命令與驅動程序進行交互,常見的 ioctl 命令有:緩存

[cpp] view plain copy ide

  1. VIDIOC_QUERYCAP     /* 獲取設備支持的操做 */  函數

  2. VIDIOC_G_FMT        /* 獲取設置支持的視頻格式 */  spa

  3. VIDIOC_S_FMT        /* 設置捕獲視頻的格式 */  .net

  4. VIDIOC_REQBUFS      /* 向驅動提出申請內存的請求 */  code

  5. VIDIOC_QUERYBUF     /* 向驅動查詢申請到的內存 */  orm

  6. VIDIOC_QBUF         /* 將空閒的內存加入可捕獲視頻的隊列 */  視頻

  7. VIDIOC_DQBUF        /* 將已經捕獲好視頻的內存拉出已捕獲視頻的隊列 */  blog

  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  /* 設置調諧器頻率 */  

一、struct v4l2_capability 與 VIDIOC_QUERYCAP
VIDIOC_QUERYCAP 命令經過結構 v4l2_capability 獲取設備支持的操做模式:

[cpp] view plain copy

  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. };  

其 中域 capabilities 表明設備支持的操做模式,常見的值有 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 表示是一個視頻捕捉設備而且具備數據流控制模式;另外 driver 域須要和 struct video_device 中的 name 匹配。
二、struct v4l2_format 與 VIDIOC_G_FMT、VIDIOC_S_FMT、VIDIOC_TRY_FMT

一般用 VIDIOC_S_FMT 命令經過結構 v4l2_format 初始化捕獲視頻的格式,若是要改變格式則用 VIDIOC_TRY_FMT 命令:

[cpp] view plain copy

  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. };  

常 見的捕獲模式爲 V4L2_BUF_TYPE_VIDEO_CAPTURE 即視頻捕捉模式,在此模式下 fmt 聯合體採用域 v4l2_pix_format:其中 width 爲視頻的寬、height 爲視頻的高、pixelformat 爲視頻數據格式(常見的值有 V4L2_PIX_FMT_YUV422P | V4L2_PIX_FMT_RGB565)、bytesperline 爲一行圖像佔用的字節數、sizeimage 則爲圖像佔用的總字節數、colorspace 指定設備的顏色空間。
三、struct v4l2_requestbuffers 與 VIDIOC_REQBUFS

VIDIOC_REQBUFS 命令經過結構 v4l2_requestbuffers 請求驅動申請一片連續的內存用於緩存視頻信息:

[cpp] view plain copy

  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. };  

count 指定根據圖像佔用空間大小申請的緩存區個數,type 爲視頻捕獲模式,memory 爲內存區的使用方式。

四、struct v4l2_buffer與 VIDIOC_QUERYBUF

VIDIOC_QUERYBUF 命令經過結構 v4l2_buffer 查詢驅動申請的內存區信息:

[cpp] view plain copy

  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. };  

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 肯定可用數據的起始地址和範圍。

五、enum v4l2_buf_type 與 VIDIOC_STREAMON、VIDIOC_STREAMOFF

這兩個命令使用的只是一個整形數據,即 v4l2_buf_type,通常只要指定其值爲 V4L2_BUF_TYPE_VIDEO_CAPTURE 便可。

六、struct v4l2_queryctrl 與 VIDIOC_QUERYCTRL

VIDIOC_QUERYCTRL 命令經過結構 v4l2_queryctrl 查詢驅動是否支持該 id 表明的命令,並返回該命令的各類參數:

[cpp] view plain copy

  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  

id 是命令的編號,常見的命令有兩種:一種以 V4L2_CID_BASE 爲起始值,是公用命令;一種以 V4L2_CID_PRIVATE_BASE 爲起始值,是私有命令。在通常的應用中命令值可見以下:

[cpp] view plain copy

  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) /* 幀率調節 */  

 type 爲命令值的類型(總共有7中類型的值),name 是命令的名稱,reserved 則是命令值的位圖表示,驅動會將全部的命令值都以 bit 的形式寫到 64 位的域中,上層應用查詢時能夠根據位圖判斷命令支持的值。

七、struct v4l2_control 與 VIDIOC_G_CTRL、VIDIOC_S_CTRL

VIDIOC_S_CTRL 或 VIDIOC_G_CTRL 命令經過結構 v4l2_control 設置或者獲取 id 命令的值:

[cpp] view plain copy

  1. struct v4l2_control {  

  2.     __u32            id;  

  3.     __s32            value;  

  4. };  

這個結構只有 2 個域,id 是命令編號,value 則是命令的值。

八、struct v4l2_tuner 與 VIDIOC_G_TUNER、VIDIOC_S_TUNER

VIDIOC_S_TUNER 或 VIDIOC_G_TUNER 命令經過結構 v4l2_tuner 設置調諧器的信息:

[cpp] view plain copy

  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. };  

其 中域 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。
九、struct v4l2_frequency 與 VIDIOC_G_FREQUENCY、VIDIOC_S_FREQUENCY

VIDIOC_S_FREQUENCY 或 VIDIOC_G_FREQUENCY 命令經過結構 v4l2_frequency 設置或獲取當前頻率值:

[cpp] view plain copy

  1. struct v4l2_frequency {  

  2.     __u32                 tuner;          /* 調諧器編號 */  

  3.     enum v4l2_tuner_type  type;           /* 調諧器類型 */  

  4.     __u32                 frequency;      /* 調諧器頻率 */  

  5.     __u32                 reserved[8];  

  6. };  

注意: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 plain copy

  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 << _IOC_NRBITS)-1)  

  21. #define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)  

  22. #define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)  

  23. #define _IOC_XSIZEMASK   ((1 << (_IOC_SIZEBITS+1))-1)  

  24. #define _IOC_DIRMASK     ((1 << _IOC_DIRBITS)-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)  << _IOC_DIRSHIFT) | \      /* 讀寫方向左移 29bit */  

  37.          ((type) << _IOC_TYPESHIFT) | \     /* 幻數左移 8bit */  

  38.          ((nr)   << _IOC_NRSHIFT) | \       /* 命令序號 */  

  39.          ((size) << _IOC_SIZESHIFT))        /* 參數大小左移 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)  

這裏特別說明一下 _IO 宏,該宏沒有可傳遞的變量,只用於發送命令。這是由於變量須要可變數據,只做爲命令(好比 reset)使用時,沒有必要判斷設備上的數據,所以設備驅動程序沒有必要執行文件相關的處理。在 v4l2 中使用示例以下:

[cpp] view plain copy

  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)  

v4l2 中對上述宏命令的處理在 video_ioctl2 函數中:

[cpp] view plain copy

  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 < _IOC_SIZE(cmd))  

  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 < 0)  

  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);  

而後咱們在 struct v4l2_file_operations 中將 ioctl 成員設置爲 video_ioctl2 便可。

相關文章
相關標籤/搜索