linux/drivers/media/pci/ttpci/av7110_hw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * av7110_hw.c: av7110 low level hardware access and firmware interface
   4 *
   5 * Copyright (C) 1999-2002 Ralph  Metzler
   6 *                       & Marcus Metzler for convergence integrated media GmbH
   7 *
   8 * originally based on code by:
   9 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
  10 *
  11 * the project's page is at https://linuxtv.org
  12 */
  13
  14/* for debugging ARM communication: */
  15//#define COM_DEBUG
  16
  17#include <stdarg.h>
  18#include <linux/types.h>
  19#include <linux/kernel.h>
  20#include <linux/string.h>
  21#include <linux/delay.h>
  22#include <linux/fs.h>
  23
  24#include "av7110.h"
  25#include "av7110_hw.h"
  26
  27#define _NOHANDSHAKE
  28
  29/*
  30 * Max transfer size done by av7110_fw_cmd()
  31 *
  32 * The maximum size passed to this function is 6 bytes. The buffer also
  33 * uses two additional ones for type and size. So, 8 bytes is enough.
  34 */
  35#define MAX_XFER_SIZE  8
  36
  37/****************************************************************************
  38 * DEBI functions
  39 ****************************************************************************/
  40
  41/* This DEBI code is based on the Stradis driver
  42   by Nathan Laredo <laredo@gnu.org> */
  43
  44int av7110_debiwrite(struct av7110 *av7110, u32 config,
  45                     int addr, u32 val, unsigned int count)
  46{
  47        struct saa7146_dev *dev = av7110->dev;
  48
  49        if (count > 32764) {
  50                printk("%s: invalid count %d\n", __func__, count);
  51                return -1;
  52        }
  53        if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  54                printk("%s: wait_for_debi_done failed\n", __func__);
  55                return -1;
  56        }
  57        saa7146_write(dev, DEBI_CONFIG, config);
  58        if (count <= 4)         /* immediate transfer */
  59                saa7146_write(dev, DEBI_AD, val);
  60        else                    /* block transfer */
  61                saa7146_write(dev, DEBI_AD, av7110->debi_bus);
  62        saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
  63        saa7146_write(dev, MC2, (2 << 16) | 2);
  64        return 0;
  65}
  66
  67u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
  68{
  69        struct saa7146_dev *dev = av7110->dev;
  70        u32 result = 0;
  71
  72        if (count > 32764) {
  73                printk("%s: invalid count %d\n", __func__, count);
  74                return 0;
  75        }
  76        if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  77                printk("%s: wait_for_debi_done #1 failed\n", __func__);
  78                return 0;
  79        }
  80        saa7146_write(dev, DEBI_AD, av7110->debi_bus);
  81        saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
  82
  83        saa7146_write(dev, DEBI_CONFIG, config);
  84        saa7146_write(dev, MC2, (2 << 16) | 2);
  85        if (count > 4)
  86                return count;
  87        if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  88                printk("%s: wait_for_debi_done #2 failed\n", __func__);
  89                return 0;
  90        }
  91
  92        result = saa7146_read(dev, DEBI_AD);
  93        result &= (0xffffffffUL >> ((4 - count) * 8));
  94        return result;
  95}
  96
  97
  98
  99/* av7110 ARM core boot stuff */
 100#if 0
 101void av7110_reset_arm(struct av7110 *av7110)
 102{
 103        saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 104
 105        /* Disable DEBI and GPIO irq */
 106        SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
 107        SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 108
 109        saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 110        msleep(30);     /* the firmware needs some time to initialize */
 111
 112        ARM_ResetMailBox(av7110);
 113
 114        SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 115        SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 116
 117        av7110->arm_ready = 1;
 118        dprintk(1, "reset ARM\n");
 119}
 120#endif  /*  0  */
 121
 122static int waitdebi(struct av7110 *av7110, int adr, int state)
 123{
 124        int k;
 125
 126        dprintk(4, "%p\n", av7110);
 127
 128        for (k = 0; k < 100; k++) {
 129                if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
 130                        return 0;
 131                udelay(5);
 132        }
 133        return -ETIMEDOUT;
 134}
 135
 136static int load_dram(struct av7110 *av7110, u32 *data, int len)
 137{
 138        int i;
 139        int blocks, rest;
 140        u32 base, bootblock = AV7110_BOOT_BLOCK;
 141
 142        dprintk(4, "%p\n", av7110);
 143
 144        blocks = len / AV7110_BOOT_MAX_SIZE;
 145        rest = len % AV7110_BOOT_MAX_SIZE;
 146        base = DRAM_START_CODE;
 147
 148        for (i = 0; i < blocks; i++) {
 149                if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 150                        printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
 151                        return -ETIMEDOUT;
 152                }
 153                dprintk(4, "writing DRAM block %d\n", i);
 154                mwdebi(av7110, DEBISWAB, bootblock,
 155                       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
 156                bootblock ^= 0x1400;
 157                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 158                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
 159                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 160                base += AV7110_BOOT_MAX_SIZE;
 161        }
 162
 163        if (rest > 0) {
 164                if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 165                        printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
 166                        return -ETIMEDOUT;
 167                }
 168                if (rest > 4)
 169                        mwdebi(av7110, DEBISWAB, bootblock,
 170                               ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
 171                else
 172                        mwdebi(av7110, DEBISWAB, bootblock,
 173                               ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 174
 175                iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 176                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
 177                iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 178        }
 179        if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 180                printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
 181                return -ETIMEDOUT;
 182        }
 183        iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
 184        iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 185        if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
 186                printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
 187                return -ETIMEDOUT;
 188        }
 189        return 0;
 190}
 191
 192
 193/* we cannot write av7110 DRAM directly, so load a bootloader into
 194 * the DPRAM which implements a simple boot protocol */
 195int av7110_bootarm(struct av7110 *av7110)
 196{
 197        const struct firmware *fw;
 198        const char *fw_name = "av7110/bootcode.bin";
 199        struct saa7146_dev *dev = av7110->dev;
 200        u32 ret;
 201        int i;
 202
 203        dprintk(4, "%p\n", av7110);
 204
 205        av7110->arm_ready = 0;
 206
 207        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 208
 209        /* Disable DEBI and GPIO irq */
 210        SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
 211        SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 212
 213        /* enable DEBI */
 214        saa7146_write(av7110->dev, MC1, 0x08800880);
 215        saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
 216        saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 217
 218        /* test DEBI */
 219        iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
 220        /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
 221        iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
 222
 223        if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
 224                printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
 225                       ret, 0x10325476);
 226                return -1;
 227        }
 228        for (i = 0; i < 8192; i += 4)
 229                iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
 230        dprintk(2, "debi test OK\n");
 231
 232        /* boot */
 233        dprintk(1, "load boot code\n");
 234        saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
 235        //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
 236        //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
 237
 238        ret = request_firmware(&fw, fw_name, &dev->pci->dev);
 239        if (ret) {
 240                printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
 241                        fw_name);
 242                return ret;
 243        }
 244
 245        mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
 246        release_firmware(fw);
 247        iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 248
 249        if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 250                printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n");
 251                return -ETIMEDOUT;
 252        }
 253        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 254        mdelay(1);
 255
 256        dprintk(1, "load dram code\n");
 257        if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
 258                printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n");
 259                return -1;
 260        }
 261
 262        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 263        mdelay(1);
 264
 265        dprintk(1, "load dpram code\n");
 266        mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
 267
 268        if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 269                printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n");
 270                return -ETIMEDOUT;
 271        }
 272        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 273        msleep(30);     /* the firmware needs some time to initialize */
 274
 275        //ARM_ClearIrq(av7110);
 276        ARM_ResetMailBox(av7110);
 277        SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 278        SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 279
 280        av7110->arm_errors = 0;
 281        av7110->arm_ready = 1;
 282        return 0;
 283}
 284MODULE_FIRMWARE("av7110/bootcode.bin");
 285
 286/****************************************************************************
 287 * DEBI command polling
 288 ****************************************************************************/
 289
 290int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
 291{
 292        unsigned long start;
 293        u32 stat;
 294        int err;
 295
 296        if (FW_VERSION(av7110->arm_app) <= 0x261c) {
 297                /* not supported by old firmware */
 298                msleep(50);
 299                return 0;
 300        }
 301
 302        /* new firmware */
 303        start = jiffies;
 304        for (;;) {
 305                err = time_after(jiffies, start + ARM_WAIT_FREE);
 306                if (mutex_lock_interruptible(&av7110->dcomlock))
 307                        return -ERESTARTSYS;
 308                stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 309                mutex_unlock(&av7110->dcomlock);
 310                if ((stat & flags) == 0)
 311                        break;
 312                if (err) {
 313                        printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
 314                                __func__, stat & flags);
 315                        return -ETIMEDOUT;
 316                }
 317                msleep(1);
 318        }
 319        return 0;
 320}
 321
 322static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 323{
 324        int i;
 325        unsigned long start;
 326        char *type = NULL;
 327        u16 flags[2] = {0, 0};
 328        u32 stat;
 329        int err;
 330
 331//      dprintk(4, "%p\n", av7110);
 332
 333        if (!av7110->arm_ready) {
 334                dprintk(1, "arm not ready.\n");
 335                return -ENXIO;
 336        }
 337
 338        start = jiffies;
 339        while (1) {
 340                err = time_after(jiffies, start + ARM_WAIT_FREE);
 341                if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 342                        break;
 343                if (err) {
 344                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
 345                        av7110->arm_errors++;
 346                        return -ETIMEDOUT;
 347                }
 348                msleep(1);
 349        }
 350
 351        if (FW_VERSION(av7110->arm_app) <= 0x261f)
 352                wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
 353
 354#ifndef _NOHANDSHAKE
 355        start = jiffies;
 356        while (1) {
 357                err = time_after(jiffies, start + ARM_WAIT_SHAKE);
 358                if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 359                        break;
 360                if (err) {
 361                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
 362                        return -ETIMEDOUT;
 363                }
 364                msleep(1);
 365        }
 366#endif
 367
 368        switch ((buf[0] >> 8) & 0xff) {
 369        case COMTYPE_PIDFILTER:
 370        case COMTYPE_ENCODER:
 371        case COMTYPE_REC_PLAY:
 372        case COMTYPE_MPEGDECODER:
 373                type = "MSG";
 374                flags[0] = GPMQOver;
 375                flags[1] = GPMQFull;
 376                break;
 377        case COMTYPE_OSD:
 378                type = "OSD";
 379                flags[0] = OSDQOver;
 380                flags[1] = OSDQFull;
 381                break;
 382        case COMTYPE_MISC:
 383                if (FW_VERSION(av7110->arm_app) >= 0x261d) {
 384                        type = "MSG";
 385                        flags[0] = GPMQOver;
 386                        flags[1] = GPMQBusy;
 387                }
 388                break;
 389        default:
 390                break;
 391        }
 392
 393        if (type != NULL) {
 394                /* non-immediate COMMAND type */
 395                start = jiffies;
 396                for (;;) {
 397                        err = time_after(jiffies, start + ARM_WAIT_FREE);
 398                        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 399                        if (stat & flags[0]) {
 400                                printk(KERN_ERR "%s: %s QUEUE overflow\n",
 401                                        __func__, type);
 402                                return -1;
 403                        }
 404                        if ((stat & flags[1]) == 0)
 405                                break;
 406                        if (err) {
 407                                printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
 408                                        __func__, type);
 409                                av7110->arm_errors++;
 410                                return -ETIMEDOUT;
 411                        }
 412                        msleep(1);
 413                }
 414        }
 415
 416        for (i = 2; i < length; i++)
 417                wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
 418
 419        if (length)
 420                wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
 421        else
 422                wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
 423
 424        wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
 425
 426        if (FW_VERSION(av7110->arm_app) <= 0x261f)
 427                wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
 428
 429#ifdef COM_DEBUG
 430        start = jiffies;
 431        while (1) {
 432                err = time_after(jiffies, start + ARM_WAIT_FREE);
 433                if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 434                        break;
 435                if (err) {
 436                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
 437                               __func__, (buf[0] >> 8) & 0xff);
 438                        return -ETIMEDOUT;
 439                }
 440                msleep(1);
 441        }
 442
 443        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 444        if (stat & GPMQOver) {
 445                printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
 446                return -ENOSPC;
 447        }
 448        else if (stat & OSDQOver) {
 449                printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
 450                return -ENOSPC;
 451        }
 452#endif
 453
 454        return 0;
 455}
 456
 457static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
 458{
 459        int ret;
 460
 461//      dprintk(4, "%p\n", av7110);
 462
 463        if (!av7110->arm_ready) {
 464                dprintk(1, "arm not ready.\n");
 465                return -1;
 466        }
 467        if (mutex_lock_interruptible(&av7110->dcomlock))
 468                return -ERESTARTSYS;
 469
 470        ret = __av7110_send_fw_cmd(av7110, buf, length);
 471        mutex_unlock(&av7110->dcomlock);
 472        if (ret && ret!=-ERESTARTSYS)
 473                printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
 474                       __func__, ret);
 475        return ret;
 476}
 477
 478int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
 479{
 480        va_list args;
 481        u16 buf[MAX_XFER_SIZE];
 482        int i, ret;
 483
 484//      dprintk(4, "%p\n", av7110);
 485
 486        if (2 + num > ARRAY_SIZE(buf)) {
 487                printk(KERN_WARNING
 488                       "%s: %s len=%d is too big!\n",
 489                       KBUILD_MODNAME, __func__, num);
 490                return -EINVAL;
 491        }
 492
 493        buf[0] = ((type << 8) | com);
 494        buf[1] = num;
 495
 496        if (num) {
 497                va_start(args, num);
 498                for (i = 0; i < num; i++)
 499                        buf[i + 2] = va_arg(args, u32);
 500                va_end(args);
 501        }
 502
 503        ret = av7110_send_fw_cmd(av7110, buf, num + 2);
 504        if (ret && ret != -ERESTARTSYS)
 505                printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
 506        return ret;
 507}
 508
 509#if 0
 510int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
 511{
 512        int i, ret;
 513        u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
 514                16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 515
 516        dprintk(4, "%p\n", av7110);
 517
 518        for(i = 0; i < len && i < 32; i++)
 519        {
 520                if(i % 2 == 0)
 521                        cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
 522                else
 523                        cmd[(i / 2) + 2] |= buf[i];
 524        }
 525
 526        ret = av7110_send_fw_cmd(av7110, cmd, 18);
 527        if (ret && ret != -ERESTARTSYS)
 528                printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
 529        return ret;
 530}
 531#endif  /*  0  */
 532
 533int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
 534                      int request_buf_len, u16 *reply_buf, int reply_buf_len)
 535{
 536        int err;
 537        s16 i;
 538        unsigned long start;
 539#ifdef COM_DEBUG
 540        u32 stat;
 541#endif
 542
 543        dprintk(4, "%p\n", av7110);
 544
 545        if (!av7110->arm_ready) {
 546                dprintk(1, "arm not ready.\n");
 547                return -1;
 548        }
 549
 550        if (mutex_lock_interruptible(&av7110->dcomlock))
 551                return -ERESTARTSYS;
 552
 553        if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
 554                mutex_unlock(&av7110->dcomlock);
 555                printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
 556                return err;
 557        }
 558
 559        start = jiffies;
 560        while (1) {
 561                err = time_after(jiffies, start + ARM_WAIT_FREE);
 562                if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 563                        break;
 564                if (err) {
 565                        printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
 566                        mutex_unlock(&av7110->dcomlock);
 567                        return -ETIMEDOUT;
 568                }
 569#ifdef _NOHANDSHAKE
 570                msleep(1);
 571#endif
 572        }
 573
 574#ifndef _NOHANDSHAKE
 575        start = jiffies;
 576        while (1) {
 577                err = time_after(jiffies, start + ARM_WAIT_SHAKE);
 578                if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 579                        break;
 580                if (err) {
 581                        printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
 582                        mutex_unlock(&av7110->dcomlock);
 583                        return -ETIMEDOUT;
 584                }
 585                msleep(1);
 586        }
 587#endif
 588
 589#ifdef COM_DEBUG
 590        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 591        if (stat & GPMQOver) {
 592                printk(KERN_ERR "%s: GPMQOver\n", __func__);
 593                mutex_unlock(&av7110->dcomlock);
 594                return -1;
 595        }
 596        else if (stat & OSDQOver) {
 597                printk(KERN_ERR "%s: OSDQOver\n", __func__);
 598                mutex_unlock(&av7110->dcomlock);
 599                return -1;
 600        }
 601#endif
 602
 603        for (i = 0; i < reply_buf_len; i++)
 604                reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 605
 606        mutex_unlock(&av7110->dcomlock);
 607        return 0;
 608}
 609
 610static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
 611{
 612        int ret;
 613        ret = av7110_fw_request(av7110, &tag, 0, buf, length);
 614        if (ret)
 615                printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
 616        return ret;
 617}
 618
 619
 620/****************************************************************************
 621 * Firmware commands
 622 ****************************************************************************/
 623
 624/* get version of the firmware ROM, RTSL, video ucode and ARM application  */
 625int av7110_firmversion(struct av7110 *av7110)
 626{
 627        u16 buf[20];
 628        u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
 629
 630        dprintk(4, "%p\n", av7110);
 631
 632        if (av7110_fw_query(av7110, tag, buf, 16)) {
 633                printk("dvb-ttpci: failed to boot firmware @ card %d\n",
 634                       av7110->dvb_adapter.num);
 635                return -EIO;
 636        }
 637
 638        av7110->arm_fw = (buf[0] << 16) + buf[1];
 639        av7110->arm_rtsl = (buf[2] << 16) + buf[3];
 640        av7110->arm_vid = (buf[4] << 16) + buf[5];
 641        av7110->arm_app = (buf[6] << 16) + buf[7];
 642        av7110->avtype = (buf[8] << 16) + buf[9];
 643
 644        printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
 645               av7110->dvb_adapter.num, av7110->arm_fw,
 646               av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
 647
 648        /* print firmware capabilities */
 649        if (FW_CI_LL_SUPPORT(av7110->arm_app))
 650                printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
 651                       av7110->dvb_adapter.num);
 652        else
 653                printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
 654                       av7110->dvb_adapter.num);
 655
 656        return 0;
 657}
 658
 659
 660int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
 661{
 662        int i, ret;
 663        u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
 664                        16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 665
 666        dprintk(4, "%p\n", av7110);
 667
 668        if (len > 10)
 669                len = 10;
 670
 671        buf[1] = len + 2;
 672        buf[2] = len;
 673
 674        if (burst != -1)
 675                buf[3] = burst ? 0x01 : 0x00;
 676        else
 677                buf[3] = 0xffff;
 678
 679        for (i = 0; i < len; i++)
 680                buf[i + 4] = msg[i];
 681
 682        ret = av7110_send_fw_cmd(av7110, buf, 18);
 683        if (ret && ret!=-ERESTARTSYS)
 684                printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
 685        return ret;
 686}
 687
 688
 689#ifdef CONFIG_DVB_AV7110_OSD
 690
 691static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
 692{
 693        return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
 694}
 695
 696static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
 697                     enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
 698{
 699        return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
 700                             windownr, colordepth, index, blending);
 701}
 702
 703static inline int SetColor_(struct av7110 *av7110, u8 windownr,
 704                     enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
 705{
 706        return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
 707                             windownr, colordepth, index, colorhi, colorlo);
 708}
 709
 710static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
 711                          u16 colorfg, u16 colorbg)
 712{
 713        return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
 714                             windownr, fontsize, colorfg, colorbg);
 715}
 716
 717static int FlushText(struct av7110 *av7110)
 718{
 719        unsigned long start;
 720        int err;
 721
 722        if (mutex_lock_interruptible(&av7110->dcomlock))
 723                return -ERESTARTSYS;
 724        start = jiffies;
 725        while (1) {
 726                err = time_after(jiffies, start + ARM_WAIT_OSD);
 727                if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
 728                        break;
 729                if (err) {
 730                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
 731                               __func__);
 732                        mutex_unlock(&av7110->dcomlock);
 733                        return -ETIMEDOUT;
 734                }
 735                msleep(1);
 736        }
 737        mutex_unlock(&av7110->dcomlock);
 738        return 0;
 739}
 740
 741static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
 742{
 743        int i, ret;
 744        unsigned long start;
 745        int length = strlen(buf) + 1;
 746        u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 747
 748        if (mutex_lock_interruptible(&av7110->dcomlock))
 749                return -ERESTARTSYS;
 750
 751        start = jiffies;
 752        while (1) {
 753                ret = time_after(jiffies, start + ARM_WAIT_OSD);
 754                if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
 755                        break;
 756                if (ret) {
 757                        printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
 758                               __func__);
 759                        mutex_unlock(&av7110->dcomlock);
 760                        return -ETIMEDOUT;
 761                }
 762                msleep(1);
 763        }
 764#ifndef _NOHANDSHAKE
 765        start = jiffies;
 766        while (1) {
 767                ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
 768                if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 769                        break;
 770                if (ret) {
 771                        printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
 772                               __func__);
 773                        mutex_unlock(&av7110->dcomlock);
 774                        return -ETIMEDOUT;
 775                }
 776                msleep(1);
 777        }
 778#endif
 779        for (i = 0; i < length / 2; i++)
 780                wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
 781                      swab16(*(u16 *)(buf + 2 * i)), 2);
 782        if (length & 1)
 783                wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
 784        ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
 785        mutex_unlock(&av7110->dcomlock);
 786        if (ret && ret!=-ERESTARTSYS)
 787                printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
 788        return ret;
 789}
 790
 791static inline int DrawLine(struct av7110 *av7110, u8 windownr,
 792                           u16 x, u16 y, u16 dx, u16 dy, u16 color)
 793{
 794        return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
 795                             windownr, x, y, dx, dy, color);
 796}
 797
 798static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
 799                            u16 x, u16 y, u16 dx, u16 dy, u16 color)
 800{
 801        return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
 802                             windownr, x, y, dx, dy, color);
 803}
 804
 805static inline int HideWindow(struct av7110 *av7110, u8 windownr)
 806{
 807        return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
 808}
 809
 810static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
 811{
 812        return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
 813}
 814
 815static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
 816{
 817        return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
 818}
 819
 820static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
 821{
 822        return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
 823}
 824
 825static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
 826                                  osd_raw_window_t disptype,
 827                                  u16 width, u16 height)
 828{
 829        return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
 830                             windownr, disptype, width, height);
 831}
 832
 833
 834static enum av7110_osd_palette_type bpp2pal[8] = {
 835        Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
 836};
 837static osd_raw_window_t bpp2bit[8] = {
 838        OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
 839};
 840
 841static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
 842{
 843        int ret = wait_event_timeout(av7110->bmpq,
 844                                av7110->bmp_state != BMP_LOADING, 10*HZ);
 845        if (ret == 0) {
 846                printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
 847                       ret, av7110->bmp_state);
 848                av7110->bmp_state = BMP_NONE;
 849                return -ETIMEDOUT;
 850        }
 851        return 0;
 852}
 853
 854static inline int LoadBitmap(struct av7110 *av7110,
 855                             u16 dx, u16 dy, int inc, u8 __user * data)
 856{
 857        u16 format;
 858        int bpp;
 859        int i;
 860        int d, delta;
 861        u8 c;
 862        int ret;
 863
 864        dprintk(4, "%p\n", av7110);
 865
 866        format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
 867
 868        av7110->bmp_state = BMP_LOADING;
 869        if      (format == OSD_BITMAP8) {
 870                bpp=8; delta = 1;
 871        } else if (format == OSD_BITMAP4) {
 872                bpp=4; delta = 2;
 873        } else if (format == OSD_BITMAP2) {
 874                bpp=2; delta = 4;
 875        } else if (format == OSD_BITMAP1) {
 876                bpp=1; delta = 8;
 877        } else {
 878                av7110->bmp_state = BMP_NONE;
 879                return -EINVAL;
 880        }
 881        av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
 882        av7110->bmpp = 0;
 883        if (av7110->bmplen > 32768) {
 884                av7110->bmp_state = BMP_NONE;
 885                return -EINVAL;
 886        }
 887        for (i = 0; i < dy; i++) {
 888                if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
 889                        av7110->bmp_state = BMP_NONE;
 890                        return -EINVAL;
 891                }
 892        }
 893        if (format != OSD_BITMAP8) {
 894                for (i = 0; i < dx * dy / delta; i++) {
 895                        c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
 896                        for (d = delta - 2; d >= 0; d--) {
 897                                c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
 898                                      << ((delta - d - 1) * bpp));
 899                                ((u8 *)av7110->bmpbuf)[1024 + i] = c;
 900                        }
 901                }
 902        }
 903        av7110->bmplen += 1024;
 904        dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
 905        ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
 906        if (!ret)
 907                ret = WaitUntilBmpLoaded(av7110);
 908        return ret;
 909}
 910
 911static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
 912{
 913        dprintk(4, "%p\n", av7110);
 914
 915        return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
 916}
 917
 918static inline int ReleaseBitmap(struct av7110 *av7110)
 919{
 920        dprintk(4, "%p\n", av7110);
 921
 922        if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
 923                return -1;
 924        if (av7110->bmp_state == BMP_LOADING)
 925                dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
 926        av7110->bmp_state = BMP_NONE;
 927        return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
 928}
 929
 930static u32 RGB2YUV(u16 R, u16 G, u16 B)
 931{
 932        u16 y, u, v;
 933        u16 Y, Cr, Cb;
 934
 935        y = R * 77 + G * 150 + B * 29;  /* Luma=0.299R+0.587G+0.114B 0..65535 */
 936        u = 2048 + B * 8 -(y >> 5);     /* Cr 0..4095 */
 937        v = 2048 + R * 8 -(y >> 5);     /* Cb 0..4095 */
 938
 939        Y = y / 256;
 940        Cb = u / 16;
 941        Cr = v / 16;
 942
 943        return Cr | (Cb << 16) | (Y << 8);
 944}
 945
 946static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
 947{
 948        int ret;
 949
 950        u16 ch, cl;
 951        u32 yuv;
 952
 953        yuv = blend ? RGB2YUV(r,g,b) : 0;
 954        cl = (yuv & 0xffff);
 955        ch = ((yuv >> 16) & 0xffff);
 956        ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
 957                        color, ch, cl);
 958        if (!ret)
 959                ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
 960                                color, ((blend >> 4) & 0x0f));
 961        return ret;
 962}
 963
 964static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
 965{
 966        int i;
 967        int length = last - first + 1;
 968
 969        if (length * 4 > DATA_BUFF3_SIZE)
 970                return -EINVAL;
 971
 972        for (i = 0; i < length; i++) {
 973                u32 color, blend, yuv;
 974
 975                if (get_user(color, colors + i))
 976                        return -EFAULT;
 977                blend = (color & 0xF0000000) >> 4;
 978                yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
 979                                     (color >> 16) & 0xFF) | blend : 0;
 980                yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
 981                wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
 982        }
 983        return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
 984                            av7110->osdwin,
 985                            bpp2pal[av7110->osdbpp[av7110->osdwin]],
 986                            first, last);
 987}
 988
 989static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
 990                       int x1, int y1, int inc, u8 __user * data)
 991{
 992        uint w, h, bpp, bpl, size, lpb, bnum, brest;
 993        int i;
 994        int rc,release_rc;
 995
 996        w = x1 - x0 + 1;
 997        h = y1 - y0 + 1;
 998        if (inc <= 0)
 999                inc = w;
1000        if (w <= 0 || w > 720 || h <= 0 || h > 576)
1001                return -EINVAL;
1002        bpp = av7110->osdbpp[av7110->osdwin] + 1;
1003        bpl = ((w * bpp + 7) & ~7) / 8;
1004        size = h * bpl;
1005        lpb = (32 * 1024) / bpl;
1006        bnum = size / (lpb * bpl);
1007        brest = size - bnum * lpb * bpl;
1008
1009        if (av7110->bmp_state == BMP_LOADING) {
1010                /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1011                BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1012                rc = WaitUntilBmpLoaded(av7110);
1013                if (rc)
1014                        return rc;
1015                /* just continue. This should work for all fw versions
1016                 * if bnum==1 && !brest && LoadBitmap was successful
1017                 */
1018        }
1019
1020        rc = 0;
1021        for (i = 0; i < bnum; i++) {
1022                rc = LoadBitmap(av7110, w, lpb, inc, data);
1023                if (rc)
1024                        break;
1025                rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1026                if (rc)
1027                        break;
1028                data += lpb * inc;
1029        }
1030        if (!rc && brest) {
1031                rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1032                if (!rc)
1033                        rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1034        }
1035        release_rc = ReleaseBitmap(av7110);
1036        if (!rc)
1037                rc = release_rc;
1038        if (rc)
1039                dprintk(1,"returns %d\n",rc);
1040        return rc;
1041}
1042
1043int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1044{
1045        int ret;
1046
1047        if (mutex_lock_interruptible(&av7110->osd_mutex))
1048                return -ERESTARTSYS;
1049
1050        switch (dc->cmd) {
1051        case OSD_Close:
1052                ret = DestroyOSDWindow(av7110, av7110->osdwin);
1053                break;
1054        case OSD_Open:
1055                av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1056                ret = CreateOSDWindow(av7110, av7110->osdwin,
1057                                bpp2bit[av7110->osdbpp[av7110->osdwin]],
1058                                dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1059                if (ret)
1060                        break;
1061                if (!dc->data) {
1062                        ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1063                        if (ret)
1064                                break;
1065                        ret = SetColorBlend(av7110, av7110->osdwin);
1066                }
1067                break;
1068        case OSD_Show:
1069                ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1070                break;
1071        case OSD_Hide:
1072                ret = HideWindow(av7110, av7110->osdwin);
1073                break;
1074        case OSD_Clear:
1075                ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1076                break;
1077        case OSD_Fill:
1078                ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1079                break;
1080        case OSD_SetColor:
1081                ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1082                break;
1083        case OSD_SetPalette:
1084                if (FW_VERSION(av7110->arm_app) >= 0x2618)
1085                        ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1086                else {
1087                        int i, len = dc->x0-dc->color+1;
1088                        u8 __user *colors = (u8 __user *)dc->data;
1089                        u8 r, g = 0, b = 0, blend = 0;
1090                        ret = 0;
1091                        for (i = 0; i<len; i++) {
1092                                if (get_user(r, colors + i * 4) ||
1093                                    get_user(g, colors + i * 4 + 1) ||
1094                                    get_user(b, colors + i * 4 + 2) ||
1095                                    get_user(blend, colors + i * 4 + 3)) {
1096                                        ret = -EFAULT;
1097                                        break;
1098                                    }
1099                                ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1100                                if (ret)
1101                                        break;
1102                        }
1103                }
1104                break;
1105        case OSD_SetPixel:
1106                ret = DrawLine(av7110, av7110->osdwin,
1107                         dc->x0, dc->y0, 0, 0, dc->color);
1108                break;
1109        case OSD_SetRow:
1110                dc->y1 = dc->y0;
1111                /* fall through */
1112        case OSD_SetBlock:
1113                ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1114                break;
1115        case OSD_FillRow:
1116                ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1117                          dc->x1-dc->x0+1, dc->y1, dc->color);
1118                break;
1119        case OSD_FillBlock:
1120                ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1121                          dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1122                break;
1123        case OSD_Line:
1124                ret = DrawLine(av7110, av7110->osdwin,
1125                         dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1126                break;
1127        case OSD_Text:
1128        {
1129                char textbuf[240];
1130
1131                if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1132                        ret = -EFAULT;
1133                        break;
1134                }
1135                textbuf[239] = 0;
1136                if (dc->x1 > 3)
1137                        dc->x1 = 3;
1138                ret = SetFont(av7110, av7110->osdwin, dc->x1,
1139                        (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1140                if (!ret)
1141                        ret = FlushText(av7110);
1142                if (!ret)
1143                        ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1144                break;
1145        }
1146        case OSD_SetWindow:
1147                if (dc->x0 < 1 || dc->x0 > 7)
1148                        ret = -EINVAL;
1149                else {
1150                        av7110->osdwin = dc->x0;
1151                        ret = 0;
1152                }
1153                break;
1154        case OSD_MoveWindow:
1155                ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1156                if (!ret)
1157                        ret = SetColorBlend(av7110, av7110->osdwin);
1158                break;
1159        case OSD_OpenRaw:
1160                if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1161                        ret = -EINVAL;
1162                        break;
1163                }
1164                if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1165                        av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1166                else
1167                        av7110->osdbpp[av7110->osdwin] = 0;
1168                ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1169                                dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1170                if (ret)
1171                        break;
1172                if (!dc->data) {
1173                        ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1174                        if (!ret)
1175                                ret = SetColorBlend(av7110, av7110->osdwin);
1176                }
1177                break;
1178        default:
1179                ret = -EINVAL;
1180                break;
1181        }
1182
1183        mutex_unlock(&av7110->osd_mutex);
1184        if (ret==-ERESTARTSYS)
1185                dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1186        else if (ret)
1187                dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1188
1189        return ret;
1190}
1191
1192int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1193{
1194        switch (cap->cmd) {
1195        case OSD_CAP_MEMSIZE:
1196                if (FW_4M_SDRAM(av7110->arm_app))
1197                        cap->val = 1000000;
1198                else
1199                        cap->val = 92000;
1200                return 0;
1201        default:
1202                return -EINVAL;
1203        }
1204}
1205#endif /* CONFIG_DVB_AV7110_OSD */
1206