blob: 4d7150e15d1e1378c244df17f95569bd15f44843 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/smp_lock.h>
37#include <linux/fs.h>
38
39#include "av7110.h"
40#include "av7110_hw.h"
41
Johannes Stezenbachce7d3c12005-09-09 13:03:10 -070042#define _NOHANDSHAKE
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/****************************************************************************
45 * DEBI functions
46 ****************************************************************************/
47
48/* This DEBI code is based on the Stradis driver
49 by Nathan Laredo <laredo@gnu.org> */
50
51int av7110_debiwrite(struct av7110 *av7110, u32 config,
52 int addr, u32 val, int count)
53{
54 struct saa7146_dev *dev = av7110->dev;
55
56 if (count <= 0 || count > 32764) {
57 printk("%s: invalid count %d\n", __FUNCTION__, count);
58 return -1;
59 }
60 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
61 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
62 return -1;
63 }
64 saa7146_write(dev, DEBI_CONFIG, config);
65 if (count <= 4) /* immediate transfer */
66 saa7146_write(dev, DEBI_AD, val);
67 else /* block transfer */
68 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
69 saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
70 saa7146_write(dev, MC2, (2 << 16) | 2);
71 return 0;
72}
73
74u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
75{
76 struct saa7146_dev *dev = av7110->dev;
77 u32 result = 0;
78
79 if (count > 32764 || count <= 0) {
80 printk("%s: invalid count %d\n", __FUNCTION__, count);
81 return 0;
82 }
83 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
84 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
85 return 0;
86 }
87 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
88 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
89
90 saa7146_write(dev, DEBI_CONFIG, config);
91 saa7146_write(dev, MC2, (2 << 16) | 2);
92 if (count > 4)
93 return count;
94 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
95 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
96 return 0;
97 }
98
99 result = saa7146_read(dev, DEBI_AD);
100 result &= (0xffffffffUL >> ((4 - count) * 8));
101 return result;
102}
103
104
105
106/* av7110 ARM core boot stuff */
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700107#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108void av7110_reset_arm(struct av7110 *av7110)
109{
110 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
111
112 /* Disable DEBI and GPIO irq */
113 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
114 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
115
116 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
117 msleep(30); /* the firmware needs some time to initialize */
118
119 ARM_ResetMailBox(av7110);
120
121 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
122 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
123
124 av7110->arm_ready = 1;
125 dprintk(1, "reset ARM\n");
126}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700127#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129static int waitdebi(struct av7110 *av7110, int adr, int state)
130{
131 int k;
132
133 dprintk(4, "%p\n", av7110);
134
135 for (k = 0; k < 100; k++) {
136 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
137 return 0;
138 udelay(5);
139 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700140 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
143static int load_dram(struct av7110 *av7110, u32 *data, int len)
144{
145 int i;
146 int blocks, rest;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200147 u32 base, bootblock = AV7110_BOOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 dprintk(4, "%p\n", av7110);
150
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200151 blocks = len / AV7110_BOOT_MAX_SIZE;
152 rest = len % AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 base = DRAM_START_CODE;
154
155 for (i = 0; i < blocks; i++) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200156 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700158 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
160 dprintk(4, "writing DRAM block %d\n", i);
161 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200162 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 bootblock ^= 0x1400;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200164 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
165 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
166 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
167 base += AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169
170 if (rest > 0) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200171 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700173 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
175 if (rest > 4)
176 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200177 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 else
179 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200180 ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200182 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
183 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
184 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200186 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700188 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200190 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
191 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
192 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700194 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
196 return 0;
197}
198
199
200/* we cannot write av7110 DRAM directly, so load a bootloader into
201 * the DPRAM which implements a simple boot protocol */
202static u8 bootcode[] = {
203 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
204 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
205 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
206 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
207 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
208 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
209 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
210 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
211 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
212 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
213 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
214 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
215 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
216 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
217 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
218 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
219 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
220 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
221};
222
223int av7110_bootarm(struct av7110 *av7110)
224{
225 struct saa7146_dev *dev = av7110->dev;
226 u32 ret;
227 int i;
228
229 dprintk(4, "%p\n", av7110);
230
Oliver Endriss66190a22006-01-09 15:32:42 -0200231 av7110->arm_ready = 0;
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
234
235 /* Disable DEBI and GPIO irq */
236 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
237 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
238
239 /* enable DEBI */
240 saa7146_write(av7110->dev, MC1, 0x08800880);
241 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
242 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
243
244 /* test DEBI */
245 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
Marco Schluessler9f3319b2006-02-24 18:53:00 -0300246 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
247 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
250 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
251 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
252 ret, 0x10325476);
253 return -1;
254 }
255 for (i = 0; i < 8192; i += 4)
256 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
257 dprintk(2, "debi test OK\n");
258
259 /* boot */
260 dprintk(1, "load boot code\n");
261 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
262 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
263 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
264
265 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200266 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
269 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
270 "saa7146_wait_for_debi_done() timed out\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700271 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
273 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
274 mdelay(1);
275
276 dprintk(1, "load dram code\n");
277 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
278 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
279 "load_dram() failed\n");
280 return -1;
281 }
282
283 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
284 mdelay(1);
285
286 dprintk(1, "load dpram code\n");
287 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
288
289 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
290 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
291 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700292 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
294 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
295 msleep(30); /* the firmware needs some time to initialize */
296
297 //ARM_ClearIrq(av7110);
298 ARM_ResetMailBox(av7110);
299 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
300 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
301
302 av7110->arm_errors = 0;
303 av7110->arm_ready = 1;
304 return 0;
305}
306
307
308/****************************************************************************
309 * DEBI command polling
310 ****************************************************************************/
311
312int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
313{
314 unsigned long start;
315 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700316 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
319 /* not supported by old firmware */
320 msleep(50);
321 return 0;
322 }
323
324 /* new firmware */
325 start = jiffies;
326 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700327 err = time_after(jiffies, start + ARM_WAIT_FREE);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200328 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return -ERESTARTSYS;
330 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200331 mutex_unlock(&av7110->dcomlock);
Oliver Endriss25de1922005-07-07 17:58:28 -0700332 if ((stat & flags) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700334 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
336 __FUNCTION__, stat & flags);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700337 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
339 msleep(1);
340 }
341 return 0;
342}
343
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700344static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 int i;
347 unsigned long start;
348 char *type = NULL;
349 u16 flags[2] = {0, 0};
350 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700351 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353// dprintk(4, "%p\n", av7110);
354
355 if (!av7110->arm_ready) {
356 dprintk(1, "arm not ready.\n");
357 return -ENXIO;
358 }
359
360 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700361 while (1) {
362 err = time_after(jiffies, start + ARM_WAIT_FREE);
363 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
364 break;
365 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
Oliver Endriss66190a22006-01-09 15:32:42 -0200367 av7110->arm_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return -ETIMEDOUT;
369 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700370 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700373 if (FW_VERSION(av7110->arm_app) <= 0x261f)
374 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376#ifndef _NOHANDSHAKE
377 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700378 while (1) {
379 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
380 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
381 break;
382 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
384 return -ETIMEDOUT;
385 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700386 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 }
388#endif
389
390 switch ((buf[0] >> 8) & 0xff) {
391 case COMTYPE_PIDFILTER:
392 case COMTYPE_ENCODER:
393 case COMTYPE_REC_PLAY:
394 case COMTYPE_MPEGDECODER:
395 type = "MSG";
396 flags[0] = GPMQOver;
397 flags[1] = GPMQFull;
398 break;
399 case COMTYPE_OSD:
400 type = "OSD";
401 flags[0] = OSDQOver;
402 flags[1] = OSDQFull;
403 break;
404 case COMTYPE_MISC:
405 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
406 type = "MSG";
407 flags[0] = GPMQOver;
408 flags[1] = GPMQBusy;
409 }
410 break;
411 default:
412 break;
413 }
414
415 if (type != NULL) {
416 /* non-immediate COMMAND type */
417 start = jiffies;
418 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700419 err = time_after(jiffies, start + ARM_WAIT_FREE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
421 if (stat & flags[0]) {
422 printk(KERN_ERR "%s: %s QUEUE overflow\n",
423 __FUNCTION__, type);
424 return -1;
425 }
426 if ((stat & flags[1]) == 0)
427 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700428 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
430 __FUNCTION__, type);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700431 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
433 msleep(1);
434 }
435 }
436
437 for (i = 2; i < length; i++)
438 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
439
440 if (length)
441 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
442 else
443 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
444
445 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
446
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700447 if (FW_VERSION(av7110->arm_app) <= 0x261f)
448 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450#ifdef COM_DEBUG
451 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700452 while (1) {
453 err = time_after(jiffies, start + ARM_WAIT_FREE);
454 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
455 break;
456 if (err) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700457 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
Oliver Endriss25de1922005-07-07 17:58:28 -0700458 __FUNCTION__, (buf[0] >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 return -ETIMEDOUT;
460 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700461 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463
464 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
465 if (stat & GPMQOver) {
466 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
467 return -ENOSPC;
468 }
469 else if (stat & OSDQOver) {
470 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
471 return -ENOSPC;
472 }
473#endif
474
475 return 0;
476}
477
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700478static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 int ret;
481
482// dprintk(4, "%p\n", av7110);
483
484 if (!av7110->arm_ready) {
485 dprintk(1, "arm not ready.\n");
486 return -1;
487 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200488 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 return -ERESTARTSYS;
490
491 ret = __av7110_send_fw_cmd(av7110, buf, length);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200492 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700493 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
495 __FUNCTION__, ret);
496 return ret;
497}
498
499int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
500{
501 va_list args;
502 u16 buf[num + 2];
503 int i, ret;
504
505// dprintk(4, "%p\n", av7110);
506
507 buf[0] = ((type << 8) | com);
508 buf[1] = num;
509
510 if (num) {
511 va_start(args, num);
512 for (i = 0; i < num; i++)
513 buf[i + 2] = va_arg(args, u32);
514 va_end(args);
515 }
516
517 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700518 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
520 return ret;
521}
522
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700523#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
525{
526 int i, ret;
527 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
528 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
529
530 dprintk(4, "%p\n", av7110);
531
532 for(i = 0; i < len && i < 32; i++)
533 {
534 if(i % 2 == 0)
535 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
536 else
537 cmd[(i / 2) + 2] |= buf[i];
538 }
539
540 ret = av7110_send_fw_cmd(av7110, cmd, 18);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700541 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
543 return ret;
544}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700545#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
548 int request_buf_len, u16 *reply_buf, int reply_buf_len)
549{
550 int err;
551 s16 i;
552 unsigned long start;
553#ifdef COM_DEBUG
554 u32 stat;
555#endif
556
557 dprintk(4, "%p\n", av7110);
558
559 if (!av7110->arm_ready) {
560 dprintk(1, "arm not ready.\n");
561 return -1;
562 }
563
Ingo Molnar3593cab2006-02-07 06:49:14 -0200564 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return -ERESTARTSYS;
566
567 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
Ingo Molnar3593cab2006-02-07 06:49:14 -0200568 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
570 return err;
571 }
572
573 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700574 while (1) {
575 err = time_after(jiffies, start + ARM_WAIT_FREE);
576 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
577 break;
578 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200580 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700581 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700583#ifdef _NOHANDSHAKE
584 msleep(1);
585#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
587
588#ifndef _NOHANDSHAKE
589 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700590 while (1) {
591 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
592 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
593 break;
594 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200596 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700597 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700599 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
601#endif
602
603#ifdef COM_DEBUG
604 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
605 if (stat & GPMQOver) {
606 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200607 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 return -1;
609 }
610 else if (stat & OSDQOver) {
611 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200612 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return -1;
614 }
615#endif
616
617 for (i = 0; i < reply_buf_len; i++)
618 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
619
Ingo Molnar3593cab2006-02-07 06:49:14 -0200620 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
622}
623
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700624static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 int ret;
627 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
628 if (ret)
629 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
630 return ret;
631}
632
633
634/****************************************************************************
635 * Firmware commands
636 ****************************************************************************/
637
638/* get version of the firmware ROM, RTSL, video ucode and ARM application */
639int av7110_firmversion(struct av7110 *av7110)
640{
641 u16 buf[20];
642 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
643
644 dprintk(4, "%p\n", av7110);
645
646 if (av7110_fw_query(av7110, tag, buf, 16)) {
647 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700648 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -EIO;
650 }
651
652 av7110->arm_fw = (buf[0] << 16) + buf[1];
653 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
654 av7110->arm_vid = (buf[4] << 16) + buf[5];
655 av7110->arm_app = (buf[6] << 16) + buf[7];
656 av7110->avtype = (buf[8] << 16) + buf[9];
657
658 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700659 av7110->dvb_adapter.num, av7110->arm_fw,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
661
662 /* print firmware capabilities */
663 if (FW_CI_LL_SUPPORT(av7110->arm_app))
664 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700665 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 else
667 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700668 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
670 return 0;
671}
672
673
674int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
675{
676 int i, ret;
677 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
678 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
679
680 dprintk(4, "%p\n", av7110);
681
682 if (len > 10)
683 len = 10;
684
685 buf[1] = len + 2;
686 buf[2] = len;
687
688 if (burst != -1)
689 buf[3] = burst ? 0x01 : 0x00;
690 else
691 buf[3] = 0xffff;
692
693 for (i = 0; i < len; i++)
694 buf[i + 4] = msg[i];
695
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700696 ret = av7110_send_fw_cmd(av7110, buf, 18);
697 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700699 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702
703#ifdef CONFIG_DVB_AV7110_OSD
704
705static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
706{
707 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
708}
709
710static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
711 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
712{
713 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
714 windownr, colordepth, index, blending);
715}
716
717static inline int SetColor_(struct av7110 *av7110, u8 windownr,
718 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
719{
720 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
721 windownr, colordepth, index, colorhi, colorlo);
722}
723
724static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
725 u16 colorfg, u16 colorbg)
726{
727 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
728 windownr, fontsize, colorfg, colorbg);
729}
730
731static int FlushText(struct av7110 *av7110)
732{
733 unsigned long start;
Oliver Endriss25de1922005-07-07 17:58:28 -0700734 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Ingo Molnar3593cab2006-02-07 06:49:14 -0200736 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return -ERESTARTSYS;
738 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700739 while (1) {
740 err = time_after(jiffies, start + ARM_WAIT_OSD);
741 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
742 break;
743 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
745 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200746 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700747 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700749 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200751 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753}
754
755static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
756{
757 int i, ret;
758 unsigned long start;
759 int length = strlen(buf) + 1;
760 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
761
Ingo Molnar3593cab2006-02-07 06:49:14 -0200762 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -ERESTARTSYS;
764
765 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700766 while (1) {
767 ret = time_after(jiffies, start + ARM_WAIT_OSD);
768 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
769 break;
770 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
772 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200773 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700774 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700776 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
778#ifndef _NOHANDSHAKE
779 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700780 while (1) {
781 ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
782 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
783 break;
784 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
786 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200787 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700788 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700790 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792#endif
793 for (i = 0; i < length / 2; i++)
794 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
795 swab16(*(u16 *)(buf + 2 * i)), 2);
796 if (length & 1)
797 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
798 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200799 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700800 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
802 return ret;
803}
804
805static inline int DrawLine(struct av7110 *av7110, u8 windownr,
806 u16 x, u16 y, u16 dx, u16 dy, u16 color)
807{
808 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
809 windownr, x, y, dx, dy, color);
810}
811
812static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
813 u16 x, u16 y, u16 dx, u16 dy, u16 color)
814{
815 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
816 windownr, x, y, dx, dy, color);
817}
818
819static inline int HideWindow(struct av7110 *av7110, u8 windownr)
820{
821 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
822}
823
824static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
825{
826 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
827}
828
829static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
830{
831 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
832}
833
834static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
835{
836 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
837}
838
839static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
840 osd_raw_window_t disptype,
841 u16 width, u16 height)
842{
843 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
844 windownr, disptype, width, height);
845}
846
847
848static enum av7110_osd_palette_type bpp2pal[8] = {
849 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
850};
851static osd_raw_window_t bpp2bit[8] = {
852 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
853};
854
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700855static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
856{
857 int ret = wait_event_interruptible_timeout(av7110->bmpq,
858 av7110->bmp_state != BMP_LOADING, 10*HZ);
859 if (ret == -ERESTARTSYS)
860 return ret;
861 if (ret == 0) {
862 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
863 ret, av7110->bmp_state);
864 av7110->bmp_state = BMP_NONE;
865 return -ETIMEDOUT;
866 }
867 return 0;
868}
869
870static inline int LoadBitmap(struct av7110 *av7110,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 u16 dx, u16 dy, int inc, u8 __user * data)
872{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700873 u16 format;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 int bpp;
875 int i;
876 int d, delta;
877 u8 c;
878 int ret;
879
880 dprintk(4, "%p\n", av7110);
881
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700882 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 av7110->bmp_state = BMP_LOADING;
885 if (format == OSD_BITMAP8) {
886 bpp=8; delta = 1;
887 } else if (format == OSD_BITMAP4) {
888 bpp=4; delta = 2;
889 } else if (format == OSD_BITMAP2) {
890 bpp=2; delta = 4;
891 } else if (format == OSD_BITMAP1) {
892 bpp=1; delta = 8;
893 } else {
894 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700895 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
898 av7110->bmpp = 0;
899 if (av7110->bmplen > 32768) {
900 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700901 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 for (i = 0; i < dy; i++) {
904 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
905 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700906 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 }
909 if (format != OSD_BITMAP8) {
910 for (i = 0; i < dx * dy / delta; i++) {
911 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
912 for (d = delta - 2; d >= 0; d--) {
913 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
914 << ((delta - d - 1) * bpp));
915 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
916 }
917 }
918 }
919 av7110->bmplen += 1024;
920 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700921 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
922 if (!ret)
923 ret = WaitUntilBmpLoaded(av7110);
924 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925}
926
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700927static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 dprintk(4, "%p\n", av7110);
930
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700931 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
934static inline int ReleaseBitmap(struct av7110 *av7110)
935{
936 dprintk(4, "%p\n", av7110);
937
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700938 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 return -1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700940 if (av7110->bmp_state == BMP_LOADING)
941 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 av7110->bmp_state = BMP_NONE;
943 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
944}
945
946static u32 RGB2YUV(u16 R, u16 G, u16 B)
947{
948 u16 y, u, v;
949 u16 Y, Cr, Cb;
950
951 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
952 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
953 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
954
955 Y = y / 256;
956 Cb = u / 16;
957 Cr = v / 16;
958
959 return Cr | (Cb << 16) | (Y << 8);
960}
961
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700962static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700964 int ret;
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 u16 ch, cl;
967 u32 yuv;
968
969 yuv = blend ? RGB2YUV(r,g,b) : 0;
970 cl = (yuv & 0xffff);
971 ch = ((yuv >> 16) & 0xffff);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700972 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
973 color, ch, cl);
974 if (!ret)
975 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
976 color, ((blend >> 4) & 0x0f));
977 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
980static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
981{
982 int i;
983 int length = last - first + 1;
984
985 if (length * 4 > DATA_BUFF3_SIZE)
986 return -EINVAL;
987
988 for (i = 0; i < length; i++) {
989 u32 color, blend, yuv;
990
991 if (get_user(color, colors + i))
992 return -EFAULT;
993 blend = (color & 0xF0000000) >> 4;
994 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
995 (color >> 16) & 0xFF) | blend : 0;
996 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
997 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
998 }
999 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
1000 av7110->osdwin,
1001 bpp2pal[av7110->osdbpp[av7110->osdwin]],
1002 first, last);
1003}
1004
1005static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
1006 int x1, int y1, int inc, u8 __user * data)
1007{
1008 uint w, h, bpp, bpl, size, lpb, bnum, brest;
1009 int i;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001010 int rc,release_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 w = x1 - x0 + 1;
1013 h = y1 - y0 + 1;
1014 if (inc <= 0)
1015 inc = w;
1016 if (w <= 0 || w > 720 || h <= 0 || h > 576)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001017 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1019 bpl = ((w * bpp + 7) & ~7) / 8;
1020 size = h * bpl;
1021 lpb = (32 * 1024) / bpl;
1022 bnum = size / (lpb * bpl);
1023 brest = size - bnum * lpb * bpl;
1024
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001025 if (av7110->bmp_state == BMP_LOADING) {
1026 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1027 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1028 rc = WaitUntilBmpLoaded(av7110);
1029 if (rc)
1030 return rc;
1031 /* just continue. This should work for all fw versions
1032 * if bnum==1 && !brest && LoadBitmap was successful
1033 */
1034 }
1035
1036 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 for (i = 0; i < bnum; i++) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001038 rc = LoadBitmap(av7110, w, lpb, inc, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001040 break;
1041 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001043 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 data += lpb * inc;
1045 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001046 if (!rc && brest) {
1047 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1048 if (!rc)
1049 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001051 release_rc = ReleaseBitmap(av7110);
1052 if (!rc)
1053 rc = release_rc;
1054 if (rc)
1055 dprintk(1,"returns %d\n",rc);
1056 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057}
1058
1059int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1060{
1061 int ret;
1062
Ingo Molnar3593cab2006-02-07 06:49:14 -02001063 if (mutex_lock_interruptible(&av7110->osd_mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return -ERESTARTSYS;
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 switch (dc->cmd) {
1067 case OSD_Close:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001068 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1069 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 case OSD_Open:
1071 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001072 ret = CreateOSDWindow(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1074 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001075 if (ret)
1076 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001078 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1079 if (ret)
1080 break;
1081 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001083 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 case OSD_Show:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001085 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 case OSD_Hide:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001088 ret = HideWindow(av7110, av7110->osdwin);
1089 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 case OSD_Clear:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001091 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1092 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 case OSD_Fill:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001094 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1095 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 case OSD_SetColor:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001097 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1098 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 case OSD_SetPalette:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001100 if (FW_VERSION(av7110->arm_app) >= 0x2618)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001102 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 int i, len = dc->x0-dc->color+1;
1104 u8 __user *colors = (u8 __user *)dc->data;
1105 u8 r, g, b, blend;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001106 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 for (i = 0; i<len; i++) {
1108 if (get_user(r, colors + i * 4) ||
1109 get_user(g, colors + i * 4 + 1) ||
1110 get_user(b, colors + i * 4 + 2) ||
1111 get_user(blend, colors + i * 4 + 3)) {
1112 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001113 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001115 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1116 if (ret)
1117 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001120 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 case OSD_SetPixel:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001122 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 dc->x0, dc->y0, 0, 0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001124 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 case OSD_SetRow:
1126 dc->y1 = dc->y0;
1127 /* fall through */
1128 case OSD_SetBlock:
1129 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001130 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 case OSD_FillRow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001132 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 dc->x1-dc->x0+1, dc->y1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001134 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 case OSD_FillBlock:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001136 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001138 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 case OSD_Line:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001140 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 case OSD_Text:
1144 {
1145 char textbuf[240];
1146
1147 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1148 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151 textbuf[239] = 0;
1152 if (dc->x1 > 3)
1153 dc->x1 = 3;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001154 ret = SetFont(av7110, av7110->osdwin, dc->x1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001156 if (!ret)
1157 ret = FlushText(av7110);
1158 if (!ret)
1159 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1160 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162 case OSD_SetWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001163 if (dc->x0 < 1 || dc->x0 > 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001165 else {
1166 av7110->osdwin = dc->x0;
1167 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001169 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 case OSD_MoveWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001171 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1172 if (!ret)
1173 ret = SetColorBlend(av7110, av7110->osdwin);
1174 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 case OSD_OpenRaw:
1176 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1177 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001178 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001180 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001182 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 av7110->osdbpp[av7110->osdwin] = 0;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001184 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001186 if (ret)
1187 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001189 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1190 if (!ret)
1191 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001193 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 default:
1195 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001196 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
1198
Ingo Molnar3593cab2006-02-07 06:49:14 -02001199 mutex_unlock(&av7110->osd_mutex);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001200 if (ret==-ERESTARTSYS)
1201 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1202 else if (ret)
1203 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return ret;
1206}
1207
1208int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1209{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001210 switch (cap->cmd) {
1211 case OSD_CAP_MEMSIZE:
1212 if (FW_4M_SDRAM(av7110->arm_app))
Michael Krufky50c25ff2006-01-09 15:25:34 -02001213 cap->val = 1000000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001214 else
Michael Krufky50c25ff2006-01-09 15:25:34 -02001215 cap->val = 92000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001216 return 0;
1217 default:
1218 return -EINVAL;
1219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220}
1221#endif /* CONFIG_DVB_AV7110_OSD */