From 8db0f9343a2a9e965257de159a140cf995f113fb Mon Sep 17 00:00:00 2001 From: Ninja Tekkaman <tekkamanninja@gmail.com> Date: Sun, 2 Sep 2012 00:51:51 +0800 Subject: [PATCH] Documentation: Chinese translation of Documentation/video4linux/v4l2-framework.txt This is a Chinese translated version of Documentation/video4linux/v4l2-framework.txt Signed-off-by: Fu Wei <tekkamanninja@gmail.com> Acked-by: Harry Wei <harryxiyou@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- .../zh_CN/video4linux/v4l2-framework.txt | 983 ++++++++++++++++++ 1 file changed, 983 insertions(+) create mode 100644 Documentation/zh_CN/video4linux/v4l2-framework.txt diff --git a/Documentation/zh_CN/video4linux/v4l2-framework.txt b/Documentation/zh_CN/video4linux/v4l2-framework.txt new file mode 100644 index 000000000000..3e74f13af426 --- /dev/null +++ b/Documentation/zh_CN/video4linux/v4l2-framework.txt @@ -0,0 +1,983 @@ +Chinese translated version of Documentation/video4linux/v4l2-framework.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Mauro Carvalho Chehab <mchehab@infradead.org> +Chinese maintainer: Fu Wei <tekkamanninja@gmail.com> +--------------------------------------------------------------------- +Documentation/video4linux/v4l2-framework.txt çä¸æç¿»è¯ + +å¦ææ³è¯è®ºææ´æ°æ¬æçå 容ï¼è¯·ç´æ¥èç³»åææ¡£çç»´æ¤è ãå¦æä½ ä½¿ç¨è±æ +交æµæå°é¾çè¯ï¼ä¹å¯ä»¥åä¸æçç»´æ¤è æ±å©ãå¦ææ¬ç¿»è¯æ´æ°ä¸åæ¶æè ç¿» +è¯åå¨é®é¢ï¼è¯·èç³»ä¸æçç»´æ¤è ã +è±æçç»´æ¤è ï¼ Mauro Carvalho Chehab <mchehab@infradead.org> +ä¸æçç»´æ¤è ï¼ å ç Fu Wei <tekkamanninja@gmail.com> +ä¸æçç¿»è¯è ï¼ å ç Fu Wei <tekkamanninja@gmail.com> +ä¸æçæ ¡è¯è ï¼ å ç Fu Wei <tekkamanninja@gmail.com> + + +以ä¸ä¸ºæ£æ +--------------------------------------------------------------------- +V4L2 驱å¨æ¡æ¶æ¦è§ +============== + +æ¬ææ¡£æè¿° V4L2 æ¡æ¶ææä¾çåç§ç»æåå®ä»¬ä¹é´çå ³ç³»ã + + +ä»ç» +---- + +大é¨åç°ä»£ V4L2 设å¤ç±å¤ä¸ª IC ç»æï¼å¨ /dev ä¸å¯¼åºå¤ä¸ªè®¾å¤èç¹ï¼ +并åæ¶å建é V4L2 设å¤ï¼å¦ DVBãALSAãFBãI2C å红å¤è¾å ¥è®¾å¤ï¼ã +ç±äºè¿ç§ç¡¬ä»¶çå¤ææ§ï¼V4L2 驱å¨ä¹åå¾é常å¤æã + +å°¤å ¶æ¯ V4L2 å¿ é¡»æ¯æ IC å®ç°é³è§é¢çå¤è·¯å¤ç¨åç¼è§£ç ï¼è¿å°±æ´å¢å äºå ¶ +å¤ææ§ãé常è¿äº IC éè¿ä¸ä¸ªæå¤ä¸ª I2C æ»çº¿è¿æ¥å°ä¸»æ¡¥é©±å¨å¨ï¼ä½ä¹å¯ +使ç¨å ¶ä»æ»çº¿ãè¿äºè®¾å¤ç§°ä¸ºâå设å¤âã + +é¿æ以æ¥ï¼è¿ä¸ªæ¡æ¶ä» éäºéè¿ video_device ç»æä½å建 V4L 设å¤èç¹ï¼ +å¹¶ä½¿ç¨ video_buf å¤çè§é¢ç¼å²ï¼æ³¨ï¼æ¬æä¸è®¨è®º video_buf æ¡æ¶ï¼ã + +è¿æå³çææ驱å¨å¿ é¡»èªå·±è®¾ç½®è®¾å¤å®ä¾å¹¶è¿æ¥å°å设å¤ãå ¶ä¸ä¸é¨åè¦æ£ç¡®å° +å®ææ¯æ¯è¾å¤æçï¼ä½¿å¾è®¸å¤é©±å¨é½æ²¡ææ£ç¡®å°å®ç°ã + +ç±äºæ¡æ¶ç缺失ï¼æå¾å¤éç¨ä»£ç é½ä¸å¯éå¤å©ç¨ã + +å æ¤ï¼è¿ä¸ªæ¡æ¶æ建ææ驱å¨é½éè¦çåºæ¬ç»æåï¼èç»ä¸çæ¡æ¶å°ä½¿éç¨ä»£ç +å建æå®ç¨å½æ°å¹¶å¨ææ驱å¨ä¸å ±äº«åå¾æ´å 容æã + + +驱å¨ç»æ +------- + +ææ V4L2 驱å¨é½æå¦ä¸ç»æï¼ + +1) æ¯ä¸ªè®¾å¤å®ä¾çç»æä½--å å«å ¶è®¾å¤ç¶æã + +2) åå§ååæ§å¶å设å¤çæ¹æ³ï¼å¦ææï¼ã + +3) å建 V4L2 设å¤èç¹ (/dev/videoXã/dev/vbiX å /dev/radioX) + 并è·è¸ªè®¾å¤èç¹çç¹å®æ°æ®ã + +4) ç¹å®æ件å¥æç»æä½--å å«æ¯ä¸ªæ件å¥æçæ°æ®ã + +5) è§é¢ç¼å²å¤çã + +以ä¸æ¯å®ä»¬çåç¥å ³ç³»å¾ï¼ + + device instancesï¼è®¾å¤å®ä¾ï¼ + | + +-sub-device instancesï¼å设å¤å®ä¾ï¼ + | + \-V4L2 device nodesï¼V4L2 设å¤èç¹ï¼ + | + \-filehandle instancesï¼æ件å¥æå®ä¾ï¼ + + +æ¡æ¶ç»æ +------- + +该æ¡æ¶é常类似驱å¨ç»æï¼å®æä¸ä¸ª v4l2_device ç»æç¨äºä¿åè®¾å¤ +å®ä¾çæ°æ®ï¼ä¸ä¸ª v4l2_subdev ç»æä½ä»£è¡¨å设å¤å®ä¾ï¼video_device +ç»æä½ä¿å V4L2 设å¤èç¹çæ°æ®ï¼å°æ¥ v4l2_fh ç»æä½å°è·è¸ªæ件å¥æ +å®ä¾ï¼ææªå°æªå®ç°ï¼ã + +V4L2 æ¡æ¶ä¹å¯ä¸åªä½æ¡æ¶æ´åï¼å¯éçï¼ãå¦æ驱å¨è®¾ç½®äº v4l2_device +ç»æä½ç mdev åï¼å设å¤åè§é¢èç¹çå ¥å£å°èªå¨åºç°å¨åªä½æ¡æ¶ä¸ã + + +v4l2_device ç»æä½ +---------------- + +æ¯ä¸ªè®¾å¤å®ä¾é½éè¿ v4l2_device (v4l2-device.h)ç»æä½æ¥è¡¨ç¤ºã +ç®å设å¤å¯ä»¥ä» åé è¿ä¸ªç»æä½ï¼ä½å¨å¤§å¤æ°æ åµä¸ï¼é½ä¼å°è¿ä¸ªç»æä½ +åµå ¥å°ä¸ä¸ªæ´å¤§çç»æä½ä¸ã + +ä½ å¿ é¡»æ³¨åè¿ä¸ªè®¾å¤å®ä¾ï¼ + + v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev); + +注åæä½å°ä¼åå§å v4l2_device ç»æä½ãå¦æ dev->driver_data å +为 NULLï¼å°±å°å ¶æå v4l2_devã + +éè¦ä¸åªä½æ¡æ¶æ´åç驱å¨å¿ é¡»æå¨è®¾ç½® dev->driver_dataï¼æåå å« +v4l2_device ç»æä½å®ä¾ç驱å¨ç¹å®è®¾å¤ç»æä½ãè¿å¯ä»¥å¨æ³¨å V4L2 è®¾å¤ +å®ä¾åéè¿ dev_set_drvdata() å½æ°å®æãåæ¶å¿ 须设置 v4l2_device +ç»æä½ç mdev åï¼æåéå½çåå§å并注åè¿ç media_device å®ä¾ã + +å¦æ v4l2_dev->name 为空ï¼åå®å°è¢«è®¾ç½®ä¸ºä» dev ä¸è¡çåºçå¼ï¼ä¸ºäº +æ´å 精确ï¼å½¢å¼ä¸ºé©±å¨ååè· bus_idï¼ãå¦æä½ å¨è°ç¨ v4l2_device_register +åå·²ç»è®¾ç½®å¥½äºï¼åä¸ä¼è¢«ä¿®æ¹ãå¦æ dev 为 NULLï¼åä½ *å¿ é¡»*å¨è°ç¨ +v4l2_device_register å设置 v4l2_dev->nameã + +ä½ å¯ä»¥åºäºé©±å¨åå驱å¨çå ¨å± atomic_t ç±»åçå®ä¾ç¼å·ï¼éè¿ +v4l2_device_set_name() 设置 nameãè¿æ ·ä¼çæ类似 ivtv0ãivtv1 ç +ååãè¥é©±å¨å以æ°åç»å°¾ï¼åä¼å¨ç¼å·å驱å¨åé´æå ¥ä¸ä¸ªç ´æå·ï¼å¦ï¼ +cx18-0ãcx18-1 çãæ¤å½æ°è¿åå®ä¾ç¼å·ã + +第ä¸ä¸ª âdevâ åæ°é常æ¯ä¸ä¸ªæå pci_devãusb_interface æ +platform_device çæéãå¾å°ä½¿å ¶ä¸º NULLï¼é¤éæ¯ä¸ä¸ªISA设å¤æè +å½ä¸ä¸ªè®¾å¤å建äºå¤ä¸ª PCI 设å¤ï¼ä½¿å¾ v4l2_dev æ æ³ä¸ä¸ä¸ªç¹å®çç¶è®¾å¤ +å ³èã + +ä½ ä¹å¯ä»¥æä¾ä¸ä¸ª notify() åè°ï¼ä½¿å设å¤å¯ä»¥è°ç¨å®å®ç°äºä»¶éç¥ã +ä½è¿ä¸ªè®¾ç½®ä¸å设å¤ç¸å ³ãå设å¤æ¯æçä»»ä½éç¥å¿ é¡»å¨ +include/media/<subdevice>.h ä¸å®ä¹ä¸ä¸ªæ¶æ¯å¤´ã + +注é v4l2_device 使ç¨å¦ä¸å½æ°ï¼ + + v4l2_device_unregister(struct v4l2_device *v4l2_dev); + +å¦æ dev->driver_data åæå v4l2_devï¼å°ä¼è¢«é置为 NULLã注éåæ¶ +ä¼èªå¨ä»è®¾å¤ä¸æ³¨éææå设å¤ã + +å¦æä½ æä¸ä¸ªçææ设å¤ï¼å¦USB设å¤ï¼ï¼åå½æå¼åçæ¶ï¼ç¶è®¾å¤å°æ æã +ç±äº v4l2_device æä¸ä¸ªæåç¶è®¾å¤çæéå¿ é¡»è¢«æ¸ é¤ï¼åæ¶æ å¿ç¶è®¾å¤ +å·²æ¶å¤±ï¼æä»¥å¿ é¡»è°ç¨ä»¥ä¸å½æ°ï¼ + + v4l2_device_disconnect(struct v4l2_device *v4l2_dev); + +è¿ä¸ªå½æ°å¹¶*ä¸*注éå设å¤ï¼å æ¤ä½ ä¾ç¶è¦è°ç¨ v4l2_device_unregister() +å½æ°ãå¦æä½ ç驱å¨å¨å¹¶éçææçï¼å°±æ²¡æå¿ è¦è°ç¨ v4l2_device_disconnect()ã + +ææ¶ä½ éè¦éåææ被ç¹å®é©±å¨æ³¨åç设å¤ãè¿é常åçå¨å¤ä¸ªè®¾å¤é©±å¨ä½¿ç¨ +åä¸ä¸ªç¡¬ä»¶çæ åµä¸ãå¦ï¼ivtvfb 驱å¨æ¯ä¸ä¸ªä½¿ç¨ ivtv 硬件ç帧ç¼å²é©±å¨ï¼ +åæ¶ alsa 驱å¨ä¹ä½¿ç¨æ¤ç¡¬ä»¶ã + +ä½ å¯ä»¥ä½¿ç¨å¦ä¸ä¾ç¨éåææ注åç设å¤ï¼ + +static int callback(struct device *dev, void *p) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + + /* æµè¯è¿ä¸ªè®¾å¤æ¯å¦å·²ç»åå§å */ + if (v4l2_dev == NULL) + return 0; + ... + return 0; +} + +int iterate(void *p) +{ + struct device_driver *drv; + int err; + + /* å¨PCI æ»çº¿ä¸æ¥æ¾ivtv驱å¨ã + pci_bus_typeæ¯å ¨å±ç. 对äºUSBæ»çº¿ä½¿ç¨usb_bus_typeã */ + drv = driver_find("ivtv", &pci_bus_type); + /* éåææçivtv设å¤å®ä¾ */ + err = driver_for_each_device(drv, NULL, p, callback); + put_driver(drv); + return err; +} + +ææ¶ä½ éè¦ä¸ä¸ªè®¾å¤å®ä¾çè¿è¡è®¡æ°ãè¿ä¸ªé常ç¨äºæ å°ä¸ä¸ªè®¾å¤å®ä¾å°ä¸ä¸ª +模åéæ©æ°ç»çç´¢å¼ã + +æ¨èæ¹æ³å¦ä¸ï¼ + +static atomic_t drv_instance = ATOMIC_INIT(0); + +static int __devinit drv_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + ... + state->instance = atomic_inc_return(&drv_instance) - 1; +} + +å¦æä½ æå¤ä¸ªè®¾å¤èç¹ï¼å¯¹äºçææ设å¤ï¼ç¥éä½æ¶æ³¨é v4l2_device ç»æä½ +å°±æ¯è¾å°é¾ãä¸ºæ¤ v4l2_device æå¼ç¨è®¡æ°æ¯æãå½è°ç¨ video_register_device +æ¶å¢å å¼ç¨è®¡æ°ï¼è设å¤èç¹éæ¾æ¶åå°å¼ç¨è®¡æ°ãå½å¼ç¨è®¡æ°ä¸ºé¶ï¼å +v4l2_device çrelease() åè°å°è¢«æ§è¡ãä½ å°±å¯ä»¥å¨æ¤æ¶åæåçæ¸ çå·¥ä½ã + +å¦æå建äºå ¶ä»è®¾å¤èç¹ï¼æ¯å¦ ALSAï¼ï¼åä½ å¯ä»¥éè¿ä»¥ä¸å½æ°æå¨å¢å +å¼ç¨è®¡æ°ï¼ + +void v4l2_device_get(struct v4l2_device *v4l2_dev); + +æ: + +int v4l2_device_put(struct v4l2_device *v4l2_dev); + +ç±äºå¼ç¨ææ¯åå§å为 1 ï¼ä½ ä¹éè¦å¨ disconnect() åè°ï¼å¯¹äº USB 设å¤ï¼ä¸ +è°ç¨ v4l2_device_putï¼æè remove() åè°ï¼ä¾å¦å¯¹äº PCI 设å¤ï¼ï¼å¦å +å¼ç¨è®¡æ°å°æ°¸è¿ä¸ä¼ä¸º 0 ã + +v4l2_subdevç»æä½ +------------------ + +许å¤é©±å¨éè¦ä¸å设å¤éä¿¡ãè¿äºè®¾å¤å¯ä»¥å®æåç§ä»»å¡ï¼ä½é常ä»ä»¬è´è´£ +é³è§é¢å¤ç¨åç¼è§£ç ãå¦ç½ç»æå头çå设å¤é常æ¯ä¼ æå¨åæå头æ§å¶å¨ã + +è¿äºä¸è¬ä¸º I2C æ¥å£è®¾å¤ï¼ä½å¹¶ä¸ä¸å®é½æ¯ã为äºç»é©±å¨æä¾è°ç¨å设å¤ç +ç»ä¸æ¥å£ï¼v4l2_subdev ç»æä½ï¼v4l2-subdev.hï¼äº§çäºã + +æ¯ä¸ªå设å¤é©±å¨é½å¿ é¡»æä¸ä¸ª v4l2_subdev ç»æä½ãè¿ä¸ªç»æä½å¯ä»¥åç¬ +代表ä¸ä¸ªç®åçå设å¤ï¼ä¹å¯ä»¥åµå ¥å°ä¸ä¸ªæ´å¤§çç»æä½ä¸ï¼ä¸æ´å¤è®¾å¤ç¶æ +ä¿¡æ¯ä¿åå¨ä¸èµ·ãé常æä¸ä¸ªä¸çº§è®¾å¤ç»æä½ï¼æ¯å¦ï¼i2c_clientï¼å å«äº +å æ ¸å建ç设å¤æ°æ®ãå»ºè®®ä½¿ç¨ v4l2_set_subdevdata() å°è¿ä¸ªç»æä½ç +æéä¿åå¨ v4l2_subdev çç§ææ°æ®å(dev_priv)ä¸ãè¿ä½¿å¾éè¿ v4l2_subdev +æ¾å°å®é çä½å±æ»çº¿ç¹å®è®¾å¤æ°æ®åå¾å®¹æã + +ä½ åæ¶éè¦ä¸ä¸ªä»ä½å±ç»æä½è·å v4l2_subdev æéçæ¹æ³ã对äºå¸¸ç¨ç +i2c_client ç»æä½ï¼i2c_set_clientdata() å½æ°å¯ç¨äºä¿åä¸ä¸ª v4l2_subdev +æéï¼å¯¹äºå ¶ä»æ»çº¿ä½ å¯è½éè¦ä½¿ç¨å ¶ä»ç¸å ³å½æ°ã + +桥驱å¨ä¸ä¹åºä¿åæ¯ä¸ªå设å¤çç§ææ°æ®ï¼æ¯å¦ä¸ä¸ªæåç¹å®æ¡¥çå设å¤ç§æ +æ°æ®çæéãä¸ºæ¤ v4l2_subdev ç»æä½æä¾ä¸»æºç§ææ°æ®å(host_priv)ï¼ +并å¯éè¿ v4l2_get_subdev_hostdata() å v4l2_set_subdev_hostdata() +访é®ã + +ä»æ»çº¿æ¡¥é©±å¨çè§è§ï¼é©±å¨å è½½å设å¤æ¨¡å并以æç§æ¹å¼è·å¾ v4l2_subdev +ç»æä½æéãå¯¹äº i2c æ»çº¿è®¾å¤ç¸å¯¹ç®åï¼è°ç¨ i2c_get_clientdata()ã +对äºå ¶ä»æ»çº¿ä¹éè¦å类似çæä½ãé对 I2C æ»çº¿ä¸çå设å¤è¾ å©å½æ°å¸®ä½ +å®æäºå¤§é¨åå¤æçå·¥ä½ã + +æ¯ä¸ª v4l2_subdev é½å å«å设å¤é©±å¨éè¦å®ç°çå½æ°æéï¼å¦æ对æ¤è®¾å¤ +ä¸éç¨ï¼å¯ä¸ºNULLï¼ãç±äºå设å¤å¯å®æ许å¤ä¸åçå·¥ä½ï¼èå¨ä¸ä¸ªåºå¤§ç +å½æ°æéç»æä½ä¸éå¸¸ä» æå°æ°æç¨çå½æ°å®ç°å ¶åè½è¯å®ä¸åéãæä»¥ï¼ +å½æ°æéæ ¹æ®å ¶å®ç°çåè½è¢«åç±»ï¼æ¯ä¸ç±»é½æèªå·±çå½æ°æéç»æä½ã + +顶å±å½æ°æéç»æä½å å«äºæååç±»å½æ°æéç»æä½çæéï¼å¦æå设å¤é©±å¨ +ä¸æ¯æ该类å½æ°ä¸çä»»ä½ä¸ä¸ªåè½ï¼åæå该类ç»æä½çæé为NULLã + +è¿äºç»æä½å®ä¹å¦ä¸ï¼ + +struct v4l2_subdev_core_ops { + int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip); + int (*log_status)(struct v4l2_subdev *sd); + int (*init)(struct v4l2_subdev *sd, u32 val); + ... +}; + +struct v4l2_subdev_tuner_ops { + ... +}; + +struct v4l2_subdev_audio_ops { + ... +}; + +struct v4l2_subdev_video_ops { + ... +}; + +struct v4l2_subdev_pad_ops { + ... +}; + +struct v4l2_subdev_ops { + const struct v4l2_subdev_core_ops *core; + const struct v4l2_subdev_tuner_ops *tuner; + const struct v4l2_subdev_audio_ops *audio; + const struct v4l2_subdev_video_ops *video; + const struct v4l2_subdev_pad_ops *video; +}; + +å ¶ä¸ coreï¼æ ¸å¿ï¼å½æ°éé常å¯ç¨äºææå设å¤ï¼å ¶ä»ç±»å«çå®ç°ä¾èµäº +å设å¤ãå¦è§é¢è®¾å¤å¯è½ä¸æ¯æé³é¢æä½å½æ°ï¼åä¹äº¦ç¶ã + +è¿æ ·ç设置å¨éå¶äºå½æ°æéæ°éçåæ¶ï¼è¿ä½¿å¢å æ°çæä½å½æ°ååç±» +åå¾è¾ä¸ºå®¹æã + +å设å¤é©±å¨å¯ä½¿ç¨å¦ä¸å½æ°åå§å v4l2_subdev ç»æä½ï¼ + + v4l2_subdev_init(sd, &ops); + +ç¶åï¼ä½ å¿ é¡»ç¨ä¸ä¸ªå¯ä¸çåååå§å subdev->nameï¼å¹¶åå§å模åç +owner åãè¥ä½¿ç¨ i2c è¾ å©å½æ°ï¼è¿äºé½ä¼å¸®ä½ å¤ç好ã + +è¥éååªä½æ¡æ¶æ´åï¼ä½ å¿ é¡»è°ç¨ media_entity_init() åå§å v4l2_subdev +ç»æä½ä¸ç media_entity ç»æä½ï¼entity åï¼ï¼ + + struct media_pad *pads = &my_sd->pads; + int err; + + err = media_entity_init(&sd->entity, npads, pads, 0); + +pads æ°ç»å¿ é¡»é¢å åå§åãæ é¡»æå¨è®¾ç½® media_entity ç type å +name åï¼ä½å¦æå¿ è¦ï¼revision åå¿ é¡»åå§åã + +å½ï¼ä»»ä½ï¼å设å¤èç¹è¢«æå¼/å ³éï¼å¯¹ entity çå¼ç¨å°è¢«èªå¨è·å/éæ¾ã + +å¨å设å¤è¢«æ³¨éä¹åï¼ä¸è¦å¿è®°æ¸ ç media_entity ç»æä½ï¼ + + media_entity_cleanup(&sd->entity); + +å¦æå设å¤é©±å¨è¶åäºå¤çè§é¢å¹¶æ´åè¿äºåªä½æ¡æ¶ï¼å¿ é¡»ä½¿ç¨ v4l2_subdev_pad_ops +æ¿ä»£ v4l2_subdev_video_ops å®ç°æ ¼å¼ç¸å ³çåè½ã + +è¿ç§æ åµä¸ï¼å设å¤é©±å¨åºè¯¥è®¾ç½® link_validate åï¼ä»¥æä¾å®èªèº«çé¾æ¥ +éªè¯å½æ°ãé¾æ¥éªè¯å½æ°åºå¯¹ç®¡éï¼ä¸¤ç«¯é¾æ¥çé½æ¯ V4L2 å设å¤ï¼ä¸çæ¯ä¸ª +é¾æ¥è°ç¨ã驱å¨è¿è¦è´è´£éªè¯å设å¤åè§é¢èç¹é´æ ¼å¼é ç½®çæ£ç¡®æ§ã + +å¦æ link_validate æä½æ²¡æ设置ï¼é»è®¤ç v4l2_subdev_link_validate_default() +å½æ°å°ä¼è¢«è°ç¨ãè¿ä¸ªå½æ°ä¿è¯å®½ãé«ååªä½æ»çº¿åç´ æ ¼å¼å¨é¾æ¥çæ¶å两端 +é½ä¸è´ãå设å¤é©±å¨é¤äºå®ä»¬èªå·±çæ£æµå¤ï¼ä¹å¯ä»¥èªç±ä½¿ç¨è¿ä¸ªå½æ°ä»¥æ§è¡ +ä¸é¢æå°çæ£æ¥ã + +设å¤ï¼æ¡¥ï¼é©±å¨ç¨åºå¿ é¡»å v4l2_device 注å v4l2_subdevï¼ + + int err = v4l2_device_register_subdev(v4l2_dev, sd); + +å¦æå设å¤æ¨¡åå¨å®æ³¨ååæ¶å¤±ï¼è¿ä¸ªæä½å¯è½å¤±è´¥ãå¨è¿ä¸ªå½æ°æåè¿ååï¼ +subdev->dev åå°±æåäº v4l2_deviceã + +å¦æ v4l2_device ç¶è®¾å¤ç mdev å为é NULL å¼ï¼åå设å¤å®ä½å°è¢«èªå¨ +注å为åªä½è®¾å¤ã + +注éå设å¤åå¯ç¨å¦ä¸å½æ°ï¼ + + v4l2_device_unregister_subdev(sd); + +æ¤åï¼å设å¤æ¨¡åå°±å¯å¸è½½ï¼ä¸ sd->dev == NULLã + +注åä¹è®¾å¤åï¼å¯éè¿ä»¥ä¸æ¹å¼ç´æ¥è°ç¨å ¶æä½å½æ°ï¼ + + err = sd->ops->core->g_chip_ident(sd, &chip); + +ä½ä½¿ç¨å¦ä¸å®ä¼æ¯è¾å®¹æä¸åéï¼ + + err = v4l2_subdev_call(sd, core, g_chip_ident, &chip); + +è¿ä¸ªå®å°ä¼å NULL æéæ£æ¥ï¼å¦æ subdev 为 NULLï¼åè¿å-ENODEVï¼å¦æ +subdev->core æ subdev->core->g_chip_ident 为 NULLï¼åè¿å -ENOIOCTLCMDï¼ +å¦åå°è¿å subdev->ops->core->g_chip_ident ops è°ç¨çå®é ç»æã + +ææ¶ä¹å¯è½åæ¶è°ç¨æææä¸ç³»åå设å¤çæ个æä½å½æ°ï¼ + + v4l2_device_call_all(v4l2_dev, 0, core, g_chip_ident, &chip); + +ä»»ä½ä¸æ¯ææ¤æä½çå设å¤é½ä¼è¢«è·³è¿ï¼å¹¶å¿½ç¥é误è¿åå¼ãä½å¦æä½ éè¦ +æ£æ¥åºéç ï¼åå¯ä½¿ç¨å¦ä¸å½æ°ï¼ + + err = v4l2_device_call_until_err(v4l2_dev, 0, core, g_chip_ident, &chip); + +é¤ -ENOIOCTLCMD å¤çä»»ä½é误é½ä¼è·³åºå¾ªç¯å¹¶è¿åé误å¼ãå¦æï¼é¤ -ENOIOCTLCMD +å¤ï¼æ²¡æé误åçï¼åè¿å 0ã + +对äºä»¥ä¸ä¸¤ä¸ªå½æ°ç第äºä¸ªåæ°ä¸ºç» IDãå¦æ为 0ï¼åææå设å¤é½ä¼æ§è¡ +è¿ä¸ªæä½ãå¦æ为é 0 å¼ï¼ååªæé£äºç» ID å¹é çå设å¤æä¼æ§è¡æ¤æä½ã +å¨æ¡¥é©±å¨æ³¨åä¸ä¸ªå设å¤åï¼å¯ä»¥è®¾ç½® sd->grp_id 为任ä½ææå¼ï¼é»è®¤å¼ä¸º +0ï¼ãè¿ä¸ªå¼å±äºæ¡¥é©±å¨ï¼ä¸å设å¤é©±å¨å°ä¸ä¼ä¿®æ¹å使ç¨å®ã + +ç» ID èµäºäºæ¡¥é©±å¨æ´å¤å¯¹äºå¦ä½è°ç¨åè°çæ§å¶ãä¾å¦ï¼çµè·¯æ¿ä¸æå¤ä¸ª +é³é¢è¯çï¼æ¯ä¸ªé½ææ¹åé³éçè½åãä½å½ç¨æ·æ³è¦æ¹åé³éçæ¶åï¼é常 +åªæä¸ä¸ªä¼è¢«å®é 使ç¨ãä½ å¯ä»¥å¯¹è¿æ ·çå设å¤è®¾ç½®ç» ID 为ï¼ä¾å¦ AUDIO_CONTROLLERï¼ +并å¨è°ç¨ v4l2_device_call_all() æ¶æå®å®ä¸ºç» ID å¼ãè¿å°±ä¿è¯äºåªæ +éè¦çå设å¤æä¼æ§è¡è¿ä¸ªåè°ã + +å¦æå设å¤éè¦éç¥å®ç v4l2_device ç¶è®¾å¤ä¸ä¸ªäºä»¶ï¼å¯ä»¥è°ç¨ +v4l2_subdev_notify(sd, notification, arg)ãè¿ä¸ªå®æ£æ¥æ¯å¦æä¸ä¸ª +notify() åè°è¢«æ³¨åï¼å¦æ没æï¼è¿å -ENODEVãå¦åè¿å notify() è°ç¨ +ç»æã + +ä½¿ç¨ v4l2_subdev ç好å¤å¨äºå®æ¯ä¸ä¸ªéç¨ç»æä½ï¼ä¸ä¸å å«ä»»ä½åºå±ç¡¬ä»¶ +ä¿¡æ¯ãææ驱å¨å¯ä»¥å å«å¤ä¸ª I2C æ»çº¿çå设å¤ï¼ä½ä¹æå设å¤æ¯éè¿ GPIO +æ§å¶ãè¿ä¸ªåºå«ä» å¨é 置设å¤æ¶æå ³ç³»ï¼ä¸æ¦å设å¤æ³¨åå®æï¼å¯¹äº v4l2 +åç³»ç»æ¥è¯´å°±å®å ¨éæäºã + + +V4L2 å设å¤ç¨æ·ç©ºé´API +-------------------- + +é¤äºéè¿ v4l2_subdev_ops ç»æ导åºçå æ ¸ APIï¼V4L2 å设å¤ä¹å¯ä»¥ç´æ¥ +éè¿ç¨æ·ç©ºé´åºç¨ç¨åºæ¥æ§å¶ã + +å¯ä»¥å¨ /dev ä¸å建å为 v4l-subdevX 设å¤èç¹ï¼ä»¥éè¿å ¶ç´æ¥è®¿é®å设å¤ã +å¦æå设å¤æ¯æç¨æ·ç©ºé´ç´æ¥é ç½®ï¼å¿ é¡»å¨æ³¨åå设置 V4L2_SUBDEV_FL_HAS_DEVNODE +æ å¿ã + +注åå设å¤ä¹åï¼ v4l2_device 驱å¨ä¼éè¿è°ç¨ v4l2_device_register_subdev_nodes() +å½æ°ä¸ºææ已注åå¹¶è®¾ç½®äº V4L2_SUBDEV_FL_HAS_DEVNODE çå设å¤å建 +设å¤èç¹ãè¿äºè®¾å¤èç¹ä¼å¨å设å¤æ³¨éæ¶èªå¨å é¤ã + +è¿äºè®¾å¤èç¹å¤ç V4L2 API çä¸ä¸ªåéã + +VIDIOC_QUERYCTRL +VIDIOC_QUERYMENU +VIDIOC_G_CTRL +VIDIOC_S_CTRL +VIDIOC_G_EXT_CTRLS +VIDIOC_S_EXT_CTRLS +VIDIOC_TRY_EXT_CTRLS + + è¿äº ioctls æ§å¶ä¸ V4L2 ä¸å®ä¹çä¸è´ãä»ä»¬è¡ä¸ºç¸åï¼å¯ä¸ç + ä¸åæ¯ä»ä»¬åªå¤çå设å¤çæ§å¶å®ç°ãæ ¹æ®é©±å¨ç¨åºï¼è¿äºæ§å¶ä¹ + å¯ä»¥éè¿ä¸ä¸ªï¼æå¤ä¸ªï¼ V4L2 设å¤èç¹è®¿é®ã + +VIDIOC_DQEVENT +VIDIOC_SUBSCRIBE_EVENT +VIDIOC_UNSUBSCRIBE_EVENT + + è¿äº ioctls äºä»¶ä¸ V4L2 ä¸å®ä¹çä¸è´ãä»ä»¬è¡ä¸ºç¸åï¼å¯ä¸ç + ä¸åæ¯ä»ä»¬åªå¤çå设å¤äº§ççäºä»¶ãæ ¹æ®é©±å¨ç¨åºï¼è¿äºäºä»¶ä¹ + å¯ä»¥éè¿ä¸ä¸ªï¼æå¤ä¸ªï¼ V4L2 设å¤èç¹ä¸æ¥ã + + è¦ä½¿ç¨äºä»¶éç¥çå设å¤é©±å¨ï¼å¨æ³¨åå设å¤åå¿ é¡»å¨ v4l2_subdev::flags + ä¸è®¾ç½® V4L2_SUBDEV_USES_EVENTS å¹¶å¨ v4l2_subdev::nevents + ä¸åå§åäºä»¶éå深度ã注åå®æåï¼äºä»¶ä¼å¨ v4l2_subdev::devnode + 设å¤èç¹ä¸åé常ä¸æ ·è¢«æéã + + 为æ£ç¡®æ¯æäºä»¶æºå¶ï¼poll() æ件æä½ä¹åºè¢«å®ç°ã + +ç§æ ioctls + + ä¸å¨ä»¥ä¸å表ä¸çææ ioctls ä¼éè¿ core::ioctl æä½ç´æ¥ä¼ é + ç»å设å¤é©±å¨ã + + +I2C å设å¤é©±å¨ +------------- + +ç±äºè¿äºé©±å¨å¾å¸¸è§ï¼æ以å ç¹æä¾äºç¹å®çè¾ å©å½æ°(v4l2-common.h)让è¿äº +设å¤ç使ç¨æ´å 容æã + +æ·»å v4l2_subdev æ¯æçæ¨èæ¹æ³æ¯è®© I2C 驱å¨å° v4l2_subdev ç»æä½ +åµå ¥å°ä¸ºæ¯ä¸ª I2C 设å¤å®ä¾å建çç¶æç»æä½ä¸ãèæç®åç设å¤æ²¡æç¶æ +ç»æä½ï¼æ¤æ¶å¯ä»¥ç´æ¥å建ä¸ä¸ª v4l2_subdev ç»æä½ã + +ä¸ä¸ªå ¸åçç¶æç»æä½å¦ä¸æ示ï¼âchipnameâç¨è¯çå代æ¿ï¼ï¼ + +struct chipname_state { + struct v4l2_subdev sd; + ... /* éå çç¶æå*/ +}; + +åå§å v4l2_subdev ç»æä½çæ¹æ³å¦ä¸ï¼ + + v4l2_i2c_subdev_init(&state->sd, client, subdev_ops); + +è¿ä¸ªå½æ°å°å¡«å v4l2_subdev ç»æä½ä¸çææåï¼å¹¶ä¿è¯ v4l2_subdev å +i2c_client é½æåå½¼æ¤ã + +åæ¶ï¼ä½ ä¹åºè¯¥ä¸ºä» v4l2_subdev æéæ¾å° chipname_state ç»æä½æé +æ·»å ä¸ä¸ªè¾ å©å èå½æ°ã + +static inline struct chipname_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct chipname_state, sd); +} + +使ç¨ä»¥ä¸å½æ°å¯ä»¥éè¿ v4l2_subdev ç»æä½æéè·å¾ i2c_client ç»æä½ +æéï¼ + + struct i2c_client *client = v4l2_get_subdevdata(sd); + +è以ä¸å½æ°åç¸åï¼éè¿ i2c_client ç»æä½æéè·å¾ v4l2_subdev ç»æä½ +æéï¼ + + struct v4l2_subdev *sd = i2c_get_clientdata(client); + +å½ remove()å½æ°è¢«è°ç¨åï¼å¿ é¡»ä¿è¯å è°ç¨ v4l2_device_unregister_subdev(sd)ã +æ¤æä½å°ä¼ä»æ¡¥é©±å¨ä¸æ³¨éå设å¤ãå³ä½¿å设å¤æ²¡æ注åï¼è°ç¨æ¤å½æ°ä¹æ¯ +å®å ¨çã + +å¿ é¡»è¿æ ·åçåå æ¯ï¼å½æ¡¥é©±å¨æ³¨é i2c éé å¨æ¶ï¼remove()åè°å½æ° +ä¼è¢«é£ä¸ªéé å¨ä¸ç i2c 设å¤è°ç¨ãæ¤åï¼ç¸åºç v4l2_subdev ç»æä½ +å°±ä¸åå¨äºï¼ææå®ä»¬å¿ é¡»å 被注éãå¨ remove()åè°å½æ°ä¸è°ç¨ +v4l2_device_unregister_subdev(sd)ï¼å¯ä»¥ä¿è¯æ§è¡æ»æ¯æ£ç¡®çã + + +桥驱å¨ä¹æä¸äºè¾ ç»å½æ°å¯ç¨ï¼ + +struct v4l2_subdev *sd = v4l2_i2c_new_subdev(v4l2_dev, adapter, + "module_foo", "chipid", 0x36, NULL); + +è¿ä¸ªå½æ°ä¼å è½½ç»å®ç模åï¼å¦æ没æ模åéè¦å è½½ï¼å¯ä»¥ä¸º NULLï¼ï¼ +并ç¨ç»å®ç i2c éé å¨ç»æä½æéï¼i2c_adapterï¼å å¨ä»¶å°åï¼chip/addressï¼ +ä½ä¸ºåæ°è°ç¨ i2c_new_device()ãå¦æä¸å顺å©ï¼åå°±å¨ v4l2_device +ä¸æ³¨åäºå设å¤ã + +ä½ ä¹å¯ä»¥å©ç¨ v4l2_i2c_new_subdev()çæåä¸ä¸ªåæ°ï¼ä¼ éä¸ä¸ªå¯è½ç +I2C å°åæ°ç»ï¼è®©å½æ°èªå¨æ¢æµãè¿äºæ¢æµå°ååªæå¨åä¸ä¸ªåæ°ä¸º 0 ç +æ åµä¸ä½¿ç¨ãéé¶åæ°æå³çä½ ç¥éåç¡®ç i2c å°åï¼æ以æ¤æ¶æ é¡»è¿è¡ +æ¢æµã + +å¦æåºéï¼ä¸¤ä¸ªå½æ°é½è¿å NULLã + +注æï¼ä¼ éç» v4l2_i2c_new_subdev()ç chipid é常ä¸æ¨¡ååä¸è´ã +å®å è®¸ä½ æå®ä¸ä¸ªè¯ççåä½ï¼æ¯å¦âsaa7114âæâsaa7115âãä¸è¬éè¿ +i2c 驱å¨èªå¨æ¢æµãchipid ç使ç¨æ¯å¨ä»åéè¦æ·±å ¥äºè§£çäºæ ãè¿ä¸ªä¸ +i2c 驱å¨ä¸åï¼è¾å®¹ææ··æ·ãè¦ç¥éæ¯æåªäºè¯çåä½ï¼ä½ å¯ä»¥æ¥é i2c +驱å¨ä»£ç ç i2c_device_id 表ï¼ä¸é¢ååºäºææå¯è½æ¯æçè¯çã + +è¿æä¸¤ä¸ªè¾ å©å½æ°ï¼ + +v4l2_i2c_new_subdev_cfgï¼è¿ä¸ªå½æ°æ·»å æ°ç irq å platform_data +åæ°ï¼å¹¶æâaddrâåâprobed_addrsâåæ°ï¼å¦æ addr éé¶ï¼åè¢«ä½¿ç¨ +ï¼ä¸æ¢æµåä½ï¼ï¼å¦å probed_addrs ä¸çå°åå°ç¨äºèªå¨æ¢æµã + +ä¾å¦ï¼ä»¥ä¸ä»£ç å°ä¼æ¢æµå°åï¼0x10ï¼ï¼ + +struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, + "module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10)); + +v4l2_i2c_new_subdev_board 使ç¨ä¸ä¸ª i2c_board_info ç»æä½ï¼å°å ¶ +æ¿ä»£ irqãplatform_data å add råæ°ä¼ éç» i2c 驱å¨ã + +å¦æå设å¤æ¯æ s_config æ ¸å¿æä½ï¼è¿ä¸ªæä½ä¼å¨å设å¤é 置好ä¹å以 irq å +platform_data 为åæ°è°ç¨ãæ©æç v4l2_i2c_new_(probed_)subdev å½æ° +åæ ·ä¹ä¼è°ç¨ s_configï¼ä½ä» å¨ irq 为 0 ä¸ platform_data 为 NULL æ¶ã + +video_deviceç»æä½ +----------------- + +å¨ /dev ç®å½ä¸çå®é 设å¤èç¹æ ¹æ® video_device ç»æä½(v4l2-dev.h) +å建ãæ¤ç»æä½æ¢å¯ä»¥å¨æåé ä¹å¯ä»¥åµå ¥å°ä¸ä¸ªæ´å¤§çç»æä½ä¸ã + +å¨æåé æ¹æ³å¦ä¸ï¼ + + struct video_device *vdev = video_device_alloc(); + + if (vdev == NULL) + return -ENOMEM; + + vdev->release = video_device_release; + +å¦æå°å ¶åµå ¥å°ä¸ä¸ªå¤§ç»æä½ä¸ï¼åå¿ é¡»èªå·±å®ç° release()åè°ã + + struct video_device *vdev = &my_vdev->vdev; + + vdev->release = my_vdev_release; + +release()åè°å¿ 须被设置ï¼ä¸å¨æåä¸ä¸ª video_device ç¨æ·éåºä¹å +被è°ç¨ã + +é»è®¤ç video_device_release()åè°åªæ¯è°ç¨ kfree æ¥éæ¾ä¹ååé ç +å åã + +ä½ åºè¯¥è®¾ç½®è¿äºåï¼ + +- v4l2_dev: 设置为 v4l2_device ç¶è®¾å¤ã + +- name: 设置为å¯ä¸çæè¿°æ§è®¾å¤åã + +- fops: 设置为已æç v4l2_file_operations ç»æä½ã + +- ioctl_ops: å¦æä½ ä½¿ç¨v4l2_ioctl_ops æ¥ç®å ioctl çç»´æ¤ + (强ç建议使ç¨ï¼ä¸å°æ¥å¯è½å为强å¶æ§ç!)ï¼ç¶åè®¾ç½®ä½ èªå·±ç + v4l2_ioctl_ops ç»æä½. + +- lock: å¦æä½ è¦å¨é©±å¨ä¸å®ç°ææçéæä½ï¼å设为 NULL ãå¦å + å°±è¦è®¾ç½®ä¸ä¸ªæå struct mutex_lock ç»æä½çæéï¼è¿ä¸ªéå° + å¨ unlocked_ioctl æ件æä½è¢«è°ç¨åç±å æ ¸è·å¾ï¼å¹¶å¨è°ç¨è¿åå + éæ¾ã详è§ä¸ä¸èã + +- prio: ä¿æ对ä¼å 级çè·è¸ªãç¨äºå®ç° VIDIOC_G/S_PRIORITYãå¦æ + 设置为 NULLï¼åä¼ä½¿ç¨ v4l2_device ä¸ç v4l2_prio_state ç»æä½ã + å¦æè¦å¯¹æ¯ä¸ªè®¾å¤èç¹ï¼ç»ï¼å®ç°ç¬ç«çä¼å 级ï¼å¯ä»¥å°å ¶æåèªå·± + å®ç°ç v4l2_prio_state ç»æä½ã + +- parent: ä» å¨ä½¿ç¨ NULL ä½ä¸ºç¶è®¾å¤ç»æä½åæ°æ³¨å v4l2_device æ¶ + 设置æ¤åæ°ãåªæå¨ä¸ä¸ªç¡¬ä»¶è®¾å¤å å«å¤ä¸ä¸ª PCI 设å¤ï¼å ±äº«åä¸ä¸ª + v4l2_device æ ¸å¿æ¶æä¼åçã + + cx88 驱å¨å°±æ¯ä¸ä¸ªä¾åï¼ä¸ä¸ª v4l2_device ç»æä½æ ¸å¿ï¼è¢«ä¸ä¸ªè£¸ç + è§é¢ PCI 设å¤(cx8800)åä¸ä¸ª MPEG PCI 设å¤(cx8802)å ±ç¨ãç±äº + v4l2_device æ æ³ä¸ç¹å®ç PCI 设å¤å ³èï¼ææ没æ设置ç¶è®¾å¤ãä½å½ + video_device é ç½®åï¼å°±ç¥é使ç¨åªä¸ªç¶ PCI 设å¤äºã + +- flagsï¼å¯éãå¦æä½ è¦è®©æ¡æ¶å¤ç设置 VIDIOC_G/S_PRIORITY ioctlsï¼ + 请设置 V4L2_FL_USE_FH_PRIOãè¿è¦æ±ä½ ä½¿ç¨ v4l2_fh ç»æä½ã + ä¸æ¦ææ驱å¨ä½¿ç¨äºæ ¸å¿çä¼å 级å¤çï¼æç»è¿ä¸ªæ å¿å°æ¶å¤±ãä½ç°å¨å® + å¿ é¡»è¢«æ¾å¼è®¾ç½®ã + +å¦æä½ ä½¿ç¨ v4l2_ioctl_opsï¼ååºè¯¥å¨ v4l2_file_operations ç»æä½ä¸ +设置 .unlocked_ioctl æå video_ioctl2ã + +请å¿ä½¿ç¨ .ioctlï¼å®å·²è¢«åºå¼ï¼ä»åå°æ¶å¤±ã + +æäºæ åµä¸ä½ è¦åè¯æ ¸å¿ï¼ä½ å¨ v4l2_ioctl_ops æå®çæ个å½æ°åºè¢«å¿½ç¥ã +ä½ å¯ä»¥å¨ video_device_register 被è°ç¨åéè¿ä»¥ä¸å½æ°æ è®°è¿ä¸ª ioctlsã + +void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd); + +åºäºå¤é¨å ç´ ï¼ä¾å¦æ个æ¿å¡å·²è¢«ä½¿ç¨ï¼ï¼å¨ä¸å建æ°ç»æä½çæ åµä¸ï¼ä½ æ³ +è¦å ³é v4l2_ioctl_ops ä¸æ个ç¹æ§å¾å¾éè¦è¿ä¸ªæºå¶ã + +v4l2_file_operations ç»æä½æ¯ file_operations çä¸ä¸ªåéãå ¶ä¸»è¦ +åºå«å¨äºï¼å inode åæ°ä»æªè¢«ä½¿ç¨ï¼å®å°è¢«å¿½ç¥ã + +å¦æéè¦ä¸åªä½æ¡æ¶æ´åï¼ä½ å¿ é¡»éè¿è°ç¨ media_entity_init() åå§å +åµå ¥å¨ video_device ç»æä½ä¸ç media_entityï¼entity åï¼ç»æä½ï¼ + + struct media_pad *pad = &my_vdev->pad; + int err; + + err = media_entity_init(&vdev->entity, 1, pad, 0); + +pads æ°ç»å¿ é¡»é¢å åå§åã没æå¿ è¦æå¨è®¾ç½® media_entity ç type å +name åã + +å½ï¼ä»»ä½ï¼å设å¤èç¹è¢«æå¼/å ³éï¼å¯¹ entity çå¼ç¨å°è¢«èªå¨è·å/éæ¾ã + +v4l2_file_operations ä¸é +-------------------------- + +ä½ å¯ä»¥å¨ video_device ç»æä½ä¸è®¾ç½®ä¸ä¸ªæå mutex_lock çæéãé常 +è¿æ¢å¯æ¯ä¸ä¸ªé¡¶å±äºæ¥éä¹å¯ä¸ºè®¾å¤èç¹èªèº«çäºæ¥éãé»è®¤æ åµä¸ï¼æ¤é +ç¨äº unlocked_ioctlï¼ä½ä¸ºäºä½¿ç¨ ioctls ä½ éè¿ä»¥ä¸å½æ°å¯ç¦ç¨éå®ï¼ + + void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd); + +ä¾å¦: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF); + +ä½ å¿ é¡»å¨æ³¨å video_device åè°ç¨è¿ä¸ªå½æ°ã + +ç¹å«æ¯å¯¹äº USB 驱å¨ç¨åºï¼æäºå½ä»¤ï¼å¦è®¾ç½®æ§å¶ï¼éè¦å¾é¿çæ¶é´ï¼å¯è½ +éè¦èªè¡ä¸ºç¼å²åºéåç ioctls å®ç°éå®ã + +å¦æä½ éè¦æ´ç»ç²åº¦çéï¼ä½ å¿ é¡»è®¾ç½® mutex_lock 为 NULLï¼å¹¶å®å ¨èªå·±å®ç° +éæºå¶ã + +è¿å®å ¨ç±é©±å¨å¼åè å³å®ä½¿ç¨ä½ç§æ¹æ³ãç¶èï¼å¦æä½ ç驱å¨åå¨é¿å»¶æ¶æä½ +ï¼ä¾å¦ï¼æ¹å USB æå头çæå æ¶é´å¯è½éè¦è¾é¿æ¶é´ï¼ï¼èä½ åæ³è®©ç¨æ· +å¨çå¾ é¿å»¶æ¶æä½å®ææé´åå ¶ä»çäºï¼åä½ æ好èªå·±å®ç°éæºå¶ã + +å¦ææå®ä¸ä¸ªéï¼åææ ioctl æä½å°å¨è¿ä¸ªéçä½ç¨ä¸ä¸²è¡æ§è¡ãå¦æä½ +ä½¿ç¨ videobufï¼åå¿ é¡»å°åä¸ä¸ªéä¼ éç» videobuf éååå§åå½æ°ï¼å¦ +videobuf å¿ é¡»çå¾ ä¸å¸§çå°è¾¾ï¼åå¯ä¸´æ¶è§£é并å¨è¿ä¹åéæ°ä¸éãå¦æé©±å¨ +ä¹å¨ä»£ç æ§è¡æé´çå¾ ï¼åå¯ååæ ·çå·¥ä½ï¼ä¸´æ¶è§£éï¼åä¸éï¼è®©å ¶ä»è¿ç¨ +å¯ä»¥å¨ç¬¬ä¸ä¸ªè¿ç¨é»å¡æ¶è®¿é®è®¾å¤èç¹ã + +å¨ä½¿ç¨ videobuf2 çæ åµä¸ï¼å¿ é¡»å®ç° wait_prepare å wait_finish åè° +å¨éå½çæ¶å解é/å éãè¿ä¸æ¥æ¥è¯´ï¼å¦æä½ å¨ video_device ç»æä½ä¸ä½¿ç¨ +éï¼åå¿ é¡»å¨ wait_prepare å wait_finish ä¸å¯¹è¿ä¸ªäºæ¥éè¿è¡è§£é/å éã + +çææçæå¼å®ç°ä¹å¿ é¡»å¨è°ç¨ v4l2_device_disconnect åè·å¾éã + +video_device注å +--------------- + +æ¥ä¸æ¥ä½ éè¦æ³¨åè§é¢è®¾å¤ï¼è¿ä¼ä¸ºä½ å建ä¸ä¸ªå符设å¤ã + + err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (err) { + video_device_release(vdev); /* or kfree(my_vdev); */ + return err; + } + +å¦æ v4l2_device ç¶è®¾å¤ç mdev å为é NULL å¼ï¼è§é¢è®¾å¤å®ä½å°èªå¨ +注å为åªä½è®¾å¤ã + +注ååªç§è®¾å¤æ¯æ ¹æ®ç±»åï¼typeï¼åæ°ãåå¨ä»¥ä¸ç±»åï¼ + +VFL_TYPE_GRABBER: ç¨äºè§é¢è¾å ¥/è¾åºè®¾å¤ç videoX +VFL_TYPE_VBI: ç¨äºåç´æ¶éæ°æ®ç vbiX (ä¾å¦ï¼éèå¼åå¹ï¼å¾æçµè§) +VFL_TYPE_RADIO: ç¨äºå¹¿æè°è°å¨ç radioX + +æåä¸ä¸ªåæ°è®©ä½ ç¡®å®ä¸ä¸ªææ§å¶è®¾å¤ç设å¤èç¹å·æ°é(ä¾å¦ videoX ä¸ç X)ã +éå¸¸ä½ å¯ä»¥ä¼ å ¥-1ï¼è®© v4l2 æ¡æ¶èªå·±éæ©ç¬¬ä¸ä¸ªç©ºé²çç¼å·ãä½æ¯ææ¶ç¨æ· +éè¦éæ©ä¸ä¸ªç¹å®çèç¹å·ã驱å¨å 许ç¨æ·éè¿é©±å¨æ¨¡ååæ°éæ©ä¸ä¸ªç¹å®ç +设å¤èç¹å·æ¯å¾æ®éçãè¿ä¸ªç¼å·å°ä¼ä¼ éç»è¿ä¸ªå½æ°ï¼ä¸ video_register_device +å°ä¼è¯å¾éæ©è¿ä¸ªè®¾å¤èç¹å·ãå¦æè¿ä¸ªç¼å·è¢«å ç¨ï¼ä¸ä¸ä¸ªç©ºé²ç设å¤èç¹ +ç¼å·å°è¢«éä¸ï¼å¹¶åå æ ¸æ¥å¿ä¸åéä¸ä¸ªè¦åä¿¡æ¯ã + +å¦ä¸ä¸ªä½¿ç¨åºæ¯æ¯å½é©±å¨å建å¤ä¸ªè®¾å¤æ¶ãè¿ç§æ åµä¸ï¼å¯¹ä¸åçè§é¢è®¾å¤å¨ +ç¼å·ä¸ä½¿ç¨ä¸åçèå´æ¯å¾æç¨çãä¾å¦ï¼è§é¢æè·è®¾å¤ä» 0 å¼å§ï¼è§é¢ +è¾åºè®¾å¤ä» 16 å¼å§ãæä»¥ä½ å¯ä»¥ä½¿ç¨æåä¸ä¸ªåæ°æ¥æå®è®¾å¤èç¹å·æå°å¼ï¼ +è v4l2 æ¡æ¶ä¼è¯å¾éæ©ç¬¬ä¸ä¸ªç空é²ç¼å·ï¼çäºæ大äºä½ æä¾çç¼å·ï¼ã +å¦æ失败ï¼åå®ä¼å°±éæ©ç¬¬ä¸ä¸ªç©ºé²çç¼å·ã + +ç±äºè¿ç§æ åµä¸ï¼ä½ ä¼å¿½ç¥æ æ³éæ©ç¹å®è®¾å¤èç¹å·çè¦åï¼åå¯è°ç¨ +video_register_device_no_warn() å½æ°é¿å è¦åä¿¡æ¯ç产çã + +åªè¦è®¾å¤èç¹è¢«å建ï¼ä¸äºå±æ§ä¹ä¼åæ¶å建ãå¨ /sys/class/video4linux +ç®å½ä¸ä½ ä¼æ¾å°è¿äºè®¾å¤ãä¾å¦è¿å ¥å ¶ä¸ç video0 ç®å½ï¼ä½ ä¼çå°ânameâå +âindexâå±æ§ãânameâå±æ§å¼å°±æ¯ video_device ç»æä½ä¸çânameâåã + +âindexâå±æ§å¼å°±æ¯è®¾å¤èç¹çç´¢å¼å¼ï¼æ¯æ¬¡è°ç¨ video_register_device()ï¼ +ç´¢å¼å¼é½éå¢ 1 ã第ä¸ä¸ªè§é¢è®¾å¤èç¹æ»æ¯ä»ç´¢å¼å¼ 0 å¼å§ã + +ç¨æ·å¯ä»¥è®¾ç½® udev è§åï¼å©ç¨ç´¢å¼å±æ§çæè±å¨ç设å¤åï¼ä¾å¦ï¼ç¨âmpegXâ +代表 MPEG è§é¢æè·è®¾å¤èç¹ï¼ã + +å¨è®¾å¤æå注ååï¼å°±å¯ä»¥ä½¿ç¨è¿äºåï¼ + +- vfl_type: ä¼ éç» video_register_device ç设å¤ç±»åã +- minor: å·²ææ´¾ç次设å¤å·ã +- num: 设å¤èç¹ç¼å· (ä¾å¦ videoX ä¸ç X)ã +- index: 设å¤ç´¢å¼å·ã + +å¦æ注å失败ï¼ä½ å¿ é¡»è°ç¨ video_device_release() æ¥éæ¾å·²åé ç +video_device ç»æä½ï¼å¦æ video_device æ¯åµå ¥å¨èªå·±å建çç»æä½ä¸ï¼ +ä½ ä¹å¿ é¡»éæ¾å®ãvdev->release() åè°ä¸ä¼å¨æ³¨å失败ä¹å被è°ç¨ï¼ +ä½ ä¹ä¸åºè¯å¾å¨æ³¨å失败å注é设å¤ã + + +video_device 注é +---------------- + +å½è§é¢è®¾å¤èç¹å·²è¢«ç§»é¤ï¼ä¸è®ºæ¯å¸è½½é©±å¨è¿æ¯USB设å¤æå¼ï¼ä½ é½åºæ³¨é +å®ä»¬ï¼ + + video_unregister_device(vdev); + +è¿ä¸ªæä½å°ä» sysfs ä¸ç§»é¤è®¾å¤èç¹ï¼å¯¼è´ udev å°å ¶ä» /dev ä¸ç§»é¤ï¼ã + +video_unregister_device() è¿åä¹åï¼å°±æ æ³å®ææå¼æä½ã尽管å¦æ¤ï¼ +USB 设å¤çæ åµåä¸åï¼æäºåºç¨ç¨åºå¯è½ä¾ç¶æå¼çå ¶ä¸ä¸ä¸ªå·²æ³¨éè®¾å¤ +èç¹ãæ以å¨æ³¨éä¹åï¼æææ件æä½ï¼å½ç¶é¤äº release ï¼ä¹åºè¿åé误å¼ã + +å½æåä¸ä¸ªè§é¢è®¾å¤èç¹çç¨æ·éåºï¼å vdev->release() åè°ä¼è¢«è°ç¨ï¼ +并ä¸ä½ å¯ä»¥åæåçæ¸ çæä½ã + +ä¸è¦å¿è®°æ¸ çä¸è§é¢è®¾å¤ç¸å ³çåªä½å ¥å£ï¼å¦æ被åå§åè¿ï¼ï¼ + + media_entity_cleanup(&vdev->entity); + +è¿å¯ä»¥å¨ release åè°ä¸å®æã + + +video_device è¾ å©å½æ° +--------------------- + +ä¸äºæç¨çè¾ å©å½æ°å¦ä¸ï¼ + +- file/video_device ç§ææ°æ® + +ä½ å¯ä»¥ç¨ä»¥ä¸å½æ°å¨ video_device ç»æä½ä¸è®¾ç½®/è·å驱å¨ç§ææ°æ®ï¼ + +void *video_get_drvdata(struct video_device *vdev); +void video_set_drvdata(struct video_device *vdev, void *data); + +注æï¼å¨è°ç¨ video_register_device() åæ§è¡ video_set_drvdata() +æ¯å®å ¨çã + +è以ä¸å½æ°ï¼ + +struct video_device *video_devdata(struct file *file); + +è¿å file ç»æä½ä¸æ¥æçç video_device æéã + +video_drvdata è¾ å©å½æ°ç»åäº video_get_drvdata å video_devdata +çåè½ï¼ + +void *video_drvdata(struct file *file); + +ä½ å¯ä»¥ä½¿ç¨å¦ä¸ä»£ç ä» video_device ç»æä½ä¸è·å v4l2_device ç»æä½ +æéï¼ + +struct v4l2_device *v4l2_dev = vdev->v4l2_dev; + +- 设å¤èç¹å + +video_device 设å¤èç¹å¨å æ ¸ä¸çå称å¯ä»¥éè¿ä»¥ä¸å½æ°è·å¾ + +const char *video_device_node_name(struct video_device *vdev); + +è¿ä¸ªåå被ç¨æ·ç©ºé´å·¥å ·ï¼ä¾å¦ udevï¼ä½ä¸ºæ示信æ¯ä½¿ç¨ãåºå°½å¯è½ä½¿ç¨ +æ¤åè½ï¼èéè®¿é® video_device::num å video_device::minor åã + + +è§é¢ç¼å²è¾ å©å½æ° +--------------- + +v4l2 æ ¸å¿ API æä¾äºä¸ä¸ªå¤çè§é¢ç¼å²çæ åæ¹æ³(称为âvideobufâ)ã +è¿äºæ¹æ³ä½¿é©±å¨å¯ä»¥éè¿ç»ä¸çæ¹å¼å®ç° read()ãmmap() å overlay()ã +ç®åå¨è®¾å¤ä¸æ¯æè§é¢ç¼å²çæ¹æ³æåæ£/èé DMA(videobuf-dma-sg)ã +çº¿æ§ DMA(videobuf-dma-contig)以å大å¤ç¨äº USB 设å¤çç¨ vmalloc +åé çç¼å²(videobuf-vmalloc)ã + +请åé Documentation/video4linux/videobufï¼ä»¥è·å¾æ´å¤å ³äº videobuf +å±ç使ç¨ä¿¡æ¯ã + +v4l2_fh ç»æä½ +------------- + +v4l2_fh ç»æä½æä¾ä¸ä¸ªä¿åç¨äº V4L2 æ¡æ¶çæ件å¥æç¹å®æ°æ®çç®åæ¹æ³ã +å¦æ video_device ç flag è®¾ç½®äº V4L2_FL_USE_FH_PRIO æ å¿ï¼æ°é©±å¨ +å¿ é¡»ä½¿ç¨ v4l2_fh ç»æä½ï¼å 为å®ä¹ç¨äºå®ç°ä¼å 级å¤çï¼VIDIOC_G/S_PRIORITYï¼ã + +v4l2_fh çç¨æ·ï¼ä½äº V4l2 æ¡æ¶ä¸ï¼å¹¶é驱å¨ï¼å¯éè¿æµè¯ +video_device->flags ä¸ç V4L2_FL_USES_V4L2_FH ä½å¾ç¥é©±å¨æ¯å¦ä½¿ç¨ +v4l2_fh ä½ä¸ºä»ç file->private_data æéãè¿ä¸ªä½ä¼å¨è°ç¨ v4l2_fh_init() +æ¶è¢«è®¾ç½®ã + +v4l2_fh ç»æä½ä½ä¸ºé©±å¨èªèº«æ件å¥æç»æä½çä¸é¨å被åé ï¼ä¸é©±å¨å¨ +å ¶æå¼å½æ°ä¸å° file->private_data æåå®ã + +å¨è®¸å¤æ åµä¸ï¼v4l2_fh ç»æä½ä¼åµå ¥å°ä¸ä¸ªæ´å¤§çç»æä½ä¸ãè¿éæ åµä¸ï¼ +åºè¯¥å¨ open() ä¸è°ç¨ v4l2_fh_init+v4l2_fh_addï¼å¹¶å¨ release() ä¸ +è°ç¨ v4l2_fh_del+v4l2_fh_exitã + +驱å¨å¯ä»¥éè¿ä½¿ç¨ container_of å®æåä»ä»¬èªå·±çæ件å¥æç»æä½ãä¾å¦ï¼ + +struct my_fh { + int blah; + struct v4l2_fh fh; +}; + +... + +int my_open(struct file *file) +{ + struct my_fh *my_fh; + struct video_device *vfd; + int ret; + + ... + + my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL); + + ... + + v4l2_fh_init(&my_fh->fh, vfd); + + ... + + file->private_data = &my_fh->fh; + v4l2_fh_add(&my_fh->fh); + return 0; +} + +int my_release(struct file *file) +{ + struct v4l2_fh *fh = file->private_data; + struct my_fh *my_fh = container_of(fh, struct my_fh, fh); + + ... + v4l2_fh_del(&my_fh->fh); + v4l2_fh_exit(&my_fh->fh); + kfree(my_fh); + return 0; +} + +以ä¸æ¯ v4l2_fh å½æ°ä½¿ç¨çç®ä»ï¼ + +void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) + + åå§åæ件å¥æãè¿*å¿ é¡»*å¨é©±å¨ç v4l2_file_operations->open() + å½æ°ä¸æ§è¡ã + +void v4l2_fh_add(struct v4l2_fh *fh) + + æ·»å ä¸ä¸ª v4l2_fh å° video_device æ件å¥æå表ãä¸æ¦æ件å¥æ + åå§åå®æå°±å¿ é¡»è°ç¨ã + +void v4l2_fh_del(struct v4l2_fh *fh) + + ä» video_device() ä¸è§£é¤æ件å¥æçå ³èãæ件å¥æçéåºå½æ°ä¹ + å°è¢«è°ç¨ã + +void v4l2_fh_exit(struct v4l2_fh *fh) + + æ¸ çæ件å¥æãå¨æ¸ çå® v4l2_fh åï¼ç¸å ³å åä¼è¢«éæ¾ã + + +å¦æ v4l2_fh ä¸æ¯åµå ¥å¨å ¶ä»ç»æä½ä¸çï¼åå¯ä»¥ç¨è¿äºè¾ å©å½æ°ï¼ + +int v4l2_fh_open(struct file *filp) + + åé ä¸ä¸ª v4l2_fh ç»æä½ç©ºé´ï¼åå§å并å°å ¶æ·»å å° file ç»æä½ç¸å ³ç + video_device ç»æä½ä¸ã + +int v4l2_fh_release(struct file *filp) + + ä» file ç»æä½ç¸å ³ç video_device ç»æä½ä¸å é¤ v4l2_fh ï¼æ¸ ç + v4l2_fh 并éæ¾ç©ºé´ã + +è¿ä¸¤ä¸ªå½æ°å¯ä»¥æå ¥å° v4l2_file_operation ç open() å release() +æä½ä¸ã + + +æäºé©±å¨éè¦å¨ç¬¬ä¸ä¸ªæ件å¥ææå¼åæåä¸ä¸ªæ件å¥æå ³éçæ¶ååäº +å·¥ä½ãæ以å å ¥äºä¸¤ä¸ªè¾ å©å½æ°ä»¥æ£æ¥ v4l2_fh ç»æä½æ¯å¦æ¯ç¸å ³è®¾å¤ +èç¹æå¼çå¯ä¸æ件å¥æã + +int v4l2_fh_is_singular(struct v4l2_fh *fh) + + å¦ææ¤æ件å¥ææ¯å¯ä¸æå¼çæ件å¥æï¼åè¿å 1 ï¼å¦åè¿å 0 ã + +int v4l2_fh_is_singular_file(struct file *filp) + + åè½ç¸åï¼ä½éè¿ filp->private_data è°ç¨ v4l2_fh_is_singularã + + +V4L2 äºä»¶æºå¶ +----------- + +V4L2 äºä»¶æºå¶æä¾äºä¸ä¸ªéç¨çæ¹æ³å°äºä»¶ä¼ éå°ç¨æ·ç©ºé´ã驱å¨å¿ é¡»ä½¿ç¨ +v4l2_fh æè½æ¯æ V4L2 äºä»¶æºå¶ã + + +äºä»¶éè¿ä¸ä¸ªç±»ååéæ© ID æ¥å®ä¹ãID 对åºä¸ä¸ª V4L2 对象ï¼ä¾å¦ +ä¸ä¸ªæ§å¶ IDãå¦ææªä½¿ç¨ï¼å ID 为 0ã + +å½ç¨æ·è®¢é ä¸ä¸ªäºä»¶ï¼é©±å¨ä¼ä¸ºæ¤åé ä¸äº kevent ç»æä½ãæ以æ¯ä¸ª +äºä»¶ç»ï¼ç±»åãIDï¼é½ä¼æèªå·±çä¸å¥ kevent ç»æä½ãè¿ä¿è¯äºå¦æ +ä¸ä¸ªé©±å¨çæ¶é´å 产çäºè®¸å¤åç±»äºä»¶ï¼ä¸ä¼è¦çå ¶ä»ç±»åçäºä»¶ã + +ä½å¦æä½ æ¶å°çäºä»¶æ°é大äºåç±»äºä»¶ kevent çä¿åæ°éï¼åææ©ç +äºä»¶å°è¢«ä¸¢å¼ï¼å¹¶å å ¥æ°äºä»¶ã + +æ¤å¤ï¼v4l2_subscribed_event ç»æä½å é¨æå¯ä¾é©±å¨è®¾ç½®ç merge() å +replace() åè°ï¼è¿äºåè°ä¼å¨æ°äºä»¶äº§çä¸æ²¡æå¤ä½ç©ºé´çæ¶å被è°ç¨ã +replace() åè°è®©ä½ å¯ä»¥å°æ©æäºä»¶çåè·æ¿æ¢ä¸ºæ°äºä»¶çåè·ï¼å°æ©æ +åè·çç¸å ³æ°æ®å并å°æ¿æ¢è¿æ¥çæ°åè·ä¸ãå½è¯¥ç±»åçäºä»¶ä» åé äºä¸ä¸ª +kevent ç»æä½æ¶ï¼å®å°è¢«è°ç¨ãmerge() åè°è®©ä½ å¯ä»¥å并ææ©çäºä»¶åè· +å°å¨å®ä¹åçé£ä¸ªäºä»¶åè·ä¸ãå½è¯¥ç±»åçäºä»¶åé äºä¸¤ä¸ªææ´å¤ kevent +ç»æä½æ¶ï¼å®å°è¢«è°ç¨ã + +è¿ç§æ¹æ³ä¸ä¼æç¶æä¿¡æ¯ä¸¢å¤±ï¼åªä¼å¯¼è´ä¸é´æ¥éª¤ä¿¡æ¯ä¸¢å¤±ã + + +å ³äº replace/merge åè°çä¸ä¸ªä¸éçä¾åå¨ v4l2-event.c ä¸ï¼ç¨äº +æ§å¶äºä»¶ç ctrls_replace() å ctrls_merge() åè°ã + +注æï¼è¿äºåè°å¯ä»¥å¨ä¸æä¸ä¸æä¸è°ç¨ï¼æ以å®ä»¬å¿ 须尽快å®æ并éåºã + +æç¨çå½æ°ï¼ + +void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) + + å°äºä»¶å å ¥è§é¢è®¾å¤çéåã驱å¨ä» è´è´£å¡«å type å data åã + å ¶ä»åç± V4L2 å¡«å ã + +int v4l2_event_subscribe(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub, unsigned elems, + const struct v4l2_subscribed_event_ops *ops) + + video_device->ioctl_ops->vidioc_subscribe_event å¿ é¡»æ£æµé©±å¨è½ + 产çç¹å® id çäºä»¶ãç¶åè°ç¨ v4l2_event_subscribe() æ¥è®¢é 该äºä»¶ã + + elems åæ°æ¯è¯¥äºä»¶çéå大å°ãè¥ä¸º 0ï¼V4L2 æ¡æ¶å°ä¼ï¼æ ¹æ®äºä»¶ç±»åï¼ + å¡«å é»è®¤å¼ã + + ops åæ°å 许驱å¨æå®ä¸ç³»ååè°ï¼ + * add: å½æ·»å ä¸ä¸ªæ°çå¬è æ¶è°ç¨ï¼éå¤è®¢é åä¸ä¸ªäºä»¶ï¼æ¤åè° + ä» è¢«æ§è¡ä¸æ¬¡ï¼ã + * del: å½ä¸ä¸ªçå¬è åæ¢çå¬æ¶è°ç¨ã + * replace: ç¨âæ°âäºä»¶æ¿æ¢âæ©æâäºä»¶ã + * merge: å°âæ©æâäºä»¶å并å°âæ°âäºä»¶ä¸ã + è¿å个è°ç¨é½æ¯å¯éçï¼å¦æä¸æ³æå®ä»»ä½åè°ï¼å ops å¯ä¸º NULLã + +int v4l2_event_unsubscribe(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) + + v4l2_ioctl_ops ç»æä½ä¸ç vidioc_unsubscribe_event åè°å½æ°ã + 驱å¨ç¨åºå¯ä»¥ç´æ¥ä½¿ç¨ v4l2_event_unsubscribe() å®ç°é订äºä»¶è¿ç¨ã + + ç¹æ®ç V4L2_EVENT_ALL ç±»åï¼å¯ç¨äºé订ææäºä»¶ã驱å¨å¯è½å¨ç¹æ® + æ åµä¸éè¦åæ¤æä½ã + +int v4l2_event_pending(struct v4l2_fh *fh) + + è¿åæªå³äºä»¶çæ°éãæå©äºå®ç°è½®è¯¢ï¼pollï¼æä½ã + +äºä»¶éè¿ poll ç³»ç»è°ç¨ä¼ éå°ç¨æ·ç©ºé´ã驱å¨å¯ç¨ +v4l2_fh->wait (wait_queue_head_t ç±»å)ä½ä¸ºåæ°è°ç¨ poll_wait()ã + +äºä»¶å为æ åäºä»¶åç§æäºä»¶ãæ°çæ åäºä»¶å¿ 须使ç¨å¯ç¨çæå°äºä»¶ç±»å +ç¼å·ã驱å¨å¿ é¡»ä»ä»ä»¬æ¬ç±»åçç¼å·èµ·å§å¤åé äºä»¶ãç±»åçç¼å·èµ·å§ä¸º +V4L2_EVENT_PRIVATE_START + n * 1000 ï¼å ¶ä¸ n 为å¯ç¨æå°ç¼å·ãæ¯ä¸ª +ç±»åä¸ç第ä¸ä¸ªäºä»¶ç±»åç¼å·æ¯ä¸ºä»¥åç使ç¨ä¿ççï¼æ以第ä¸ä¸ªå¯ç¨äºä»¶ +ç±»åç¼å·æ¯âclass base + 1âã + +V4L2 äºä»¶æºå¶ç使ç¨å®ä¾å¯ä»¥å¨ OMAP3 ISP çé©±å¨ +(drivers/media/video/omap3isp)ä¸æ¾å°ã -- 2.34.1