mirror of https://gitee.com/openkylin/linux.git
[media] au0828: reset streaming when a new frequency is set
As reported by Trevor, doing several opening/streaming/closing operations to the demux causes it to fail. I was able to simulate this bug too. I also noticed that, sometimes, changing channels with au0828, the same thing happens. Most of the issues seem to be due to some hardware bug, that causes the device to not fill all the URBs allocated. When the bug happens, the only known fix is to either replug the device, or to send an USB reset to it. There's also a hack a the au0828 driver that starts a thread that tries to reset the device when a package doesn't start with a sync. One of the culpits for this bad hardware behavior seem to be caused by the lack of stopping and restarting the stream every time a new channel is set. This patch warrants that the stream will be properly reset every time the set_frontend callback is called, partially solving the problem. A complete fix, however, would also need to check the PM conditions for the tuner and demux. Reported-by: Trevor Graffa <tlgraffa@gmail.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
c35fbd03ae
commit
f6fef86341
|
@ -256,8 +256,6 @@ static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
|
|||
au0828_write(dev, 0x60b, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dvb_demux *demux = feed->demux;
|
||||
|
@ -300,6 +298,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
|
|||
dprintk(1, "%s()\n", __func__);
|
||||
|
||||
if (dvb) {
|
||||
cancel_work_sync(&dev->restart_streaming);
|
||||
|
||||
mutex_lock(&dvb->lock);
|
||||
dvb->stop_count++;
|
||||
dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
|
||||
|
@ -342,6 +342,41 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
|
|||
mutex_unlock(&dvb->lock);
|
||||
}
|
||||
|
||||
static int au0828_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct au0828_dev *dev = fe->dvb->priv;
|
||||
struct au0828_dvb *dvb = &dev->dvb;
|
||||
int ret, was_streaming;
|
||||
|
||||
mutex_lock(&dvb->lock);
|
||||
was_streaming = dev->urb_streaming;
|
||||
if (was_streaming) {
|
||||
au0828_stop_transport(dev, 1);
|
||||
|
||||
/*
|
||||
* We can't hold a mutex here, as the restart_streaming
|
||||
* kthread may also hold it.
|
||||
*/
|
||||
mutex_unlock(&dvb->lock);
|
||||
cancel_work_sync(&dev->restart_streaming);
|
||||
mutex_lock(&dvb->lock);
|
||||
|
||||
stop_urb_transfer(dev);
|
||||
}
|
||||
mutex_unlock(&dvb->lock);
|
||||
|
||||
ret = dvb->set_frontend(fe);
|
||||
|
||||
if (was_streaming) {
|
||||
mutex_lock(&dvb->lock);
|
||||
au0828_start_transport(dev);
|
||||
start_urb_transfer(dev);
|
||||
mutex_unlock(&dvb->lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvb_register(struct au0828_dev *dev)
|
||||
{
|
||||
struct au0828_dvb *dvb = &dev->dvb;
|
||||
|
@ -386,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev)
|
|||
goto fail_frontend;
|
||||
}
|
||||
|
||||
/* Hook dvb frontend */
|
||||
dvb->set_frontend = dvb->frontend->ops.set_frontend;
|
||||
dvb->frontend->ops.set_frontend = au0828_set_frontend;
|
||||
|
||||
/* register demux stuff */
|
||||
dvb->demux.dmx.capabilities =
|
||||
DMX_TS_FILTERING | DMX_SECTION_FILTERING |
|
||||
|
|
|
@ -104,6 +104,8 @@ struct au0828_dvb {
|
|||
int feeding;
|
||||
int start_count;
|
||||
int stop_count;
|
||||
|
||||
int (*set_frontend)(struct dvb_frontend *fe);
|
||||
};
|
||||
|
||||
enum au0828_stream_state {
|
||||
|
|
Loading…
Reference in New Issue