}
}
+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)
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);
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;
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)
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++;
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:
fail1:
v4l2_device_unregister(&dev->v4l2_dev);
fail0:
+#ifdef CONFIG_MEDIA_CONTROLLER
+ kfree(dev->media_dev);
+#endif
kfree(dev);
return err;
}
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);
}
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,
*nplanes = 1;
sizes[0] = size;
alloc_ctxs[0] = dev->alloc_ctx;
+
+ saa7134_enable_analog_tuner(dev);
+
return 0;
}