1、概述node
Video for Linux 2,簡稱V4l2,是Linux內核中關於視頻設備的內核驅動框架,爲上層的訪問底層的視頻設備提供了統一的接口。linux
攝像頭驅動是屬於字符設備驅動程序。(分析linux3.4.2內核)數組
2、如何寫字符設備驅動app
一、對於簡單的驅動:框架
1).構造一個file_operations:.open=drv_open .read=drv_read
2).告訴內核:register_chrdev(主設備號,名字,&file_operations)
3).入口函數:調用register_chrdev
4).出口函數:卸載
通常採用register_chrdev的代替方法:分配、設置cdev,cdev_addide
二、對於稍複雜的驅動程序採用分層思想函數
例如LCD驅動中分爲兩層:上層通用的核心層內核已經幫咱們作好,即在fbmem.c
1.構造file_operations(open/ read /write ...)
2.註冊 this
3.入口、出口spa
咱們作的是硬件相關層,供上層file_operations調用
1.分配一個fb_info 結構體
2.設置
3.註冊
4.硬件相關的操做
code
3、分析V4L2框架
把usb設備接到系統前臺,會有打印信息,根據打印信息在內核裏找出驅動,用dmsg命令查看;
grep "Found UVC" * -nR 搜索 在uvc_driver.c裏,這是個硬件相關的驅動。
分析代碼,猜想V4L2 框架 確定也是分爲至少兩層 。
應用層:
/*調用 open read write -->調用 v4l2_fops 裏的 open read write->調用硬件相關層的video_device 裏提供的函數*/
----------------------------------------------------------------------------------------------------------
核心層:v4l2-dev.c __video_register_device
構造:v4l2_fops(
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open, ...)
註冊:
vdev->cdev = cdev_alloc(); //1.字符設備cdev_alloc
vdev->cdev->ops = &v4l2_fops; //2.設置fops
cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); //3.cdev_add
----------------------------------------------------------------------------------------------------------
硬件相關層:如uvc_driver.c Found UVC
->v4l2_device_register(這個不重要)
->video_device_alloc->video_register_device(向核心層註冊)
->v4l2-dev.h->__video_register_device(v4l2-dev.c)
---------------------------------------------------------------------------------------------------------
即分配結構體 video_device (裏面的函數供上層v4l2_fops調用)
設置 註冊video_register_device
4、經過vivi.c分析v4l2核心驅動框架
(virtual video driver )虛擬視頻驅動
分析以下:
vivi_init (入口函數) vivi_create_instance(i); v4l2_device_register //非主要,僅初始化一些鎖等,實際未註冊啥 spin_lock_init(&v4l2_dev->lock); ... get_device(dev); v4l2_dev->dev = dev; vfd = video_device_alloc(); //分配video_device //設置 1.*vfd = vivi_template; //內容設置爲vivi_template /*最底層的vivi 操做函數*/ static struct video_device vivi_template = { .name = "vivi", .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, ... }; 2.vfd->v4l2_dev = &dev->v4l2_dev; 3.設置「Ctrl屬性」(用於APP的ioctl),音量、亮度、增益等 dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, 16); ... // 結構體vfd 類型 number video_register_device(video_device, VFL_TYPE_GRABBER, nr); //向上註冊 __video_register_device /* Part 1: check device type */ 檢驗設備類型 ... /* Part 2: find a free minor, device node number and device index. */ ... 互斥鎖相關 /* Part 3: Initialize the character device */ 初始化字符設備 vdev->cdev = cdev_alloc(); vdev->cdev->ops = &v4l2_fops; cdev_add ... /* Part 6: Activate this minor. The char device can now be used. */ video_device[vdev->minor] = vdev; //以次設備號爲下標,將vdev存入數組
************************************************************************************
分析vivi.c的open、read、write、ioctl過程 1. open app: open ("/dev/video0",...) ---------------------------------------------- drv: v4l2_open vdev = video_devdata(filp); //根據次設備號從數組中獲得video_device ret = vdev->fops->open(filp);//調用open函數 調用vivi.c 裏的v4l2_fh_open 2. read app: read... ---------------------------------------------- drv: v412_read struct video_device *vdev = video_devdata(filp); ret = vdev->fops->read(filp, buf, sz, off); 3. ioctl app: ioctl ---------------------------------------------- drv: v4l2_fops.unlocked_ioctl v4l2_ioctl struct video_device *vdev = video_devdata(filp); ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); 調用vivi.c 裏的video_ioctl2 /*把用戶空間的參數複製進來,而後調用__video_do_ioctl*/ video_usercopy(file, cmd, arg, __video_do_ioctl); __video_do_ioctl *vdev = video_devdata(filp) 根據APP傳入的cmd來得到、設置某些屬性
/*在vivi.c 裏一開始的vivi_create_instance裏設置*/
由上分析可知vivi.c主要完成了如下工做:
1 、初始化 v4l2_device結構體(表明一個 v4l2設備)
v4l2_device_register、 v4l2_device
二、分配video_device結構體
vfd = video_device_alloc()
三、設置video_device結構
a、 .vfd->v4l2_dev
b、vfd:
.fops 設置vfd的fops 裏的open、read、write 被上層調用
.ioctl_ops 最終會調用到ioctl(設置屬性被上層調用 )
四、 註冊video_device結構體
(video_device 是內核對 v4l2_device的官方封裝,用於管理v4l2_device數據),向上層用戶提供訪問接口
video_register_device
問:APP能夠經過ioctl來設置(得到)亮度等信息,在驅動程序裏,誰來接收、存儲、設置到硬件(提供這些信息)?
答:在驅動程序中抽象出來一個結構體v4l2_ctrl, 每一個Ctrl對應其中的一項(音量、亮度等等);
由v4l2_ctrl_handler來管理他們
1.初始化
v4l2_ctrl_handler_init
2.設置
v4l2_ctrl_new_std
v4l2_ctrl_new_custom
這些函數就是建立各個屬性,而且放入v4l2_ctrl_handler的鏈表
3.跟vdev關聯
dev->v4l2_dev.ctrl_handler = hdl;
小結:
v4l2框架並未脫離字符設備驅動框架,只是ioctl的實現較爲複雜。