From dbecb44c11d9517d604240b53581951ac4e3b5e6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Apr 2008 15:08:55 -0300 Subject: [PATCH] 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 --- drivers/media/video/em28xx/em28xx-video.c | 35 +++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index db3bbacb3a77..10928dccaecc 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); } /* -- 2.20.1