aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDevin Heitmueller <dheitmueller@kernellabs.com>2012-08-06 21:46:53 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-08-09 19:31:30 -0400
commit43f2cccfc81c0af719a425ea816ce8003bb09748 (patch)
tree6d86a5eb76e6117ae98da89f1de9f8a773906e30 /drivers
parentb0c4878ebe3ad9706ea2e452331550fd6d171977 (diff)
[media] au8522: properly recover from the au8522 delivering misaligned TS streams
There is an apparent bug in the au8522 TS clocking which can result in it delivering a TS payload to the au0828 that is shifted by some number of bits. For example, the device will announce a packet containing "FA 38 FF F8" which if you shift left one bit is "1F 47 1F FF F0..." This presents itself as no TS stream being delivered from the kernel to userland, since the kernel demux will drop every packet. In the event that this condition occurs, restart the DVB stream. Also, this patch includes a couple of lines of cleanup to not change the FIFO configuration while the FIFO is running (which can screw up the state machine), and dequeue the buffers before turning off the FIFO. This puts the logic in sync with the Windows driver. Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c54
-rw-r--r--drivers/media/video/au0828/au0828.h1
2 files changed, 49 insertions, 6 deletions
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 39ece8e24985..b328f6550d0b 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -101,11 +101,14 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = {
101 .gate = TDA18271_GATE_DIGITAL, 101 .gate = TDA18271_GATE_DIGITAL,
102}; 102};
103 103
104static void au0828_restart_dvb_streaming(struct work_struct *work);
105
104/*-------------------------------------------------------------------*/ 106/*-------------------------------------------------------------------*/
105static void urb_completion(struct urb *purb) 107static void urb_completion(struct urb *purb)
106{ 108{
107 struct au0828_dev *dev = purb->context; 109 struct au0828_dev *dev = purb->context;
108 int ptype = usb_pipetype(purb->pipe); 110 int ptype = usb_pipetype(purb->pipe);
111 unsigned char *ptr;
109 112
110 dprintk(2, "%s()\n", __func__); 113 dprintk(2, "%s()\n", __func__);
111 114
@@ -121,6 +124,16 @@ static void urb_completion(struct urb *purb)
121 return; 124 return;
122 } 125 }
123 126
127 /* See if the stream is corrupted (to work around a hardware
128 bug where the stream gets misaligned */
129 ptr = purb->transfer_buffer;
130 if (purb->actual_length > 0 && ptr[0] != 0x47) {
131 dprintk(1, "Need to restart streaming %02x len=%d!\n",
132 ptr[0], purb->actual_length);
133 schedule_work(&dev->restart_streaming);
134 return;
135 }
136
124 /* Feed the transport payload into the kernel demux */ 137 /* Feed the transport payload into the kernel demux */
125 dvb_dmx_swfilter_packets(&dev->dvb.demux, 138 dvb_dmx_swfilter_packets(&dev->dvb.demux,
126 purb->transfer_buffer, purb->actual_length / 188); 139 purb->transfer_buffer, purb->actual_length / 188);
@@ -138,14 +151,13 @@ static int stop_urb_transfer(struct au0828_dev *dev)
138 151
139 dprintk(2, "%s()\n", __func__); 152 dprintk(2, "%s()\n", __func__);
140 153
154 dev->urb_streaming = 0;
141 for (i = 0; i < URB_COUNT; i++) { 155 for (i = 0; i < URB_COUNT; i++) {
142 usb_kill_urb(dev->urbs[i]); 156 usb_kill_urb(dev->urbs[i]);
143 kfree(dev->urbs[i]->transfer_buffer); 157 kfree(dev->urbs[i]->transfer_buffer);
144 usb_free_urb(dev->urbs[i]); 158 usb_free_urb(dev->urbs[i]);
145 } 159 }
146 160
147 dev->urb_streaming = 0;
148
149 return 0; 161 return 0;
150} 162}
151 163
@@ -246,11 +258,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
246 mutex_lock(&dvb->lock); 258 mutex_lock(&dvb->lock);
247 if (--dvb->feeding == 0) { 259 if (--dvb->feeding == 0) {
248 /* Stop transport */ 260 /* Stop transport */
249 au0828_write(dev, 0x608, 0x00);
250 au0828_write(dev, 0x609, 0x00);
251 au0828_write(dev, 0x60a, 0x00);
252 au0828_write(dev, 0x60b, 0x00);
253 ret = stop_urb_transfer(dev); 261 ret = stop_urb_transfer(dev);
262 au0828_write(dev, 0x60b, 0x00);
254 } 263 }
255 mutex_unlock(&dvb->lock); 264 mutex_unlock(&dvb->lock);
256 } 265 }
@@ -258,6 +267,37 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
258 return ret; 267 return ret;
259} 268}
260 269
270static void au0828_restart_dvb_streaming(struct work_struct *work)
271{
272 struct au0828_dev *dev = container_of(work, struct au0828_dev,
273 restart_streaming);
274 struct au0828_dvb *dvb = &dev->dvb;
275 int ret;
276
277 if (dev->urb_streaming == 0)
278 return;
279
280 dprintk(1, "Restarting streaming...!\n");
281
282 mutex_lock(&dvb->lock);
283
284 /* Stop transport */
285 ret = stop_urb_transfer(dev);
286 au0828_write(dev, 0x608, 0x00);
287 au0828_write(dev, 0x609, 0x00);
288 au0828_write(dev, 0x60a, 0x00);
289 au0828_write(dev, 0x60b, 0x00);
290
291 /* Start transport */
292 au0828_write(dev, 0x608, 0x90);
293 au0828_write(dev, 0x609, 0x72);
294 au0828_write(dev, 0x60a, 0x71);
295 au0828_write(dev, 0x60b, 0x01);
296 ret = start_urb_transfer(dev);
297
298 mutex_unlock(&dvb->lock);
299}
300
261static int dvb_register(struct au0828_dev *dev) 301static int dvb_register(struct au0828_dev *dev)
262{ 302{
263 struct au0828_dvb *dvb = &dev->dvb; 303 struct au0828_dvb *dvb = &dev->dvb;
@@ -265,6 +305,8 @@ static int dvb_register(struct au0828_dev *dev)
265 305
266 dprintk(1, "%s()\n", __func__); 306 dprintk(1, "%s()\n", __func__);
267 307
308 INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
309
268 /* register adapter */ 310 /* register adapter */
269 result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, 311 result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
270 &dev->usbdev->dev, adapter_nr); 312 &dev->usbdev->dev, adapter_nr);
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 9cde35321824..61cd63e2bc63 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -197,6 +197,7 @@ struct au0828_dev {
197 197
198 /* Digital */ 198 /* Digital */
199 struct au0828_dvb dvb; 199 struct au0828_dvb dvb;
200 struct work_struct restart_streaming;
200 201
201 /* Analog */ 202 /* Analog */
202 struct v4l2_device v4l2_dev; 203 struct v4l2_device v4l2_dev;