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