]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/media/dvb/ttpci/av7110_hw.c
V4L/DVB (8074): av7110: OSD transfers should not be interrupted
[mirror_ubuntu-hirsute-kernel.git] / drivers / media / dvb / ttpci / av7110_hw.c
CommitLineData
1da177e4
LT
1/*
2 * av7110_hw.c: av7110 low level hardware access and firmware interface
3 *
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
6 *
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
24 *
25 * the project's page is at http://www.linuxtv.org/dvb/
26 */
27
28/* for debugging ARM communication: */
29//#define COM_DEBUG
30
31#include <stdarg.h>
32#include <linux/types.h>
33#include <linux/kernel.h>
34#include <linux/string.h>
1da177e4 35#include <linux/delay.h>
1da177e4
LT
36#include <linux/fs.h>
37
38#include "av7110.h"
39#include "av7110_hw.h"
40
ce7d3c11
JS
41#define _NOHANDSHAKE
42
1da177e4
LT
43/****************************************************************************
44 * DEBI functions
45 ****************************************************************************/
46
47/* This DEBI code is based on the Stradis driver
48 by Nathan Laredo <laredo@gnu.org> */
49
50int av7110_debiwrite(struct av7110 *av7110, u32 config,
51 int addr, u32 val, int count)
52{
53 struct saa7146_dev *dev = av7110->dev;
54
55 if (count <= 0 || count > 32764) {
3ca7fc84 56 printk("%s: invalid count %d\n", __func__, count);
1da177e4
LT
57 return -1;
58 }
59 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
3ca7fc84 60 printk("%s: wait_for_debi_done failed\n", __func__);
1da177e4
LT
61 return -1;
62 }
63 saa7146_write(dev, DEBI_CONFIG, config);
64 if (count <= 4) /* immediate transfer */
65 saa7146_write(dev, DEBI_AD, val);
66 else /* block transfer */
67 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
68 saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
69 saa7146_write(dev, MC2, (2 << 16) | 2);
70 return 0;
71}
72
73u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
74{
75 struct saa7146_dev *dev = av7110->dev;
76 u32 result = 0;
77
78 if (count > 32764 || count <= 0) {
3ca7fc84 79 printk("%s: invalid count %d\n", __func__, count);
1da177e4
LT
80 return 0;
81 }
82 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
3ca7fc84 83 printk("%s: wait_for_debi_done #1 failed\n", __func__);
1da177e4
LT
84 return 0;
85 }
86 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
87 saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
88
89 saa7146_write(dev, DEBI_CONFIG, config);
90 saa7146_write(dev, MC2, (2 << 16) | 2);
91 if (count > 4)
92 return count;
93 if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
3ca7fc84 94 printk("%s: wait_for_debi_done #2 failed\n", __func__);
1da177e4
LT
95 return 0;
96 }
97
98 result = saa7146_read(dev, DEBI_AD);
99 result &= (0xffffffffUL >> ((4 - count) * 8));
100 return result;
101}
102
103
104
105/* av7110 ARM core boot stuff */
d91b730d 106#if 0
1da177e4
LT
107void av7110_reset_arm(struct av7110 *av7110)
108{
109 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
110
111 /* Disable DEBI and GPIO irq */
112 SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
113 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
114
115 saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
116 msleep(30); /* the firmware needs some time to initialize */
117
118 ARM_ResetMailBox(av7110);
119
120 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
121 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
122
123 av7110->arm_ready = 1;
124 dprintk(1, "reset ARM\n");
125}
d91b730d 126#endif /* 0 */
1da177e4
LT
127
128static int waitdebi(struct av7110 *av7110, int adr, int state)
129{
130 int k;
131
132 dprintk(4, "%p\n", av7110);
133
134 for (k = 0; k < 100; k++) {
135 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
136 return 0;
137 udelay(5);
138 }
c9090ebb 139 return -ETIMEDOUT;
1da177e4
LT
140}
141
142static int load_dram(struct av7110 *av7110, u32 *data, int len)
143{
144 int i;
145 int blocks, rest;
fabd2386 146 u32 base, bootblock = AV7110_BOOT_BLOCK;
1da177e4
LT
147
148 dprintk(4, "%p\n", av7110);
149
fabd2386
MCC
150 blocks = len / AV7110_BOOT_MAX_SIZE;
151 rest = len % AV7110_BOOT_MAX_SIZE;
1da177e4
LT
152 base = DRAM_START_CODE;
153
154 for (i = 0; i < blocks; i++) {
fabd2386 155 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
1da177e4 156 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
c9090ebb 157 return -ETIMEDOUT;
1da177e4
LT
158 }
159 dprintk(4, "writing DRAM block %d\n", i);
160 mwdebi(av7110, DEBISWAB, bootblock,
804b4458 161 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
1da177e4 162 bootblock ^= 0x1400;
fabd2386
MCC
163 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
164 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
165 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
166 base += AV7110_BOOT_MAX_SIZE;
1da177e4
LT
167 }
168
169 if (rest > 0) {
fabd2386 170 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
1da177e4 171 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
c9090ebb 172 return -ETIMEDOUT;
1da177e4
LT
173 }
174 if (rest > 4)
175 mwdebi(av7110, DEBISWAB, bootblock,
804b4458 176 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
1da177e4
LT
177 else
178 mwdebi(av7110, DEBISWAB, bootblock,
804b4458 179 ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
1da177e4 180
fabd2386
MCC
181 iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
182 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
183 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
1da177e4 184 }
fabd2386 185 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
1da177e4 186 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
c9090ebb 187 return -ETIMEDOUT;
1da177e4 188 }
fabd2386
MCC
189 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
190 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
191 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
1da177e4 192 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
c9090ebb 193 return -ETIMEDOUT;
1da177e4
LT
194 }
195 return 0;
196}
197
198
199/* we cannot write av7110 DRAM directly, so load a bootloader into
200 * the DPRAM which implements a simple boot protocol */
201static u8 bootcode[] = {
202 0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
203 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
204 0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
205 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
206 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
207 0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
208 0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
209 0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
210 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
211 0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
212 0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
213 0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
214 0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
215 0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
216 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
217 0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
218 0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
219 0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
220};
221
222int av7110_bootarm(struct av7110 *av7110)
223{
224 struct saa7146_dev *dev = av7110->dev;
225 u32 ret;
226 int i;
227
228 dprintk(4, "%p\n", av7110);
229
66190a27
OE
230 av7110->arm_ready = 0;
231
1da177e4
LT
232 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
233
234 /* Disable DEBI and GPIO irq */
235 SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
236 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
237
238 /* enable DEBI */
239 saa7146_write(av7110->dev, MC1, 0x08800880);
240 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
241 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
242
243 /* test DEBI */
244 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
9f3319b4
MS
245 /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
246 iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
247
1da177e4
LT
248 if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
249 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
250 "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
251 ret, 0x10325476);
252 return -1;
253 }
254 for (i = 0; i < 8192; i += 4)
255 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
256 dprintk(2, "debi test OK\n");
257
258 /* boot */
259 dprintk(1, "load boot code\n");
260 saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
261 //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
262 //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
263
264 mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
fabd2386 265 iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
1da177e4
LT
266
267 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
268 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
269 "saa7146_wait_for_debi_done() timed out\n");
c9090ebb 270 return -ETIMEDOUT;
1da177e4
LT
271 }
272 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
273 mdelay(1);
274
275 dprintk(1, "load dram code\n");
276 if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
277 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
278 "load_dram() failed\n");
279 return -1;
280 }
281
282 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
283 mdelay(1);
284
285 dprintk(1, "load dpram code\n");
286 mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
287
288 if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
289 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
290 "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
c9090ebb 291 return -ETIMEDOUT;
1da177e4
LT
292 }
293 saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
294 msleep(30); /* the firmware needs some time to initialize */
295
296 //ARM_ClearIrq(av7110);
297 ARM_ResetMailBox(av7110);
298 SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
299 SAA7146_IER_ENABLE(av7110->dev, MASK_03);
300
301 av7110->arm_errors = 0;
302 av7110->arm_ready = 1;
303 return 0;
304}
305
306
307/****************************************************************************
308 * DEBI command polling
309 ****************************************************************************/
310
311int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
312{
313 unsigned long start;
314 u32 stat;
25de1926 315 int err;
1da177e4
LT
316
317 if (FW_VERSION(av7110->arm_app) <= 0x261c) {
318 /* not supported by old firmware */
319 msleep(50);
320 return 0;
321 }
322
323 /* new firmware */
324 start = jiffies;
325 for (;;) {
25de1926 326 err = time_after(jiffies, start + ARM_WAIT_FREE);
3593cab5 327 if (mutex_lock_interruptible(&av7110->dcomlock))
1da177e4
LT
328 return -ERESTARTSYS;
329 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
3593cab5 330 mutex_unlock(&av7110->dcomlock);
25de1926 331 if ((stat & flags) == 0)
1da177e4 332 break;
25de1926 333 if (err) {
1da177e4 334 printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
3ca7fc84 335 __func__, stat & flags);
c9090ebb 336 return -ETIMEDOUT;
1da177e4
LT
337 }
338 msleep(1);
339 }
340 return 0;
341}
342
d91b730d 343static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
1da177e4
LT
344{
345 int i;
346 unsigned long start;
347 char *type = NULL;
348 u16 flags[2] = {0, 0};
349 u32 stat;
25de1926 350 int err;
1da177e4
LT
351
352// dprintk(4, "%p\n", av7110);
353
354 if (!av7110->arm_ready) {
355 dprintk(1, "arm not ready.\n");
356 return -ENXIO;
357 }
358
359 start = jiffies;
25de1926
OE
360 while (1) {
361 err = time_after(jiffies, start + ARM_WAIT_FREE);
362 if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
363 break;
364 if (err) {
3ca7fc84 365 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
66190a27 366 av7110->arm_errors++;
1da177e4
LT
367 return -ETIMEDOUT;
368 }
7d87bc39 369 msleep(1);
1da177e4
LT
370 }
371
9a7b102e
OE
372 if (FW_VERSION(av7110->arm_app) <= 0x261f)
373 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
1da177e4
LT
374
375#ifndef _NOHANDSHAKE
376 start = jiffies;
25de1926
OE
377 while (1) {
378 err = time_after(jiffies, start + ARM_WAIT_SHAKE);
379 if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
380 break;
381 if (err) {
3ca7fc84 382 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
1da177e4
LT
383 return -ETIMEDOUT;
384 }
7d87bc39 385 msleep(1);
1da177e4
LT
386 }
387#endif
388
389 switch ((buf[0] >> 8) & 0xff) {
390 case COMTYPE_PIDFILTER:
391 case COMTYPE_ENCODER:
392 case COMTYPE_REC_PLAY:
393 case COMTYPE_MPEGDECODER:
394 type = "MSG";
395 flags[0] = GPMQOver;
396 flags[1] = GPMQFull;
397 break;
398 case COMTYPE_OSD:
399 type = "OSD";
400 flags[0] = OSDQOver;
401 flags[1] = OSDQFull;
402 break;
403 case COMTYPE_MISC:
404 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
405 type = "MSG";
406 flags[0] = GPMQOver;
407 flags[1] = GPMQBusy;
408 }
409 break;
410 default:
411 break;
412 }
413
414 if (type != NULL) {
415 /* non-immediate COMMAND type */
416 start = jiffies;
417 for (;;) {
25de1926 418 err = time_after(jiffies, start + ARM_WAIT_FREE);
1da177e4
LT
419 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
420 if (stat & flags[0]) {
421 printk(KERN_ERR "%s: %s QUEUE overflow\n",
3ca7fc84 422 __func__, type);
1da177e4
LT
423 return -1;
424 }
425 if ((stat & flags[1]) == 0)
426 break;
25de1926 427 if (err) {
1da177e4 428 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
3ca7fc84 429 __func__, type);
edabaffc 430 av7110->arm_errors++;
c9090ebb 431 return -ETIMEDOUT;
1da177e4
LT
432 }
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
9a7b102e
OE
447 if (FW_VERSION(av7110->arm_app) <= 0x261f)
448 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
1da177e4
LT
449
450#ifdef COM_DEBUG
451 start = jiffies;
25de1926
OE
452 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) {
c9090ebb 457 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
3ca7fc84 458 __func__, (buf[0] >> 8) & 0xff);
1da177e4
LT
459 return -ETIMEDOUT;
460 }
7d87bc39 461 msleep(1);
1da177e4
LT
462 }
463
464 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
465 if (stat & GPMQOver) {
3ca7fc84 466 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
1da177e4
LT
467 return -ENOSPC;
468 }
469 else if (stat & OSDQOver) {
3ca7fc84 470 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
1da177e4
LT
471 return -ENOSPC;
472 }
473#endif
474
475 return 0;
476}
477
d91b730d 478static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
1da177e4
LT
479{
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 }
3593cab5 488 if (mutex_lock_interruptible(&av7110->dcomlock))
1da177e4
LT
489 return -ERESTARTSYS;
490
491 ret = __av7110_send_fw_cmd(av7110, buf, length);
3593cab5 492 mutex_unlock(&av7110->dcomlock);
c9090ebb 493 if (ret && ret!=-ERESTARTSYS)
1da177e4 494 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
3ca7fc84 495 __func__, ret);
1da177e4
LT
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);
c9090ebb 518 if (ret && ret != -ERESTARTSYS)
1da177e4
LT
519 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
520 return ret;
521}
522
d91b730d 523#if 0
1da177e4
LT
524int 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);
c9090ebb 541 if (ret && ret != -ERESTARTSYS)
1da177e4
LT
542 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
543 return ret;
544}
d91b730d 545#endif /* 0 */
1da177e4
LT
546
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
3593cab5 564 if (mutex_lock_interruptible(&av7110->dcomlock))
1da177e4
LT
565 return -ERESTARTSYS;
566
567 if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
3593cab5 568 mutex_unlock(&av7110->dcomlock);
1da177e4
LT
569 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
570 return err;
571 }
572
573 start = jiffies;
25de1926
OE
574 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) {
3ca7fc84 579 printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
3593cab5 580 mutex_unlock(&av7110->dcomlock);
c9090ebb 581 return -ETIMEDOUT;
1da177e4 582 }
7d87bc39
JS
583#ifdef _NOHANDSHAKE
584 msleep(1);
585#endif
1da177e4
LT
586 }
587
588#ifndef _NOHANDSHAKE
589 start = jiffies;
25de1926
OE
590 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) {
3ca7fc84 595 printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
3593cab5 596 mutex_unlock(&av7110->dcomlock);
c9090ebb 597 return -ETIMEDOUT;
1da177e4 598 }
7d87bc39 599 msleep(1);
1da177e4
LT
600 }
601#endif
602
603#ifdef COM_DEBUG
604 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
605 if (stat & GPMQOver) {
3ca7fc84 606 printk(KERN_ERR "%s: GPMQOver\n", __func__);
3593cab5 607 mutex_unlock(&av7110->dcomlock);
1da177e4
LT
608 return -1;
609 }
610 else if (stat & OSDQOver) {
3ca7fc84 611 printk(KERN_ERR "%s: OSDQOver\n", __func__);
3593cab5 612 mutex_unlock(&av7110->dcomlock);
1da177e4
LT
613 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
3593cab5 620 mutex_unlock(&av7110->dcomlock);
1da177e4
LT
621 return 0;
622}
623
d91b730d 624static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
1da177e4
LT
625{
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",
fdc53a6d 648 av7110->dvb_adapter.num);
1da177e4
LT
649 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",
fdc53a6d 659 av7110->dvb_adapter.num, av7110->arm_fw,
1da177e4
LT
660 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",
fdc53a6d 665 av7110->dvb_adapter.num);
1da177e4
LT
666 else
667 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
fdc53a6d 668 av7110->dvb_adapter.num);
1da177e4
LT
669
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
c9090ebb
WR
696 ret = av7110_send_fw_cmd(av7110, buf, 18);
697 if (ret && ret!=-ERESTARTSYS)
1da177e4 698 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
c9090ebb 699 return ret;
1da177e4
LT
700}
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;
25de1926 734 int err;
1da177e4 735
3593cab5 736 if (mutex_lock_interruptible(&av7110->dcomlock))
1da177e4
LT
737 return -ERESTARTSYS;
738 start = jiffies;
25de1926
OE
739 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) {
1da177e4 744 printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
3ca7fc84 745 __func__);
3593cab5 746 mutex_unlock(&av7110->dcomlock);
c9090ebb 747 return -ETIMEDOUT;
1da177e4 748 }
7d87bc39 749 msleep(1);
1da177e4 750 }
3593cab5 751 mutex_unlock(&av7110->dcomlock);
1da177e4
LT
752 return 0;
753}
754
804b4458 755static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
1da177e4
LT
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
3593cab5 762 if (mutex_lock_interruptible(&av7110->dcomlock))
1da177e4
LT
763 return -ERESTARTSYS;
764
765 start = jiffies;
25de1926
OE
766 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) {
1da177e4 771 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
3ca7fc84 772 __func__);
3593cab5 773 mutex_unlock(&av7110->dcomlock);
c9090ebb 774 return -ETIMEDOUT;
1da177e4 775 }
7d87bc39 776 msleep(1);
1da177e4
LT
777 }
778#ifndef _NOHANDSHAKE
779 start = jiffies;
25de1926
OE
780 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) {
1da177e4 785 printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
3ca7fc84 786 __func__);
3593cab5 787 mutex_unlock(&av7110->dcomlock);
c9090ebb 788 return -ETIMEDOUT;
1da177e4 789 }
7d87bc39 790 msleep(1);
1da177e4
LT
791 }
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);
3593cab5 799 mutex_unlock(&av7110->dcomlock);
c9090ebb 800 if (ret && ret!=-ERESTARTSYS)
1da177e4
LT
801 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
c9090ebb
WR
855static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
856{
0b915e74 857 int ret = wait_event_timeout(av7110->bmpq,
c9090ebb 858 av7110->bmp_state != BMP_LOADING, 10*HZ);
c9090ebb
WR
859 if (ret == 0) {
860 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
861 ret, av7110->bmp_state);
862 av7110->bmp_state = BMP_NONE;
863 return -ETIMEDOUT;
864 }
865 return 0;
866}
867
868static inline int LoadBitmap(struct av7110 *av7110,
1da177e4
LT
869 u16 dx, u16 dy, int inc, u8 __user * data)
870{
c9090ebb 871 u16 format;
1da177e4
LT
872 int bpp;
873 int i;
874 int d, delta;
875 u8 c;
876 int ret;
877
878 dprintk(4, "%p\n", av7110);
879
c9090ebb 880 format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
1da177e4
LT
881
882 av7110->bmp_state = BMP_LOADING;
883 if (format == OSD_BITMAP8) {
884 bpp=8; delta = 1;
885 } else if (format == OSD_BITMAP4) {
886 bpp=4; delta = 2;
887 } else if (format == OSD_BITMAP2) {
888 bpp=2; delta = 4;
889 } else if (format == OSD_BITMAP1) {
890 bpp=1; delta = 8;
891 } else {
892 av7110->bmp_state = BMP_NONE;
c9090ebb 893 return -EINVAL;
1da177e4
LT
894 }
895 av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
896 av7110->bmpp = 0;
897 if (av7110->bmplen > 32768) {
898 av7110->bmp_state = BMP_NONE;
c9090ebb 899 return -EINVAL;
1da177e4
LT
900 }
901 for (i = 0; i < dy; i++) {
902 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
903 av7110->bmp_state = BMP_NONE;
c9090ebb 904 return -EINVAL;
1da177e4
LT
905 }
906 }
907 if (format != OSD_BITMAP8) {
908 for (i = 0; i < dx * dy / delta; i++) {
909 c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
910 for (d = delta - 2; d >= 0; d--) {
911 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
912 << ((delta - d - 1) * bpp));
913 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
914 }
915 }
916 }
917 av7110->bmplen += 1024;
918 dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
c9090ebb
WR
919 ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
920 if (!ret)
921 ret = WaitUntilBmpLoaded(av7110);
922 return ret;
1da177e4
LT
923}
924
c9090ebb 925static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
1da177e4 926{
1da177e4
LT
927 dprintk(4, "%p\n", av7110);
928
c9090ebb 929 return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
1da177e4
LT
930}
931
932static inline int ReleaseBitmap(struct av7110 *av7110)
933{
934 dprintk(4, "%p\n", av7110);
935
c9090ebb 936 if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
1da177e4 937 return -1;
c9090ebb
WR
938 if (av7110->bmp_state == BMP_LOADING)
939 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
1da177e4
LT
940 av7110->bmp_state = BMP_NONE;
941 return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
942}
943
944static u32 RGB2YUV(u16 R, u16 G, u16 B)
945{
946 u16 y, u, v;
947 u16 Y, Cr, Cb;
948
949 y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
950 u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
951 v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
952
953 Y = y / 256;
954 Cb = u / 16;
955 Cr = v / 16;
956
957 return Cr | (Cb << 16) | (Y << 8);
958}
959
c9090ebb 960static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
1da177e4 961{
c9090ebb
WR
962 int ret;
963
1da177e4
LT
964 u16 ch, cl;
965 u32 yuv;
966
967 yuv = blend ? RGB2YUV(r,g,b) : 0;
968 cl = (yuv & 0xffff);
969 ch = ((yuv >> 16) & 0xffff);
c9090ebb
WR
970 ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
971 color, ch, cl);
972 if (!ret)
973 ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
974 color, ((blend >> 4) & 0x0f));
975 return ret;
1da177e4
LT
976}
977
978static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
979{
b930e1d8
MK
980 int i;
981 int length = last - first + 1;
1da177e4 982
b930e1d8
MK
983 if (length * 4 > DATA_BUFF3_SIZE)
984 return -EINVAL;
1da177e4 985
b930e1d8
MK
986 for (i = 0; i < length; i++) {
987 u32 color, blend, yuv;
1da177e4 988
b930e1d8
MK
989 if (get_user(color, colors + i))
990 return -EFAULT;
991 blend = (color & 0xF0000000) >> 4;
992 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
1da177e4 993 (color >> 16) & 0xFF) | blend : 0;
b930e1d8
MK
994 yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
995 wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
996 }
997 return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
1da177e4
LT
998 av7110->osdwin,
999 bpp2pal[av7110->osdbpp[av7110->osdwin]],
1000 first, last);
1001}
1002
1003static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
1004 int x1, int y1, int inc, u8 __user * data)
1005{
1006 uint w, h, bpp, bpl, size, lpb, bnum, brest;
1007 int i;
c9090ebb 1008 int rc,release_rc;
1da177e4
LT
1009
1010 w = x1 - x0 + 1;
1011 h = y1 - y0 + 1;
1012 if (inc <= 0)
1013 inc = w;
1014 if (w <= 0 || w > 720 || h <= 0 || h > 576)
c9090ebb 1015 return -EINVAL;
1da177e4
LT
1016 bpp = av7110->osdbpp[av7110->osdwin] + 1;
1017 bpl = ((w * bpp + 7) & ~7) / 8;
1018 size = h * bpl;
1019 lpb = (32 * 1024) / bpl;
1020 bnum = size / (lpb * bpl);
1021 brest = size - bnum * lpb * bpl;
1022
c9090ebb
WR
1023 if (av7110->bmp_state == BMP_LOADING) {
1024 /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
1025 BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
1026 rc = WaitUntilBmpLoaded(av7110);
1da177e4
LT
1027 if (rc)
1028 return rc;
c9090ebb
WR
1029 /* just continue. This should work for all fw versions
1030 * if bnum==1 && !brest && LoadBitmap was successful
1031 */
1da177e4 1032 }
c9090ebb
WR
1033
1034 rc = 0;
1035 for (i = 0; i < bnum; i++) {
1036 rc = LoadBitmap(av7110, w, lpb, inc, data);
1da177e4 1037 if (rc)
c9090ebb
WR
1038 break;
1039 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1da177e4 1040 if (rc)
c9090ebb
WR
1041 break;
1042 data += lpb * inc;
1da177e4 1043 }
c9090ebb
WR
1044 if (!rc && brest) {
1045 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1046 if (!rc)
1047 rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1048 }
1049 release_rc = ReleaseBitmap(av7110);
1050 if (!rc)
1051 rc = release_rc;
1052 if (rc)
1053 dprintk(1,"returns %d\n",rc);
1054 return rc;
1da177e4
LT
1055}
1056
1057int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1058{
1059 int ret;
1060
3593cab5 1061 if (mutex_lock_interruptible(&av7110->osd_mutex))
1da177e4
LT
1062 return -ERESTARTSYS;
1063
1da177e4
LT
1064 switch (dc->cmd) {
1065 case OSD_Close:
c9090ebb
WR
1066 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1067 break;
1da177e4
LT
1068 case OSD_Open:
1069 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
c9090ebb 1070 ret = CreateOSDWindow(av7110, av7110->osdwin,
1da177e4
LT
1071 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1072 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
c9090ebb
WR
1073 if (ret)
1074 break;
1da177e4 1075 if (!dc->data) {
c9090ebb
WR
1076 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1077 if (ret)
1078 break;
1079 ret = SetColorBlend(av7110, av7110->osdwin);
1da177e4 1080 }
c9090ebb 1081 break;
1da177e4 1082 case OSD_Show:
c9090ebb
WR
1083 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1084 break;
1da177e4 1085 case OSD_Hide:
c9090ebb
WR
1086 ret = HideWindow(av7110, av7110->osdwin);
1087 break;
1da177e4 1088 case OSD_Clear:
c9090ebb
WR
1089 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1090 break;
1da177e4 1091 case OSD_Fill:
c9090ebb
WR
1092 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1093 break;
1da177e4 1094 case OSD_SetColor:
c9090ebb
WR
1095 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1096 break;
1da177e4 1097 case OSD_SetPalette:
c9090ebb 1098 if (FW_VERSION(av7110->arm_app) >= 0x2618)
1da177e4 1099 ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
c9090ebb 1100 else {
1da177e4
LT
1101 int i, len = dc->x0-dc->color+1;
1102 u8 __user *colors = (u8 __user *)dc->data;
1103 u8 r, g, b, blend;
c9090ebb 1104 ret = 0;
1da177e4
LT
1105 for (i = 0; i<len; i++) {
1106 if (get_user(r, colors + i * 4) ||
1107 get_user(g, colors + i * 4 + 1) ||
1108 get_user(b, colors + i * 4 + 2) ||
1109 get_user(blend, colors + i * 4 + 3)) {
1110 ret = -EFAULT;
c9090ebb 1111 break;
1da177e4 1112 }
c9090ebb
WR
1113 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1114 if (ret)
1115 break;
1da177e4
LT
1116 }
1117 }
c9090ebb 1118 break;
1da177e4 1119 case OSD_SetPixel:
c9090ebb 1120 ret = DrawLine(av7110, av7110->osdwin,
1da177e4 1121 dc->x0, dc->y0, 0, 0, dc->color);
c9090ebb 1122 break;
1da177e4
LT
1123 case OSD_SetRow:
1124 dc->y1 = dc->y0;
1125 /* fall through */
1126 case OSD_SetBlock:
1127 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
c9090ebb 1128 break;
1da177e4 1129 case OSD_FillRow:
c9090ebb 1130 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1da177e4 1131 dc->x1-dc->x0+1, dc->y1, dc->color);
c9090ebb 1132 break;
1da177e4 1133 case OSD_FillBlock:
c9090ebb 1134 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1da177e4 1135 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
c9090ebb 1136 break;
1da177e4 1137 case OSD_Line:
c9090ebb 1138 ret = DrawLine(av7110, av7110->osdwin,
1da177e4 1139 dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
c9090ebb 1140 break;
1da177e4
LT
1141 case OSD_Text:
1142 {
1143 char textbuf[240];
1144
1145 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1146 ret = -EFAULT;
c9090ebb 1147 break;
1da177e4
LT
1148 }
1149 textbuf[239] = 0;
1150 if (dc->x1 > 3)
1151 dc->x1 = 3;
c9090ebb 1152 ret = SetFont(av7110, av7110->osdwin, dc->x1,
1da177e4 1153 (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
c9090ebb
WR
1154 if (!ret)
1155 ret = FlushText(av7110);
1156 if (!ret)
1157 ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1158 break;
1da177e4
LT
1159 }
1160 case OSD_SetWindow:
c9090ebb 1161 if (dc->x0 < 1 || dc->x0 > 7)
1da177e4 1162 ret = -EINVAL;
c9090ebb
WR
1163 else {
1164 av7110->osdwin = dc->x0;
1165 ret = 0;
1da177e4 1166 }
c9090ebb 1167 break;
1da177e4 1168 case OSD_MoveWindow:
c9090ebb
WR
1169 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1170 if (!ret)
1171 ret = SetColorBlend(av7110, av7110->osdwin);
1172 break;
1da177e4
LT
1173 case OSD_OpenRaw:
1174 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1175 ret = -EINVAL;
c9090ebb 1176 break;
1da177e4 1177 }
c9090ebb 1178 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1da177e4 1179 av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
c9090ebb 1180 else
1da177e4 1181 av7110->osdbpp[av7110->osdwin] = 0;
c9090ebb 1182 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1da177e4 1183 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
c9090ebb
WR
1184 if (ret)
1185 break;
1da177e4 1186 if (!dc->data) {
c9090ebb
WR
1187 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1188 if (!ret)
1189 ret = SetColorBlend(av7110, av7110->osdwin);
1da177e4 1190 }
c9090ebb 1191 break;
1da177e4
LT
1192 default:
1193 ret = -EINVAL;
c9090ebb 1194 break;
1da177e4
LT
1195 }
1196
3593cab5 1197 mutex_unlock(&av7110->osd_mutex);
c9090ebb
WR
1198 if (ret==-ERESTARTSYS)
1199 dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
1200 else if (ret)
1201 dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
1202
1da177e4
LT
1203 return ret;
1204}
1205
1206int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1207{
9101e622
MCC
1208 switch (cap->cmd) {
1209 case OSD_CAP_MEMSIZE:
1210 if (FW_4M_SDRAM(av7110->arm_app))
50c25fff 1211 cap->val = 1000000;
9101e622 1212 else
50c25fff 1213 cap->val = 92000;
9101e622
MCC
1214 return 0;
1215 default:
1216 return -EINVAL;
1217 }
1da177e4
LT
1218}
1219#endif /* CONFIG_DVB_AV7110_OSD */