梦想天地

导航

摄像头的驱动分析1

分析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 }

对于其他命令分析类似。

 

posted on 2016-03-28 22:01  梦想天地  阅读(534)  评论(0编辑  收藏  举报