Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / drivers / media / dvb / ttpci / av7110_hw.c
bloba468aa2e485475ba5583765b0e643781943f4ae1
1 /*
2 * av7110_hw.c: av7110 low level hardware access and firmware interface
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
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.
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.
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
25 * the project's page is at http://www.linuxtv.org/dvb/
28 /* for debugging ARM communication: */
29 //#define COM_DEBUG
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>
38 #include "av7110.h"
39 #include "av7110_hw.h"
41 #define _NOHANDSHAKE
43 /****************************************************************************
44 * DEBI functions
45 ****************************************************************************/
47 /* This DEBI code is based on the Stradis driver
48 by Nathan Laredo <laredo@gnu.org> */
50 int av7110_debiwrite(struct av7110 *av7110, u32 config,
51 int addr, u32 val, int count)
53 struct saa7146_dev *dev = av7110->dev;
55 if (count <= 0 || count > 32764) {
56 printk("%s: invalid count %d\n", __FUNCTION__, count);
57 return -1;
59 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
60 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
61 return -1;
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;
73 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
75 struct saa7146_dev *dev = av7110->dev;
76 u32 result = 0;
78 if (count > 32764 || count <= 0) {
79 printk("%s: invalid count %d\n", __FUNCTION__, count);
80 return 0;
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;
86 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
87 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
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;
98 result = saa7146_read(dev, DEBI_AD);
99 result &= (0xffffffffUL >> ((4 - count) * 8));
100 return result;
105 /* av7110 ARM core boot stuff */
106 #if 0
107 void av7110_reset_arm(struct av7110 *av7110)
109 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
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);
115 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
116 msleep(30); /* the firmware needs some time to initialize */
118 ARM_ResetMailBox(av7110);
120 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
121 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
123 av7110->arm_ready = 1;
124 dprintk(1, "reset ARM\n");
126 #endif /* 0 */
128 static int waitdebi(struct av7110 *av7110, int adr, int state)
130 int k;
132 dprintk(4, "%p\n", av7110);
134 for (k = 0; k < 100; k++) {
135 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
136 return 0;
137 udelay(5);
139 return -ETIMEDOUT;
142 static int load_dram(struct av7110 *av7110, u32 *data, int len)
144 int i;
145 int blocks, rest;
146 u32 base, bootblock = AV7110_BOOT_BLOCK;
148 dprintk(4, "%p\n", av7110);
150 blocks = len / AV7110_BOOT_MAX_SIZE;
151 rest = len % AV7110_BOOT_MAX_SIZE;
152 base = DRAM_START_CODE;
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;
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;
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;
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);
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);
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;
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;
195 return 0;
199 /* we cannot write av7110 DRAM directly, so load a bootloader into
200 * the DPRAM which implements a simple boot protocol */
201 static u8 bootcode[] = {
202 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
203 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
204 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
205 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
206 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
207 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
208 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
209 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
210 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
211 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
212 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
213 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
214 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
215 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
216 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
217 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
218 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
219 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
222 int av7110_bootarm(struct av7110 *av7110)
224 struct saa7146_dev *dev = av7110->dev;
225 u32 ret;
226 int i;
228 dprintk(4, "%p\n", av7110);
230 av7110->arm_ready = 0;
232 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
234 /* Disable DEBI and GPIO irq */
235 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
236 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
238 /* enable DEBI */
239 saa7146_write(av7110->dev, MC1, 0x08800880);
240 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
241 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
243 /* test DEBI */
244 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
245 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
246 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
248 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
249 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
250 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
251 ret, 0x10325476);
252 return -1;
254 for (i = 0; i < 8192; i += 4)
255 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
256 dprintk(2, "debi test OK\n");
258 /* boot */
259 dprintk(1, "load boot code\n");
260 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
261 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
262 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
264 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
265 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
267 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
268 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
269 "saa7146_wait_for_debi_done() timed out\n");
270 return -ETIMEDOUT;
272 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
273 mdelay(1);
275 dprintk(1, "load dram code\n");
276 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
277 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
278 "load_dram() failed\n");
279 return -1;
282 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
283 mdelay(1);
285 dprintk(1, "load dpram code\n");
286 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
288 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
289 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
290 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
291 return -ETIMEDOUT;
293 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
294 msleep(30); /* the firmware needs some time to initialize */
296 //ARM_ClearIrq(av7110);
297 ARM_ResetMailBox(av7110);
298 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
299 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
301 av7110->arm_errors = 0;
302 av7110->arm_ready = 1;
303 return 0;
307 /****************************************************************************
308 * DEBI command polling
309 ****************************************************************************/
311 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
313 unsigned long start;
314 u32 stat;
315 int err;
317 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
318 /* not supported by old firmware */
319 msleep(50);
320 return 0;
323 /* new firmware */
324 start = jiffies;
325 for (;;) {
326 err = time_after(jiffies, start + ARM_WAIT_FREE);
327 if (mutex_lock_interruptible(&av7110->dcomlock))
328 return -ERESTARTSYS;
329 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
330 mutex_unlock(&av7110->dcomlock);
331 if ((stat & flags) == 0)
332 break;
333 if (err) {
334 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
335 __FUNCTION__, stat & flags);
336 return -ETIMEDOUT;
338 msleep(1);
340 return 0;
343 static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
345 int i;
346 unsigned long start;
347 char *type = NULL;
348 u16 flags[2] = {0, 0};
349 u32 stat;
350 int err;
352 // dprintk(4, "%p\n", av7110);
354 if (!av7110->arm_ready) {
355 dprintk(1, "arm not ready.\n");
356 return -ENXIO;
359 start = jiffies;
360 while (1) {
361 err = time_after(jiffies, start + ARM_WAIT_FREE);
362 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
363 break;
364 if (err) {
365 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
366 av7110->arm_errors++;
367 return -ETIMEDOUT;
369 msleep(1);
372 if (FW_VERSION(av7110->arm_app) <= 0x261f)
373 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
375 #ifndef _NOHANDSHAKE
376 start = jiffies;
377 while (1) {
378 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
379 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
380 break;
381 if (err) {
382 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
383 return -ETIMEDOUT;
385 msleep(1);
387 #endif
389 switch ((buf[0] >> 8) & 0xff) {
390 case COMTYPE_PIDFILTER:
391 case COMTYPE_ENCODER:
392 case COMTYPE_REC_PLAY:
393 case COMTYPE_MPEGDECODER:
394 type = "MSG";
395 flags[0] = GPMQOver;
396 flags[1] = GPMQFull;
397 break;
398 case COMTYPE_OSD:
399 type = "OSD";
400 flags[0] = OSDQOver;
401 flags[1] = OSDQFull;
402 break;
403 case COMTYPE_MISC:
404 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
405 type = "MSG";
406 flags[0] = GPMQOver;
407 flags[1] = GPMQBusy;
409 break;
410 default:
411 break;
414 if (type != NULL) {
415 /* non-immediate COMMAND type */
416 start = jiffies;
417 for (;;) {
418 err = time_after(jiffies, start + ARM_WAIT_FREE);
419 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
420 if (stat & flags[0]) {
421 printk(KERN_ERR "%s: %s QUEUE overflow\n",
422 __FUNCTION__, type);
423 return -1;
425 if ((stat & flags[1]) == 0)
426 break;
427 if (err) {
428 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
429 __FUNCTION__, type);
430 return -ETIMEDOUT;
432 msleep(1);
436 for (i = 2; i < length; i++)
437 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
439 if (length)
440 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
441 else
442 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
444 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
446 if (FW_VERSION(av7110->arm_app) <= 0x261f)
447 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
449 #ifdef COM_DEBUG
450 start = jiffies;
451 while (1) {
452 err = time_after(jiffies, start + ARM_WAIT_FREE);
453 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
454 break;
455 if (err) {
456 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
457 __FUNCTION__, (buf[0] >> 8) & 0xff);
458 return -ETIMEDOUT;
460 msleep(1);
463 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
464 if (stat & GPMQOver) {
465 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
466 return -ENOSPC;
468 else if (stat & OSDQOver) {
469 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
470 return -ENOSPC;
472 #endif
474 return 0;
477 static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
479 int ret;
481 // dprintk(4, "%p\n", av7110);
483 if (!av7110->arm_ready) {
484 dprintk(1, "arm not ready.\n");
485 return -1;
487 if (mutex_lock_interruptible(&av7110->dcomlock))
488 return -ERESTARTSYS;
490 ret = __av7110_send_fw_cmd(av7110, buf, length);
491 mutex_unlock(&av7110->dcomlock);
492 if (ret && ret!=-ERESTARTSYS)
493 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
494 __FUNCTION__, ret);
495 return ret;
498 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
500 va_list args;
501 u16 buf[num + 2];
502 int i, ret;
504 // dprintk(4, "%p\n", av7110);
506 buf[0] = ((type << 8) | com);
507 buf[1] = num;
509 if (num) {
510 va_start(args, num);
511 for (i = 0; i < num; i++)
512 buf[i + 2] = va_arg(args, u32);
513 va_end(args);
516 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
517 if (ret && ret != -ERESTARTSYS)
518 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
519 return ret;
522 #if 0
523 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
525 int i, ret;
526 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
527 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
529 dprintk(4, "%p\n", av7110);
531 for(i = 0; i < len && i < 32; i++)
533 if(i % 2 == 0)
534 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
535 else
536 cmd[(i / 2) + 2] |= buf[i];
539 ret = av7110_send_fw_cmd(av7110, cmd, 18);
540 if (ret && ret != -ERESTARTSYS)
541 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
542 return ret;
544 #endif /* 0 */
546 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
547 int request_buf_len, u16 *reply_buf, int reply_buf_len)
549 int err;
550 s16 i;
551 unsigned long start;
552 #ifdef COM_DEBUG
553 u32 stat;
554 #endif
556 dprintk(4, "%p\n", av7110);
558 if (!av7110->arm_ready) {
559 dprintk(1, "arm not ready.\n");
560 return -1;
563 if (mutex_lock_interruptible(&av7110->dcomlock))
564 return -ERESTARTSYS;
566 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
567 mutex_unlock(&av7110->dcomlock);
568 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
569 return err;
572 start = jiffies;
573 while (1) {
574 err = time_after(jiffies, start + ARM_WAIT_FREE);
575 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
576 break;
577 if (err) {
578 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
579 mutex_unlock(&av7110->dcomlock);
580 return -ETIMEDOUT;
582 #ifdef _NOHANDSHAKE
583 msleep(1);
584 #endif
587 #ifndef _NOHANDSHAKE
588 start = jiffies;
589 while (1) {
590 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
591 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
592 break;
593 if (err) {
594 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
595 mutex_unlock(&av7110->dcomlock);
596 return -ETIMEDOUT;
598 msleep(1);
600 #endif
602 #ifdef COM_DEBUG
603 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
604 if (stat & GPMQOver) {
605 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
606 mutex_unlock(&av7110->dcomlock);
607 return -1;
609 else if (stat & OSDQOver) {
610 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
611 mutex_unlock(&av7110->dcomlock);
612 return -1;
614 #endif
616 for (i = 0; i < reply_buf_len; i++)
617 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
619 mutex_unlock(&av7110->dcomlock);
620 return 0;
623 static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
625 int ret;
626 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
627 if (ret)
628 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
629 return ret;
633 /****************************************************************************
634 * Firmware commands
635 ****************************************************************************/
637 /* get version of the firmware ROM, RTSL, video ucode and ARM application */
638 int av7110_firmversion(struct av7110 *av7110)
640 u16 buf[20];
641 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
643 dprintk(4, "%p\n", av7110);
645 if (av7110_fw_query(av7110, tag, buf, 16)) {
646 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
647 av7110->dvb_adapter.num);
648 return -EIO;
651 av7110->arm_fw = (buf[0] << 16) + buf[1];
652 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
653 av7110->arm_vid = (buf[4] << 16) + buf[5];
654 av7110->arm_app = (buf[6] << 16) + buf[7];
655 av7110->avtype = (buf[8] << 16) + buf[9];
657 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
658 av7110->dvb_adapter.num, av7110->arm_fw,
659 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
661 /* print firmware capabilities */
662 if (FW_CI_LL_SUPPORT(av7110->arm_app))
663 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
664 av7110->dvb_adapter.num);
665 else
666 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
667 av7110->dvb_adapter.num);
669 return 0;
673 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
675 int i, ret;
676 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
677 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
679 dprintk(4, "%p\n", av7110);
681 if (len > 10)
682 len = 10;
684 buf[1] = len + 2;
685 buf[2] = len;
687 if (burst != -1)
688 buf[3] = burst ? 0x01 : 0x00;
689 else
690 buf[3] = 0xffff;
692 for (i = 0; i < len; i++)
693 buf[i + 4] = msg[i];
695 ret = av7110_send_fw_cmd(av7110, buf, 18);
696 if (ret && ret!=-ERESTARTSYS)
697 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
698 return ret;
702 #ifdef CONFIG_DVB_AV7110_OSD
704 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
706 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
709 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
710 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
712 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
713 windownr, colordepth, index, blending);
716 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
717 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
719 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
720 windownr, colordepth, index, colorhi, colorlo);
723 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
724 u16 colorfg, u16 colorbg)
726 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
727 windownr, fontsize, colorfg, colorbg);
730 static int FlushText(struct av7110 *av7110)
732 unsigned long start;
733 int err;
735 if (mutex_lock_interruptible(&av7110->dcomlock))
736 return -ERESTARTSYS;
737 start = jiffies;
738 while (1) {
739 err = time_after(jiffies, start + ARM_WAIT_OSD);
740 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
741 break;
742 if (err) {
743 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
744 __FUNCTION__);
745 mutex_unlock(&av7110->dcomlock);
746 return -ETIMEDOUT;
748 msleep(1);
750 mutex_unlock(&av7110->dcomlock);
751 return 0;
754 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
756 int i, ret;
757 unsigned long start;
758 int length = strlen(buf) + 1;
759 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
761 if (mutex_lock_interruptible(&av7110->dcomlock))
762 return -ERESTARTSYS;
764 start = jiffies;
765 while (1) {
766 ret = time_after(jiffies, start + ARM_WAIT_OSD);
767 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
768 break;
769 if (ret) {
770 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
771 __FUNCTION__);
772 mutex_unlock(&av7110->dcomlock);
773 return -ETIMEDOUT;
775 msleep(1);
777 #ifndef _NOHANDSHAKE
778 start = jiffies;
779 while (1) {
780 ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
781 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
782 break;
783 if (ret) {
784 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
785 __FUNCTION__);
786 mutex_unlock(&av7110->dcomlock);
787 return -ETIMEDOUT;
789 msleep(1);
791 #endif
792 for (i = 0; i < length / 2; i++)
793 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
794 swab16(*(u16 *)(buf + 2 * i)), 2);
795 if (length & 1)
796 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
797 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
798 mutex_unlock(&av7110->dcomlock);
799 if (ret && ret!=-ERESTARTSYS)
800 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
801 return ret;
804 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
805 u16 x, u16 y, u16 dx, u16 dy, u16 color)
807 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
808 windownr, x, y, dx, dy, color);
811 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
812 u16 x, u16 y, u16 dx, u16 dy, u16 color)
814 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
815 windownr, x, y, dx, dy, color);
818 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
820 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
823 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
825 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
828 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
830 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
833 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
835 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
838 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
839 osd_raw_window_t disptype,
840 u16 width, u16 height)
842 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
843 windownr, disptype, width, height);
847 static enum av7110_osd_palette_type bpp2pal[8] = {
848 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
850 static osd_raw_window_t bpp2bit[8] = {
851 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
854 static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
856 int ret = wait_event_interruptible_timeout(av7110->bmpq,
857 av7110->bmp_state != BMP_LOADING, 10*HZ);
858 if (ret == -ERESTARTSYS)
859 return ret;
860 if (ret == 0) {
861 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
862 ret, av7110->bmp_state);
863 av7110->bmp_state = BMP_NONE;
864 return -ETIMEDOUT;
866 return 0;
869 static inline int LoadBitmap(struct av7110 *av7110,
870 u16 dx, u16 dy, int inc, u8 __user * data)
872 u16 format;
873 int bpp;
874 int i;
875 int d, delta;
876 u8 c;
877 int ret;
879 dprintk(4, "%p\n", av7110);
881 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
883 av7110->bmp_state = BMP_LOADING;
884 if (format == OSD_BITMAP8) {
885 bpp=8; delta = 1;
886 } else if (format == OSD_BITMAP4) {
887 bpp=4; delta = 2;
888 } else if (format == OSD_BITMAP2) {
889 bpp=2; delta = 4;
890 } else if (format == OSD_BITMAP1) {
891 bpp=1; delta = 8;
892 } else {
893 av7110->bmp_state = BMP_NONE;
894 return -EINVAL;
896 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
897 av7110->bmpp = 0;
898 if (av7110->bmplen > 32768) {
899 av7110->bmp_state = BMP_NONE;
900 return -EINVAL;
902 for (i = 0; i < dy; i++) {
903 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
904 av7110->bmp_state = BMP_NONE;
905 return -EINVAL;
908 if (format != OSD_BITMAP8) {
909 for (i = 0; i < dx * dy / delta; i++) {
910 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
911 for (d = delta - 2; d >= 0; d--) {
912 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
913 << ((delta - d - 1) * bpp));
914 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
918 av7110->bmplen += 1024;
919 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
920 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
921 if (!ret)
922 ret = WaitUntilBmpLoaded(av7110);
923 return ret;
926 static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
928 dprintk(4, "%p\n", av7110);
930 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
933 static inline int ReleaseBitmap(struct av7110 *av7110)
935 dprintk(4, "%p\n", av7110);
937 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
938 return -1;
939 if (av7110->bmp_state == BMP_LOADING)
940 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
941 av7110->bmp_state = BMP_NONE;
942 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
945 static u32 RGB2YUV(u16 R, u16 G, u16 B)
947 u16 y, u, v;
948 u16 Y, Cr, Cb;
950 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
951 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
952 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
954 Y = y / 256;
955 Cb = u / 16;
956 Cr = v / 16;
958 return Cr | (Cb << 16) | (Y << 8);
961 static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
963 int ret;
965 u16 ch, cl;
966 u32 yuv;
968 yuv = blend ? RGB2YUV(r,g,b) : 0;
969 cl = (yuv & 0xffff);
970 ch = ((yuv >> 16) & 0xffff);
971 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
972 color, ch, cl);
973 if (!ret)
974 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
975 color, ((blend >> 4) & 0x0f));
976 return ret;
979 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
981 int i;
982 int length = last - first + 1;
984 if (length * 4 > DATA_BUFF3_SIZE)
985 return -EINVAL;
987 for (i = 0; i < length; i++) {
988 u32 color, blend, yuv;
990 if (get_user(color, colors + i))
991 return -EFAULT;
992 blend = (color & 0xF0000000) >> 4;
993 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
994 (color >> 16) & 0xFF) | blend : 0;
995 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
996 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
998 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
999 av7110->osdwin,
1000 bpp2pal[av7110->osdbpp[av7110->osdwin]],
1001 first, last);
1004 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
1005 int x1, int y1, int inc, u8 __user * data)
1007 uint w, h, bpp, bpl, size, lpb, bnum, brest;
1008 int i;
1009 int rc,release_rc;
1011 w = x1 - x0 + 1;
1012 h = y1 - y0 + 1;
1013 if (inc <= 0)
1014 inc = w;
1015 if (w <= 0 || w > 720 || h <= 0 || h > 576)
1016 return -EINVAL;
1017 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1018 bpl = ((w * bpp + 7) & ~7) / 8;
1019 size = h * bpl;
1020 lpb = (32 * 1024) / bpl;
1021 bnum = size / (lpb * bpl);
1022 brest = size - bnum * lpb * bpl;
1024 if (av7110->bmp_state == BMP_LOADING) {
1025 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1026 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1027 rc = WaitUntilBmpLoaded(av7110);
1028 if (rc)
1029 return rc;
1030 /* just continue. This should work for all fw versions
1031 * if bnum==1 && !brest && LoadBitmap was successful
1035 rc = 0;
1036 for (i = 0; i < bnum; i++) {
1037 rc = LoadBitmap(av7110, w, lpb, inc, data);
1038 if (rc)
1039 break;
1040 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1041 if (rc)
1042 break;
1043 data += lpb * inc;
1045 if (!rc && brest) {
1046 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1047 if (!rc)
1048 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1050 release_rc = ReleaseBitmap(av7110);
1051 if (!rc)
1052 rc = release_rc;
1053 if (rc)
1054 dprintk(1,"returns %d\n",rc);
1055 return rc;
1058 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1060 int ret;
1062 if (mutex_lock_interruptible(&av7110->osd_mutex))
1063 return -ERESTARTSYS;
1065 switch (dc->cmd) {
1066 case OSD_Close:
1067 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1068 break;
1069 case OSD_Open:
1070 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1071 ret = CreateOSDWindow(av7110, av7110->osdwin,
1072 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1073 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1074 if (ret)
1075 break;
1076 if (!dc->data) {
1077 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1078 if (ret)
1079 break;
1080 ret = SetColorBlend(av7110, av7110->osdwin);
1082 break;
1083 case OSD_Show:
1084 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1085 break;
1086 case OSD_Hide:
1087 ret = HideWindow(av7110, av7110->osdwin);
1088 break;
1089 case OSD_Clear:
1090 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1091 break;
1092 case OSD_Fill:
1093 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1094 break;
1095 case OSD_SetColor:
1096 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1097 break;
1098 case OSD_SetPalette:
1099 if (FW_VERSION(av7110->arm_app) >= 0x2618)
1100 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1101 else {
1102 int i, len = dc->x0-dc->color+1;
1103 u8 __user *colors = (u8 __user *)dc->data;
1104 u8 r, g, b, blend;
1105 ret = 0;
1106 for (i = 0; i<len; i++) {
1107 if (get_user(r, colors + i * 4) ||
1108 get_user(g, colors + i * 4 + 1) ||
1109 get_user(b, colors + i * 4 + 2) ||
1110 get_user(blend, colors + i * 4 + 3)) {
1111 ret = -EFAULT;
1112 break;
1114 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1115 if (ret)
1116 break;
1119 break;
1120 case OSD_SetPixel:
1121 ret = DrawLine(av7110, av7110->osdwin,
1122 dc->x0, dc->y0, 0, 0, dc->color);
1123 break;
1124 case OSD_SetRow:
1125 dc->y1 = dc->y0;
1126 /* fall through */
1127 case OSD_SetBlock:
1128 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1129 break;
1130 case OSD_FillRow:
1131 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1132 dc->x1-dc->x0+1, dc->y1, dc->color);
1133 break;
1134 case OSD_FillBlock:
1135 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1136 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1137 break;
1138 case OSD_Line:
1139 ret = DrawLine(av7110, av7110->osdwin,
1140 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1141 break;
1142 case OSD_Text:
1144 char textbuf[240];
1146 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1147 ret = -EFAULT;
1148 break;
1150 textbuf[239] = 0;
1151 if (dc->x1 > 3)
1152 dc->x1 = 3;
1153 ret = SetFont(av7110, av7110->osdwin, dc->x1,
1154 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1155 if (!ret)
1156 ret = FlushText(av7110);
1157 if (!ret)
1158 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1159 break;
1161 case OSD_SetWindow:
1162 if (dc->x0 < 1 || dc->x0 > 7)
1163 ret = -EINVAL;
1164 else {
1165 av7110->osdwin = dc->x0;
1166 ret = 0;
1168 break;
1169 case OSD_MoveWindow:
1170 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1171 if (!ret)
1172 ret = SetColorBlend(av7110, av7110->osdwin);
1173 break;
1174 case OSD_OpenRaw:
1175 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1176 ret = -EINVAL;
1177 break;
1179 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1180 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1181 else
1182 av7110->osdbpp[av7110->osdwin] = 0;
1183 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1184 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1185 if (ret)
1186 break;
1187 if (!dc->data) {
1188 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1189 if (!ret)
1190 ret = SetColorBlend(av7110, av7110->osdwin);
1192 break;
1193 default:
1194 ret = -EINVAL;
1195 break;
1198 mutex_unlock(&av7110->osd_mutex);
1199 if (ret==-ERESTARTSYS)
1200 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1201 else if (ret)
1202 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1204 return ret;
1207 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1209 switch (cap->cmd) {
1210 case OSD_CAP_MEMSIZE:
1211 if (FW_4M_SDRAM(av7110->arm_app))
1212 cap->val = 1000000;
1213 else
1214 cap->val = 92000;
1215 return 0;
1216 default:
1217 return -EINVAL;
1220 #endif /* CONFIG_DVB_AV7110_OSD */