Загрузка данных


int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev)
{
	struct mxc_isi_m2m *m2m = &isi->m2m;
	struct video_device *vdev = &m2m->vdev;
	struct media_link *link;
	int ret;

	m2m->isi = isi;
	m2m->pipe = &isi->pipes[0];

	mutex_init(&m2m->lock);

	/* Initialize the video device and create controls. */
	snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.m2m");

	vdev->fops	= &mxc_isi_m2m_fops;
	vdev->ioctl_ops	= &mxc_isi_m2m_ioctl_ops;
	vdev->v4l2_dev	= v4l2_dev;
	vdev->minor	= -1;
	vdev->release	= video_device_release_empty;
	vdev->vfl_dir	= VFL_DIR_M2M;

	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
	video_set_drvdata(vdev, m2m);

	/* Create the M2M device. */
	m2m->m2m_dev = v4l2_m2m_init(&mxc_isi_m2m_ops);
	if (IS_ERR(m2m->m2m_dev)) {
		dev_err(isi->dev, "failed to initialize m2m device\n");
		ret = PTR_ERR(m2m->m2m_dev);
		goto err_mutex;
	}

	/* Register the video device. */
	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
	if (ret < 0) {
		dev_err(isi->dev, "failed to register m2m device\n");
		goto err_m2m;
	}

	/*
	 * Populate the media graph. We can't use the mem2mem helper
	 * v4l2_m2m_register_media_controller() as the M2M interface needs to
	 * be connected to the existing entities in the graph, so we have to
	 * wire things up manually:
	 *
	 * - The entity in the video_device, which isn't touched by the V4L2
	 *   core for M2M devices, is used as the source I/O entity in the
	 *   graph, connected to the crossbar switch.
	 *
	 * - The video device at the end of the pipeline provides the sink
	 *   entity, and is already wired up in the graph.
	 *
	 * - A new interface is created, pointing at both entities. The sink
	 *   entity will thus have two interfaces pointing to it.
	 */
	m2m->pad.flags = MEDIA_PAD_FL_SOURCE;
	vdev->entity.name = "mxc_isi.output";
	vdev->entity.function = MEDIA_ENT_F_IO_V4L;
	ret = media_entity_pads_init(&vdev->entity, 1, &m2m->pad);
	if (ret)
		goto err_video;

	ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity);
	if (ret)
		goto err_entity_cleanup;

	ret = media_create_pad_link(&vdev->entity, 0,
				    &m2m->isi->crossbar.sd.entity,
				    m2m->isi->crossbar.num_sinks - 1,
				    MEDIA_LNK_FL_IMMUTABLE |
				    MEDIA_LNK_FL_ENABLED);
	if (ret)
		goto err_entity_unreg;

	m2m->intf = media_devnode_create(v4l2_dev->mdev, MEDIA_INTF_T_V4L_VIDEO,
					 0, VIDEO_MAJOR, vdev->minor);
	if (!m2m->intf) {
		ret = -ENOMEM;
		goto err_entity_unreg;
	}

	link = media_create_intf_link(&vdev->entity, &m2m->intf->intf,
				      MEDIA_LNK_FL_IMMUTABLE |
				      MEDIA_LNK_FL_ENABLED);
	if (!link) {
		ret = -ENOMEM;
		goto err_devnode;
	}

	link = media_create_intf_link(&m2m->pipe->video.vdev.entity,
				      &m2m->intf->intf,
				      MEDIA_LNK_FL_IMMUTABLE |
				      MEDIA_LNK_FL_ENABLED);
	if (!link) {
		ret = -ENOMEM;
		goto err_devnode;
	}

	return 0;

err_devnode:
	media_devnode_remove(m2m->intf);
err_entity_unreg:
	media_device_unregister_entity(&vdev->entity);
err_entity_cleanup:
	media_entity_cleanup(&vdev->entity);
err_video:
	video_unregister_device(vdev);
err_m2m:
	v4l2_m2m_release(m2m->m2m_dev);
err_mutex:
	mutex_destroy(&m2m->lock);
	return ret;
}