]> err.no Git - linux-2.6/blob - drivers/media/dvb/ttpci/av7110_hw.c
Merge branches 'at91', 'dyntick', 'ep93xx', 'iop', 'ixp', 'misc', 'orion', 'omap...
[linux-2.6] / drivers / media / dvb / ttpci / av7110_hw.c
1 /*
2  * av7110_hw.c: av7110 low level hardware access and firmware interface
3  *
4  * Copyright (C) 1999-2002 Ralph  Metzler
5  *                       & Marcus Metzler for convergence integrated media GmbH
6  *
7  * originally based on code by:
8  * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
24  *
25  * the project's page is at http://www.linuxtv.org/dvb/
26  */
27
28 /* for debugging ARM communication: */
29 //#define COM_DEBUG
30
31 #include <stdarg.h>
32 #include <linux/types.h>
33 #include <linux/kernel.h>
34 #include <linux/string.h>
35 #include <linux/delay.h>
36 #include <linux/fs.h>
37
38 #include "av7110.h"
39 #include "av7110_hw.h"
40
41 #define _NOHANDSHAKE
42
43 /****************************************************************************
44  * DEBI functions
45  ****************************************************************************/
46
47 /* This DEBI code is based on the Stradis driver
48    by Nathan Laredo <laredo@gnu.org> */
49
50 int av7110_debiwrite(struct av7110 *av7110, u32 config,
51                      int addr, u32 val, int count)
52 {
53         struct saa7146_dev *dev = av7110->dev;
54
55         if (count <= 0 || count > 32764) {
56                 printk("%s: invalid count %d\n", __func__, count);
57                 return -1;
58         }
59         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
60                 printk("%s: wait_for_debi_done failed\n", __func__);
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
73 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
74 {
75         struct saa7146_dev *dev = av7110->dev;
76         u32 result = 0;
77
78         if (count > 32764 || count <= 0) {
79                 printk("%s: invalid count %d\n", __func__, count);
80                 return 0;
81         }
82         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
83                 printk("%s: wait_for_debi_done #1 failed\n", __func__);
84                 return 0;
85         }
86         saa7146_write(dev, DEBI_AD, av7110->debi_bus);
87         saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
88
89         saa7146_write(dev, DEBI_CONFIG, config);
90         saa7146_write(dev, MC2, (2 << 16) | 2);
91         if (count > 4)
92                 return count;
93         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
94                 printk("%s: wait_for_debi_done #2 failed\n", __func__);
95                 return 0;
96         }
97
98         result = saa7146_read(dev, DEBI_AD);
99         result &= (0xffffffffUL >> ((4 - count) * 8));
100         return result;
101 }
102
103
104
105 /* av7110 ARM core boot stuff */
106 #if 0
107 void 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 }
126 #endif  /*  0  */
127
128 static 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         }
139         return -ETIMEDOUT;
140 }
141
142 static int load_dram(struct av7110 *av7110, u32 *data, int len)
143 {
144         int i;
145         int blocks, rest;
146         u32 base, bootblock = AV7110_BOOT_BLOCK;
147
148         dprintk(4, "%p\n", av7110);
149
150         blocks = len / AV7110_BOOT_MAX_SIZE;
151         rest = len % AV7110_BOOT_MAX_SIZE;
152         base = DRAM_START_CODE;
153
154         for (i = 0; i < blocks; i++) {
155                 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
156                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
157                         return -ETIMEDOUT;
158                 }
159                 dprintk(4, "writing DRAM block %d\n", i);
160                 mwdebi(av7110, DEBISWAB, bootblock,
161                        ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
162                 bootblock ^= 0x1400;
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;
167         }
168
169         if (rest > 0) {
170                 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
171                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
172                         return -ETIMEDOUT;
173                 }
174                 if (rest > 4)
175                         mwdebi(av7110, DEBISWAB, bootblock,
176                                ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
177                 else
178                         mwdebi(av7110, DEBISWAB, bootblock,
179                                ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
180
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);
184         }
185         if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
186                 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
187                 return -ETIMEDOUT;
188         }
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) {
192                 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
193                 return -ETIMEDOUT;
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 */
201 static 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
222 int 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
230         av7110->arm_ready = 0;
231
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);
245         /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
246         iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
247
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));
265         iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
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");
270                 return -ETIMEDOUT;
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");
291                 return -ETIMEDOUT;
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
311 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
312 {
313         unsigned long start;
314         u32 stat;
315         int err;
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 (;;) {
326                 err = time_after(jiffies, start + ARM_WAIT_FREE);
327                 if (mutex_lock_interruptible(&av7110->dcomlock))
328                         return -ERESTARTSYS;
329                 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
330                 mutex_unlock(&av7110->dcomlock);
331                 if ((stat & flags) == 0)
332                         break;
333                 if (err) {
334                         printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
335                                 __func__, stat & flags);
336                         return -ETIMEDOUT;
337                 }
338                 msleep(1);
339         }
340         return 0;
341 }
342
343 static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
344 {
345         int i;
346         unsigned long start;
347         char *type = NULL;
348         u16 flags[2] = {0, 0};
349         u32 stat;
350         int err;
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;
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) {
365                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
366                         av7110->arm_errors++;
367                         return -ETIMEDOUT;
368                 }
369                 msleep(1);
370         }
371
372         if (FW_VERSION(av7110->arm_app) <= 0x261f)
373                 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
374
375 #ifndef _NOHANDSHAKE
376         start = jiffies;
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) {
382                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
383                         return -ETIMEDOUT;
384                 }
385                 msleep(1);
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 (;;) {
418                         err = time_after(jiffies, start + ARM_WAIT_FREE);
419                         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
420                         if (stat & flags[0]) {
421                                 printk(KERN_ERR "%s: %s QUEUE overflow\n",
422                                         __func__, type);
423                                 return -1;
424                         }
425                         if ((stat & flags[1]) == 0)
426                                 break;
427                         if (err) {
428                                 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
429                                         __func__, type);
430                                 av7110->arm_errors++;
431                                 return -ETIMEDOUT;
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
447         if (FW_VERSION(av7110->arm_app) <= 0x261f)
448                 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
449
450 #ifdef COM_DEBUG
451         start = jiffies;
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) {
457                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
458                                __func__, (buf[0] >> 8) & 0xff);
459                         return -ETIMEDOUT;
460                 }
461                 msleep(1);
462         }
463
464         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
465         if (stat & GPMQOver) {
466                 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
467                 return -ENOSPC;
468         }
469         else if (stat & OSDQOver) {
470                 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
471                 return -ENOSPC;
472         }
473 #endif
474
475         return 0;
476 }
477
478 static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
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         }
488         if (mutex_lock_interruptible(&av7110->dcomlock))
489                 return -ERESTARTSYS;
490
491         ret = __av7110_send_fw_cmd(av7110, buf, length);
492         mutex_unlock(&av7110->dcomlock);
493         if (ret && ret!=-ERESTARTSYS)
494                 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
495                        __func__, ret);
496         return ret;
497 }
498
499 int 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);
518         if (ret && ret != -ERESTARTSYS)
519                 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
520         return ret;
521 }
522
523 #if 0
524 int 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);
541         if (ret && ret != -ERESTARTSYS)
542                 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
543         return ret;
544 }
545 #endif  /*  0  */
546
547 int 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
564         if (mutex_lock_interruptible(&av7110->dcomlock))
565                 return -ERESTARTSYS;
566
567         if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
568                 mutex_unlock(&av7110->dcomlock);
569                 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
570                 return err;
571         }
572
573         start = jiffies;
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) {
579                         printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
580                         mutex_unlock(&av7110->dcomlock);
581                         return -ETIMEDOUT;
582                 }
583 #ifdef _NOHANDSHAKE
584                 msleep(1);
585 #endif
586         }
587
588 #ifndef _NOHANDSHAKE
589         start = jiffies;
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) {
595                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
596                         mutex_unlock(&av7110->dcomlock);
597                         return -ETIMEDOUT;
598                 }
599                 msleep(1);
600         }
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", __func__);
607                 mutex_unlock(&av7110->dcomlock);
608                 return -1;
609         }
610         else if (stat & OSDQOver) {
611                 printk(KERN_ERR "%s: OSDQOver\n", __func__);
612                 mutex_unlock(&av7110->dcomlock);
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
620         mutex_unlock(&av7110->dcomlock);
621         return 0;
622 }
623
624 static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
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  */
639 int 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",
648                        av7110->dvb_adapter.num);
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",
659                av7110->dvb_adapter.num, av7110->arm_fw,
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",
665                        av7110->dvb_adapter.num);
666         else
667                 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
668                        av7110->dvb_adapter.num);
669
670         return 0;
671 }
672
673
674 int 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
696         ret = av7110_send_fw_cmd(av7110, buf, 18);
697         if (ret && ret!=-ERESTARTSYS)
698                 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
699         return ret;
700 }
701
702
703 #ifdef CONFIG_DVB_AV7110_OSD
704
705 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
706 {
707         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
708 }
709
710 static 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
717 static 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
724 static 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
731 static int FlushText(struct av7110 *av7110)
732 {
733         unsigned long start;
734         int err;
735
736         if (mutex_lock_interruptible(&av7110->dcomlock))
737                 return -ERESTARTSYS;
738         start = jiffies;
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) {
744                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
745                                __func__);
746                         mutex_unlock(&av7110->dcomlock);
747                         return -ETIMEDOUT;
748                 }
749                 msleep(1);
750         }
751         mutex_unlock(&av7110->dcomlock);
752         return 0;
753 }
754
755 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *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
762         if (mutex_lock_interruptible(&av7110->dcomlock))
763                 return -ERESTARTSYS;
764
765         start = jiffies;
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) {
771                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
772                                __func__);
773                         mutex_unlock(&av7110->dcomlock);
774                         return -ETIMEDOUT;
775                 }
776                 msleep(1);
777         }
778 #ifndef _NOHANDSHAKE
779         start = jiffies;
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) {
785                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
786                                __func__);
787                         mutex_unlock(&av7110->dcomlock);
788                         return -ETIMEDOUT;
789                 }
790                 msleep(1);
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);
799         mutex_unlock(&av7110->dcomlock);
800         if (ret && ret!=-ERESTARTSYS)
801                 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
802         return ret;
803 }
804
805 static 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
812 static 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
819 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
820 {
821         return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
822 }
823
824 static 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
829 static 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
834 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
835 {
836         return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
837 }
838
839 static 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
848 static enum av7110_osd_palette_type bpp2pal[8] = {
849         Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
850 };
851 static osd_raw_window_t bpp2bit[8] = {
852         OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
853 };
854
855 static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
856 {
857         int ret = wait_event_timeout(av7110->bmpq,
858                                 av7110->bmp_state != BMP_LOADING, 10*HZ);
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
868 static inline int LoadBitmap(struct av7110 *av7110,
869                              u16 dx, u16 dy, int inc, u8 __user * data)
870 {
871         u16 format;
872         int bpp;
873         int i;
874         int d, delta;
875         u8 c;
876         int ret;
877
878         dprintk(4, "%p\n", av7110);
879
880         format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
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;
893                 return -EINVAL;
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;
899                 return -EINVAL;
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;
904                         return -EINVAL;
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);
919         ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
920         if (!ret)
921                 ret = WaitUntilBmpLoaded(av7110);
922         return ret;
923 }
924
925 static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
926 {
927         dprintk(4, "%p\n", av7110);
928
929         return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
930 }
931
932 static inline int ReleaseBitmap(struct av7110 *av7110)
933 {
934         dprintk(4, "%p\n", av7110);
935
936         if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
937                 return -1;
938         if (av7110->bmp_state == BMP_LOADING)
939                 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
940         av7110->bmp_state = BMP_NONE;
941         return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
942 }
943
944 static 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
960 static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
961 {
962         int ret;
963
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);
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;
976 }
977
978 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
979 {
980         int i;
981         int length = last - first + 1;
982
983         if (length * 4 > DATA_BUFF3_SIZE)
984                 return -EINVAL;
985
986         for (i = 0; i < length; i++) {
987                 u32 color, blend, yuv;
988
989                 if (get_user(color, colors + i))
990                         return -EFAULT;
991                 blend = (color & 0xF0000000) >> 4;
992                 yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
993                                      (color >> 16) & 0xFF) | blend : 0;
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,
998                             av7110->osdwin,
999                             bpp2pal[av7110->osdbpp[av7110->osdwin]],
1000                             first, last);
1001 }
1002
1003 static 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;
1008         int rc,release_rc;
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)
1015                 return -EINVAL;
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
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);
1027                 if (rc)
1028                         return rc;
1029                 /* just continue. This should work for all fw versions
1030                  * if bnum==1 && !brest && LoadBitmap was successful
1031                  */
1032         }
1033
1034         rc = 0;
1035         for (i = 0; i < bnum; i++) {
1036                 rc = LoadBitmap(av7110, w, lpb, inc, data);
1037                 if (rc)
1038                         break;
1039                 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1040                 if (rc)
1041                         break;
1042                 data += lpb * inc;
1043         }
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;
1055 }
1056
1057 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1058 {
1059         int ret;
1060
1061         if (mutex_lock_interruptible(&av7110->osd_mutex))
1062                 return -ERESTARTSYS;
1063
1064         switch (dc->cmd) {
1065         case OSD_Close:
1066                 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1067                 break;
1068         case OSD_Open:
1069                 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1070                 ret = CreateOSDWindow(av7110, av7110->osdwin,
1071                                 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1072                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1073                 if (ret)
1074                         break;
1075                 if (!dc->data) {
1076                         ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1077                         if (ret)
1078                                 break;
1079                         ret = SetColorBlend(av7110, av7110->osdwin);
1080                 }
1081                 break;
1082         case OSD_Show:
1083                 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1084                 break;
1085         case OSD_Hide:
1086                 ret = HideWindow(av7110, av7110->osdwin);
1087                 break;
1088         case OSD_Clear:
1089                 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1090                 break;
1091         case OSD_Fill:
1092                 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1093                 break;
1094         case OSD_SetColor:
1095                 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1096                 break;
1097         case OSD_SetPalette:
1098                 if (FW_VERSION(av7110->arm_app) >= 0x2618)
1099                         ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1100                 else {
1101                         int i, len = dc->x0-dc->color+1;
1102                         u8 __user *colors = (u8 __user *)dc->data;
1103                         u8 r, g, b, blend;
1104                         ret = 0;
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;
1111                                         break;
1112                                     }
1113                                 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1114                                 if (ret)
1115                                         break;
1116                         }
1117                 }
1118                 break;
1119         case OSD_SetPixel:
1120                 ret = DrawLine(av7110, av7110->osdwin,
1121                          dc->x0, dc->y0, 0, 0, dc->color);
1122                 break;
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);
1128                 break;
1129         case OSD_FillRow:
1130                 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1131                           dc->x1-dc->x0+1, dc->y1, dc->color);
1132                 break;
1133         case OSD_FillBlock:
1134                 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1135                           dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1136                 break;
1137         case OSD_Line:
1138                 ret = DrawLine(av7110, av7110->osdwin,
1139                          dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1140                 break;
1141         case OSD_Text:
1142         {
1143                 char textbuf[240];
1144
1145                 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1146                         ret = -EFAULT;
1147                         break;
1148                 }
1149                 textbuf[239] = 0;
1150                 if (dc->x1 > 3)
1151                         dc->x1 = 3;
1152                 ret = SetFont(av7110, av7110->osdwin, dc->x1,
1153                         (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1154                 if (!ret)
1155                         ret = FlushText(av7110);
1156                 if (!ret)
1157                         ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1158                 break;
1159         }
1160         case OSD_SetWindow:
1161                 if (dc->x0 < 1 || dc->x0 > 7)
1162                         ret = -EINVAL;
1163                 else {
1164                         av7110->osdwin = dc->x0;
1165                         ret = 0;
1166                 }
1167                 break;
1168         case OSD_MoveWindow:
1169                 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1170                 if (!ret)
1171                         ret = SetColorBlend(av7110, av7110->osdwin);
1172                 break;
1173         case OSD_OpenRaw:
1174                 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1175                         ret = -EINVAL;
1176                         break;
1177                 }
1178                 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1179                         av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1180                 else
1181                         av7110->osdbpp[av7110->osdwin] = 0;
1182                 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1183                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1184                 if (ret)
1185                         break;
1186                 if (!dc->data) {
1187                         ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1188                         if (!ret)
1189                                 ret = SetColorBlend(av7110, av7110->osdwin);
1190                 }
1191                 break;
1192         default:
1193                 ret = -EINVAL;
1194                 break;
1195         }
1196
1197         mutex_unlock(&av7110->osd_mutex);
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
1203         return ret;
1204 }
1205
1206 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1207 {
1208         switch (cap->cmd) {
1209         case OSD_CAP_MEMSIZE:
1210                 if (FW_4M_SDRAM(av7110->arm_app))
1211                         cap->val = 1000000;
1212                 else
1213                         cap->val = 92000;
1214                 return 0;
1215         default:
1216                 return -EINVAL;
1217         }
1218 }
1219 #endif /* CONFIG_DVB_AV7110_OSD */