|
@@ -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);
|
|
|
}
|