I'm trying to setup vdr with debian unstable on arm (little endian) (NSLU2) with a WideView WT-220U PenType Receiver (USB). At first the system would freeze when the device got activated by vdr or scan. This is because arm has some problems with cache coherence. The appended patch fixes that.

The next thing is that although video output is working, there's still some trouble with the epg.data not properly handled. epg.data file looks like this:
C T-8468-12289-2 arte
C T-8468-12289-3 Phoenix

The same setup on x86 works fine, I double checked that. So I started debugging with gdb and had a look at the raw epg data that is copied from usb, comparing the output from arm and x86 looks quite similar so I guess to that point things are ok. In case you wonder I compared the output of unsigned char buf[4096] in void cSectionHandler::Action(void). I tried to narrow things further down with lots of debugging and I think the problem is related to the following code in libsi/si.h

template <class T> class StructureLoop : public Loop {
  //currently you must use a while-loop testing for hasNext()
  //i must be 0 to get the first descriptor (with the first call)
  bool getNext(T &obj, Iterator &it)
        if (!isValid() || it.i >= getLength())
           return false;
        CharArray d=data;
        T ret;
        if (!checkSize(ret.getLength()))
           return false;
        return true;

By putting in some printf statements I found out it.i gets increased some bytes, these bytes are processes and that happens till getLength is reached. Then the chunk has been processed completely. That works fine on x86 but not on arm, I observed it.i increase far beyond getLength after a while. At this point things get pretty low-level and I'm stuck.


Index: linux-source-2.6.23/arch/arm/common/dmabounce.c
--- linux-source-2.6.23.orig/arch/arm/common/dmabounce.c	2007-10-09 22:31:38.000000000 +0200
+++ linux-source-2.6.23/arch/arm/common/dmabounce.c	2008-01-11 18:14:16.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/list.h>
+#include <linux/interrupt.h>
 #include <asm/cacheflush.h>
@@ -45,6 +46,9 @@
 struct safe_buffer {
 	struct list_head node;
+	/* safe buffer info */
+	struct device *dev;
 	/* original request */
 	void		*ptr;
 	size_t		size;
@@ -125,6 +129,7 @@
 		return NULL;
+	buf->dev = device_info->dev;
 	buf->ptr = ptr;
 	buf->size = size;
 	buf->direction = dir;
@@ -179,6 +184,38 @@
 	read_unlock_irqrestore(&device_info->lock, flags);
 	return rb;
+/* The free safe buffer part. dma_free_coherent cannot be called irq disabled.
+ To cope with that, a tasklet (do_free) does the job upon request */
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+static void do_free(unsigned long ignored)
+ spin_lock_irq(&buflock);
+ while (!list_empty(&buffers)) {
+ struct safe_buffer *buf;
+ buf = list_entry(buffers.next,
+                struct safe_buffer,
+                node);
+ list_del(&buf->node);
+ spin_unlock_irq(&buflock);
+     if (buf->pool)
+         dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
+     else
+         dma_free_coherent(buf->dev, buf->size, buf->safe,
+                 buf->safe_dma_addr);
+     kfree(buf);
+ spin_lock_irq(&buflock);
+ }
+ spin_unlock_irq(&buflock);
+static DECLARE_TASKLET(deferred_free, do_free, 0);
 static inline void
 free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *buf)
@@ -193,13 +230,11 @@
 	write_unlock_irqrestore(&device_info->lock, flags);
-	if (buf->pool)
-		dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
-	else
-		dma_free_coherent(device_info->dev, buf->size, buf->safe,
-				    buf->safe_dma_addr);
-	kfree(buf);
+	/* pass the safe buffer to the tasklet */
+	spin_lock_irqsave(&buflock, flags);
+	list_add_tail(&buf->node, &buffers);
+	tasklet_schedule(&deferred_free);
+	spin_unlock_irqrestore(&buflock, flags);
 /* ************************************************** */

vdr mailing list

Reply via email to