Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac90aa02 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

[media] saa7134: add media controller support



Register saa7134 at the media controller core and provide
support for both analog TV and DVB.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 7047f298
Loading
Loading
Loading
Loading
+187 −4
Original line number Diff line number Diff line
@@ -806,6 +806,153 @@ static void must_configure_manually(int has_eeprom)
	}
}

static void saa7134_unregister_media_device(struct saa7134_dev *dev)
{

#ifdef CONFIG_MEDIA_CONTROLLER
	if (!dev->media_dev)
		return;
	media_device_unregister(dev->media_dev);
	media_device_cleanup(dev->media_dev);
	kfree(dev->media_dev);
	dev->media_dev = NULL;
#endif
}

static void saa7134_media_release(struct saa7134_dev *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
	int i;

	for (i = 0; i < SAA7134_INPUT_MAX + 1; i++)
		media_device_unregister_entity(&dev->input_ent[i]);
#endif
}

static void saa7134_create_entities(struct saa7134_dev *dev)
{
#if defined(CONFIG_MEDIA_CONTROLLER)
	int ret, i;
	struct media_entity *entity;
	struct media_entity *decoder = NULL;

	/* Check if it is using an external analog TV demod */
	media_device_for_each_entity(entity, dev->media_dev) {
		if (entity->function == MEDIA_ENT_F_ATV_DECODER)
			decoder = entity;
			break;
	}

	/*
	 * saa713x is not using an external ATV demod.
	 * Register the internal one
	 */
	if (!decoder) {
		dev->demod.name = "saa713x";
		dev->demod_pad[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
		dev->demod_pad[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
		dev->demod_pad[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
		dev->demod.function = MEDIA_ENT_F_ATV_DECODER;

		ret = media_entity_pads_init(&dev->demod, DEMOD_NUM_PADS,
					     dev->demod_pad);
		if (ret < 0)
			pr_err("failed to initialize demod pad!\n");

		ret = media_device_register_entity(dev->media_dev, &dev->demod);
		if (ret < 0)
			pr_err("failed to register demod entity!\n");

		dev->decoder = &dev->demod;
	} else {
		dev->decoder = decoder;
	}

	/* Initialize Video, VBI and Radio pads */
	dev->video_pad.flags = MEDIA_PAD_FL_SINK;
	ret = media_entity_pads_init(&dev->video_dev->entity, 1,
				     &dev->video_pad);
	if (ret < 0)
		pr_err("failed to initialize video media entity!\n");

	dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
	ret = media_entity_pads_init(&dev->vbi_dev->entity, 1,
					&dev->vbi_pad);
	if (ret < 0)
		pr_err("failed to initialize vbi media entity!\n");

	/* Create entities for each input connector */
	for (i = 0; i < SAA7134_INPUT_MAX; i++) {
		struct media_entity *ent = &dev->input_ent[i];
		struct saa7134_input *in = &card_in(dev, i);

		if (in->type == SAA7134_NO_INPUT)
			break;

		/* This input uses the S-Video connector */
		if (in->type == SAA7134_INPUT_COMPOSITE_OVER_SVIDEO)
			continue;

		ent->name = saa7134_input_name[in->type];
		ent->flags = MEDIA_ENT_FL_CONNECTOR;
		dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;

		switch (in->type) {
		case SAA7134_INPUT_COMPOSITE:
		case SAA7134_INPUT_COMPOSITE0:
		case SAA7134_INPUT_COMPOSITE1:
		case SAA7134_INPUT_COMPOSITE2:
		case SAA7134_INPUT_COMPOSITE3:
		case SAA7134_INPUT_COMPOSITE4:
			ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
			break;
		case SAA7134_INPUT_SVIDEO:
		case SAA7134_INPUT_SVIDEO0:
		case SAA7134_INPUT_SVIDEO1:
			ent->function = MEDIA_ENT_F_CONN_SVIDEO;
			break;
		default:
			/*
			 * SAA7134_INPUT_TV and SAA7134_INPUT_TV_MONO.
			 *
			 * Please notice that neither SAA7134_INPUT_MUTE or
			 * SAA7134_INPUT_RADIO are defined at
			 * saa7134_board.input.
			 */
			ent->function = MEDIA_ENT_F_CONN_RF;
			break;
		}

		ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
		if (ret < 0)
			pr_err("failed to initialize input pad[%d]!\n", i);

		ret = media_device_register_entity(dev->media_dev, ent);
		if (ret < 0)
			pr_err("failed to register input entity %d!\n", i);
	}

	/* Create input for Radio RF connector */
	if (card_has_radio(dev)) {
		struct saa7134_input *in = &saa7134_boards[dev->board].radio;
		struct media_entity *ent = &dev->input_ent[i];

		ent->name = saa7134_input_name[in->type];
		ent->flags = MEDIA_ENT_FL_CONNECTOR;
		dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
		ent->function = MEDIA_ENT_F_CONN_RF;

		ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
		if (ret < 0)
			pr_err("failed to initialize input pad[%d]!\n", i);

		ret = media_device_register_entity(dev->media_dev, ent);
		if (ret < 0)
			pr_err("failed to register input entity %d!\n", i);
	}
#endif
}

static struct video_device *vdev_init(struct saa7134_dev *dev,
				      struct video_device *template,
				      char *type)
@@ -826,6 +973,8 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,

static void saa7134_unregister_video(struct saa7134_dev *dev)
{
	saa7134_media_release(dev);

	if (dev->video_dev) {
		if (video_is_registered(dev->video_dev))
			video_unregister_device(dev->video_dev);
@@ -889,6 +1038,18 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
	if (NULL == dev)
		return -ENOMEM;

	dev->nr = saa7134_devcount;
	sprintf(dev->name, "saa%x[%d]", pci_dev->device, dev->nr);

#ifdef CONFIG_MEDIA_CONTROLLER
	dev->media_dev = v4l2_mc_pci_media_device_init(pci_dev, dev->name);
	if (!dev->media_dev) {
		err = -ENOMEM;
		goto fail0;
	}
	dev->v4l2_dev.mdev = dev->media_dev;
#endif

	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
	if (err)
		goto fail0;
@@ -900,9 +1061,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
		goto fail1;
	}

	dev->nr = saa7134_devcount;
	sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr);

	/* pci quirks */
	if (pci_pci_problems) {
		if (pci_pci_problems & PCIPCI_TRITON)
@@ -1102,6 +1260,15 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
		       dev->name, video_device_node_name(dev->radio_dev));
	}

#ifdef CONFIG_MEDIA_CONTROLLER
	saa7134_create_entities(dev);

	err = v4l2_mc_create_media_graph(dev->media_dev);
	if (err) {
		pr_err("failed to create media graph\n");
		goto fail5;
	}
#endif
	/* everything worked */
	saa7134_devcount++;

@@ -1109,6 +1276,18 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
		saa7134_dmasound_init(dev);

	request_submodules(dev);

	/*
	 * Do it at the end, to reduce dynamic configuration changes during
	 * the device init. Yet, as request_modules() can be async, the
	 * topology will likely change after load the saa7134 subdrivers.
	 */
#ifdef CONFIG_MEDIA_CONTROLLER
	err = media_device_register(dev->media_dev);
	if (err)
		goto fail5;
#endif

	return 0;

 fail5:
@@ -1126,6 +1305,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
 fail1:
	v4l2_device_unregister(&dev->v4l2_dev);
 fail0:
#ifdef CONFIG_MEDIA_CONTROLLER
	kfree(dev->media_dev);
#endif
	kfree(dev);
	return err;
}
@@ -1188,9 +1370,10 @@ static void saa7134_finidev(struct pci_dev *pci_dev)
	release_mem_region(pci_resource_start(pci_dev,0),
			   pci_resource_len(pci_dev,0));


	v4l2_device_unregister(&dev->v4l2_dev);

	saa7134_unregister_media_device(dev);

	/* free memory */
	kfree(dev);
}
+8 −1
Original line number Diff line number Diff line
@@ -1883,8 +1883,15 @@ static int dvb_init(struct saa7134_dev *dev)
	fe0->dvb.frontend->callback = saa7134_tuner_callback;

	/* register everything else */
#ifndef CONFIG_MEDIA_CONTROLLER_DVB
	ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
				   &dev->pci->dev, NULL, adapter_nr, 0);
				   &dev->pci->dev, NULL,
				   adapter_nr, 0);
#else
	ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
				   &dev->pci->dev, dev->media_dev,
				   adapter_nr, 0);
#endif

	/* this sequence is necessary to make the tda1004x load its firmware
	 * and to enter analog mode of hybrid boards
+60 −0
Original line number Diff line number Diff line
@@ -785,6 +785,63 @@ static int stop_preview(struct saa7134_dev *dev)
	return 0;
}

/*
 * Media Controller helper functions
 */

static int saa7134_enable_analog_tuner(struct saa7134_dev *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER
	struct media_device *mdev = dev->media_dev;
	struct media_entity *source;
	struct media_link *link, *found_link = NULL;
	int ret, active_links = 0;

	if (!mdev || !dev->decoder)
		return 0;

	/*
	 * This will find the tuner that is connected into the decoder.
	 * Technically, this is not 100% correct, as the device may be
	 * using an analog input instead of the tuner. However, as we can't
	 * do DVB streaming while the DMA engine is being used for V4L2,
	 * this should be enough for the actual needs.
	 */
	list_for_each_entry(link, &dev->decoder->links, list) {
		if (link->sink->entity == dev->decoder) {
			found_link = link;
			if (link->flags & MEDIA_LNK_FL_ENABLED)
				active_links++;
			break;
		}
	}

	if (active_links == 1 || !found_link)
		return 0;

	source = found_link->source->entity;
	list_for_each_entry(link, &source->links, list) {
		struct media_entity *sink;
		int flags = 0;

		sink = link->sink->entity;

		if (sink == dev->decoder)
			flags = MEDIA_LNK_FL_ENABLED;

		ret = media_entity_setup_link(link, flags);
		if (ret) {
			pr_err("Couldn't change link %s->%s to %s. Error %d\n",
			       source->name, sink->name,
			       flags ? "enabled" : "disabled",
			       ret);
			return ret;
		}
	}
#endif
	return 0;
}

/* ------------------------------------------------------------------ */

static int buffer_activate(struct saa7134_dev *dev,
@@ -924,6 +981,9 @@ static int queue_setup(struct vb2_queue *q,
	*nplanes = 1;
	sizes[0] = size;
	alloc_ctxs[0] = dev->alloc_ctx;

	saa7134_enable_analog_tuner(dev);

	return 0;
}

+13 −0
Original line number Diff line number Diff line
@@ -671,6 +671,19 @@ struct saa7134_dev {
	/* I2C keyboard data */
	struct IR_i2c_init_data    init_data;

#ifdef CONFIG_MEDIA_CONTROLLER
	struct media_device *media_dev;

	struct media_entity input_ent[SAA7134_INPUT_MAX + 1];
	struct media_pad input_pad[SAA7134_INPUT_MAX + 1];

	struct media_entity demod;
	struct media_pad demod_pad[DEMOD_NUM_PADS];

	struct media_pad video_pad, vbi_pad;
	struct media_entity *decoder;
#endif

#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
	/* SAA7134_MPEG_DVB only */
	struct vb2_dvb_frontends frontends;