diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-26 10:18:53 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-26 10:18:53 -0200 |
commit | 51a176c3be0ea97b23912d5854262a82b0ac0a85 (patch) | |
tree | 776dec2ce7713b9ed750130f3efd22918466cc3d | |
parent | e6492dcefb2814303a51c9ba5459c189df6c5130 (diff) | |
download | mediapointer-dvb-s2-51a176c3be0ea97b23912d5854262a82b0ac0a85.tar.gz mediapointer-dvb-s2-51a176c3be0ea97b23912d5854262a82b0ac0a85.tar.bz2 |
tm6000: avoid kernel panic while retrieving the filling buffer
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Instead of storing next buf on a temp var, saved over URB
processing, restore it using get_next_buf.
Priority: normal
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | linux/drivers/staging/tm6000/tm6000-video.c | 71 |
1 files changed, 46 insertions, 25 deletions
diff --git a/linux/drivers/staging/tm6000/tm6000-video.c b/linux/drivers/staging/tm6000/tm6000-video.c index 9b968a4b1..3859e5d42 100644 --- a/linux/drivers/staging/tm6000/tm6000-video.c +++ b/linux/drivers/staging/tm6000/tm6000-video.c @@ -136,20 +136,32 @@ static LIST_HEAD(tm6000_corelist); /* * video-buf generic routine to get the next available buffer */ -static inline int get_next_buf(struct tm6000_dmaqueue *dma_q, +static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, struct tm6000_buffer **buf) { struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); +#if 1 + char *outp; +#endif if (list_empty(&dma_q->active)) { dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n"); - return 0; + return; } *buf = list_entry(dma_q->active.next, struct tm6000_buffer, vb.queue); - return 1; +#if 1 + if (!buf) + return; + + /* Cleans up buffer - Usefull for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); +#endif + + return; } /* @@ -266,7 +278,9 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, buffer_filled (dev, dma_q, *buf); dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - rc=get_next_buf (dma_q, buf); + get_next_buf (dma_q, buf); + if (!*buf) + return rc; } } @@ -415,11 +429,9 @@ static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len, /* Announces that a new buffer were filled */ buffer_filled (dev, dma_q, *buf); dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - rc=get_next_buf (dma_q, buf); - if (rc<=0) { - *buf=NULL; + get_next_buf (dma_q, buf); + if (!*buf) break; - } } } @@ -530,27 +542,21 @@ static void tm6000_irq_callback(struct urb *urb, struct pt_regs *regs) static void tm6000_irq_callback(struct urb *urb) #endif { - struct tm6000_buffer *buf; + struct tm6000_buffer *buf = NULL; struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int rc; unsigned long flags; - spin_lock_irqsave(&dev->slock, flags); - - buf = dev->isoc_ctl.buf; + if (!dev) + return; - if (!buf) { - rc = get_next_buf(dma_q, &buf); - if (rc <= 0) - goto ret; - } + spin_lock_irqsave(&dev->slock, flags); - /* Copy data from URB */ - rc = tm6000_isoc_copy(urb, &buf); + get_next_buf(dma_q, &buf); + if (buf) + tm6000_isoc_copy(urb, &buf); + spin_unlock_irqrestore(&dev->slock, flags); - dev->isoc_ctl.buf = buf; -ret: #if 0 /* Reset urb buffers */ for (i = 0; i < urb->number_of_packets; i++) { @@ -563,8 +569,6 @@ ret: if (urb->status) tm6000_err("urb resubmit failed (error=%i)\n", urb->status); - - spin_unlock_irqrestore(&dev->slock, flags); } /* @@ -749,10 +753,27 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) { + struct tm6000_fh *fh = vq->priv_data; + struct tm6000_core *dev = fh->dev; + unsigned long flags; + if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.buf == buf) + dev->isoc_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + videobuf_vmalloc_free(&buf->vb); buf->vb.state = VIDEOBUF_NEEDS_INIT; } |