diff --git a/[refs] b/[refs] index a7033322d9c0..f8edc28b3136 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b0c4878ebe3ad9706ea2e452331550fd6d171977 +refs/heads/master: 43f2cccfc81c0af719a425ea816ce8003bb09748 diff --git a/trunk/drivers/media/video/au0828/au0828-dvb.c b/trunk/drivers/media/video/au0828/au0828-dvb.c index 39ece8e24985..b328f6550d0b 100644 --- a/trunk/drivers/media/video/au0828/au0828-dvb.c +++ b/trunk/drivers/media/video/au0828/au0828-dvb.c @@ -101,11 +101,14 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = { .gate = TDA18271_GATE_DIGITAL, }; +static void au0828_restart_dvb_streaming(struct work_struct *work); + /*-------------------------------------------------------------------*/ static void urb_completion(struct urb *purb) { struct au0828_dev *dev = purb->context; int ptype = usb_pipetype(purb->pipe); + unsigned char *ptr; dprintk(2, "%s()\n", __func__); @@ -121,6 +124,16 @@ static void urb_completion(struct urb *purb) return; } + /* See if the stream is corrupted (to work around a hardware + bug where the stream gets misaligned */ + ptr = purb->transfer_buffer; + if (purb->actual_length > 0 && ptr[0] != 0x47) { + dprintk(1, "Need to restart streaming %02x len=%d!\n", + ptr[0], purb->actual_length); + schedule_work(&dev->restart_streaming); + return; + } + /* Feed the transport payload into the kernel demux */ dvb_dmx_swfilter_packets(&dev->dvb.demux, purb->transfer_buffer, purb->actual_length / 188); @@ -138,14 +151,13 @@ static int stop_urb_transfer(struct au0828_dev *dev) dprintk(2, "%s()\n", __func__); + dev->urb_streaming = 0; for (i = 0; i < URB_COUNT; i++) { usb_kill_urb(dev->urbs[i]); kfree(dev->urbs[i]->transfer_buffer); usb_free_urb(dev->urbs[i]); } - dev->urb_streaming = 0; - return 0; } @@ -246,11 +258,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) mutex_lock(&dvb->lock); if (--dvb->feeding == 0) { /* Stop transport */ - au0828_write(dev, 0x608, 0x00); - au0828_write(dev, 0x609, 0x00); - au0828_write(dev, 0x60a, 0x00); - au0828_write(dev, 0x60b, 0x00); ret = stop_urb_transfer(dev); + au0828_write(dev, 0x60b, 0x00); } mutex_unlock(&dvb->lock); } @@ -258,6 +267,37 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) return ret; } +static void au0828_restart_dvb_streaming(struct work_struct *work) +{ + struct au0828_dev *dev = container_of(work, struct au0828_dev, + restart_streaming); + struct au0828_dvb *dvb = &dev->dvb; + int ret; + + if (dev->urb_streaming == 0) + return; + + dprintk(1, "Restarting streaming...!\n"); + + mutex_lock(&dvb->lock); + + /* Stop transport */ + ret = stop_urb_transfer(dev); + au0828_write(dev, 0x608, 0x00); + au0828_write(dev, 0x609, 0x00); + au0828_write(dev, 0x60a, 0x00); + au0828_write(dev, 0x60b, 0x00); + + /* Start transport */ + au0828_write(dev, 0x608, 0x90); + au0828_write(dev, 0x609, 0x72); + au0828_write(dev, 0x60a, 0x71); + au0828_write(dev, 0x60b, 0x01); + ret = start_urb_transfer(dev); + + mutex_unlock(&dvb->lock); +} + static int dvb_register(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; @@ -265,6 +305,8 @@ static int dvb_register(struct au0828_dev *dev) dprintk(1, "%s()\n", __func__); + INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); + /* register adapter */ result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, &dev->usbdev->dev, adapter_nr); diff --git a/trunk/drivers/media/video/au0828/au0828.h b/trunk/drivers/media/video/au0828/au0828.h index 9cde35321824..61cd63e2bc63 100644 --- a/trunk/drivers/media/video/au0828/au0828.h +++ b/trunk/drivers/media/video/au0828/au0828.h @@ -197,6 +197,7 @@ struct au0828_dev { /* Digital */ struct au0828_dvb dvb; + struct work_struct restart_streaming; /* Analog */ struct v4l2_device v4l2_dev;