blob: 75736f2fe83864bb6bf48e7204a28c6a9930e806 [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>
37#include <linux/byteorder/swabb.h>
38#include <linux/smp_lock.h>
39#include <linux/fs.h>
40
41#include "av7110.h"
42#include "av7110_hw.h"
43
Johannes Stezenbachce7d3c12005-09-09 13:03:10 -070044#define _NOHANDSHAKE
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046/****************************************************************************
47 * DEBI functions
48 ****************************************************************************/
49
50/* This DEBI code is based on the Stradis driver
51 by Nathan Laredo <laredo@gnu.org> */
52
53int av7110_debiwrite(struct av7110 *av7110, u32 config,
54 int addr, u32 val, int count)
55{
56 struct saa7146_dev *dev = av7110->dev;
57
58 if (count <= 0 || count > 32764) {
59 printk("%s: invalid count %d\n", __FUNCTION__, count);
60 return -1;
61 }
62 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
63 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
64 return -1;
65 }
66 saa7146_write(dev, DEBI_CONFIG, config);
67 if (count <= 4) /* immediate transfer */
68 saa7146_write(dev, DEBI_AD, val);
69 else /* block transfer */
70 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
71 saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
72 saa7146_write(dev, MC2, (2 << 16) | 2);
73 return 0;
74}
75
76u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
77{
78 struct saa7146_dev *dev = av7110->dev;
79 u32 result = 0;
80
81 if (count > 32764 || count <= 0) {
82 printk("%s: invalid count %d\n", __FUNCTION__, count);
83 return 0;
84 }
85 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
86 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
87 return 0;
88 }
89 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
90 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
91
92 saa7146_write(dev, DEBI_CONFIG, config);
93 saa7146_write(dev, MC2, (2 << 16) | 2);
94 if (count > 4)
95 return count;
96 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
97 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
98 return 0;
99 }
100
101 result = saa7146_read(dev, DEBI_AD);
102 result &= (0xffffffffUL >> ((4 - count) * 8));
103 return result;
104}
105
106
107
108/* av7110 ARM core boot stuff */
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700109#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110void av7110_reset_arm(struct av7110 *av7110)
111{
112 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
113
114 /* Disable DEBI and GPIO irq */
115 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
116 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
117
118 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
119 msleep(30); /* the firmware needs some time to initialize */
120
121 ARM_ResetMailBox(av7110);
122
123 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
124 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
125
126 av7110->arm_ready = 1;
127 dprintk(1, "reset ARM\n");
128}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700129#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131static int waitdebi(struct av7110 *av7110, int adr, int state)
132{
133 int k;
134
135 dprintk(4, "%p\n", av7110);
136
137 for (k = 0; k < 100; k++) {
138 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
139 return 0;
140 udelay(5);
141 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700142 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
145static int load_dram(struct av7110 *av7110, u32 *data, int len)
146{
147 int i;
148 int blocks, rest;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200149 u32 base, bootblock = AV7110_BOOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 dprintk(4, "%p\n", av7110);
152
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200153 blocks = len / AV7110_BOOT_MAX_SIZE;
154 rest = len % AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 base = DRAM_START_CODE;
156
157 for (i = 0; i < blocks; i++) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200158 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700160 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162 dprintk(4, "writing DRAM block %d\n", i);
163 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200164 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 bootblock ^= 0x1400;
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200166 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
167 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
168 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
169 base += AV7110_BOOT_MAX_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 }
171
172 if (rest > 0) {
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200173 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700175 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 }
177 if (rest > 4)
178 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200179 ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 else
181 mwdebi(av7110, DEBISWAB, bootblock,
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200182 ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200184 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
185 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
186 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200188 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700190 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 }
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200192 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
193 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
194 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700196 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
198 return 0;
199}
200
201
202/* we cannot write av7110 DRAM directly, so load a bootloader into
203 * the DPRAM which implements a simple boot protocol */
204static u8 bootcode[] = {
205 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
206 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
207 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
208 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
209 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
210 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
211 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
212 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
213 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
214 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
215 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
216 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
217 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
218 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
219 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
220 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
221 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
222 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
223};
224
225int av7110_bootarm(struct av7110 *av7110)
226{
227 struct saa7146_dev *dev = av7110->dev;
228 u32 ret;
229 int i;
230
231 dprintk(4, "%p\n", av7110);
232
Oliver Endriss66190a22006-01-09 15:32:42 -0200233 av7110->arm_ready = 0;
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
236
237 /* Disable DEBI and GPIO irq */
238 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
239 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
240
241 /* enable DEBI */
242 saa7146_write(av7110->dev, MC1, 0x08800880);
243 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
244 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
245
246 /* test DEBI */
247 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
Marco Schluessler9f3319b2006-02-24 18:53:00 -0300248 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
249 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
252 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
253 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
254 ret, 0x10325476);
255 return -1;
256 }
257 for (i = 0; i < 8192; i += 4)
258 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
259 dprintk(2, "debi test OK\n");
260
261 /* boot */
262 dprintk(1, "load boot code\n");
263 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
264 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
265 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
266
267 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
Mauro Carvalho Chehabfabd2382006-01-15 08:12:14 -0200268 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
271 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
272 "saa7146_wait_for_debi_done() timed out\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700273 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 }
275 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
276 mdelay(1);
277
278 dprintk(1, "load dram code\n");
279 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
280 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
281 "load_dram() failed\n");
282 return -1;
283 }
284
285 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
286 mdelay(1);
287
288 dprintk(1, "load dpram code\n");
289 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
290
291 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
292 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
293 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700294 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
297 msleep(30); /* the firmware needs some time to initialize */
298
299 //ARM_ClearIrq(av7110);
300 ARM_ResetMailBox(av7110);
301 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
302 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
303
304 av7110->arm_errors = 0;
305 av7110->arm_ready = 1;
306 return 0;
307}
308
309
310/****************************************************************************
311 * DEBI command polling
312 ****************************************************************************/
313
314int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
315{
316 unsigned long start;
317 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700318 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
321 /* not supported by old firmware */
322 msleep(50);
323 return 0;
324 }
325
326 /* new firmware */
327 start = jiffies;
328 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700329 err = time_after(jiffies, start + ARM_WAIT_FREE);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200330 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return -ERESTARTSYS;
332 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200333 mutex_unlock(&av7110->dcomlock);
Oliver Endriss25de1922005-07-07 17:58:28 -0700334 if ((stat & flags) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700336 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
338 __FUNCTION__, stat & flags);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700339 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341 msleep(1);
342 }
343 return 0;
344}
345
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700346static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 int i;
349 unsigned long start;
350 char *type = NULL;
351 u16 flags[2] = {0, 0};
352 u32 stat;
Oliver Endriss25de1922005-07-07 17:58:28 -0700353 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355// dprintk(4, "%p\n", av7110);
356
357 if (!av7110->arm_ready) {
358 dprintk(1, "arm not ready.\n");
359 return -ENXIO;
360 }
361
362 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700363 while (1) {
364 err = time_after(jiffies, start + ARM_WAIT_FREE);
365 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
366 break;
367 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
Oliver Endriss66190a22006-01-09 15:32:42 -0200369 av7110->arm_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return -ETIMEDOUT;
371 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700372 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700375 if (FW_VERSION(av7110->arm_app) <= 0x261f)
376 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378#ifndef _NOHANDSHAKE
379 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700380 while (1) {
381 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
382 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
383 break;
384 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
386 return -ETIMEDOUT;
387 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700388 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 }
390#endif
391
392 switch ((buf[0] >> 8) & 0xff) {
393 case COMTYPE_PIDFILTER:
394 case COMTYPE_ENCODER:
395 case COMTYPE_REC_PLAY:
396 case COMTYPE_MPEGDECODER:
397 type = "MSG";
398 flags[0] = GPMQOver;
399 flags[1] = GPMQFull;
400 break;
401 case COMTYPE_OSD:
402 type = "OSD";
403 flags[0] = OSDQOver;
404 flags[1] = OSDQFull;
405 break;
406 case COMTYPE_MISC:
407 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
408 type = "MSG";
409 flags[0] = GPMQOver;
410 flags[1] = GPMQBusy;
411 }
412 break;
413 default:
414 break;
415 }
416
417 if (type != NULL) {
418 /* non-immediate COMMAND type */
419 start = jiffies;
420 for (;;) {
Oliver Endriss25de1922005-07-07 17:58:28 -0700421 err = time_after(jiffies, start + ARM_WAIT_FREE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
423 if (stat & flags[0]) {
424 printk(KERN_ERR "%s: %s QUEUE overflow\n",
425 __FUNCTION__, type);
426 return -1;
427 }
428 if ((stat & flags[1]) == 0)
429 break;
Oliver Endriss25de1922005-07-07 17:58:28 -0700430 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
432 __FUNCTION__, type);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700433 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 }
435 msleep(1);
436 }
437 }
438
439 for (i = 2; i < length; i++)
440 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
441
442 if (length)
443 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
444 else
445 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
446
447 wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
448
Oliver Endriss9a7b1022005-09-09 13:03:11 -0700449 if (FW_VERSION(av7110->arm_app) <= 0x261f)
450 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452#ifdef COM_DEBUG
453 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700454 while (1) {
455 err = time_after(jiffies, start + ARM_WAIT_FREE);
456 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
457 break;
458 if (err) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700459 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
Oliver Endriss25de1922005-07-07 17:58:28 -0700460 __FUNCTION__, (buf[0] >> 8) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return -ETIMEDOUT;
462 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700463 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 }
465
466 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
467 if (stat & GPMQOver) {
468 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
469 return -ENOSPC;
470 }
471 else if (stat & OSDQOver) {
472 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
473 return -ENOSPC;
474 }
475#endif
476
477 return 0;
478}
479
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700480static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 int ret;
483
484// dprintk(4, "%p\n", av7110);
485
486 if (!av7110->arm_ready) {
487 dprintk(1, "arm not ready.\n");
488 return -1;
489 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200490 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return -ERESTARTSYS;
492
493 ret = __av7110_send_fw_cmd(av7110, buf, length);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200494 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700495 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
497 __FUNCTION__, ret);
498 return ret;
499}
500
501int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
502{
503 va_list args;
504 u16 buf[num + 2];
505 int i, ret;
506
507// dprintk(4, "%p\n", av7110);
508
509 buf[0] = ((type << 8) | com);
510 buf[1] = num;
511
512 if (num) {
513 va_start(args, num);
514 for (i = 0; i < num; i++)
515 buf[i + 2] = va_arg(args, u32);
516 va_end(args);
517 }
518
519 ret = av7110_send_fw_cmd(av7110, buf, num + 2);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700520 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
522 return ret;
523}
524
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700525#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
527{
528 int i, ret;
529 u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
530 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
531
532 dprintk(4, "%p\n", av7110);
533
534 for(i = 0; i < len && i < 32; i++)
535 {
536 if(i % 2 == 0)
537 cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
538 else
539 cmd[(i / 2) + 2] |= buf[i];
540 }
541
542 ret = av7110_send_fw_cmd(av7110, cmd, 18);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700543 if (ret && ret != -ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
545 return ret;
546}
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700547#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
550 int request_buf_len, u16 *reply_buf, int reply_buf_len)
551{
552 int err;
553 s16 i;
554 unsigned long start;
555#ifdef COM_DEBUG
556 u32 stat;
557#endif
558
559 dprintk(4, "%p\n", av7110);
560
561 if (!av7110->arm_ready) {
562 dprintk(1, "arm not ready.\n");
563 return -1;
564 }
565
Ingo Molnar3593cab2006-02-07 06:49:14 -0200566 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return -ERESTARTSYS;
568
569 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
Ingo Molnar3593cab2006-02-07 06:49:14 -0200570 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
572 return err;
573 }
574
575 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700576 while (1) {
577 err = time_after(jiffies, start + ARM_WAIT_FREE);
578 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
579 break;
580 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200582 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700583 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700585#ifdef _NOHANDSHAKE
586 msleep(1);
587#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
589
590#ifndef _NOHANDSHAKE
591 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700592 while (1) {
593 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
594 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
595 break;
596 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200598 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700599 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700601 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
603#endif
604
605#ifdef COM_DEBUG
606 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
607 if (stat & GPMQOver) {
608 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200609 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return -1;
611 }
612 else if (stat & OSDQOver) {
613 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200614 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return -1;
616 }
617#endif
618
619 for (i = 0; i < reply_buf_len; i++)
620 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
621
Ingo Molnar3593cab2006-02-07 06:49:14 -0200622 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 0;
624}
625
Johannes Stezenbachd91b7302005-05-16 21:54:38 -0700626static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 int ret;
629 ret = av7110_fw_request(av7110, &tag, 0, buf, length);
630 if (ret)
631 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
632 return ret;
633}
634
635
636/****************************************************************************
637 * Firmware commands
638 ****************************************************************************/
639
640/* get version of the firmware ROM, RTSL, video ucode and ARM application */
641int av7110_firmversion(struct av7110 *av7110)
642{
643 u16 buf[20];
644 u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
645
646 dprintk(4, "%p\n", av7110);
647
648 if (av7110_fw_query(av7110, tag, buf, 16)) {
649 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700650 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return -EIO;
652 }
653
654 av7110->arm_fw = (buf[0] << 16) + buf[1];
655 av7110->arm_rtsl = (buf[2] << 16) + buf[3];
656 av7110->arm_vid = (buf[4] << 16) + buf[5];
657 av7110->arm_app = (buf[6] << 16) + buf[7];
658 av7110->avtype = (buf[8] << 16) + buf[9];
659
660 printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700661 av7110->dvb_adapter.num, av7110->arm_fw,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
663
664 /* print firmware capabilities */
665 if (FW_CI_LL_SUPPORT(av7110->arm_app))
666 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700667 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 else
669 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700670 av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 return 0;
673}
674
675
676int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
677{
678 int i, ret;
679 u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
680 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
681
682 dprintk(4, "%p\n", av7110);
683
684 if (len > 10)
685 len = 10;
686
687 buf[1] = len + 2;
688 buf[2] = len;
689
690 if (burst != -1)
691 buf[3] = burst ? 0x01 : 0x00;
692 else
693 buf[3] = 0xffff;
694
695 for (i = 0; i < len; i++)
696 buf[i + 4] = msg[i];
697
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700698 ret = av7110_send_fw_cmd(av7110, buf, 18);
699 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700701 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702}
703
704
705#ifdef CONFIG_DVB_AV7110_OSD
706
707static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
708{
709 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
710}
711
712static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
713 enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
714{
715 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
716 windownr, colordepth, index, blending);
717}
718
719static inline int SetColor_(struct av7110 *av7110, u8 windownr,
720 enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
721{
722 return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
723 windownr, colordepth, index, colorhi, colorlo);
724}
725
726static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
727 u16 colorfg, u16 colorbg)
728{
729 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
730 windownr, fontsize, colorfg, colorbg);
731}
732
733static int FlushText(struct av7110 *av7110)
734{
735 unsigned long start;
Oliver Endriss25de1922005-07-07 17:58:28 -0700736 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Ingo Molnar3593cab2006-02-07 06:49:14 -0200738 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return -ERESTARTSYS;
740 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700741 while (1) {
742 err = time_after(jiffies, start + ARM_WAIT_OSD);
743 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
744 break;
745 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
747 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200748 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700749 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700751 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200753 mutex_unlock(&av7110->dcomlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 return 0;
755}
756
757static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
758{
759 int i, ret;
760 unsigned long start;
761 int length = strlen(buf) + 1;
762 u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
763
Ingo Molnar3593cab2006-02-07 06:49:14 -0200764 if (mutex_lock_interruptible(&av7110->dcomlock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return -ERESTARTSYS;
766
767 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700768 while (1) {
769 ret = time_after(jiffies, start + ARM_WAIT_OSD);
770 if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
771 break;
772 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
774 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200775 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700776 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700778 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780#ifndef _NOHANDSHAKE
781 start = jiffies;
Oliver Endriss25de1922005-07-07 17:58:28 -0700782 while (1) {
783 ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
784 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
785 break;
786 if (ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
788 __FUNCTION__);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200789 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700790 return -ETIMEDOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
Johannes Stezenbach7d87bc32005-07-07 17:57:56 -0700792 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794#endif
795 for (i = 0; i < length / 2; i++)
796 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
797 swab16(*(u16 *)(buf + 2 * i)), 2);
798 if (length & 1)
799 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
800 ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200801 mutex_unlock(&av7110->dcomlock);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700802 if (ret && ret!=-ERESTARTSYS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
804 return ret;
805}
806
807static inline int DrawLine(struct av7110 *av7110, u8 windownr,
808 u16 x, u16 y, u16 dx, u16 dy, u16 color)
809{
810 return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
811 windownr, x, y, dx, dy, color);
812}
813
814static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
815 u16 x, u16 y, u16 dx, u16 dy, u16 color)
816{
817 return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
818 windownr, x, y, dx, dy, color);
819}
820
821static inline int HideWindow(struct av7110 *av7110, u8 windownr)
822{
823 return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
824}
825
826static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
827{
828 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
829}
830
831static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
832{
833 return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
834}
835
836static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
837{
838 return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
839}
840
841static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
842 osd_raw_window_t disptype,
843 u16 width, u16 height)
844{
845 return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
846 windownr, disptype, width, height);
847}
848
849
850static enum av7110_osd_palette_type bpp2pal[8] = {
851 Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
852};
853static osd_raw_window_t bpp2bit[8] = {
854 OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
855};
856
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700857static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
858{
859 int ret = wait_event_interruptible_timeout(av7110->bmpq,
860 av7110->bmp_state != BMP_LOADING, 10*HZ);
861 if (ret == -ERESTARTSYS)
862 return ret;
863 if (ret == 0) {
864 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
865 ret, av7110->bmp_state);
866 av7110->bmp_state = BMP_NONE;
867 return -ETIMEDOUT;
868 }
869 return 0;
870}
871
872static inline int LoadBitmap(struct av7110 *av7110,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 u16 dx, u16 dy, int inc, u8 __user * data)
874{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700875 u16 format;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 int bpp;
877 int i;
878 int d, delta;
879 u8 c;
880 int ret;
881
882 dprintk(4, "%p\n", av7110);
883
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700884 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 av7110->bmp_state = BMP_LOADING;
887 if (format == OSD_BITMAP8) {
888 bpp=8; delta = 1;
889 } else if (format == OSD_BITMAP4) {
890 bpp=4; delta = 2;
891 } else if (format == OSD_BITMAP2) {
892 bpp=2; delta = 4;
893 } else if (format == OSD_BITMAP1) {
894 bpp=1; delta = 8;
895 } else {
896 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700897 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
900 av7110->bmpp = 0;
901 if (av7110->bmplen > 32768) {
902 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700903 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
905 for (i = 0; i < dy; i++) {
906 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
907 av7110->bmp_state = BMP_NONE;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700908 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
910 }
911 if (format != OSD_BITMAP8) {
912 for (i = 0; i < dx * dy / delta; i++) {
913 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
914 for (d = delta - 2; d >= 0; d--) {
915 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
916 << ((delta - d - 1) * bpp));
917 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
918 }
919 }
920 }
921 av7110->bmplen += 1024;
922 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700923 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
924 if (!ret)
925 ret = WaitUntilBmpLoaded(av7110);
926 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927}
928
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700929static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 dprintk(4, "%p\n", av7110);
932
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700933 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
936static inline int ReleaseBitmap(struct av7110 *av7110)
937{
938 dprintk(4, "%p\n", av7110);
939
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700940 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 return -1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700942 if (av7110->bmp_state == BMP_LOADING)
943 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 av7110->bmp_state = BMP_NONE;
945 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
946}
947
948static u32 RGB2YUV(u16 R, u16 G, u16 B)
949{
950 u16 y, u, v;
951 u16 Y, Cr, Cb;
952
953 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
954 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
955 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
956
957 Y = y / 256;
958 Cb = u / 16;
959 Cr = v / 16;
960
961 return Cr | (Cb << 16) | (Y << 8);
962}
963
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700964static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700966 int ret;
967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 u16 ch, cl;
969 u32 yuv;
970
971 yuv = blend ? RGB2YUV(r,g,b) : 0;
972 cl = (yuv & 0xffff);
973 ch = ((yuv >> 16) & 0xffff);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -0700974 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
975 color, ch, cl);
976 if (!ret)
977 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
978 color, ((blend >> 4) & 0x0f));
979 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
982static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
983{
984 int i;
985 int length = last - first + 1;
986
987 if (length * 4 > DATA_BUFF3_SIZE)
988 return -EINVAL;
989
990 for (i = 0; i < length; i++) {
991 u32 color, blend, yuv;
992
993 if (get_user(color, colors + i))
994 return -EFAULT;
995 blend = (color & 0xF0000000) >> 4;
996 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
997 (color >> 16) & 0xFF) | blend : 0;
998 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
999 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
1000 }
1001 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
1002 av7110->osdwin,
1003 bpp2pal[av7110->osdbpp[av7110->osdwin]],
1004 first, last);
1005}
1006
1007static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
1008 int x1, int y1, int inc, u8 __user * data)
1009{
1010 uint w, h, bpp, bpl, size, lpb, bnum, brest;
1011 int i;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001012 int rc,release_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 w = x1 - x0 + 1;
1015 h = y1 - y0 + 1;
1016 if (inc <= 0)
1017 inc = w;
1018 if (w <= 0 || w > 720 || h <= 0 || h > 576)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001019 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1021 bpl = ((w * bpp + 7) & ~7) / 8;
1022 size = h * bpl;
1023 lpb = (32 * 1024) / bpl;
1024 bnum = size / (lpb * bpl);
1025 brest = size - bnum * lpb * bpl;
1026
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001027 if (av7110->bmp_state == BMP_LOADING) {
1028 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1029 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1030 rc = WaitUntilBmpLoaded(av7110);
1031 if (rc)
1032 return rc;
1033 /* just continue. This should work for all fw versions
1034 * if bnum==1 && !brest && LoadBitmap was successful
1035 */
1036 }
1037
1038 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 for (i = 0; i < bnum; i++) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001040 rc = LoadBitmap(av7110, w, lpb, inc, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001042 break;
1043 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 if (rc)
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001045 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 data += lpb * inc;
1047 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001048 if (!rc && brest) {
1049 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1050 if (!rc)
1051 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001053 release_rc = ReleaseBitmap(av7110);
1054 if (!rc)
1055 rc = release_rc;
1056 if (rc)
1057 dprintk(1,"returns %d\n",rc);
1058 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1062{
1063 int ret;
1064
Ingo Molnar3593cab2006-02-07 06:49:14 -02001065 if (mutex_lock_interruptible(&av7110->osd_mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return -ERESTARTSYS;
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 switch (dc->cmd) {
1069 case OSD_Close:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001070 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1071 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 case OSD_Open:
1073 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001074 ret = CreateOSDWindow(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1076 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001077 if (ret)
1078 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001080 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1081 if (ret)
1082 break;
1083 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001085 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 case OSD_Show:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001087 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1088 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 case OSD_Hide:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001090 ret = HideWindow(av7110, av7110->osdwin);
1091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 case OSD_Clear:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001093 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1094 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 case OSD_Fill:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001096 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1097 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 case OSD_SetColor:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001099 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1100 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 case OSD_SetPalette:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001102 if (FW_VERSION(av7110->arm_app) >= 0x2618)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001104 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 int i, len = dc->x0-dc->color+1;
1106 u8 __user *colors = (u8 __user *)dc->data;
1107 u8 r, g, b, blend;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001108 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 for (i = 0; i<len; i++) {
1110 if (get_user(r, colors + i * 4) ||
1111 get_user(g, colors + i * 4 + 1) ||
1112 get_user(b, colors + i * 4 + 2) ||
1113 get_user(blend, colors + i * 4 + 3)) {
1114 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001115 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001117 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1118 if (ret)
1119 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 }
1121 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001122 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 case OSD_SetPixel:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001124 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 dc->x0, dc->y0, 0, 0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001126 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 case OSD_SetRow:
1128 dc->y1 = dc->y0;
1129 /* fall through */
1130 case OSD_SetBlock:
1131 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001132 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 case OSD_FillRow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001134 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 dc->x1-dc->x0+1, dc->y1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001136 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 case OSD_FillBlock:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001138 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001140 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 case OSD_Line:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001142 ret = DrawLine(av7110, av7110->osdwin,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001144 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 case OSD_Text:
1146 {
1147 char textbuf[240];
1148
1149 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1150 ret = -EFAULT;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153 textbuf[239] = 0;
1154 if (dc->x1 > 3)
1155 dc->x1 = 3;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001156 ret = SetFont(av7110, av7110->osdwin, dc->x1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001158 if (!ret)
1159 ret = FlushText(av7110);
1160 if (!ret)
1161 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1162 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164 case OSD_SetWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001165 if (dc->x0 < 1 || dc->x0 > 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001167 else {
1168 av7110->osdwin = dc->x0;
1169 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001171 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 case OSD_MoveWindow:
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001173 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1174 if (!ret)
1175 ret = SetColorBlend(av7110, av7110->osdwin);
1176 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 case OSD_OpenRaw:
1178 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1179 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001180 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001182 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001184 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 av7110->osdbpp[av7110->osdwin] = 0;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001186 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001188 if (ret)
1189 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (!dc->data) {
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001191 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1192 if (!ret)
1193 ret = SetColorBlend(av7110, av7110->osdwin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 }
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001195 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 default:
1197 ret = -EINVAL;
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001198 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 }
1200
Ingo Molnar3593cab2006-02-07 06:49:14 -02001201 mutex_unlock(&av7110->osd_mutex);
Wolfgang Rohdewaldc9090eb2005-07-07 17:57:55 -07001202 if (ret==-ERESTARTSYS)
1203 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1204 else if (ret)
1205 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return ret;
1208}
1209
1210int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1211{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001212 switch (cap->cmd) {
1213 case OSD_CAP_MEMSIZE:
1214 if (FW_4M_SDRAM(av7110->arm_app))
Michael Krufky50c25ff2006-01-09 15:25:34 -02001215 cap->val = 1000000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001216 else
Michael Krufky50c25ff2006-01-09 15:25:34 -02001217 cap->val = 92000;
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -08001218 return 0;
1219 default:
1220 return -EINVAL;
1221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222}
1223#endif /* CONFIG_DVB_AV7110_OSD */