blob: 37de2e88a273b9616a8af19129f7cf880682d766 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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/sched.h>
36#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/smp_lock.h>
38#include <linux/fs.h>
39
40#include "av7110.h"
41#include "av7110_hw.h"
42
Johannes Stezenbachce7d3c12005-09-09 13:03:10 -070043#define _NOHANDSHAKE
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/****************************************************************************
46 * DEBI functions
47 ****************************************************************************/
48
49/* This DEBI code is based on the Stradis driver
50 by Nathan Laredo <laredo@gnu.org> */
51
52int av7110_debiwrite(struct av7110 *av7110, u32 config,
53 int addr, u32 val, int count)
54{
55 struct saa7146_dev *dev = av7110->dev;
56
57 if (count <= 0 || count > 32764) {
58 printk("%s: invalid count %d\n", __FUNCTION__, count);
59 return -1;
60 }
61 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
62 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
63 return -1;
64 }
65 saa7146_write(dev, DEBI_CONFIG, config);
66 if (count <= 4) /* immediate transfer */
67 saa7146_write(dev, DEBI_AD, val);
68 else /* block transfer */
69 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
70 saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
71 saa7146_write(dev, MC2, (2 << 16) | 2);
72 return 0;
73}
74
75u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
76{
77 struct saa7146_dev *dev = av7110->dev;
78 u32 result = 0;
79
80 if (count > 32764 || count <= 0) {
81 printk("%s: invalid count %d\n", __FUNCTION__, count);
82 return 0;
83 }
84 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
85 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
86 return 0;
87 }
88 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
89 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
90
91 saa7146_write(dev, DEBI_CONFIG, config);
92 saa7146_write(dev, MC2, (2 << 16) | 2);
93 if (count > 4)
94 return count;
95 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
96 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
97 return 0;
98 }
99
100 result = saa7146_read(dev, DEBI_AD);
101 result &= (0xffffffffUL >> ((4 - count) * 8));
102 return result;
103}
104
105
106
107/* av7110 ARM core boot stuff */
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700108#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109void av7110_reset_arm(struct av7110 *av7110)
110{
111 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
112
113 /* Disable DEBI and GPIO irq */
114 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
115 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
116
117 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
118 msleep(30); /* the firmware needs some time to initialize */
119
120 ARM_ResetMailBox(av7110);
121
122 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
123 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
124
125 av7110->arm_ready = 1;
126 dprintk(1, "reset ARM\n");
127}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700128#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130static int waitdebi(struct av7110 *av7110, int adr, int state)
131{
132 int k;
133
134 dprintk(4, "%p\n", av7110);
135
136 for (k = 0; k < 100; k++) {
137 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
138 return 0;
139 udelay(5);
140 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700141 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
144static int load_dram(struct av7110 *av7110, u32 *data, int len)
145{
146 int i;
147 int blocks, rest;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200148 u32 base, bootblock = AV7110_BOOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 dprintk(4, "%p\n", av7110);
151
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200152 blocks = len / AV7110_BOOT_MAX_SIZE;
153 rest = len % AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 base = DRAM_START_CODE;
155
156 for (i = 0; i < blocks; i++) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200157 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700159 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161 dprintk(4, "writing DRAM block %d\n", i);
162 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200163 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 bootblock ^= 0x1400;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200165 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
166 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
167 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
168 base += AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 }
170
171 if (rest > 0) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200172 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700174 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
176 if (rest > 4)
177 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200178 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 else
180 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200181 ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200183 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
184 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
185 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200187 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700189 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200191 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
192 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
193 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700195 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 }
197 return 0;
198}
199
200
201/* we cannot write av7110 DRAM directly, so load a bootloader into
202 * the DPRAM which implements a simple boot protocol */
203static u8 bootcode[] = {
204 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
205 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
206 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
207 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
208 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
209 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
210 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
211 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
212 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
213 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
214 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
215 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
216 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
217 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
218 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
219 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
220 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
221 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
222};
223
224int av7110_bootarm(struct av7110 *av7110)
225{
226 struct saa7146_dev *dev = av7110->dev;
227 u32 ret;
228 int i;
229
230 dprintk(4, "%p\n", av7110);
231
Oliver Endriss66190a22006-01-09 15:32:42 -0200232 av7110->arm_ready = 0;
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
235
236 /* Disable DEBI and GPIO irq */
237 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
238 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
239
240 /* enable DEBI */
241 saa7146_write(av7110->dev, MC1, 0x08800880);
242 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
243 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
244
245 /* test DEBI */
246 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
Marco Schluessler9f3319b2006-02-24 18:53:00 -0300247 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
248 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
251 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
252 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
253 ret, 0x10325476);
254 return -1;
255 }
256 for (i = 0; i < 8192; i += 4)
257 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
258 dprintk(2, "debi test OK\n");
259
260 /* boot */
261 dprintk(1, "load boot code\n");
262 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
263 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
264 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
265
266 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200267 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
270 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
271 "saa7146_wait_for_debi_done() timed out\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700272 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 }
274 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
275 mdelay(1);
276
277 dprintk(1, "load dram code\n");
278 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
279 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
280 "load_dram() failed\n");
281 return -1;
282 }
283
284 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
285 mdelay(1);
286
287 dprintk(1, "load dpram code\n");
288 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
289
290 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
291 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
292 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700293 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
295 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
296 msleep(30); /* the firmware needs some time to initialize */
297
298 //ARM_ClearIrq(av7110);
299 ARM_ResetMailBox(av7110);
300 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
301 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
302
303 av7110->arm_errors = 0;
304 av7110->arm_ready = 1;
305 return 0;
306}
307
308
309/****************************************************************************
310 * DEBI command polling
311 ****************************************************************************/
312
313int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
314{
315 unsigned long start;
316 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700317 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
320 /* not supported by old firmware */
321 msleep(50);
322 return 0;
323 }
324
325 /* new firmware */
326 start = jiffies;
327 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700328 err = time_after(jiffies, start + ARM_WAIT_FREE);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200329 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return -ERESTARTSYS;
331 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200332 mutex_unlock(&av7110->dcomlock);
Oliver Endriss25de1922005-07-07 17:58:28 -0700333 if ((stat & flags) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700335 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
337 __FUNCTION__, stat & flags);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700338 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 }
340 msleep(1);
341 }
342 return 0;
343}
344
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700345static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 int i;
348 unsigned long start;
349 char *type = NULL;
350 u16 flags[2] = {0, 0};
351 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700352 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354// dprintk(4, "%p\n", av7110);
355
356 if (!av7110->arm_ready) {
357 dprintk(1, "arm not ready.\n");
358 return -ENXIO;
359 }
360
361 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700362 while (1) {
363 err = time_after(jiffies, start + ARM_WAIT_FREE);
364 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
365 break;
366 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
Oliver Endriss66190a22006-01-09 15:32:42 -0200368 av7110->arm_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return -ETIMEDOUT;
370 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700371 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
373
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700374 if (FW_VERSION(av7110->arm_app) <= 0x261f)
375 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377#ifndef _NOHANDSHAKE
378 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700379 while (1) {
380 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
381 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
382 break;
383 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
385 return -ETIMEDOUT;
386 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700387 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389#endif
390
391 switch ((buf[0] >> 8) & 0xff) {
392 case COMTYPE_PIDFILTER:
393 case COMTYPE_ENCODER:
394 case COMTYPE_REC_PLAY:
395 case COMTYPE_MPEGDECODER:
396 type = "MSG";
397 flags[0] = GPMQOver;
398 flags[1] = GPMQFull;
399 break;
400 case COMTYPE_OSD:
401 type = "OSD";
402 flags[0] = OSDQOver;
403 flags[1] = OSDQFull;
404 break;
405 case COMTYPE_MISC:
406 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
407 type = "MSG";
408 flags[0] = GPMQOver;
409 flags[1] = GPMQBusy;
410 }
411 break;
412 default:
413 break;
414 }
415
416 if (type != NULL) {
417 /* non-immediate COMMAND type */
418 start = jiffies;
419 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700420 err = time_after(jiffies, start + ARM_WAIT_FREE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
422 if (stat & flags[0]) {
423 printk(KERN_ERR "%s: %s QUEUE overflow\n",
424 __FUNCTION__, type);
425 return -1;
426 }
427 if ((stat & flags[1]) == 0)
428 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700429 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
431 __FUNCTION__, type);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700432 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
434 msleep(1);
435 }
436 }
437
438 for (i = 2; i < length; i++)
439 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
440
441 if (length)
442 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
443 else
444 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
445
446 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
447
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700448 if (FW_VERSION(av7110->arm_app) <= 0x261f)
449 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451#ifdef COM_DEBUG
452 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700453 while (1) {
454 err = time_after(jiffies, start + ARM_WAIT_FREE);
455 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
456 break;
457 if (err) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700458 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
Oliver Endriss25de1922005-07-07 17:58:28 -0700459 __FUNCTION__, (buf[0] >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return -ETIMEDOUT;
461 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700462 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
464
465 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
466 if (stat & GPMQOver) {
467 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
468 return -ENOSPC;
469 }
470 else if (stat & OSDQOver) {
471 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
472 return -ENOSPC;
473 }
474#endif
475
476 return 0;
477}
478
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700479static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
481 int ret;
482
483// dprintk(4, "%p\n", av7110);
484
485 if (!av7110->arm_ready) {
486 dprintk(1, "arm not ready.\n");
487 return -1;
488 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200489 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return -ERESTARTSYS;
491
492 ret = __av7110_send_fw_cmd(av7110, buf, length);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200493 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700494 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
496 __FUNCTION__, ret);
497 return ret;
498}
499
500int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
501{
502 va_list args;
503 u16 buf[num + 2];
504 int i, ret;
505
506// dprintk(4, "%p\n", av7110);
507
508 buf[0] = ((type << 8) | com);
509 buf[1] = num;
510
511 if (num) {
512 va_start(args, num);
513 for (i = 0; i < num; i++)
514 buf[i + 2] = va_arg(args, u32);
515 va_end(args);
516 }
517
518 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700519 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
521 return ret;
522}
523
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700524#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
526{
527 int i, ret;
528 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
529 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
530
531 dprintk(4, "%p\n", av7110);
532
533 for(i = 0; i < len && i < 32; i++)
534 {
535 if(i % 2 == 0)
536 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
537 else
538 cmd[(i / 2) + 2] |= buf[i];
539 }
540
541 ret = av7110_send_fw_cmd(av7110, cmd, 18);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700542 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
544 return ret;
545}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700546#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
549 int request_buf_len, u16 *reply_buf, int reply_buf_len)
550{
551 int err;
552 s16 i;
553 unsigned long start;
554#ifdef COM_DEBUG
555 u32 stat;
556#endif
557
558 dprintk(4, "%p\n", av7110);
559
560 if (!av7110->arm_ready) {
561 dprintk(1, "arm not ready.\n");
562 return -1;
563 }
564
Ingo Molnar3593cab2006-02-07 06:49:14 -0200565 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 return -ERESTARTSYS;
567
568 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
Ingo Molnar3593cab2006-02-07 06:49:14 -0200569 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
571 return err;
572 }
573
574 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700575 while (1) {
576 err = time_after(jiffies, start + ARM_WAIT_FREE);
577 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
578 break;
579 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200581 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700582 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700584#ifdef _NOHANDSHAKE
585 msleep(1);
586#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
588
589#ifndef _NOHANDSHAKE
590 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700591 while (1) {
592 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
593 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
594 break;
595 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200597 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700598 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700600 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602#endif
603
604#ifdef COM_DEBUG
605 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
606 if (stat & GPMQOver) {
607 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200608 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return -1;
610 }
611 else if (stat & OSDQOver) {
612 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200613 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 return -1;
615 }
616#endif
617
618 for (i = 0; i < reply_buf_len; i++)
619 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
620
Ingo Molnar3593cab2006-02-07 06:49:14 -0200621 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return 0;
623}
624
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700625static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 int ret;
628 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
629 if (ret)
630 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
631 return ret;
632}
633
634
635/****************************************************************************
636 * Firmware commands
637 ****************************************************************************/
638
639/* get version of the firmware ROM, RTSL, video ucode and ARM application */
640int av7110_firmversion(struct av7110 *av7110)
641{
642 u16 buf[20];
643 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
644
645 dprintk(4, "%p\n", av7110);
646
647 if (av7110_fw_query(av7110, tag, buf, 16)) {
648 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700649 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return -EIO;
651 }
652
653 av7110->arm_fw = (buf[0] << 16) + buf[1];
654 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
655 av7110->arm_vid = (buf[4] << 16) + buf[5];
656 av7110->arm_app = (buf[6] << 16) + buf[7];
657 av7110->avtype = (buf[8] << 16) + buf[9];
658
659 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700660 av7110->dvb_adapter.num, av7110->arm_fw,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
662
663 /* print firmware capabilities */
664 if (FW_CI_LL_SUPPORT(av7110->arm_app))
665 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700666 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 else
668 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700669 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 return 0;
672}
673
674
675int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
676{
677 int i, ret;
678 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
679 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
680
681 dprintk(4, "%p\n", av7110);
682
683 if (len > 10)
684 len = 10;
685
686 buf[1] = len + 2;
687 buf[2] = len;
688
689 if (burst != -1)
690 buf[3] = burst ? 0x01 : 0x00;
691 else
692 buf[3] = 0xffff;
693
694 for (i = 0; i < len; i++)
695 buf[i + 4] = msg[i];
696
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700697 ret = av7110_send_fw_cmd(av7110, buf, 18);
698 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700700 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
703
704#ifdef CONFIG_DVB_AV7110_OSD
705
706static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
707{
708 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
709}
710
711static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
712 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
713{
714 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
715 windownr, colordepth, index, blending);
716}
717
718static inline int SetColor_(struct av7110 *av7110, u8 windownr,
719 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
720{
721 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
722 windownr, colordepth, index, colorhi, colorlo);
723}
724
725static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
726 u16 colorfg, u16 colorbg)
727{
728 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
729 windownr, fontsize, colorfg, colorbg);
730}
731
732static int FlushText(struct av7110 *av7110)
733{
734 unsigned long start;
Oliver Endriss25de1922005-07-07 17:58:28 -0700735 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Ingo Molnar3593cab2006-02-07 06:49:14 -0200737 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return -ERESTARTSYS;
739 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700740 while (1) {
741 err = time_after(jiffies, start + ARM_WAIT_OSD);
742 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
743 break;
744 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
746 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200747 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700748 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700750 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200752 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return 0;
754}
755
756static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
757{
758 int i, ret;
759 unsigned long start;
760 int length = strlen(buf) + 1;
761 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
762
Ingo Molnar3593cab2006-02-07 06:49:14 -0200763 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -ERESTARTSYS;
765
766 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700767 while (1) {
768 ret = time_after(jiffies, start + ARM_WAIT_OSD);
769 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
770 break;
771 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
773 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200774 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700775 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700777 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779#ifndef _NOHANDSHAKE
780 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700781 while (1) {
782 ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
783 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
784 break;
785 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
787 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200788 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700789 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700791 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
793#endif
794 for (i = 0; i < length / 2; i++)
795 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
796 swab16(*(u16 *)(buf + 2 * i)), 2);
797 if (length & 1)
798 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
799 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200800 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700801 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
803 return ret;
804}
805
806static inline int DrawLine(struct av7110 *av7110, u8 windownr,
807 u16 x, u16 y, u16 dx, u16 dy, u16 color)
808{
809 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
810 windownr, x, y, dx, dy, color);
811}
812
813static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
814 u16 x, u16 y, u16 dx, u16 dy, u16 color)
815{
816 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
817 windownr, x, y, dx, dy, color);
818}
819
820static inline int HideWindow(struct av7110 *av7110, u8 windownr)
821{
822 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
823}
824
825static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
826{
827 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
828}
829
830static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
831{
832 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
833}
834
835static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
836{
837 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
838}
839
840static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
841 osd_raw_window_t disptype,
842 u16 width, u16 height)
843{
844 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
845 windownr, disptype, width, height);
846}
847
848
849static enum av7110_osd_palette_type bpp2pal[8] = {
850 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
851};
852static osd_raw_window_t bpp2bit[8] = {
853 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
854};
855
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700856static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
857{
858 int ret = wait_event_interruptible_timeout(av7110->bmpq,
859 av7110->bmp_state != BMP_LOADING, 10*HZ);
860 if (ret == -ERESTARTSYS)
861 return ret;
862 if (ret == 0) {
863 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
864 ret, av7110->bmp_state);
865 av7110->bmp_state = BMP_NONE;
866 return -ETIMEDOUT;
867 }
868 return 0;
869}
870
871static inline int LoadBitmap(struct av7110 *av7110,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 u16 dx, u16 dy, int inc, u8 __user * data)
873{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700874 u16 format;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 int bpp;
876 int i;
877 int d, delta;
878 u8 c;
879 int ret;
880
881 dprintk(4, "%p\n", av7110);
882
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700883 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 av7110->bmp_state = BMP_LOADING;
886 if (format == OSD_BITMAP8) {
887 bpp=8; delta = 1;
888 } else if (format == OSD_BITMAP4) {
889 bpp=4; delta = 2;
890 } else if (format == OSD_BITMAP2) {
891 bpp=2; delta = 4;
892 } else if (format == OSD_BITMAP1) {
893 bpp=1; delta = 8;
894 } else {
895 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700896 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
899 av7110->bmpp = 0;
900 if (av7110->bmplen > 32768) {
901 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700902 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 for (i = 0; i < dy; i++) {
905 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
906 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700907 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 }
910 if (format != OSD_BITMAP8) {
911 for (i = 0; i < dx * dy / delta; i++) {
912 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
913 for (d = delta - 2; d >= 0; d--) {
914 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
915 << ((delta - d - 1) * bpp));
916 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
917 }
918 }
919 }
920 av7110->bmplen += 1024;
921 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700922 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
923 if (!ret)
924 ret = WaitUntilBmpLoaded(av7110);
925 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926}
927
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700928static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 dprintk(4, "%p\n", av7110);
931
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700932 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
934
935static inline int ReleaseBitmap(struct av7110 *av7110)
936{
937 dprintk(4, "%p\n", av7110);
938
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700939 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 return -1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700941 if (av7110->bmp_state == BMP_LOADING)
942 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 av7110->bmp_state = BMP_NONE;
944 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
945}
946
947static u32 RGB2YUV(u16 R, u16 G, u16 B)
948{
949 u16 y, u, v;
950 u16 Y, Cr, Cb;
951
952 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
953 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
954 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
955
956 Y = y / 256;
957 Cb = u / 16;
958 Cr = v / 16;
959
960 return Cr | (Cb << 16) | (Y << 8);
961}
962
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700963static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700965 int ret;
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 u16 ch, cl;
968 u32 yuv;
969
970 yuv = blend ? RGB2YUV(r,g,b) : 0;
971 cl = (yuv & 0xffff);
972 ch = ((yuv >> 16) & 0xffff);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700973 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
974 color, ch, cl);
975 if (!ret)
976 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
977 color, ((blend >> 4) & 0x0f));
978 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
981static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
982{
983 int i;
984 int length = last - first + 1;
985
986 if (length * 4 > DATA_BUFF3_SIZE)
987 return -EINVAL;
988
989 for (i = 0; i < length; i++) {
990 u32 color, blend, yuv;
991
992 if (get_user(color, colors + i))
993 return -EFAULT;
994 blend = (color & 0xF0000000) >> 4;
995 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
996 (color >> 16) & 0xFF) | blend : 0;
997 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
998 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
999 }
1000 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
1001 av7110->osdwin,
1002 bpp2pal[av7110->osdbpp[av7110->osdwin]],
1003 first, last);
1004}
1005
1006static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
1007 int x1, int y1, int inc, u8 __user * data)
1008{
1009 uint w, h, bpp, bpl, size, lpb, bnum, brest;
1010 int i;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001011 int rc,release_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 w = x1 - x0 + 1;
1014 h = y1 - y0 + 1;
1015 if (inc <= 0)
1016 inc = w;
1017 if (w <= 0 || w > 720 || h <= 0 || h > 576)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001018 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1020 bpl = ((w * bpp + 7) & ~7) / 8;
1021 size = h * bpl;
1022 lpb = (32 * 1024) / bpl;
1023 bnum = size / (lpb * bpl);
1024 brest = size - bnum * lpb * bpl;
1025
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001026 if (av7110->bmp_state == BMP_LOADING) {
1027 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1028 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1029 rc = WaitUntilBmpLoaded(av7110);
1030 if (rc)
1031 return rc;
1032 /* just continue. This should work for all fw versions
1033 * if bnum==1 && !brest && LoadBitmap was successful
1034 */
1035 }
1036
1037 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 for (i = 0; i < bnum; i++) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001039 rc = LoadBitmap(av7110, w, lpb, inc, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001041 break;
1042 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001044 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 data += lpb * inc;
1046 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001047 if (!rc && brest) {
1048 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1049 if (!rc)
1050 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001052 release_rc = ReleaseBitmap(av7110);
1053 if (!rc)
1054 rc = release_rc;
1055 if (rc)
1056 dprintk(1,"returns %d\n",rc);
1057 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058}
1059
1060int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1061{
1062 int ret;
1063
Ingo Molnar3593cab2006-02-07 06:49:14 -02001064 if (mutex_lock_interruptible(&av7110->osd_mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return -ERESTARTSYS;
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 switch (dc->cmd) {
1068 case OSD_Close:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001069 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1070 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 case OSD_Open:
1072 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001073 ret = CreateOSDWindow(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1075 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001076 if (ret)
1077 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001079 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1080 if (ret)
1081 break;
1082 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001084 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 case OSD_Show:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001086 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1087 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 case OSD_Hide:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001089 ret = HideWindow(av7110, av7110->osdwin);
1090 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 case OSD_Clear:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001092 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1093 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 case OSD_Fill:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001095 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1096 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 case OSD_SetColor:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001098 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1099 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 case OSD_SetPalette:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001101 if (FW_VERSION(av7110->arm_app) >= 0x2618)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001103 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 int i, len = dc->x0-dc->color+1;
1105 u8 __user *colors = (u8 __user *)dc->data;
1106 u8 r, g, b, blend;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001107 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 for (i = 0; i<len; i++) {
1109 if (get_user(r, colors + i * 4) ||
1110 get_user(g, colors + i * 4 + 1) ||
1111 get_user(b, colors + i * 4 + 2) ||
1112 get_user(blend, colors + i * 4 + 3)) {
1113 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001114 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001116 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1117 if (ret)
1118 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
1120 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001121 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 case OSD_SetPixel:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001123 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 dc->x0, dc->y0, 0, 0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001125 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 case OSD_SetRow:
1127 dc->y1 = dc->y0;
1128 /* fall through */
1129 case OSD_SetBlock:
1130 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001131 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 case OSD_FillRow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001133 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 dc->x1-dc->x0+1, dc->y1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001135 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 case OSD_FillBlock:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001137 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001139 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 case OSD_Line:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001141 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001143 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 case OSD_Text:
1145 {
1146 char textbuf[240];
1147
1148 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1149 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001150 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152 textbuf[239] = 0;
1153 if (dc->x1 > 3)
1154 dc->x1 = 3;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001155 ret = SetFont(av7110, av7110->osdwin, dc->x1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001157 if (!ret)
1158 ret = FlushText(av7110);
1159 if (!ret)
1160 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1161 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 case OSD_SetWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001164 if (dc->x0 < 1 || dc->x0 > 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001166 else {
1167 av7110->osdwin = dc->x0;
1168 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001170 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 case OSD_MoveWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001172 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1173 if (!ret)
1174 ret = SetColorBlend(av7110, av7110->osdwin);
1175 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 case OSD_OpenRaw:
1177 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1178 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001179 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001181 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001183 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 av7110->osdbpp[av7110->osdwin] = 0;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001185 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001187 if (ret)
1188 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001190 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1191 if (!ret)
1192 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001194 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 default:
1196 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001197 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 }
1199
Ingo Molnar3593cab2006-02-07 06:49:14 -02001200 mutex_unlock(&av7110->osd_mutex);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001201 if (ret==-ERESTARTSYS)
1202 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1203 else if (ret)
1204 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return ret;
1207}
1208
1209int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1210{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001211 switch (cap->cmd) {
1212 case OSD_CAP_MEMSIZE:
1213 if (FW_4M_SDRAM(av7110->arm_app))
Michael Krufky50c25ff2006-01-09 15:25:34 -02001214 cap->val = 1000000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001215 else
Michael Krufky50c25ff2006-01-09 15:25:34 -02001216 cap->val = 92000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001217 return 0;
1218 default:
1219 return -EINVAL;
1220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221}
1222#endif /* CONFIG_DVB_AV7110_OSD */