开始学习v4l2中camera的架构
app调用v4l2框架,然后v4l2框架再调用具体的驱动
如:在app:open----->v4l2:open------->driver:open
v4l2提供的是一个通用的框架,然后驱动去实现具体的内容。
问题:那么v4l2是怎么调用driver的呢?
这个我们看看相关代码就很清楚了。
//drivers/media/video/v4l2-dev.c
- static int v4l2_open(struct inode *inode, struct file *filp)
- {
- printk("<6>\nsong:**************v4l2_open************\n");
- struct video_device *vdev;
- int ret = 0;
- /* Check if the video device is available */
- mutex_lock(&videodev_lock);
- //这里就是从我们的在驱动中注册的video_device->cdev得到video_device.
- vdev = video_devdata(filp);
- /* return ENODEV if the video device has been removed
- already or if it is not registered anymore. */
- if (vdev == NULL || !video_is_registered(vdev)) {
- mutex_unlock(&videodev_lock);
- return -ENODEV;
- }
- /* and increase the device refcount */
- video_get(vdev);
- mutex_unlock(&videodev_lock);
- //调用在驱动注册的open方法
- if (vdev->fops->open)
- ret = vdev->fops->open(filp);
- /* decrease the refcount in case of an error */
- if (ret)
- video_put(vdev);
- return ret;
- }
static int v4l2_open(struct inode *inode, struct file *filp)
{
printk("<6>\nsong:**************v4l2_open************\n");
struct video_device *vdev;
int ret = 0;
/* Check if the video device is available */
mutex_lock(&videodev_lock);
//这里就是从我们的在驱动中注册的video_device->cdev得到video_device.
vdev = video_devdata(filp);
/* return ENODEV if the video device has been removed
already or if it is not registered anymore. */
if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
}
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
//调用在驱动注册的open方法
if (vdev->fops->open)
ret = vdev->fops->open(filp);
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
return ret;
}
其它操作和open操作是一样的。
下面来看具体的驱动代码:
1.首先dcam_init()
在初始化的时候要注册一个platform driver:
platform_driver_register(&dcam_driver)
然后进行相关初始化:create_instance(i)
相关代码:
- int __init dcam_v4l2_init(void)
- {
- int ret = 0, i;
- if(platform_driver_register(&dcam_driver) != 0) {
- printk("platform device register Failed \n");
- return -1;
- }
- // 省略
- ret = create_instance(i);
- // 省略
- return ret;}
- static struct platform_driver dcam_driver = {
- .probe = dcam_probe,
- .remove = dcam_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "XXXXX_dcam",
- },
- };
- static int __init create_instance(int inst)
- {
- struct dcam_dev *dev;
- struct video_device *vfd;
- int ret, i;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s-%03d", DCAM_MODULE_NAME, inst);
- ret = v4l2_device_register(NULL, &dev->v4l2_dev);
- //初始化v4l2_device
- if (ret)
- goto free_dev;
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- init_waitqueue_head(&dev->vidq.wq);
- /* initialize locks */
- spin_lock_init(&dev->slock);
- mutex_init(&dev->mutex);
- ret = -ENOMEM;
- //为video_device分配内存
- vfd = video_device_alloc();
- if (!vfd)
- goto unreg_dev;
- //为vfd赋值
- *vfd = dcam_template;
- vfd->debug = debug;
- //注册video_device,主要作用是注册cdev,具体看实现,这个函数很重要
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
- if (ret < 0)
- goto rel_vdev;
- video_set_drvdata(vfd, dev);
- /* Set all controls to their default value. */
- for (i = 0; i < ARRAY_SIZE(dcam_qctrl); i++)
- dev->qctl_regs[i] = dcam_qctrl[i].default_value;
- /* Now that everything is fine, let's add it to device list */
- list_add_tail(&dev->dcam_devlist, &dcam_devlist);
- snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
- dcam_template.name, vfd->num);
- if (video_nr >= 0)
- video_nr++;
- dev->vfd = vfd;
- v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
- vfd->num);
- return 0;
- rel_vdev:
- video_device_release(vfd);
- unreg_dev:
- v4l2_device_unregister(&dev->v4l2_dev);
- free_dev:
- kfree(dev);
- return ret;
- }
- static struct video_device dcam_template = {
- .name = "dcam",
- .fops = &dcam_fops,
- .ioctl_ops = &dcam_ioctl_ops,
- .minor = -1,
- .release = video_device_release,
- .tvnorms = V4L2_STD_525_60,
- .current_norm = V4L2_STD_NTSC_M,
- };
- //现在分析probe函数
- //主要作用是注册一个miscdevice
- int dcam_probe(struct platform_device *pdev)
- {
- int ret;
- printk(KERN_ALERT"dcam_probe called\n");
- ret = misc_register(&dcam_v4l2_dev);//这个可以去查看相关的注册过程
- if (ret) {
- printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
- DCAM_MINOR, ret);
- return ret;
- }
- lock = (struct mutex *)kmalloc(sizeof(struct mutex), GFP_KERNEL);
- if (lock == NULL)
- return -1;
- mutex_init(lock);
- printk(KERN_ALERT "dcam_probe Success.\n");
- return 0;
- }
- static struct miscdevice dcam_v4l2_dev = {
- .minor = DCAM_MINOR,
- .name = "sc8800g_dcam",
- .fops = &dcam_fops,
- };
int __init dcam_v4l2_init(void)
{
int ret = 0, i;
if(platform_driver_register(&dcam_driver) != 0) {
printk("platform device register Failed \n");
return -1;
}
// 省略
ret = create_instance(i);
// 省略
return ret;}
static struct platform_driver dcam_driver = {
.probe = dcam_probe,
.remove = dcam_remove,
.driver = {
.owner = THIS_MODULE,
.name = "XXXXX_dcam",
},
};
static int __init create_instance(int inst)
{
struct dcam_dev *dev;
struct video_device *vfd;
int ret, i;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
"%s-%03d", DCAM_MODULE_NAME, inst);
ret = v4l2_device_register(NULL, &dev->v4l2_dev);
//初始化v4l2_device
if (ret)
goto free_dev;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
ret = -ENOMEM;
//为video_device分配内存
vfd = video_device_alloc();
if (!vfd)
goto unreg_dev;
//为vfd赋值
*vfd = dcam_template;
vfd->debug = debug;
//注册video_device,主要作用是注册cdev,具体看实现,这个函数很重要
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0)
goto rel_vdev;
video_set_drvdata(vfd, dev);
/* Set all controls to their default value. */
for (i = 0; i < ARRAY_SIZE(dcam_qctrl); i++)
dev->qctl_regs[i] = dcam_qctrl[i].default_value;
/* Now that everything is fine, let's add it to device list */
list_add_tail(&dev->dcam_devlist, &dcam_devlist);
snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
dcam_template.name, vfd->num);
if (video_nr >= 0)
video_nr++;
dev->vfd = vfd;
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
vfd->num);
return 0;
rel_vdev:
video_device_release(vfd);
unreg_dev:
v4l2_device_unregister(&dev->v4l2_dev);
free_dev:
kfree(dev);
return ret;
}
static struct video_device dcam_template = {
.name = "dcam",
.fops = &dcam_fops,
.ioctl_ops = &dcam_ioctl_ops,
.minor = -1,
.release = video_device_release,
.tvnorms = V4L2_STD_525_60,
.current_norm = V4L2_STD_NTSC_M,
};
//现在分析probe函数
//主要作用是注册一个miscdevice
int dcam_probe(struct platform_device *pdev)
{
int ret;
printk(KERN_ALERT"dcam_probe called\n");
ret = misc_register(&dcam_v4l2_dev);//这个可以去查看相关的注册过程
if (ret) {
printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
DCAM_MINOR, ret);
return ret;
}
lock = (struct mutex *)kmalloc(sizeof(struct mutex), GFP_KERNEL);
if (lock == NULL)
return -1;
mutex_init(lock);
printk(KERN_ALERT "dcam_probe Success.\n");
return 0;
}
static struct miscdevice dcam_v4l2_dev = {
.minor = DCAM_MINOR,
.name = "sc8800g_dcam",
.fops = &dcam_fops,
};
这样基本上一个设备就可以正常工作了。