UVC設備也是一個usb設備,在uvc_driver.c中的init函數會調用usb_register註冊,根據id_table發送可支持的設備後調用probe函數,其會去uvc_register_chains註冊全部uvc_device,前面說的根據id_table匹配的過程是usb_bus總線,uvc是另外一個東西了數組
vivi.c是一個攝像頭驅動模板或者實例,安裝vivi模塊後會產生一個虛擬的攝像頭,使用應用程序能夠得到其提供的虛擬數據並顯示。app
vivi_init
vivi_create_instance
v4l2_device_register // 不是主要, 只是用於初始化一些東西,好比自旋鎖、引用計數ide
hdl = &dev->ctrl_handler;//hdl 是用於保存子設備控制方法集的結構體,對於視頻設備這些ctrls包括設置亮度、飽和度、對比度和 清晰度 等,用鏈表的方式來保存ctrls,能夠經過v4l2_ctrl_new_std函數向鏈表添加ctrls。在下面的代碼中用到了這個函數。
video_device_alloc
// 設置
1. vfd:
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
2.
vfd->v4l2_dev = &dev->v4l2_dev;
3. 設置"ctrl屬性",並掛接到hdl的鏈表上(用於應用的ioctl)://後續會根據這裏設置的屬性調用真正的ioctl,用戶空間能夠經過ioctl的VIDIOC_S_CTRL指令調用到hdl(v4l2_ctrl_handler結構體)
v4l2_ctrl_handler_init(hdl, 11);
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); 函數
video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
__video_register_device
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;//真正的fops是vivi_fops
cdev_add
video_device[vdev->minor] = vdev;//把包含真正fops結構體的變量放入video_device數組,以次設備號爲下標視頻
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
blog
分析vivi.c的open,read,write,ioctl過程
1. open
app: open("/dev/video0",....)
---------------------------------------------------
drv: v4l2_fops.v4l2_open
vdev = video_devdata(filp); // 根據次設備號從數組中獲得video_device
ret = vdev->fops->open(filp);
vivi_ioctl_ops.open
v4l2_fh_opencmd
2. read
app: read ....
---------------------------------------------------
drv: v4l2_fops.v4l2_read
struct video_device *vdev = video_devdata(filp);
ret = vdev->fops->read(filp, buf, sz, off);it
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);
video_ioctl2
video_usercopy(file, cmd, arg, __video_do_ioctl);
__video_do_ioctl
struct video_device *vfd = video_devdata(file);
根據應用傳入的cmd來得到、設置"某些屬性"io
v4l2_ctrl_handler的使用過程:(v4l2_ctrl_handler是屬性鏈表,在video_device_alloc被設置)
__video_do_ioctl//往上面數5行,video_usercopy裏面調用__video_do_ioctl這個函數,最終ioctrl會表用vivi_ioctl_ops結構體裏面的ioctrl函數
struct video_device *vfd = video_devdata(file);table
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *p = arg;
if (vfh && vfh->ctrl_handler)
ret = v4l2_queryctrl(vfh->ctrl_handler, p);
else if (vfd->ctrl_handler) // 在哪設置?在video_register_device中vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler,vdev->v4l2_dev在video_register_device前經過vfd->v4l2_dev = &dev->v4l2_dev複製,這裏的dev是vivi_device,dev->v4l2_dev.ctrl_handler = hdl,這裏的hdl就是vivi_init過程當中在v4l2_ctrl_new_std裏面被設置,vfd就是video_device結構體類型;ctrl_handler是v4l2_ctrl_handler
ret = v4l2_queryctrl(vfd->ctrl_handler, p);
// 根據ID在ctrl_handler裏找到v4l2_ctrl,返回它的值,ID在v4l2_ctrl_new_std裏面被設置
怎麼寫V4L2驅動?
一、分配、設置、註冊V4L2_device (v4l2_device_register,v4l2_device)(僅初始化,並提供一些屬性參數供ioctl設置,輔助做用,屬性在這個v4l2_ctrl_handler裏面被管理,v4l2_ctrl來表示屬性,v4l2_ctrl_new_std來建立v4l2_ctrl,放入v4l2_ctrl_handler鏈表)
二、分配video_device(video_device_alloc)
三、設置 video_device()
vfd->v4l2_dev = &dev->v4l2_dev;//把video_device和第一部裏面設置的屬性關聯起來,後面會用來ioctl設置屬性,好比亮度、飽和度等參數
fops=真真的v4l2_file_operations,v4l2_fops中的read等會指向這裏設置的fops;
ioctl_ops=真真的ioctl函數,v4l2_fops->unlocked_ioctl調用v4l2_file_operations->unlocked_ioctl,調用ioctl_ops