|
@@ -796,64 +796,6 @@ int au0828_v4l2_device_register(struct usb_interface *interface,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int au0828_enable_analog_tuner(struct au0828_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;
|
|
|
|
- } else
|
|
|
|
- au0828_isocdbg(
|
|
|
|
- "link %s->%s was %s\n",
|
|
|
|
- source->name, sink->name,
|
|
|
|
- flags ? "ENABLED" : "disabled");
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int queue_setup(struct vb2_queue *vq,
|
|
static int queue_setup(struct vb2_queue *vq,
|
|
unsigned int *nbuffers, unsigned int *nplanes,
|
|
unsigned int *nbuffers, unsigned int *nplanes,
|
|
unsigned int sizes[], void *alloc_ctxs[])
|
|
unsigned int sizes[], void *alloc_ctxs[])
|
|
@@ -865,9 +807,6 @@ static int queue_setup(struct vb2_queue *vq,
|
|
return sizes[0] < size ? -EINVAL : 0;
|
|
return sizes[0] < size ? -EINVAL : 0;
|
|
*nplanes = 1;
|
|
*nplanes = 1;
|
|
sizes[0] = size;
|
|
sizes[0] = size;
|
|
-
|
|
|
|
- au0828_enable_analog_tuner(dev);
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1235,8 +1174,39 @@ static int au0828_v4l2_close(struct file *filp)
|
|
goto end;
|
|
goto end;
|
|
|
|
|
|
if (dev->users == 1) {
|
|
if (dev->users == 1) {
|
|
- /* Save some power by putting tuner to sleep */
|
|
|
|
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Avoid putting tuner in sleep if DVB or ALSA are
|
|
|
|
+ * streaming.
|
|
|
|
+ *
|
|
|
|
+ * On most USB devices like au0828 the tuner can
|
|
|
|
+ * be safely put in sleep stare here if ALSA isn't
|
|
|
|
+ * streaming. Exceptions are some very old USB tuner
|
|
|
|
+ * models such as em28xx-based WinTV USB2 which have
|
|
|
|
+ * a separate audio output jack. The devices that have
|
|
|
|
+ * a separate audio output jack have analog tuners,
|
|
|
|
+ * like Philips FM1236. Those devices are always on,
|
|
|
|
+ * so the s_power callback are silently ignored.
|
|
|
|
+ * So, the current logic here does the following:
|
|
|
|
+ * Disable (put tuner to sleep) when
|
|
|
|
+ * - ALSA and DVB aren't not streaming;
|
|
|
|
+ * - the last V4L2 file handler is closed.
|
|
|
|
+ *
|
|
|
|
+ * FIXME:
|
|
|
|
+ *
|
|
|
|
+ * Additionally, this logic could be improved to
|
|
|
|
+ * disable the media source if the above conditions
|
|
|
|
+ * are met and if the device:
|
|
|
|
+ * - doesn't have a separate audio out plug (or
|
|
|
|
+ * - doesn't use a silicon tuner like xc2028/3028/4000/5000).
|
|
|
|
+ *
|
|
|
|
+ * Once this additional logic is in place, a callback
|
|
|
|
+ * is needed to enable the media source and power on
|
|
|
|
+ * the tuner, for radio to work.
|
|
|
|
+ */
|
|
|
|
+ ret = v4l_enable_media_source(vdev);
|
|
|
|
+ if (ret == 0)
|
|
|
|
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core,
|
|
|
|
+ s_power, 0);
|
|
dev->std_set_in_tuner_core = 0;
|
|
dev->std_set_in_tuner_core = 0;
|
|
|
|
|
|
/* When close the device, set the usb intf0 into alt0 to free
|
|
/* When close the device, set the usb intf0 into alt0 to free
|
|
@@ -1636,10 +1606,16 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
|
|
static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
|
|
static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
|
|
{
|
|
{
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
+ struct video_device *vfd = video_devdata(file);
|
|
|
|
+ int ret;
|
|
|
|
|
|
if (t->index != 0)
|
|
if (t->index != 0)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
+ ret = v4l_enable_media_source(vfd);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
|
|
dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|