aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorAidan Thornton <makosoft@googlemail.com>2008-04-13 14:09:36 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:09:39 -0400
commit3b5fa928a6b2971ec65571745defc5d9758b4bc1 (patch)
tree80854c270cec4154a9b86e4ed02b4970897104b5 /drivers/media
parentb4916f8ca1da71bb97fb6dcf1e8da3f9c64cf80e (diff)
V4L/DVB (7565): em28xx: fix buffer underrun handling
This patch fixes three related issues and a fourth trivial one: - Use buffers even if no-one's currently waiting for them (fixes underrun issues); - Don't return incomplete/mangled frames at the start of streaming and in the case of buffer underruns; - Fix an issue which could cause the driver to write to a buffer that's been freed after videobuf_queue_cancel is called (exposed by the previous two fixes - for some reason, ignoring buffers that weren't being waited on worked around the issue); - Fix a bug which could cause only one field to be filled in the first buffer (or first few buffers) after streaming is started. Signed-off-by: Aidan Thornton <makosoft@googlemail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c84
-rw-r--r--drivers/media/video/em28xx/em28xx.h3
2 files changed, 42 insertions, 45 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index d5728c2cd360..f8bbf397d3a7 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -266,7 +266,7 @@ static inline void print_err_status(struct em28xx *dev,
266/* 266/*
267 * video-buf generic routine to get the next available buffer 267 * video-buf generic routine to get the next available buffer
268 */ 268 */
269static inline int get_next_buf(struct em28xx_dmaqueue *dma_q, 269static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
270 struct em28xx_buffer **buf) 270 struct em28xx_buffer **buf)
271{ 271{
272 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); 272 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
@@ -275,38 +275,20 @@ static inline int get_next_buf(struct em28xx_dmaqueue *dma_q,
275 if (list_empty(&dma_q->active)) { 275 if (list_empty(&dma_q->active)) {
276 em28xx_isocdbg("No active queue to serve\n"); 276 em28xx_isocdbg("No active queue to serve\n");
277 dev->isoc_ctl.buf = NULL; 277 dev->isoc_ctl.buf = NULL;
278 return 0;
279 }
280
281 /* Check if the last buffer were fully filled */
282 *buf = dev->isoc_ctl.buf;
283
284 /* Nobody is waiting on this buffer - discards */
285 if (*buf && !waitqueue_active(&(*buf)->vb.done)) {
286 dev->isoc_ctl.buf = NULL;
287 *buf = NULL; 278 *buf = NULL;
279 return;
288 } 280 }
289 281
290 /* Returns the last buffer, to be filled with remaining data */
291 if (*buf)
292 return 1;
293
294 /* Get the next buffer */ 282 /* Get the next buffer */
295 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); 283 *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
296 284
297 /* Nobody is waiting on the next buffer. returns */
298 if (!*buf || !waitqueue_active(&(*buf)->vb.done)) {
299 em28xx_isocdbg("No active queue to serve\n");
300 return 0;
301 }
302
303 /* Cleans up buffer - Usefull for testing for frame/URB loss */ 285 /* Cleans up buffer - Usefull for testing for frame/URB loss */
304 outp = videobuf_to_vmalloc(&(*buf)->vb); 286 outp = videobuf_to_vmalloc(&(*buf)->vb);
305 memset(outp, 0, (*buf)->vb.size); 287 memset(outp, 0, (*buf)->vb.size);
306 288
307 dev->isoc_ctl.buf = *buf; 289 dev->isoc_ctl.buf = *buf;
308 290
309 return 1; 291 return;
310} 292}
311 293
312/* 294/*
@@ -317,7 +299,7 @@ static inline int em28xx_isoc_copy(struct urb *urb)
317 struct em28xx_buffer *buf; 299 struct em28xx_buffer *buf;
318 struct em28xx_dmaqueue *dma_q = urb->context; 300 struct em28xx_dmaqueue *dma_q = urb->context;
319 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); 301 struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
320 unsigned char *outp; 302 unsigned char *outp = NULL;
321 int i, len = 0, rc = 1; 303 int i, len = 0, rc = 1;
322 unsigned char *p; 304 unsigned char *p;
323 305
@@ -333,11 +315,9 @@ static inline int em28xx_isoc_copy(struct urb *urb)
333 return 0; 315 return 0;
334 } 316 }
335 317
336 rc = get_next_buf(dma_q, &buf); 318 buf = dev->isoc_ctl.buf;
337 if (rc <= 0) 319 if (buf != NULL)
338 return rc; 320 outp = videobuf_to_vmalloc(&buf->vb);
339
340 outp = videobuf_to_vmalloc(&buf->vb);
341 321
342 for (i = 0; i < urb->number_of_packets; i++) { 322 for (i = 0; i < urb->number_of_packets; i++) {
343 int status = urb->iso_frame_desc[i].status; 323 int status = urb->iso_frame_desc[i].status;
@@ -374,24 +354,27 @@ static inline int em28xx_isoc_copy(struct urb *urb)
374 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], 354 em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
375 len, (p[2] & 1)? "odd" : "even"); 355 len, (p[2] & 1)? "odd" : "even");
376 356
377 if (p[2] & 1) 357 if (!(p[2] & 1)) {
378 buf->top_field = 0; 358 if (buf != NULL)
379 else 359 buffer_filled(dev, dma_q, buf);
380 buf->top_field = 1; 360 get_next_buf(dma_q, &buf);
381 361 if (buf == NULL)
382// if (dev->isoc_ctl.last_field && !buf->top_field) { 362 outp = NULL;
383 if (dev->isoc_ctl.last_field != buf->top_field) { 363 else
384 buffer_filled(dev, dma_q, buf); 364 outp = videobuf_to_vmalloc(&buf->vb);
385 rc = get_next_buf(dma_q, &buf); 365 }
386 if (rc <= 0) 366
387 return rc; 367 if (buf != NULL) {
388 outp = videobuf_to_vmalloc(&buf->vb); 368 if (p[2] & 1)
369 buf->top_field = 0;
370 else
371 buf->top_field = 1;
389 } 372 }
390 dev->isoc_ctl.last_field = buf->top_field;
391 373
392 dma_q->pos = 0; 374 dma_q->pos = 0;
393 } 375 }
394 em28xx_copy_video(dev, dma_q, buf, p, outp, len); 376 if (buf != NULL)
377 em28xx_copy_video(dev, dma_q, buf, p, outp, len);
395 } 378 }
396 return rc; 379 return rc;
397} 380}
@@ -597,12 +580,29 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
597 return 0; 580 return 0;
598} 581}
599 582
583/* This is called *without* dev->slock held; please keep it that way */
600static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) 584static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
601{ 585{
586 struct em28xx_fh *fh = vq->priv_data;
587 struct em28xx *dev = fh->dev;
588 unsigned long flags = 0;
602 if (in_interrupt()) 589 if (in_interrupt())
603 BUG(); 590 BUG();
604 591
605 videobuf_waiton(&buf->vb, 0, 0); 592 /* We used to wait for the buffer to finish here, but this didn't work
593 because, as we were keeping the state as VIDEOBUF_QUEUED,
594 videobuf_queue_cancel marked it as finished for us.
595 (Also, it could wedge forever if the hardware was misconfigured.)
596
597 This should be safe; by the time we get here, the buffer isn't
598 queued anymore. If we ever start marking the buffers as
599 VIDEOBUF_ACTIVE, it won't be, though.
600 */
601 spin_lock_irqsave(&dev->slock, flags);
602 if (dev->isoc_ctl.buf == buf)
603 dev->isoc_ctl.buf = NULL;
604 spin_unlock_irqrestore(&dev->slock, flags);
605
606 videobuf_vmalloc_free(&buf->vb); 606 videobuf_vmalloc_free(&buf->vb);
607 buf->vb.state = VIDEOBUF_NEEDS_INIT; 607 buf->vb.state = VIDEOBUF_NEEDS_INIT;
608} 608}
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 993c1ed05cc3..6d62357a038f 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -114,9 +114,6 @@ struct em28xx_usb_isoc_ctl {
114 /* Stores already requested buffers */ 114 /* Stores already requested buffers */
115 struct em28xx_buffer *buf; 115 struct em28xx_buffer *buf;
116 116
117 /* Store last filled frame */
118 int last_field;
119
120 /* Stores the number of received fields */ 117 /* Stores the number of received fields */
121 int nfields; 118 int nfields;
122}; 119};