summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-10-26 10:18:53 -0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-26 10:18:53 -0200
commit51a176c3be0ea97b23912d5854262a82b0ac0a85 (patch)
tree776dec2ce7713b9ed750130f3efd22918466cc3d
parente6492dcefb2814303a51c9ba5459c189df6c5130 (diff)
downloadmediapointer-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.c71
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;
}