aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-09 05:17:55 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-05-25 16:50:02 -0400
commitf6fef8634163cc86f9aa193db360ffce26821bf3 (patch)
tree4eadc8479fc0bba8813b6ad9a504dc2bc3fe0c18
parentc35fbd03ae22ca7d36622f63d0e58dadc77dfc44 (diff)
[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>
-rwxr-xr-xdrivers/media/usb/au0828/au0828-dvb.c43
-rw-r--r--drivers/media/usb/au0828/au0828.h2
2 files changed, 43 insertions, 2 deletions
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index ab5f93643021..d8b5d9480279 100755
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -256,8 +256,6 @@ static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
256 au0828_write(dev, 0x60b, 0x00); 256 au0828_write(dev, 0x60b, 0x00);
257} 257}
258 258
259
260
261static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) 259static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
262{ 260{
263 struct dvb_demux *demux = feed->demux; 261 struct dvb_demux *demux = feed->demux;
@@ -300,6 +298,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
300 dprintk(1, "%s()\n", __func__); 298 dprintk(1, "%s()\n", __func__);
301 299
302 if (dvb) { 300 if (dvb) {
301 cancel_work_sync(&dev->restart_streaming);
302
303 mutex_lock(&dvb->lock); 303 mutex_lock(&dvb->lock);
304 dvb->stop_count++; 304 dvb->stop_count++;
305 dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, 305 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)
342 mutex_unlock(&dvb->lock); 342 mutex_unlock(&dvb->lock);
343} 343}
344 344
345static int au0828_set_frontend(struct dvb_frontend *fe)
346{
347 struct au0828_dev *dev = fe->dvb->priv;
348 struct au0828_dvb *dvb = &dev->dvb;
349 int ret, was_streaming;
350
351 mutex_lock(&dvb->lock);
352 was_streaming = dev->urb_streaming;
353 if (was_streaming) {
354 au0828_stop_transport(dev, 1);
355
356 /*
357 * We can't hold a mutex here, as the restart_streaming
358 * kthread may also hold it.
359 */
360 mutex_unlock(&dvb->lock);
361 cancel_work_sync(&dev->restart_streaming);
362 mutex_lock(&dvb->lock);
363
364 stop_urb_transfer(dev);
365 }
366 mutex_unlock(&dvb->lock);
367
368 ret = dvb->set_frontend(fe);
369
370 if (was_streaming) {
371 mutex_lock(&dvb->lock);
372 au0828_start_transport(dev);
373 start_urb_transfer(dev);
374 mutex_unlock(&dvb->lock);
375 }
376
377 return ret;
378}
379
345static int dvb_register(struct au0828_dev *dev) 380static int dvb_register(struct au0828_dev *dev)
346{ 381{
347 struct au0828_dvb *dvb = &dev->dvb; 382 struct au0828_dvb *dvb = &dev->dvb;
@@ -386,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev)
386 goto fail_frontend; 421 goto fail_frontend;
387 } 422 }
388 423
424 /* Hook dvb frontend */
425 dvb->set_frontend = dvb->frontend->ops.set_frontend;
426 dvb->frontend->ops.set_frontend = au0828_set_frontend;
427
389 /* register demux stuff */ 428 /* register demux stuff */
390 dvb->demux.dmx.capabilities = 429 dvb->demux.dmx.capabilities =
391 DMX_TS_FILTERING | DMX_SECTION_FILTERING | 430 DMX_TS_FILTERING | DMX_SECTION_FILTERING |
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 5439772c1551..7112b9d956fa 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -104,6 +104,8 @@ struct au0828_dvb {
104 int feeding; 104 int feeding;
105 int start_count; 105 int start_count;
106 int stop_count; 106 int stop_count;
107
108 int (*set_frontend)(struct dvb_frontend *fe);
107}; 109};
108 110
109enum au0828_stream_state { 111enum au0828_stream_state {