首页 > 代码库 > soc camera子系统之注冊video device设备
soc camera子系统之注冊video device设备
该函数是用于soc camera 子系统向v4l2子系统注冊video_device设备,这个设备是v4l2子系统的核心设备。先展开代码.
首先展开video_dev_create函数,代码例如以下:
static int video_dev_create(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct video_device *vdev = video_device_alloc(); //为video device申请内存。 if (!vdev) return -ENOMEM; strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); vdev->parent = &icd->dev; //通过这个pointer,能够由vdev来获取到icd vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops;//该函数集相似于file_opration,事实上就是用来作为v4l2 子系统的默认的file_opration函数集中的回调函数。以下会有相应的分析。 static struct v4l2_file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, //作为v4l2_open函数的回调函数 .release = soc_camera_close, //作为v4l2_release函数的回调函数 .unlocked_ioctl = video_ioctl2,//作为v4l2_ioctl函数的回调函数。 .read = soc_camera_read,//作为v4l2_read函数的回调函数 .mmap = soc_camera_mmap,//作为v4l2_mmcp函数的回调函数。 .poll = soc_camera_poll,//作为v4l2_poll函数的回调函数 }; vdev->ioctl_ops = &soc_camera_ioctl_ops; //该函数集是soc camera.c中实现的核心函数集,作为videp_ioctl2函数的回调函数集,依据用户空间传入的不同的ioctl命令。 vdev->release = video_device_release; vdev->tvnorms = V4L2_STD_UNKNOWN; icd->vdev = vdev; //让icd的成员指针指向已经初始化的video device设备。 return 0; }
好了,我们如今着重分析soc_camera_video_start函数
static int soc_camera_video_start(struct soc_camera_device *icd) { const struct device_type *type = icd->vdev->dev.type; int ret; if (!icd->dev.parent) return -ENODEV; if (!icd->ops || !icd->ops->query_bus_param || !icd->ops->set_bus_param) return -EINVAL; ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);核心行为。向v4l2子系统注冊video device设备。事实上v4l2子系统向上实质是抽象成了一个字符设备。以下就会看到。type指定为VFL_TYPE_GRABBRER类型。相应video设备。 if (ret < 0) { dev_err(&icd->dev, "video_register_device failed: %d\n", ret); return ret; } /* Restore device type, possibly set by the subdevice driver */ icd->vdev->dev.type = type; return 0; }
我们来着重分析一下video_register_device函数。该函数体内就是直接调用函数__video_register_device,所以我们真正要着重分析的函数是__video_register_device。这是一个非常长的函数,我们须要慢慢分析,展开代码例如以下:
int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use, struct module *owner) { int i = 0; int ret; int minor_offset = 0; int minor_cnt = VIDEO_NUM_DEVICES; //做多能够注冊的设备数目256 const char *name_base; /* A minor value of -1 marks this video device as never having been registered */ vdev->minor = -1; ...... /* Part 1: check device type */ switch (type) { case VFL_TYPE_GRABBER: name_base = "video"; break; case VFL_TYPE_VBI: name_base = "vbi"; break; case VFL_TYPE_RADIO: name_base = "radio"; break; case VFL_TYPE_SUBDEV: name_base = "v4l-subdev"; break; default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); return -EINVAL; } vdev->vfl_type = type; //type类型为VFL_TYPE_GRABBER vdev->cdev = NULL;/ ...... /* Part 2: find a free minor, device node number and device index. */ #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES /* Keep the ranges for the first four types for historical * reasons. * Newer devices (not yet in place) should use the range * of 128-191 and just pick the first free minor there * (new style). */ switch (type) { case VFL_TYPE_GRABBER: minor_offset = 0; minor_cnt = 64; break; case VFL_TYPE_RADIO: minor_offset = 64; minor_cnt = 64; break; case VFL_TYPE_VBI: minor_offset = 224; minor_cnt = 32; break; default: minor_offset = 128; minor_cnt = 64; break; } #endif /* Pick a device node number */ mutex_lock(&videodev_lock); //下面几行主要是为了寻找次设备号。nr = devnode_find(vdev, nr == -1 ?
0 : nr, minor_cnt); if (nr == minor_cnt) nr = devnode_find(vdev, 0, minor_cnt); if (nr == minor_cnt) { printk(KERN_ERR "could not get a free device node number\n"); mutex_unlock(&videodev_lock); return -ENFILE; } #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES /* 1-on-1 mapping of device node number to minor number */ i = nr; //假设定义了改宏。那么video device的次设备号由nr和minor_offset共同决定。
#else /* The device node number and minor numbers are independent, so we just find the first free minor number. */ 为新注冊的video device在数组video_device中寻找一个位置。 for (i = 0; i < VIDEO_NUM_DEVICES; i++) if (video_device[i] == NULL) break; ...... #endif vdev->minor = i + minor_offset; //计算出设备的次设备号 假设定义CONFIG_VIDEO_FIXED_MINOR_RANGES vdev->minor = i + minor_offset. 否则 vdev->minor = vdeio_device数组中第一个空暇的位置(从低地址開始。
) vdev->num = nr; devnode_set(vdev); /* Should not happen since we thought this minor was free */ WARN_ON(video_device[vdev->minor] != NULL); vdev->index = get_index(vdev); mutex_unlock(&videodev_lock); /* Part 3: Initialize the character device */、 //下面是初始化一个char dev结构,然后注冊字符设备。 vdev->cdev = cdev_alloc(); if (vdev->cdev == NULL) { ret = -ENOMEM; goto cleanup; } vdev->cdev->ops = &v4l2_fops; //v4l2子系统实现的默认的file opration操作函数集。每一个成员函数内会调用相应的v4l2_file_oprations操作函数集。 vdev->cdev->owner = owner; ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); //注冊字符设备 if (ret < 0) { printk(KERN_ERR "%s: cdev_add failed\n", __func__); kfree(vdev->cdev); vdev->cdev = NULL; goto cleanup; } ....... return ret; }
soc camera子系统之注冊video device设备