1. v4l2_device_register
/* kernel/drivers/media/video/v4l2-device.c */ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) { if (v4l2_dev == NULL) return -EINVAL; INIT_LIST_HEAD(&v4l2_dev->subdevs); // 初始化一个将要挂在v4l2_device上的子设备列表 spin_lock_init(&v4l2_dev->lock); // 初始化一个spin lock mutex_init(&v4l2_dev->ioctl_lock); // 初始化一个mutex,看来会在ioctrl上使用的mutex v4l2_prio_init(&v4l2_dev->prio); // 优先级 kref_init(&v4l2_dev->ref); // 将v4l2_dev的父设备指定为struct device *dev v4l2_dev->dev = dev; // 父设备 if (dev == NULL) { // 如果dev为空,v4l2->dev->name必须设置 /* If dev == NULL, then name must be filled in by the caller */ WARN_ON(!v4l2_dev->name[0]); return 0; } /* Set name to driver name + device name if it is empty. */ if (!v4l2_dev->name[0]) snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", // 如果v4l2_dev->name为空,那么由dev_name(dev)来设置 driver name + device name dev->driver->name, dev_name(dev)); if (!dev_get_drvdata(dev)) dev_set_drvdata(dev, v4l2_dev); // 将dev和v4l2_dev关联:dev->p->driver_data = v4l2_dev return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register);
int dev_set_drvdata(struct device *dev, void *data) { int error; if (!dev->p) { error = device_private_init(dev); if (error) return error; } dev->p->driver_data = data; return 0; } EXPORT_SYMBOL(dev_set_drvdata);
2. v4l2_i2c_new_subdev_board
/* Load an i2c sub-device. */ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, struct i2c_adapter *adapter, struct i2c_board_info *info, const unsigned short *probe_addrs) { struct v4l2_subdev *sd = NULL; struct i2c_client *client; BUG_ON(!v4l2_dev); request_module(I2C_MODULE_PREFIX "%s", info->type);/* Create the i2c client */ if (info->addr == 0 && probe_addrs) client = i2c_new_probed_device(adapter, info, probe_addrs, NULL); else client = i2c_new_device(adapter, info); // 此时会调用ov8858的probe函数,在probe函数中调用v4l2_i2c_subdev_init(sd, client, &ov8858_ops); /* Note: by loading the module first we are certain that c->driver will be set if the driver was found. If the module was not loaded first, then the i2c core tries to delay-load the module for us, and then c->driver is still NULL until the module is finally loaded. This delay-load mechanism doesn‘t work if other drivers want to use the i2c device, so explicitly loading the module is the best alternative. */ if (client == NULL || client->driver == NULL) goto error; /* Lock the module so we can safely get the v4l2_subdev pointer */ if (!try_module_get(client->driver->driver.owner)) goto error; sd = i2c_get_clientdata(client); // 在ov8858这个module加载的时候会调用v4l2_i2c_subdev_init,在这个函数值sd和client发生关系,所以此时可以通过client获取sd /* Register with the v4l2_device which increases the module‘s use count as well. */ if (v4l2_device_register_subdev(v4l2_dev, sd)) // v4l2_device_register_subdev sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); error: /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ if (client && sd == NULL) i2c_unregister_device(client); return sd; } EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
上边我们说到在加载ov8858 module时,调用了至关重要的函数:v4l2_i2c_subdev_init:
/* v4l2-common.c */ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) // ops 由于我们是OV8858,是一个Camera Sensor,所以只实现了core和video的ops { v4l2_subdev_init(sd, ops); sd->flags |= V4L2_SUBDEV_FL_IS_I2C; // 这个宏的注释:Set this flag if this subdev is a i2c device. /* the owner is the same as the i2c_client‘s driver owner */ sd->owner = client->driver->driver.owner; /* i2c_client and v4l2_subdev point to one another */ v4l2_set_subdevdata(sd, client); // sd->dev_priv = client i2c_set_clientdata(client, sd); // client->dev->p->driver_data = sd; /* initialize name */ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", client->driver->driver.name, i2c_adapter_id(client->adapter), client->addr); } EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
1 /* v4l2-subdev.c */ 2 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 3 { 4 INIT_LIST_HEAD(&sd->list); 5 BUG_ON(!ops); 6 sd->ops = ops; 7 sd->v4l2_dev = NULL; 8 sd->flags = 0; 9 sd->name[0] = ‘\0‘; 10 sd->grp_id = 0; 11 sd->dev_priv = NULL; 12 sd->host_priv = NULL; 13 #if defined(CONFIG_MEDIA_CONTROLLER) 14 sd->entity.name = sd->name; 15 sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; 16 #endif 17 } 18 EXPORT_SYMBOL(v4l2_subdev_init);
1 /* v4l2-subdev.h */ 2 static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) 3 { 4 sd->dev_priv = p; 5 }
/* */ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) { dev_set_drvdata(&dev->dev, data); } /* dd.c */ int dev_set_drvdata(struct device *dev, void *data) { int error; if (!dev->p) { error = device_private_init(dev); if (error) return error; } dev->p->driver_data = data; return 0; } EXPORT_SYMBOL(dev_set_drvdata);
在v4l2_i2c_new_subdev_board中,加载ov8858 module,并调用v4l2_i2c_subdev_init实现v4l2_subdev的初始化后,又调用了v4l2_device_register_subdev来注册subdev.
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd) { #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity *entity = &sd->entity; #endif int err; /* Check for valid input */ if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) return -EINVAL; /* Warn if we apparently re-register a subdev */ WARN_ON(sd->v4l2_dev != NULL); if (!try_module_get(sd->owner)) return -ENODEV; sd->v4l2_dev = v4l2_dev; // 此时,subdev和v4l2_dev发生关系:sd->v4l2_dev = v4l2_dev; if (sd->internal_ops && sd->internal_ops->registered) { err = sd->internal_ops->registered(sd); if (err) { module_put(sd->owner); return err; } } /* This just returns 0 if either of the two args is NULL */ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); if (err) { if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); module_put(sd->owner); return err; } #if defined(CONFIG_MEDIA_CONTROLLER) /* Register the entity. */ if (v4l2_dev->mdev) { err = media_device_register_entity(v4l2_dev->mdev, entity); if (err < 0) { if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); module_put(sd->owner); return err; } } #endif spin_lock(&v4l2_dev->lock); list_add_tail(&sd->list, &v4l2_dev->subdevs); spin_unlock(&v4l2_dev->lock); return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
3. video_device_alloc
/* v4l2-dev.c */struct video_device *video_device_alloc(void) { return kzalloc(sizeof(struct video_device), GFP_KERNEL); } EXPORT_SYMBOL(video_device_alloc);
4. video_register_device
/* v4l2-dev.h */ /* Register video devices. Note that if video_register_device fails, the release() callback of the video_device structure is *not* called, so the caller is responsible for freeing any data. Usually that means that you call video_device_release() on failure. *//* 注册video_device。如果注册失败,vieo_device的release()函数将不会被回调。因此,video_register_device的调用者应该来释放数据。 通常在注册失败时,调用video_device_release即可。*//* 我们是这么调用的: ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); 第二个参数是type:#define VFL_TYPE_GRABBER 0 表明一个图像采集设备——包括摄像头/调谐器,诸如此类#define VFL_TYPE_VBI 1 代表设备是从视频消隐时间段取得信息的设备#define VFL_TYPE_RADIO 2 代表无线电设备#define VFL_TYPE_SUBDEV 3 不知道代表什么,可能是代表除上述以外其他的设备吧#define VFL_TYPE_MAX 4 最大值*/ static inline int __must_check video_register_device(struct video_device *vdev, int type, int nr) { return __video_register_device(vdev, type, nr, 1, vdev->fops->owner); }
/** * __video_register_device - register video4linux devices * @vdev: video device structure we want to register * @type: type of device to register * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... * -1 == first free) * @warn_if_nr_in_use: warn if the desired device node number * was already in use and another number was chosen instead. * @owner: module that owns the video device node * * The registration code assigns minor numbers and device node numbers * based on the requested type and registers the new device node with * the kernel. * * This function assumes that struct video_device was zeroed when it * was allocated and does not contain any stale date. * * An error is returned if no free minor or device node number could be * found, or if the registration of the device node failed. * * Zero is returned on success. * * Valid types are * * %VFL_TYPE_GRABBER - A frame grabber * * %VFL_TYPE_VBI - Vertical blank data (undecoded) * * %VFL_TYPE_RADIO - A radio card * * %VFL_TYPE_SUBDEV - A subdevice */ 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; const char *name_base; /* A minor value of -1 marks this video device as never having been registered */ vdev->minor = -1; // 将minor设置为-1,,标志video device从没有被注册过 /* the release callback MUST be present */ WARN_ON(!vdev->release); // release回调函数必须设置 if (!vdev->release) return -EINVAL; /* v4l2_fh support */ spin_lock_init(&vdev->fh_lock); // fh_lock:Lock for all v4l2_fhs INIT_LIST_HEAD(&vdev->fh_list); // fb_list:List of struct v4l2_fh /* 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; vdev->cdev = NULL; if (vdev->v4l2_dev) { if (vdev->v4l2_dev->dev) vdev->parent = vdev->v4l2_dev->dev; // 如果vdev->v4l2_dev->dev不为空,那么将vdev的父设备和vdev->v4l2_dev的父设备指向同一个设备 if (vdev->ctrl_handler == NULL) vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; /* If the prio state pointer is NULL, then use the v4l2_device prio state. */ if (vdev->prio == NULL) vdev->prio = &vdev->v4l2_dev->prio; // 如果vdev没有设置优先级proi,那么使用vdev->v4l2_dev的优先级 } /* 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; #else /* The device node number and minor numbers are independent, so we just find the first free minor number. */ for (i = 0; i < VIDEO_NUM_DEVICES; i++) if (video_device[i] == NULL) break; if (i == VIDEO_NUM_DEVICES) { mutex_unlock(&videodev_lock); printk(KERN_ERR "could not get a free minor\n"); return -ENFILE; } #endif vdev->minor = i + minor_offset; 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 */ vdev->cdev = cdev_alloc(); if (vdev->cdev == NULL) { ret = -ENOMEM; goto cleanup; } vdev->cdev->ops = &v4l2_fops; 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; } /* Part 4: register the device with sysfs */ vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); if (vdev->parent) vdev->dev.parent = vdev->parent; dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); ret = device_register(&vdev->dev); if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __func__); goto cleanup; } /* Register the release callback that will be called when the last reference to the device goes away. */ vdev->dev.release = v4l2_device_release; if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, name_base, nr, video_device_node_name(vdev)); /* Increase v4l2_device refcount */ if (vdev->v4l2_dev) v4l2_device_get(vdev->v4l2_dev); #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; vdev->entity.v4l.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) printk(KERN_WARNING "%s: media_device_register_entity failed\n", __func__); } #endif /* Part 6: Activate this minor. The char device can now be used. */ set_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_lock(&videodev_lock); video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); return 0; cleanup: mutex_lock(&videodev_lock); if (vdev->cdev) cdev_del(vdev->cdev); devnode_clear(vdev); mutex_unlock(&videodev_lock); /* Mark this video device as never having been registered. */ vdev->minor = -1; return ret; } EXPORT_SYMBOL(__video_register_device);
说了一大堆,核心部分就是video_device的成员的设置和字符设备的添加。
5. video_set_drvdata
由于我们将video_device结构体嵌入到一个更大的结构体ovisp_camera_dev中,所有video_device和ovisp_camera_dev发生关系是必然的:
/* v4l2-dev.c */static inline void video_set_drvdata(struct video_device *vdev, void *data) { dev_set_drvdata(&vdev->dev, data); // videv->dev->p->driver_data = data }
/* dd.c */int dev_set_drvdata(struct device *dev, void *data) { int error; if (!dev->p) { error = device_private_init(dev); if (error) return error; } dev->p->driver_data = data; return 0; } EXPORT_SYMBOL(dev_set_drvdata);
时间: 2024-11-07 13:19:01