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