Skip to content

Commit

Permalink
[media] saa7134: add media controller support
Browse files Browse the repository at this point in the history
Register saa7134 at the media controller core and provide
support for both analog TV and DVB.

Signed-off-by: Mauro Carvalho Chehab <[email protected]>
  • Loading branch information
mchehab committed Feb 10, 2016
1 parent 7047f29 commit ac90aa0
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 5 deletions.
191 changes: 187 additions & 4 deletions drivers/media/pci/saa7134/saa7134-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -1102,13 +1260,34 @@ 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++;

if (saa7134_dmasound_init && !dev->dmasound.priv_data)
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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down
9 changes: 8 additions & 1 deletion drivers/media/pci/saa7134/saa7134-dvb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions drivers/media/pci/saa7134/saa7134-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down
13 changes: 13 additions & 0 deletions drivers/media/pci/saa7134/saa7134.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit ac90aa0

Please sign in to comment.