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