摄像头的驱动分析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 }
对于其他命令分析类似。