forked from Minki/linux
[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: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
parent
7047f2982a
commit
ac90aa02d5
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user