fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / dvb / ttpci / av7110_hw.c
index f56e9dc..37de2e8 100644 (file)
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
-#define DEBUG_VARIABLE av7110_debug
-extern int av7110_debug;
-
 #include "av7110.h"
 #include "av7110_hw.h"
-#include "dvb_functions.h"
+
+#define _NOHANDSHAKE
 
 /****************************************************************************
  * DEBI functions
@@ -57,10 +54,14 @@ int av7110_debiwrite(struct av7110 *av7110, u32 config,
 {
        struct saa7146_dev *dev = av7110->dev;
 
-       if (count <= 0 || count > 32764)
+       if (count <= 0 || count > 32764) {
+               printk("%s: invalid count %d\n", __FUNCTION__, count);
                return -1;
-       if (saa7146_wait_for_debi_done(av7110->dev) < 0)
+       }
+       if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+               printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
                return -1;
+       }
        saa7146_write(dev, DEBI_CONFIG, config);
        if (count <= 4)         /* immediate transfer */
                saa7146_write(dev, DEBI_AD, val);
@@ -76,10 +77,14 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
        struct saa7146_dev *dev = av7110->dev;
        u32 result = 0;
 
-       if (count > 32764 || count <= 0)
+       if (count > 32764 || count <= 0) {
+               printk("%s: invalid count %d\n", __FUNCTION__, count);
                return 0;
-       if (saa7146_wait_for_debi_done(av7110->dev) < 0)
+       }
+       if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+               printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
                return 0;
+       }
        saa7146_write(dev, DEBI_AD, av7110->debi_bus);
        saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
 
@@ -87,7 +92,11 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
        saa7146_write(dev, MC2, (2 << 16) | 2);
        if (count > 4)
                return count;
-       saa7146_wait_for_debi_done(av7110->dev);
+       if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+               printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
+               return 0;
+       }
+
        result = saa7146_read(dev, DEBI_AD);
        result &= (0xffffffffUL >> ((4 - count) * 8));
        return result;
@@ -96,87 +105,95 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
 
 
 /* av7110 ARM core boot stuff */
-
+#if 0
 void av7110_reset_arm(struct av7110 *av7110)
 {
        saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 
        /* Disable DEBI and GPIO irq */
-       IER_DISABLE(av7110->dev, (MASK_19 | MASK_03));
-       saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
+       SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
+       SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 
        saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-       dvb_delay(30);  /* the firmware needs some time to initialize */
+       msleep(30);     /* the firmware needs some time to initialize */
 
        ARM_ResetMailBox(av7110);
 
-       saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
-       IER_ENABLE(av7110->dev, MASK_03);
+       SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+       SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 
        av7110->arm_ready = 1;
-       printk("av7110: ARM RESET\n");
+       dprintk(1, "reset ARM\n");
 }
-
+#endif  /*  0  */
 
 static int waitdebi(struct av7110 *av7110, int adr, int state)
 {
        int k;
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        for (k = 0; k < 100; k++) {
                if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
                        return 0;
                udelay(5);
        }
-       return -1;
+       return -ETIMEDOUT;
 }
 
 static int load_dram(struct av7110 *av7110, u32 *data, int len)
 {
        int i;
        int blocks, rest;
-       u32 base, bootblock = BOOT_BLOCK;
+       u32 base, bootblock = AV7110_BOOT_BLOCK;
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
-       blocks = len / BOOT_MAX_SIZE;
-       rest = len % BOOT_MAX_SIZE;
+       blocks = len / AV7110_BOOT_MAX_SIZE;
+       rest = len % AV7110_BOOT_MAX_SIZE;
        base = DRAM_START_CODE;
 
        for (i = 0; i < blocks; i++) {
-               if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
-                       return -1;
-               DEB_D(("Writing DRAM block %d\n", i));
+               if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+                       printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
+                       return -ETIMEDOUT;
+               }
+               dprintk(4, "writing DRAM block %d\n", i);
                mwdebi(av7110, DEBISWAB, bootblock,
-                      ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
+                      ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
                bootblock ^= 0x1400;
-               iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
-               iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, BOOT_MAX_SIZE, 2);
-               iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-               base += BOOT_MAX_SIZE;
+               iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
+               iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
+               iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+               base += AV7110_BOOT_MAX_SIZE;
        }
 
        if (rest > 0) {
-               if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
-                       return -1;
+               if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+                       printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
+                       return -ETIMEDOUT;
+               }
                if (rest > 4)
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * BOOT_MAX_SIZE, rest);
+                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
                else
                        mwdebi(av7110, DEBISWAB, bootblock,
-                              ((char*)data) + i * BOOT_MAX_SIZE - 4, rest + 4);
+                              ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 
-               iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
-               iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2);
-               iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+               iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
+               iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
+               iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+       }
+       if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
+               printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
+               return -ETIMEDOUT;
+       }
+       iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
+       iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+       if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
+               printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
+               return -ETIMEDOUT;
        }
-       if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0)
-               return -1;
-       iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
-       iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
-       if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0)
-               return -1;
        return 0;
 }
 
@@ -210,13 +227,15 @@ int av7110_bootarm(struct av7110 *av7110)
        u32 ret;
        int i;
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
+
+       av7110->arm_ready = 0;
 
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 
        /* Disable DEBI and GPIO irq */
-       IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
-       saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
+       SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
+       SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 
        /* enable DEBI */
        saa7146_write(av7110->dev, MC1, 0x08800880);
@@ -225,55 +244,61 @@ int av7110_bootarm(struct av7110 *av7110)
 
        /* test DEBI */
        iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
+       /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
+       iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
+
        if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
-               printk(KERN_ERR "dvb: debi test in av7110_bootarm() failed: "
-                      "%08x != %08x (check your BIOS hotplug settings)\n",
+               printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
+                      "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
                       ret, 0x10325476);
                return -1;
        }
        for (i = 0; i < 8192; i += 4)
                iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
-       DEB_D(("av7110_bootarm: debi test OK\n"));
+       dprintk(2, "debi test OK\n");
 
        /* boot */
-       DEB_D(("av7110_bootarm: load boot code\n"));
+       dprintk(1, "load boot code\n");
        saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
        //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
        //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
 
        mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
-       iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
+       iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 
-       if (saa7146_wait_for_debi_done(av7110->dev)) {
-               printk(KERN_ERR "dvb: av7110_bootarm(): "
+       if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
+               printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
                       "saa7146_wait_for_debi_done() timed out\n");
-               return -1;
+               return -ETIMEDOUT;
        }
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
        mdelay(1);
 
-       DEB_D(("av7110_bootarm: load dram code\n"));
-       if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0)
+       dprintk(1, "load dram code\n");
+       if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
+               printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
+                      "load_dram() failed\n");
                return -1;
+       }
 
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
        mdelay(1);
 
-       DEB_D(("av7110_bootarm: load dpram code\n"));
+       dprintk(1, "load dpram code\n");
        mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
 
-       if (saa7146_wait_for_debi_done(av7110->dev)) {
-               printk(KERN_ERR "dvb: av7110_bootarm(): "
+       if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
+               printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
                       "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
-               return -1;
+               return -ETIMEDOUT;
        }
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
-       dvb_delay(30);  /* the firmware needs some time to initialize */
+       msleep(30);     /* the firmware needs some time to initialize */
 
        //ARM_ClearIrq(av7110);
        ARM_ResetMailBox(av7110);
-       saa7146_write(av7110->dev, ISR, (MASK_19 | MASK_03));
-       IER_ENABLE(av7110->dev, MASK_03);
+       SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
+       SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 
        av7110->arm_errors = 0;
        av7110->arm_ready = 1;
@@ -285,49 +310,131 @@ int av7110_bootarm(struct av7110 *av7110)
  * DEBI command polling
  ****************************************************************************/
 
-int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
+{
+       unsigned long start;
+       u32 stat;
+       int err;
+
+       if (FW_VERSION(av7110->arm_app) <= 0x261c) {
+               /* not supported by old firmware */
+               msleep(50);
+               return 0;
+       }
+
+       /* new firmware */
+       start = jiffies;
+       for (;;) {
+               err = time_after(jiffies, start + ARM_WAIT_FREE);
+               if (mutex_lock_interruptible(&av7110->dcomlock))
+                       return -ERESTARTSYS;
+               stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+               mutex_unlock(&av7110->dcomlock);
+               if ((stat & flags) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
+                               __FUNCTION__, stat & flags);
+                       return -ETIMEDOUT;
+               }
+               msleep(1);
+       }
+       return 0;
+}
+
+static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 {
        int i;
        unsigned long start;
-#ifdef COM_DEBUG
+       char *type = NULL;
+       u16 flags[2] = {0, 0};
        u32 stat;
-#endif
+       int err;
 
-//     DEB_EE(("av7110: %p\n", av7110));
+//     dprintk(4, "%p\n", av7110);
 
        if (!av7110->arm_ready) {
-               DEB_D(("arm not ready.\n"));
-               return -1;
+               dprintk(1, "arm not ready.\n");
+               return -ENXIO;
        }
 
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_FREE)) {
-                       printk(KERN_ERR "%s: timeout waiting for COMMAND idle\n", __FUNCTION__);
-                       return -1;
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_FREE);
+               if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+                       av7110->arm_errors++;
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 
+       if (FW_VERSION(av7110->arm_app) <= 0x261f)
+               wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
+
 #ifndef _NOHANDSHAKE
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
-                       printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-                       return -1;
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+               if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 #endif
 
-       start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2) & OSDQFull) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_OSD)) {
-                       printk(KERN_ERR "%s: timeout waiting for !OSDQFull\n", __FUNCTION__);
-                       return -1;
+       switch ((buf[0] >> 8) & 0xff) {
+       case COMTYPE_PIDFILTER:
+       case COMTYPE_ENCODER:
+       case COMTYPE_REC_PLAY:
+       case COMTYPE_MPEGDECODER:
+               type = "MSG";
+               flags[0] = GPMQOver;
+               flags[1] = GPMQFull;
+               break;
+       case COMTYPE_OSD:
+               type = "OSD";
+               flags[0] = OSDQOver;
+               flags[1] = OSDQFull;
+               break;
+       case COMTYPE_MISC:
+               if (FW_VERSION(av7110->arm_app) >= 0x261d) {
+                       type = "MSG";
+                       flags[0] = GPMQOver;
+                       flags[1] = GPMQBusy;
                }
+               break;
+       default:
+               break;
        }
+
+       if (type != NULL) {
+               /* non-immediate COMMAND type */
+               start = jiffies;
+               for (;;) {
+                       err = time_after(jiffies, start + ARM_WAIT_FREE);
+                       stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
+                       if (stat & flags[0]) {
+                               printk(KERN_ERR "%s: %s QUEUE overflow\n",
+                                       __FUNCTION__, type);
+                               return -1;
+                       }
+                       if ((stat & flags[1]) == 0)
+                               break;
+                       if (err) {
+                               printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
+                                       __FUNCTION__, type);
+                               return -ETIMEDOUT;
+                       }
+                       msleep(1);
+               }
+       }
+
        for (i = 2; i < length; i++)
                wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
 
@@ -338,48 +445,55 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 
        wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
 
+       if (FW_VERSION(av7110->arm_app) <= 0x261f)
+               wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
+
 #ifdef COM_DEBUG
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_FREE)) {
-                       printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n",
-                              __FUNCTION__);
-                       return -1;
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_FREE);
+               if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+                              __FUNCTION__, (buf[0] >> 8) & 0xff);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 
        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
        if (stat & GPMQOver) {
-               printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
-               return -1;
+               printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
+               return -ENOSPC;
        }
        else if (stat & OSDQOver) {
-               printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
-               return -1;
+               printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
+               return -ENOSPC;
        }
 #endif
 
        return 0;
 }
 
-int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 {
        int ret;
 
-//     DEB_EE(("av7110: %p\n", av7110));
+//     dprintk(4, "%p\n", av7110);
 
        if (!av7110->arm_ready) {
-               DEB_D(("arm not ready.\n"));
+               dprintk(1, "arm not ready.\n");
                return -1;
        }
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        ret = __av7110_send_fw_cmd(av7110, buf, length);
-       up(&av7110->dcomlock);
-       if (ret)
-               printk("av7110_send_fw_cmd error\n");
+       mutex_unlock(&av7110->dcomlock);
+       if (ret && ret!=-ERESTARTSYS)
+               printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
+                      __FUNCTION__, ret);
        return ret;
 }
 
@@ -389,7 +503,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
        u16 buf[num + 2];
        int i, ret;
 
-//     DEB_EE(("av7110: %p\n",av7110));
+//     dprintk(4, "%p\n", av7110);
 
        buf[0] = ((type << 8) | com);
        buf[1] = num;
@@ -402,18 +516,19 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
        }
 
        ret = av7110_send_fw_cmd(av7110, buf, num + 2);
-       if (ret)
-               printk("av7110_fw_cmd error\n");
+       if (ret && ret != -ERESTARTSYS)
+               printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
        return ret;
 }
 
+#if 0
 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
 {
        int i, ret;
        u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
                16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        for(i = 0; i < len && i < 32; i++)
        {
@@ -424,10 +539,11 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
        }
 
        ret = av7110_send_fw_cmd(av7110, cmd, 18);
-       if (ret)
-               printk("av7110_send_ci_cmd error\n");
+       if (ret && ret != -ERESTARTSYS)
+               printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
        return ret;
 }
+#endif  /*  0  */
 
 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
                      int request_buf_len, u16 *reply_buf, int reply_buf_len)
@@ -439,43 +555,49 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
        u32 stat;
 #endif
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        if (!av7110->arm_ready) {
-               DEB_D(("arm not ready.\n"));
+               dprintk(1, "arm not ready.\n");
                return -1;
        }
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
-               up(&av7110->dcomlock);
-               printk("av7110_fw_request error\n");
+               mutex_unlock(&av7110->dcomlock);
+               printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
                return err;
        }
 
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_FREE);
+               if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
+                       mutex_unlock(&av7110->dcomlock);
+                       return -ETIMEDOUT;
+               }
 #ifdef _NOHANDSHAKE
-               dvb_delay(1);
+               msleep(1);
 #endif
-               if (time_after(jiffies, start + ARM_WAIT_FREE)) {
-                       printk("%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
-                       up(&av7110->dcomlock);
-                       return -1;
-               }
        }
 
 #ifndef _NOHANDSHAKE
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+               if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+                       break;
+               if (err) {
                        printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-                       up(&av7110->dcomlock);
-                       return -1;
+                       mutex_unlock(&av7110->dcomlock);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 #endif
 
@@ -483,12 +605,12 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
        if (stat & GPMQOver) {
                printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                return -1;
        }
        else if (stat & OSDQOver) {
                printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                return -1;
        }
 #endif
@@ -496,16 +618,16 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
        for (i = 0; i < reply_buf_len; i++)
                reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        return 0;
 }
 
-int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
+static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
 {
        int ret;
        ret = av7110_fw_request(av7110, &tag, 0, buf, length);
        if (ret)
-               printk("av7110_fw_query error\n");
+               printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
        return ret;
 }
 
@@ -520,11 +642,11 @@ int av7110_firmversion(struct av7110 *av7110)
        u16 buf[20];
        u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        if (av7110_fw_query(av7110, tag, buf, 16)) {
-               printk("DVB: AV7110-%d: ERROR: Failed to boot firmware\n",
-                      av7110->dvb_adapter->num);
+               printk("dvb-ttpci: failed to boot firmware @ card %d\n",
+                      av7110->dvb_adapter.num);
                return -EIO;
        }
 
@@ -534,17 +656,17 @@ int av7110_firmversion(struct av7110 *av7110)
        av7110->arm_app = (buf[6] << 16) + buf[7];
        av7110->avtype = (buf[8] << 16) + buf[9];
 
-       printk("DVB: AV711%d(%d) - firm %08x, rtsl %08x, vid %08x, app %08x\n",
-              av7110->avtype, av7110->dvb_adapter->num, av7110->arm_fw,
+       printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
+              av7110->dvb_adapter.num, av7110->arm_fw,
               av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
 
        /* print firmware capabilities */
        if (FW_CI_LL_SUPPORT(av7110->arm_app))
-               printk("DVB: AV711%d(%d) - firmware supports CI link layer interface\n",
-                      av7110->avtype, av7110->dvb_adapter->num);
+               printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
+                      av7110->dvb_adapter.num);
        else
-               printk("DVB: AV711%d(%d) - no firmware support for CI link layer interface\n",
-                      av7110->avtype, av7110->dvb_adapter->num);
+               printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
+                      av7110->dvb_adapter.num);
 
        return 0;
 }
@@ -552,11 +674,11 @@ int av7110_firmversion(struct av7110 *av7110)
 
 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
 {
-       int i;
+       int i, ret;
        u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
                        16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
        if (len > 10)
                len = 10;
@@ -572,30 +694,20 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
        for (i = 0; i < len; i++)
                buf[i + 4] = msg[i];
 
-       if (av7110_send_fw_cmd(av7110, buf, 18))
-               printk("av7110_diseqc_send error\n");
-
-       return 0;
+       ret = av7110_send_fw_cmd(av7110, buf, 18);
+       if (ret && ret!=-ERESTARTSYS)
+               printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
+       return ret;
 }
 
 
 #ifdef CONFIG_DVB_AV7110_OSD
 
-static inline int ResetBlend(struct av7110 *av7110, u8 windownr)
-{
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, SetNonBlend, 1, windownr);
-}
-
 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
 {
        return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
 }
 
-static inline int SetWindowBlend(struct av7110 *av7110, u8 windownr, u8 blending)
-{
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, SetWBlend, 2, windownr, blending);
-}
-
 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
                     enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
 {
@@ -610,11 +722,6 @@ static inline int SetColor_(struct av7110 *av7110, u8 windownr,
                             windownr, colordepth, index, colorhi, colorlo);
 }
 
-static inline int BringToTop(struct av7110 *av7110, u8 windownr)
-{
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, WTop, 1, windownr);
-}
-
 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
                          u16 colorfg, u16 colorbg)
 {
@@ -625,20 +732,24 @@ static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
 static int FlushText(struct av7110 *av7110)
 {
        unsigned long start;
+       int err;
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_OSD)) {
-                       printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
+       while (1) {
+               err = time_after(jiffies, start + ARM_WAIT_OSD);
+               if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+                       break;
+               if (err) {
+                       printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
-                       return -1;
+                       mutex_unlock(&av7110->dcomlock);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        return 0;
 }
 
@@ -649,29 +760,35 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
        int length = strlen(buf) + 1;
        u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_OSD)) {
-                       printk(KERN_ERR "%s: timeout waiting for BUFF1_BASE == 0\n",
+       while (1) {
+               ret = time_after(jiffies, start + ARM_WAIT_OSD);
+               if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+                       break;
+               if (ret) {
+                       printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
-                       return -1;
+                       mutex_unlock(&av7110->dcomlock);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 #ifndef _NOHANDSHAKE
        start = jiffies;
-       while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
-               dvb_delay(1);
-               if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
-                       printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n",
+       while (1) {
+               ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
+               if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+                       break;
+               if (ret) {
+                       printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
-                       return -1;
+                       mutex_unlock(&av7110->dcomlock);
+                       return -ETIMEDOUT;
                }
+               msleep(1);
        }
 #endif
        for (i = 0; i < length / 2; i++)
@@ -680,9 +797,9 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
        if (length & 1)
                wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
        ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
-       up(&av7110->dcomlock);
-       if (ret)
-               printk("WriteText error\n");
+       mutex_unlock(&av7110->dcomlock);
+       if (ret && ret!=-ERESTARTSYS)
+               printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
        return ret;
 }
 
@@ -721,7 +838,7 @@ static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
 }
 
 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
-                                 enum av7110_window_display_type disptype,
+                                 osd_raw_window_t disptype,
                                  u16 width, u16 height)
 {
        return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
@@ -732,61 +849,65 @@ static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
 static enum av7110_osd_palette_type bpp2pal[8] = {
        Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
 };
-static enum av7110_window_display_type bpp2bit[8] = {
-       BITMAP1, BITMAP2, 0, BITMAP4, 0, 0, 0, BITMAP8
+static osd_raw_window_t bpp2bit[8] = {
+       OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
 };
 
-static inline int LoadBitmap(struct av7110 *av7110, u16 format,
-                            u16 dx, u16 dy, int inc, u8* data)
+static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
+{
+       int ret = wait_event_interruptible_timeout(av7110->bmpq,
+                               av7110->bmp_state != BMP_LOADING, 10*HZ);
+       if (ret == -ERESTARTSYS)
+               return ret;
+       if (ret == 0) {
+               printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+                      ret, av7110->bmp_state);
+               av7110->bmp_state = BMP_NONE;
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static inline int LoadBitmap(struct av7110 *av7110,
+                            u16 dx, u16 dy, int inc, u8 __user * data)
 {
+       u16 format;
        int bpp;
        int i;
        int d, delta;
        u8 c;
-       DECLARE_WAITQUEUE(wait, current);
+       int ret;
 
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
+
+       format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
 
-       if (av7110->bmp_state == BMP_LOADING) {
-               add_wait_queue(&av7110->bmpq, &wait);
-               while (1) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (av7110->bmp_state != BMP_LOADING
-                           || signal_pending(current))
-                               break;
-                       schedule();
-               }
-               set_current_state(TASK_RUNNING);
-               remove_wait_queue(&av7110->bmpq, &wait);
-       }
-       if (av7110->bmp_state == BMP_LOADING)
-               return -1;
        av7110->bmp_state = BMP_LOADING;
-       if      (format == BITMAP8) {
+       if      (format == OSD_BITMAP8) {
                bpp=8; delta = 1;
-       } else if (format == BITMAP4) {
+       } else if (format == OSD_BITMAP4) {
                bpp=4; delta = 2;
-       } else if (format == BITMAP2) {
+       } else if (format == OSD_BITMAP2) {
                bpp=2; delta = 4;
-       } else if (format == BITMAP1) {
+       } else if (format == OSD_BITMAP1) {
                bpp=1; delta = 8;
        } else {
                av7110->bmp_state = BMP_NONE;
-               return -1;
+               return -EINVAL;
        }
        av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
        av7110->bmpp = 0;
        if (av7110->bmplen > 32768) {
                av7110->bmp_state = BMP_NONE;
-               return -1;
+               return -EINVAL;
        }
        for (i = 0; i < dy; i++) {
                if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
                        av7110->bmp_state = BMP_NONE;
-                       return -1;
+                       return -EINVAL;
                }
        }
-       if (format != BITMAP8) {
+       if (format != OSD_BITMAP8) {
                for (i = 0; i < dx * dy / delta; i++) {
                        c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
                        for (d = delta - 2; d >= 0; d--) {
@@ -797,40 +918,28 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
                }
        }
        av7110->bmplen += 1024;
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+       dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
+       ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+       if (!ret)
+               ret = WaitUntilBmpLoaded(av7110);
+       return ret;
 }
 
-static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
+static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       DEB_EE(("av7110: %p\n", av7110));
+       dprintk(4, "%p\n", av7110);
 
-       if (av7110->bmp_state == BMP_NONE)
-               return -1;
-       if (av7110->bmp_state == BMP_LOADING) {
-               add_wait_queue(&av7110->bmpq, &wait);
-               while (1) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (av7110->bmp_state != BMP_LOADING
-                           || signal_pending(current))
-                               break;
-                       schedule();
-               }
-               set_current_state(TASK_RUNNING);
-               remove_wait_queue(&av7110->bmpq, &wait);
-       }
-       if (av7110->bmp_state == BMP_LOADED)
-               return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
-       return -1;
+       return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
 }
 
 static inline int ReleaseBitmap(struct av7110 *av7110)
 {
-       DEB_EE(("av7110: %p\n",av7110));
+       dprintk(4, "%p\n", av7110);
 
-       if (av7110->bmp_state != BMP_LOADED)
+       if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
                return -1;
+       if (av7110->bmp_state == BMP_LOADING)
+               dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
        av7110->bmp_state = BMP_NONE;
        return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
 }
@@ -851,32 +960,40 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B)
        return Cr | (Cb << 16) | (Y << 8);
 }
 
-static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
+static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
 {
+       int ret;
+
        u16 ch, cl;
        u32 yuv;
 
        yuv = blend ? RGB2YUV(r,g,b) : 0;
        cl = (yuv & 0xffff);
        ch = ((yuv >> 16) & 0xffff);
-       SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-                 color, ch, cl);
-       SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
-                 color, ((blend >> 4) & 0x0f));
+       ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+                       color, ch, cl);
+       if (!ret)
+               ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+                               color, ((blend >> 4) & 0x0f));
+       return ret;
 }
 
-static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
+static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
 {
        int i;
        int length = last - first + 1;
 
        if (length * 4 > DATA_BUFF3_SIZE)
-              return -1;
+              return -EINVAL;
 
        for (i = 0; i < length; i++) {
-              u32 blend = (colors[i] & 0xF0000000) >> 4;
-              u32 yuv = blend ? RGB2YUV(colors[i] & 0xFF, (colors[i] >> 8) & 0xFF,
-                                        (colors[i] >> 16) & 0xFF) | blend : 0;
+              u32 color, blend, yuv;
+
+              if (get_user(color, colors + i))
+                      return -EFAULT;
+              blend = (color & 0xF0000000) >> 4;
+              yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+                                    (color >> 16) & 0xFF) | blend : 0;
               yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
               wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
        }
@@ -887,17 +1004,18 @@ static int OSDSetPalette(struct av7110 *av7110, u32 *colors, u8 first, u8 last)
 }
 
 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
-                      int x1, int y1, int inc, u8 *data)
+                      int x1, int y1, int inc, u8 __user * data)
 {
        uint w, h, bpp, bpl, size, lpb, bnum, brest;
        int i;
+       int rc,release_rc;
 
        w = x1 - x0 + 1;
        h = y1 - y0 + 1;
        if (inc <= 0)
                inc = w;
        if (w <= 0 || w > 720 || h <= 0 || h > 576)
-               return -1;
+               return -EINVAL;
        bpp = av7110->osdbpp[av7110->osdwin] + 1;
        bpl = ((w * bpp + 7) & ~7) / 8;
        size = h * bpl;
@@ -905,122 +1023,197 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
        bnum = size / (lpb * bpl);
        brest = size - bnum * lpb * bpl;
 
+       if (av7110->bmp_state == BMP_LOADING) {
+               /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
+               BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
+               rc = WaitUntilBmpLoaded(av7110);
+               if (rc)
+                       return rc;
+               /* just continue. This should work for all fw versions
+                * if bnum==1 && !brest && LoadBitmap was successful
+                */
+       }
+
+       rc = 0;
        for (i = 0; i < bnum; i++) {
-               LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
-                          w, lpb, inc, data);
-               BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+               rc = LoadBitmap(av7110, w, lpb, inc, data);
+               if (rc)
+                       break;
+               rc = BlitBitmap(av7110, x0, y0 + i * lpb);
+               if (rc)
+                       break;
                data += lpb * inc;
        }
-       if (brest) {
-               LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
-                          w, brest / bpl, inc, data);
-               BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
+       if (!rc && brest) {
+               rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
+               if (!rc)
+                       rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
        }
-       ReleaseBitmap(av7110);
-       return 0;
+       release_rc = ReleaseBitmap(av7110);
+       if (!rc)
+               rc = release_rc;
+       if (rc)
+               dprintk(1,"returns %d\n",rc);
+       return rc;
 }
 
 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
 {
+       int ret;
+
+       if (mutex_lock_interruptible(&av7110->osd_mutex))
+               return -ERESTARTSYS;
+
        switch (dc->cmd) {
        case OSD_Close:
-               DestroyOSDWindow(av7110, av7110->osdwin);
-               return 0;
+               ret = DestroyOSDWindow(av7110, av7110->osdwin);
+               break;
        case OSD_Open:
                av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
-               CreateOSDWindow(av7110, av7110->osdwin,
+               ret = CreateOSDWindow(av7110, av7110->osdwin,
                                bpp2bit[av7110->osdbpp[av7110->osdwin]],
                                dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+               if (ret)
+                       break;
                if (!dc->data) {
-                       MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-                       SetColorBlend(av7110, av7110->osdwin);
+                       ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+                       if (ret)
+                               break;
+                       ret = SetColorBlend(av7110, av7110->osdwin);
                }
-               return 0;
+               break;
        case OSD_Show:
-               MoveWindowRel(av7110, av7110->osdwin, 0, 0);
-               return 0;
+               ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
+               break;
        case OSD_Hide:
-               HideWindow(av7110, av7110->osdwin);
-               return 0;
+               ret = HideWindow(av7110, av7110->osdwin);
+               break;
        case OSD_Clear:
-               DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
-               return 0;
+               ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
+               break;
        case OSD_Fill:
-               DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
-               return 0;
+               ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
+               break;
        case OSD_SetColor:
-               OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
-               return 0;
+               ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
+               break;
        case OSD_SetPalette:
-       {
                if (FW_VERSION(av7110->arm_app) >= 0x2618)
-                       OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0);
+                       ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
                else {
                        int i, len = dc->x0-dc->color+1;
-                       u8 *colors = (u8 *)dc->data;
-
-                       for (i = 0; i<len; i++)
-                               OSDSetColor(av7110, dc->color + i,
-                                       colors[i * 4], colors[i * 4 + 1],
-                                       colors[i * 4 + 2], colors[i * 4 + 3]);
+                       u8 __user *colors = (u8 __user *)dc->data;
+                       u8 r, g, b, blend;
+                       ret = 0;
+                       for (i = 0; i<len; i++) {
+                               if (get_user(r, colors + i * 4) ||
+                                   get_user(g, colors + i * 4 + 1) ||
+                                   get_user(b, colors + i * 4 + 2) ||
+                                   get_user(blend, colors + i * 4 + 3)) {
+                                       ret = -EFAULT;
+                                       break;
+                                   }
+                               ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+                               if (ret)
+                                       break;
+                       }
                }
-               return 0;
-       }
-       case OSD_SetTrans:
-               return 0;
+               break;
        case OSD_SetPixel:
-               DrawLine(av7110, av7110->osdwin,
+               ret = DrawLine(av7110, av7110->osdwin,
                         dc->x0, dc->y0, 0, 0, dc->color);
-               return 0;
-       case OSD_GetPixel:
-               return 0;
-
+               break;
        case OSD_SetRow:
                dc->y1 = dc->y0;
                /* fall through */
        case OSD_SetBlock:
-               OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
-               return 0;
-
+               ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
+               break;
        case OSD_FillRow:
-               DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+               ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
                          dc->x1-dc->x0+1, dc->y1, dc->color);
-               return 0;
+               break;
        case OSD_FillBlock:
-               DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+               ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
                          dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
-               return 0;
+               break;
        case OSD_Line:
-               DrawLine(av7110, av7110->osdwin,
+               ret = DrawLine(av7110, av7110->osdwin,
                         dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
-               return 0;
-       case OSD_Query:
-               return 0;
-       case OSD_Test:
-               return 0;
+               break;
        case OSD_Text:
        {
                char textbuf[240];
 
-               if (strncpy_from_user(textbuf, dc->data, 240) < 0)
-                       return -EFAULT;
+               if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
+                       ret = -EFAULT;
+                       break;
+               }
                textbuf[239] = 0;
                if (dc->x1 > 3)
                        dc->x1 = 3;
-               SetFont(av7110, av7110->osdwin, dc->x1,
+               ret = SetFont(av7110, av7110->osdwin, dc->x1,
                        (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
-               FlushText(av7110);
-               WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
-               return 0;
+               if (!ret)
+                       ret = FlushText(av7110);
+               if (!ret)
+                       ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
+               break;
        }
        case OSD_SetWindow:
                if (dc->x0 < 1 || dc->x0 > 7)
-                       return -EINVAL;
-               av7110->osdwin = dc->x0;
-               return 0;
+                       ret = -EINVAL;
+               else {
+                       av7110->osdwin = dc->x0;
+                       ret = 0;
+               }
+               break;
        case OSD_MoveWindow:
-               MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
-               SetColorBlend(av7110, av7110->osdwin);
+               ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+               if (!ret)
+                       ret = SetColorBlend(av7110, av7110->osdwin);
+               break;
+       case OSD_OpenRaw:
+               if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
+                       av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
+               else
+                       av7110->osdbpp[av7110->osdwin] = 0;
+               ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+                               dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+               if (ret)
+                       break;
+               if (!dc->data) {
+                       ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+                       if (!ret)
+                               ret = SetColorBlend(av7110, av7110->osdwin);
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&av7110->osd_mutex);
+       if (ret==-ERESTARTSYS)
+               dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+       else if (ret)
+               dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+
+       return ret;
+}
+
+int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
+{
+       switch (cap->cmd) {
+       case OSD_CAP_MEMSIZE:
+               if (FW_4M_SDRAM(av7110->arm_app))
+                       cap->val = 1000000;
+               else
+                       cap->val = 92000;
                return 0;
        default:
                return -EINVAL;