diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-13 15:08:55 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 14:09:39 -0300 |
commit | dbecb44c11d9517d604240b53581951ac4e3b5e6 (patch) | |
tree | 3bf65736b1ae105e16227110452aa72d2dc21847 /drivers | |
parent | 0cf4daee31d88086cf3508d1d8d1f4e451c27906 (diff) |
V4L/DVB (7563): em28xx: Add missing checks
There are some cases where nobody is waiting for a buffer. Due to the
lack of check, if you try to abort the userspace app, machine were
hanging, since IRQ were trying to use a buffer that were disallocated.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index db3bbacb3a7..10928dccaec 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -270,19 +270,39 @@ static inline int get_next_buf(struct em28xx_dmaqueue *dma_q, struct em28xx_buffer **buf) { struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + char *outp; - /* If the previous buffer were not filled yet, continue */ + if (list_empty(&dma_q->active)) { + em28xx_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.buf = NULL; + return 0; + } + + /* Check if the last buffer were fully filled */ *buf = dev->isoc_ctl.buf; + + /* Nobody is waiting on this buffer - discards */ + if (*buf && !waitqueue_active(&(*buf)->vb.done)) { + dev->isoc_ctl.buf = NULL; + *buf = NULL; + } + + /* Returns the last buffer, to be filled with remaining data */ if (*buf) return 1; - if (list_empty(&dma_q->active)) { + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); + + /* Nobody is waiting on the next buffer. returns */ + if (!*buf || !waitqueue_active(&(*buf)->vb.done)) { em28xx_isocdbg("No active queue to serve\n"); return 0; } - *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - + /* Cleans up buffer - Usefull for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); dev->isoc_ctl.buf = *buf; @@ -387,12 +407,11 @@ static void em28xx_irq_callback(struct urb *urb) struct em28xx_dmaqueue *dma_q = urb->context; struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); int rc, i; - unsigned long flags; - - spin_lock_irqsave(&dev->slock, flags); /* Copy data from URB */ + spin_lock(&dev->slock); rc = em28xx_isoc_copy(urb); + spin_unlock(&dev->slock); /* Reset urb buffers */ for (i = 0; i < urb->number_of_packets; i++) { @@ -406,8 +425,6 @@ static void em28xx_irq_callback(struct urb *urb) em28xx_err("urb resubmit failed (error=%i)\n", urb->status); } - - spin_unlock_irqrestore(&dev->slock, flags); } /* |