Linux 媒体框架(Media Framework)一

Linux V4l2 框架 一

v4l2的框架图

Linux 媒体框架(Media Framework)一_第1张图片

1.Linux Media Framework( 媒体框架)

1.基本概念

media framework 是嵌入到lv4l2 框架中,主要分成entity pad link三大部分,entity设备的实例

pad 用来作为entity的连接点 link 用来连接entity 下图可以直观的看到

Linux 媒体框架(Media Framework)一_第2张图片

2.media的源码

1.注册media总线

首先看media-devnode.c文件,在/sys/bus/下注册了media总线,后续相关的media设备都会注册到下面

Z:\RV1109\kernel\drivers\media\media-devnode.c
subsys_initcall(media_devnode_init);

static int __init media_devnode_init(void)
{
	int ret;

	pr_info("Linux media interface: v0.10\n");
	ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
				  MEDIA_NAME);
	if (ret < 0) {
		pr_warn("unable to allocate major\n");
		return ret;
	}

	ret = bus_register(&media_bus_type);
	if (ret < 0) {
		unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
		pr_warn("bus_register failed\n");
		return -EIO;
	}

	return 0;
}


2.注册media实例

注册完总线后需要把媒体设备实例化,调用注册媒体设备接口在media总线下注册

Z:\RV1109\kernel\drivers\media\media-device.c
//初始化media device下的 entity pad link  链表
void media_device_init(struct media_device *mdev)
{
	INIT_LIST_HEAD(&mdev->entities);
	INIT_LIST_HEAD(&mdev->interfaces);
	INIT_LIST_HEAD(&mdev->pads);
	INIT_LIST_HEAD(&mdev->links);
	INIT_LIST_HEAD(&mdev->entity_notify);
	mutex_init(&mdev->graph_mutex);
	ida_init(&mdev->entity_internal_idx);

	dev_dbg(mdev->dev, "Media device initialized\n");
}    
//将媒体实例化注册到media总线下 实际调用media_devnode_register 注册media节点
int __must_check __media_device_register(struct media_device *mdev,
					 struct module *owner)
{
	struct media_devnode *devnode;
	int ret;

	devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
	if (!devnode)
		return -ENOMEM;

	/* Register the device node. */
	mdev->devnode = devnode;
	devnode->fops = &media_device_fops;
	devnode->parent = mdev->dev;
	devnode->release = media_device_release;

	/* Set version 0 to indicate user-space that the graph is static */
	mdev->topology_version = 0;

	ret = media_devnode_register(mdev, devnode, owner);
	if (ret < 0) {
		/* devnode free is handled in media_devnode_*() */
		mdev->devnode = NULL;
		return ret;
	}

	ret = device_create_file(&devnode->dev, &dev_attr_model);
	if (ret < 0) {
		/* devnode free is handled in media_devnode_*() */
		mdev->devnode = NULL;
		media_devnode_unregister_prepare(devnode);
		media_devnode_unregister(devnode);
		return ret;
	}

	dev_dbg(mdev->dev, "Media device registered\n");

	return 0;
}
//注册media node节点
int __must_check media_devnode_register(struct media_device *mdev,
					struct media_devnode *devnode,
					struct module *owner)
{
	int minor;
	int ret;

	/* Part 1: Find a free minor number */
	mutex_lock(&media_devnode_lock);
	minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
	if (minor == MEDIA_NUM_DEVICES) {
		mutex_unlock(&media_devnode_lock);
		pr_err("could not get a free minor\n");
		kfree(devnode);
		return -ENFILE;
	}

	set_bit(minor, media_devnode_nums);
	mutex_unlock(&media_devnode_lock);

	devnode->minor = minor;
	devnode->media_dev = mdev;

	/* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
	devnode->dev.bus = &media_bus_type;
	devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
	devnode->dev.release = media_devnode_release;
	if (devnode->parent)
		devnode->dev.parent = devnode->parent;
	dev_set_name(&devnode->dev, "media%d", devnode->minor);
	device_initialize(&devnode->dev);

	/* Part 2: Initialize the character device */
	cdev_init(&devnode->cdev, &media_devnode_fops);
	devnode->cdev.owner = owner;

	/* Part 3: Add the media and char device */
	ret = cdev_device_add(&devnode->cdev, &devnode->dev);
	if (ret < 0) {
		pr_err("%s: cdev_device_add failed\n", __func__);
		goto cdev_add_error;
	}

	/* Part 4: Activate this minor. The char device can now be used. */
	set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);

	return 0;

cdev_add_error:
	mutex_lock(&media_devnode_lock);
	clear_bit(devnode->minor, media_devnode_nums);
	devnode->media_dev = NULL;
	mutex_unlock(&media_devnode_lock);

	put_device(&devnode->dev);
	return ret;
}
3.初始化entity 实例相关
//pads entity links 头文件
media/media-entity.h
//entity init
int media_entity_init(struct media_entity *entity, u16 num_pads,
		  struct media_pad *pads, u16 extra_links)
//entity pad init
int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
			   struct media_pad *pads)
{
	struct media_device *mdev = entity->graph_obj.mdev;
	unsigned int i;

	if (num_pads >= MEDIA_ENTITY_MAX_PADS)
		return -E2BIG;

	entity->num_pads = num_pads;
	entity->pads = pads;

	if (mdev)
		mutex_lock(&mdev->graph_mutex);

	for (i = 0; i < num_pads; i++) {
		pads[i].entity = entity;
		pads[i].index = i;
		if (mdev)
			media_gobj_create(mdev, MEDIA_GRAPH_PAD,
					&entity->pads[i].graph_obj);
	}

	if (mdev)
		mutex_unlock(&mdev->graph_mutex);

	return 0;
} 
//控制pipeline开启
__must_check int media_pipeline_start(struct media_entity *entity,
				      struct media_pipeline *pipe)
{
	struct media_device *mdev = entity->graph_obj.mdev;
	int ret;

	mutex_lock(&mdev->graph_mutex);
	ret = __media_pipeline_start(entity, pipe);
	mutex_unlock(&mdev->graph_mutex);
	return ret;
}
//控制pipeline 关闭
void media_pipeline_stop(struct media_entity *entity)
{
	struct media_device *mdev = entity->graph_obj.mdev;

	mutex_lock(&mdev->graph_mutex);
	__media_pipeline_stop(entity);
	mutex_unlock(&mdev->graph_mutex);
}
4.links的连接
//entity的相关连接是通过pad之间的连接
//创建pad -> pad 的连接
media_create_pad_link()
//remove link
media_entity_remove_links()
//interface to entity的连接
media_create_intf_link()
//remove
media_remove_intf_links()
    

2.linux V4l2 Framework

1.v4l2 device

1.V4L2 device 实例基本概念

每个设备实体都代表着一个struct v4l2_device,在linux中我们往往把这个结构嵌入到大框架中,旗下包含着设备实体

2.v4l2 设备的注册以及相关操作
//注册v4l2 device
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
	if (v4l2_dev == NULL)
		return -EINVAL;

	INIT_LIST_HEAD(&v4l2_dev->subdevs);
	spin_lock_init(&v4l2_dev->lock);
	v4l2_prio_init(&v4l2_dev->prio);
	kref_init(&v4l2_dev->ref);
	get_device(dev);
	v4l2_dev->dev = dev;
	if (dev == NULL) {
		/* If dev == NULL, then name must be filled in by the caller */
		if (WARN_ON(!v4l2_dev->name[0]))
			return -EINVAL;
		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",
			dev->driver->name, dev_name(dev));
	if (!dev_get_drvdata(dev))
		dev_set_drvdata(dev, v4l2_dev);
	return 0;
}
//初始化v4l2 device name
int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
						atomic_t *instance)
{
	int num = atomic_inc_return(instance) - 1;
	int len = strlen(basename);

	if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
		snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
				"%s-%d", basename, num);
	else
		snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
				"%s%d", basename, num);
	return num;
}

2.v4l2 subdevice

相对于一个监控系统来说,v4l2 subdevice 通常是作为一个sensor来做相应的操作

1.v4l2 sudevice相关操作
//v4l2 subdevice init
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
{
	INIT_LIST_HEAD(&sd->list);
	BUG_ON(!ops);
	sd->ops = ops;
	sd->v4l2_dev = NULL;
	sd->flags = 0;
	sd->name[0] = '\0';
	sd->grp_id = 0;
	sd->dev_priv = NULL;
	sd->host_priv = NULL;
#if defined(CONFIG_MEDIA_CONTROLLER)
	sd->entity.name = sd->name;
	sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
	sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
#endif
}
//v4l2 subdevice通常引入media framework
//注册subdevice到v4l2 框架中
v4l2_device_register_subdev();
2.I2c subdevice 相关操作
//初始化device
v4l2_i2c_subdev_init()
//v4l2_subdev struct to the i2c_client struct
struct i2c_client *client = v4l2_get_subdevdata(sd);
//i2c_client to a v4l2_subdev struct
struct v4l2_subdev *sd = i2c_get_clientdata(client);

work
//注册subdevice到v4l2 框架中
v4l2_device_register_subdev();


#### 2.I2c subdevice 相关操作

```c
//初始化device
v4l2_i2c_subdev_init()
//v4l2_subdev struct to the i2c_client struct
struct i2c_client *client = v4l2_get_subdevdata(sd);
//i2c_client to a v4l2_subdev struct
struct v4l2_subdev *sd = i2c_get_clientdata(client);

你可能感兴趣的:(linux,kernel,linux,物联网,驱动程序)