摄像头的驱动分析1

时间:2022-11-24 17:26:21

分析linux-3.4.2内核的摄像头驱动程序,强烈推荐先学习内核自带的是vivi.c,这是一个虚拟摄像头,拿这个学习摄像头驱动程序比较好。

具体分析如下:

打开linux-3.4.2_patch.tar\linux-3.4.2\drivers\media\video\Vivi.c

先分析

static int __init vivi_init(void)

{

    ret = vivi_create_instance(i);/*创建设备*/

}

  1 static int __init vivi_create_instance(int inst)
2 {
3 struct vivi_dev *dev;
4 struct video_device *vfd;
5 struct v4l2_ctrl_handler *hdl;
6 struct vb2_queue *q;
7 int ret;
8
9 dev = kzalloc(sizeof(*dev), GFP_KERNEL);/*分配一个viv_dev ,其中嵌套v4l2_device和鍁ideo_device*/
10 if (!dev)
11 return -ENOMEM;
12
13 snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
14 "%s-%03d", VIVI_MODULE_NAME, inst);
15 ret = v4l2_device_register(NULL, &dev->v4l2_dev);/*注册viv_dev中的v4l2_device*/
16 if (ret)
17 goto free_dev;
18
19 dev->fmt = &formats[0];
20 dev->width = 640;
21 dev->height = 480;
22 hdl = &dev->ctrl_handler;
23 v4l2_ctrl_handler_init(hdl, 11);//初始化 &dev->ctrl_handler,也就是初始化hdl中的链?
24 //下面就是对hdl中的链表进行填充
25 dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
26 V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
27 dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
28 V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
29 dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
30 V4L2_CID_CONTRAST, 0, 255, 1, 16);
31 dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
32 V4L2_CID_SATURATION, 0, 255, 1, 127);
33 dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
34 V4L2_CID_HUE, -128, 127, 1, 0);
35 dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
36 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
37 dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
38 V4L2_CID_GAIN, 0, 255, 1, 100);
39 dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
40 dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
41 dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
42 dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
43 dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
44 dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
45 dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
46 if (hdl->error) {
47 ret = hdl->error;
48 goto unreg_dev;
49 }
50 v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
51 dev->v4l2_dev.ctrl_handler = hdl;
52
53 /* initialize locks */
54 spin_lock_init(&dev->slock);/*初始化锁*/
55
56 /* initialize queue */
57 q = &dev->vb_vidq;
58 memset(q, 0, sizeof(dev->vb_vidq));
59 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//类型是摄像头扑捉
60 q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
61 q->drv_priv = dev;
62 q->buf_struct_size = sizeof(struct vivi_buffer);
63 q->ops = &vivi_video_qops;
64 q->mem_ops = &vb2_vmalloc_memops;
65
66 vb2_queue_init(q);/*初始化队列*/
67
68 mutex_init(&dev->mutex);
69
70 /* init video dma queues */
71 INIT_LIST_HEAD(&dev->vidq.active);
72 init_waitqueue_head(&dev->vidq.wq);
73
74 ret = -ENOMEM;
75 vfd = video_device_alloc();/*动态分配一个video_device结构体*/
76 if (!vfd)
77 goto unreg_dev;
78
79 *vfd = vivi_template;/*把viv_template结构体赋值给video_device*/
80 vfd->debug = debug;
81 vfd->v4l2_dev = &dev->v4l2_dev;
82 set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
83
84 /*
85 * Provide a mutex to v4l2 core. It will be used to protect
86 * all fops and v4l2 ioctls.
87 */
88 vfd->lock = &dev->mutex;
89
90 ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);//注册这个vfd结构体
91 if (ret < 0)
92 goto rel_vdev;
93
94 video_set_drvdata(vfd, dev);/*初始化驱动程序专有数据*/
95
96 /* Now that everything is fine, let's add it to device list */
97 list_add_tail(&dev->vivi_devlist, &vivi_devlist);/*加入viv_devlist链表*/
98
99 if (video_nr != -1)
100 video_nr++;
101
102 dev->vfd = vfd;
103 v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
104 video_device_node_name(vfd));
105 return 0;
106
107 rel_vdev:
108 video_device_release(vfd);
109 unreg_dev:
110 v4l2_ctrl_handler_free(hdl);
111 v4l2_device_unregister(&dev->v4l2_dev);
112 free_dev:
113 kfree(dev);
114 return ret;
115 }

 

则进一步分析ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);//注册这个vfd结构体

  1 */
2 int __video_register_device(struct video_device *vdev, int type, int nr,
3 int warn_if_nr_in_use, struct module *owner)
4 {
5 int i = 0;
6 int ret;
7 int minor_offset = 0;
8 int minor_cnt = VIDEO_NUM_DEVICES;
9 const char *name_base;
10
11 /* A minor value of -1 marks this video device as never
12 having been registered */
13 vdev->minor = -1;
14
15 /* the release callback MUST be present */
16 if (WARN_ON(!vdev->release))
17 return -EINVAL;
18
19 /* v4l2_fh support */
20 spin_lock_init(&vdev->fh_lock);
21 INIT_LIST_HEAD(&vdev->fh_list);
22
23 /* Part 1: check device type */
24 switch (type) {//设备设备类型
25 case VFL_TYPE_GRABBER:
26 name_base = "video";
27 break;
28 case VFL_TYPE_VBI:
29 name_base = "vbi";
30 break;
31 case VFL_TYPE_RADIO:
32 name_base = "radio";
33 break;
34 case VFL_TYPE_SUBDEV:
35 name_base = "v4l-subdev";
36 break;
37 default:
38 printk(KERN_ERR "%s called with unknown type: %d\n",
39 __func__, type);
40 return -EINVAL;
41 }
42
43 vdev->vfl_type = type;
44 vdev->cdev = NULL;
45 if (vdev->v4l2_dev) {//这个初始化在hdl = &dev->ctrl_handler;
46 // dev->v4l2_dev.ctrl_handler = hdl;
47 // vfd->v4l2_dev = &dev->v4l2_dev;
48 if (vdev->v4l2_dev->dev)
49 vdev->parent = vdev->v4l2_dev->dev;
50 if (vdev->ctrl_handler == NULL)
51 vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;//得到vdev->ctrl_handler= hdl;
52 /* If the prio state pointer is NULL, then use the v4l2_device
53 prio state. */
54 if (vdev->prio == NULL)
55 vdev->prio = &vdev->v4l2_dev->prio;
56 }
57
58 /* Part 2: find a free minor, device node number and device index. */
59 #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
60 /* Keep the ranges for the first four types for historical
61 * reasons.
62 * Newer devices (not yet in place) should use the range
63 * of 128-191 and just pick the first free minor there
64 * (new style). */
65 switch (type) {
66 case VFL_TYPE_GRABBER:
67 minor_offset = 0;
68 minor_cnt = 64;
69 break;
70 case VFL_TYPE_RADIO:
71 minor_offset = 64;
72 minor_cnt = 64;
73 break;
74 case VFL_TYPE_VBI:
75 minor_offset = 224;
76 minor_cnt = 32;
77 break;
78 default:
79 minor_offset = 128;
80 minor_cnt = 64;
81 break;
82 }
83 #endif
84
85 /* Pick a device node number */
86 mutex_lock(&videodev_lock);
87 nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
88 if (nr == minor_cnt)
89 nr = devnode_find(vdev, 0, minor_cnt);
90 if (nr == minor_cnt) {
91 printk(KERN_ERR "could not get a free device node number\n");
92 mutex_unlock(&videodev_lock);
93 return -ENFILE;
94 }
95 #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
96 /* 1-on-1 mapping of device node number to minor number */
97 i = nr;
98 #else
99 /* The device node number and minor numbers are independent, so
100 we just find the first free minor number. */
101 for (i = 0; i < VIDEO_NUM_DEVICES; i++)
102 if (video_device[i] == NULL)//找打一个空的video_device[]数组项,然后把注册的video_device放入这个数组中
103 break;
104 if (i == VIDEO_NUM_DEVICES) {
105 mutex_unlock(&videodev_lock);
106 printk(KERN_ERR "could not get a free minor\n");
107 return -ENFILE;
108 }
109 #endif
110 vdev->minor = i + minor_offset;//次设备号是数组索引值加minor_offset
111 vdev->num = nr;
112 devnode_set(vdev);
113
114 /* Should not happen since we thought this minor was free */
115 WARN_ON(video_device[vdev->minor] != NULL);
116 vdev->index = get_index(vdev);
117 mutex_unlock(&videodev_lock);
118
119 /* Part 3: Initialize the character device */
120 vdev->cdev = cdev_alloc();//分配一个cdev设备
121 if (vdev->cdev == NULL) {
122 ret = -ENOMEM;
123 goto cleanup;
124 }
125 vdev->cdev->ops = &v4l2_fops;//初始化这个设备
126 vdev->cdev->owner = owner;
127 ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);//添加这个设备
128 if (ret < 0) {
129 printk(KERN_ERR "%s: cdev_add failed\n", __func__);
130 kfree(vdev->cdev);
131 vdev->cdev = NULL;
132 goto cleanup;
133 }
134
135 /* Part 4: register the device with sysfs */
136 vdev->dev.class = &video_class;
137 vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
138 if (vdev->parent)
139 vdev->dev.parent = vdev->parent;
140 dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
141 ret = device_register(&vdev->dev);//注册这个设备
142 if (ret < 0) {
143 printk(KERN_ERR "%s: device_register failed\n", __func__);
144 goto cleanup;
145 }
146 /* Register the release callback that will be called when the last
147 reference to the device goes away. */
148 vdev->dev.release = v4l2_device_release;
149
150 if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
151 printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
152 name_base, nr, video_device_node_name(vdev));
153
154 /* Increase v4l2_device refcount */
155 if (vdev->v4l2_dev)//增加引用计数
156 v4l2_device_get(vdev->v4l2_dev);
157
158 #if defined(CONFIG_MEDIA_CONTROLLER)
159 /* Part 5: Register the entity. */
160 if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
161 vdev->vfl_type != VFL_TYPE_SUBDEV) {
162 vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
163 vdev->entity.name = vdev->name;
164 vdev->entity.info.v4l.major = VIDEO_MAJOR;
165 vdev->entity.info.v4l.minor = vdev->minor;
166 ret = media_device_register_entity(vdev->v4l2_dev->mdev,
167 &vdev->entity);
168 if (ret < 0)
169 printk(KERN_WARNING
170 "%s: media_device_register_entity failed\n",
171 __func__);
172 }
173 #endif
174 /* Part 6: Activate this minor. The char device can now be used. */
175 set_bit(V4L2_FL_REGISTERED, &vdev->flags);
176 mutex_lock(&videodev_lock);
177 video_device[vdev->minor] = vdev;//把video_device存放人video_device[i]中
178 mutex_unlock(&videodev_lock);
179
180 return 0;
181
182 cleanup:
183 mutex_lock(&videodev_lock);
184 if (vdev->cdev)
185 cdev_del(vdev->cdev);
186 devnode_clear(vdev);
187 mutex_unlock(&videodev_lock);
188 /* Mark this video device as never having been registered. */
189 vdev->minor = -1;
190 return ret;
191 }

这个函数主要的工作是初始化video_device这个设备,

vdev->cdev = cdev_alloc();//分配一个cdev设备

vdev->cdev->ops = &v4l2_fops;//初始化这个设备
vdev->cdev->owner = owner;

ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);//添加这个设备

ret = device_register(&vdev->dev);

当应用程序执行open时,会调用次字符设备注册v4l2_fops->open函数

把初始化的video_device*vdev结构体存放在一个video_device数组中,索引值为字符设备的次设备号,、

3.分析应用程序是怎么调用驱动里面的函数

  当应用程序执行open函数时,会调用字符设备注册的vdev->cdev->ops = &v4l2_fops.open函数

     open -->v4l2_fops->open

 1 static const struct file_operations v4l2_fops = {
2 .owner = THIS_MODULE,
3 .read = v4l2_read,
4 .write = v4l2_write,
5 .open = v4l2_open,
6 .get_unmapped_area = v4l2_get_unmapped_area,
7 .mmap = v4l2_mmap,
8 .unlocked_ioctl = v4l2_ioctl,
9 #ifdef CONFIG_COMPAT
10 .compat_ioctl = v4l2_compat_ioctl32,
11 #endif
12 .release = v4l2_release,
13 .poll = v4l2_poll,
14 .llseek = no_llseek,
15 };

分析open函数

 1 static int v4l2_open(struct inode *inode, struct file *filp)
2 {
3 struct video_device *vdev;
4 int ret = 0;
5
6 /* Check if the video device is available */
7 mutex_lock(&videodev_lock);
8 vdev = video_devdata(filp);//根据打开设备次设备号找到video_device数组中的鍁ido_device
9 /* return ENODEV if the video device has already been removed. */
10 if (vdev == NULL || !video_is_registered(vdev)) {
11 mutex_unlock(&videodev_lock);
12 return -ENODEV;
13 }
14 /* and increase the device refcount */
15 video_get(vdev);//修改引用计数
16 mutex_unlock(&videodev_lock);
17 if (vdev->fops->open) {//如果video_device中的file_operations中的open被定义
18 //在vivi.c中被初始化video_device = vivi_template;
19 if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
20 ret = -ERESTARTSYS;
21 goto err;
22 }
23 if (video_is_registered(vdev))
24 ret = vdev->fops->open(filp);//执行open函数
25 else
26 ret = -ENODEV;
27 if (vdev->lock)
28 mutex_unlock(vdev->lock);
29 }
30
31 err:
32 /* decrease the refcount in case of an error */
33 if (ret)
34 video_put(vdev);
35 return ret;
36 }

对于其他命令分析类似。