Pull delete-sigdelayed into release branch
[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/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
44 #define _NOHANDSHAKE
45
46 /****************************************************************************
47  * DEBI functions
48  ****************************************************************************/
49
50 /* This DEBI code is based on the Stradis driver
51    by Nathan Laredo <laredo@gnu.org> */
52
53 int 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
76 u32 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 */
109 #if 0
110 void 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 }
129 #endif  /*  0  */
130
131 static 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         }
142         return -ETIMEDOUT;
143 }
144
145 static int load_dram(struct av7110 *av7110, u32 *data, int len)
146 {
147         int i;
148         int blocks, rest;
149         u32 base, bootblock = AV7110_BOOT_BLOCK;
150
151         dprintk(4, "%p\n", av7110);
152
153         blocks = len / AV7110_BOOT_MAX_SIZE;
154         rest = len % AV7110_BOOT_MAX_SIZE;
155         base = DRAM_START_CODE;
156
157         for (i = 0; i < blocks; i++) {
158                 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
159                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
160                         return -ETIMEDOUT;
161                 }
162                 dprintk(4, "writing DRAM block %d\n", i);
163                 mwdebi(av7110, DEBISWAB, bootblock,
164                        ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
165                 bootblock ^= 0x1400;
166                 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;
170         }
171
172         if (rest > 0) {
173                 if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
174                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
175                         return -ETIMEDOUT;
176                 }
177                 if (rest > 4)
178                         mwdebi(av7110, DEBISWAB, bootblock,
179                                ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
180                 else
181                         mwdebi(av7110, DEBISWAB, bootblock,
182                                ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
183
184                 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);
187         }
188         if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
189                 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
190                 return -ETIMEDOUT;
191         }
192         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) {
195                 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
196                 return -ETIMEDOUT;
197         }
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 */
204 static 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
225 int 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
233         av7110->arm_ready = 0;
234
235         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);
248         /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
249         iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
250
251         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));
268         iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
269
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");
273                 return -ETIMEDOUT;
274         }
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");
294                 return -ETIMEDOUT;
295         }
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
314 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
315 {
316         unsigned long start;
317         u32 stat;
318         int err;
319
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 (;;) {
329                 err = time_after(jiffies, start + ARM_WAIT_FREE);
330                 if (down_interruptible(&av7110->dcomlock))
331                         return -ERESTARTSYS;
332                 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
333                 up(&av7110->dcomlock);
334                 if ((stat & flags) == 0)
335                         break;
336                 if (err) {
337                         printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
338                                 __FUNCTION__, stat & flags);
339                         return -ETIMEDOUT;
340                 }
341                 msleep(1);
342         }
343         return 0;
344 }
345
346 static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
347 {
348         int i;
349         unsigned long start;
350         char *type = NULL;
351         u16 flags[2] = {0, 0};
352         u32 stat;
353         int err;
354
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;
363         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) {
368                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
369                         av7110->arm_errors++;
370                         return -ETIMEDOUT;
371                 }
372                 msleep(1);
373         }
374
375         if (FW_VERSION(av7110->arm_app) <= 0x261f)
376                 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
377
378 #ifndef _NOHANDSHAKE
379         start = jiffies;
380         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) {
385                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
386                         return -ETIMEDOUT;
387                 }
388                 msleep(1);
389         }
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 (;;) {
421                         err = time_after(jiffies, start + ARM_WAIT_FREE);
422                         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;
430                         if (err) {
431                                 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
432                                         __FUNCTION__, type);
433                                 return -ETIMEDOUT;
434                         }
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
449         if (FW_VERSION(av7110->arm_app) <= 0x261f)
450                 wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
451
452 #ifdef COM_DEBUG
453         start = jiffies;
454         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) {
459                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
460                                __FUNCTION__, (buf[0] >> 8) & 0xff);
461                         return -ETIMEDOUT;
462                 }
463                 msleep(1);
464         }
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
480 static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
481 {
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         }
490         if (down_interruptible(&av7110->dcomlock))
491                 return -ERESTARTSYS;
492
493         ret = __av7110_send_fw_cmd(av7110, buf, length);
494         up(&av7110->dcomlock);
495         if (ret && ret!=-ERESTARTSYS)
496                 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
497                        __FUNCTION__, ret);
498         return ret;
499 }
500
501 int 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);
520         if (ret && ret != -ERESTARTSYS)
521                 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
522         return ret;
523 }
524
525 #if 0
526 int 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);
543         if (ret && ret != -ERESTARTSYS)
544                 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
545         return ret;
546 }
547 #endif  /*  0  */
548
549 int 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
566         if (down_interruptible(&av7110->dcomlock))
567                 return -ERESTARTSYS;
568
569         if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
570                 up(&av7110->dcomlock);
571                 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
572                 return err;
573         }
574
575         start = jiffies;
576         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) {
581                         printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
582                         up(&av7110->dcomlock);
583                         return -ETIMEDOUT;
584                 }
585 #ifdef _NOHANDSHAKE
586                 msleep(1);
587 #endif
588         }
589
590 #ifndef _NOHANDSHAKE
591         start = jiffies;
592         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) {
597                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
598                         up(&av7110->dcomlock);
599                         return -ETIMEDOUT;
600                 }
601                 msleep(1);
602         }
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__);
609                 up(&av7110->dcomlock);
610                 return -1;
611         }
612         else if (stat & OSDQOver) {
613                 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
614                 up(&av7110->dcomlock);
615                 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
622         up(&av7110->dcomlock);
623         return 0;
624 }
625
626 static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
627 {
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  */
641 int 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",
650                        av7110->dvb_adapter.num);
651                 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",
661                av7110->dvb_adapter.num, av7110->arm_fw,
662                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",
667                        av7110->dvb_adapter.num);
668         else
669                 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
670                        av7110->dvb_adapter.num);
671
672         return 0;
673 }
674
675
676 int 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
698         ret = av7110_send_fw_cmd(av7110, buf, 18);
699         if (ret && ret!=-ERESTARTSYS)
700                 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
701         return ret;
702 }
703
704
705 #ifdef CONFIG_DVB_AV7110_OSD
706
707 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
708 {
709         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
710 }
711
712 static 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
719 static 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
726 static 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
733 static int FlushText(struct av7110 *av7110)
734 {
735         unsigned long start;
736         int err;
737
738         if (down_interruptible(&av7110->dcomlock))
739                 return -ERESTARTSYS;
740         start = jiffies;
741         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) {
746                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
747                                __FUNCTION__);
748                         up(&av7110->dcomlock);
749                         return -ETIMEDOUT;
750                 }
751                 msleep(1);
752         }
753         up(&av7110->dcomlock);
754         return 0;
755 }
756
757 static 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
764         if (down_interruptible(&av7110->dcomlock))
765                 return -ERESTARTSYS;
766
767         start = jiffies;
768         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) {
773                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
774                                __FUNCTION__);
775                         up(&av7110->dcomlock);
776                         return -ETIMEDOUT;
777                 }
778                 msleep(1);
779         }
780 #ifndef _NOHANDSHAKE
781         start = jiffies;
782         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) {
787                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
788                                __FUNCTION__);
789                         up(&av7110->dcomlock);
790                         return -ETIMEDOUT;
791                 }
792                 msleep(1);
793         }
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);
801         up(&av7110->dcomlock);
802         if (ret && ret!=-ERESTARTSYS)
803                 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
804         return ret;
805 }
806
807 static 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
814 static 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
821 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
822 {
823         return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
824 }
825
826 static 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
831 static 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
836 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
837 {
838         return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
839 }
840
841 static 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
850 static enum av7110_osd_palette_type bpp2pal[8] = {
851         Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
852 };
853 static osd_raw_window_t bpp2bit[8] = {
854         OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
855 };
856
857 static 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
872 static inline int LoadBitmap(struct av7110 *av7110,
873                              u16 dx, u16 dy, int inc, u8 __user * data)
874 {
875         u16 format;
876         int bpp;
877         int i;
878         int d, delta;
879         u8 c;
880         int ret;
881
882         dprintk(4, "%p\n", av7110);
883
884         format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
885
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;
897                 return -EINVAL;
898         }
899         av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
900         av7110->bmpp = 0;
901         if (av7110->bmplen > 32768) {
902                 av7110->bmp_state = BMP_NONE;
903                 return -EINVAL;
904         }
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;
908                         return -EINVAL;
909                 }
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);
923         ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
924         if (!ret)
925                 ret = WaitUntilBmpLoaded(av7110);
926         return ret;
927 }
928
929 static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
930 {
931         dprintk(4, "%p\n", av7110);
932
933         return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
934 }
935
936 static inline int ReleaseBitmap(struct av7110 *av7110)
937 {
938         dprintk(4, "%p\n", av7110);
939
940         if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
941                 return -1;
942         if (av7110->bmp_state == BMP_LOADING)
943                 dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
944         av7110->bmp_state = BMP_NONE;
945         return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
946 }
947
948 static 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
964 static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
965 {
966         int ret;
967
968         u16 ch, cl;
969         u32 yuv;
970
971         yuv = blend ? RGB2YUV(r,g,b) : 0;
972         cl = (yuv & 0xffff);
973         ch = ((yuv >> 16) & 0xffff);
974         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;
980 }
981
982 static 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
1007 static 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;
1012         int rc,release_rc;
1013
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)
1019                 return -EINVAL;
1020         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
1027         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;
1039         for (i = 0; i < bnum; i++) {
1040                 rc = LoadBitmap(av7110, w, lpb, inc, data);
1041                 if (rc)
1042                         break;
1043                 rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1044                 if (rc)
1045                         break;
1046                 data += lpb * inc;
1047         }
1048         if (!rc && brest) {
1049                 rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1050                 if (!rc)
1051                         rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1052         }
1053         release_rc = ReleaseBitmap(av7110);
1054         if (!rc)
1055                 rc = release_rc;
1056         if (rc)
1057                 dprintk(1,"returns %d\n",rc);
1058         return rc;
1059 }
1060
1061 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1062 {
1063         int ret;
1064
1065         if (down_interruptible(&av7110->osd_sema))
1066                 return -ERESTARTSYS;
1067
1068         switch (dc->cmd) {
1069         case OSD_Close:
1070                 ret = DestroyOSDWindow(av7110, av7110->osdwin);
1071                 break;
1072         case OSD_Open:
1073                 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1074                 ret = CreateOSDWindow(av7110, av7110->osdwin,
1075                                 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1076                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1077                 if (ret)
1078                         break;
1079                 if (!dc->data) {
1080                         ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1081                         if (ret)
1082                                 break;
1083                         ret = SetColorBlend(av7110, av7110->osdwin);
1084                 }
1085                 break;
1086         case OSD_Show:
1087                 ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1088                 break;
1089         case OSD_Hide:
1090                 ret = HideWindow(av7110, av7110->osdwin);
1091                 break;
1092         case OSD_Clear:
1093                 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1094                 break;
1095         case OSD_Fill:
1096                 ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1097                 break;
1098         case OSD_SetColor:
1099                 ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1100                 break;
1101         case OSD_SetPalette:
1102                 if (FW_VERSION(av7110->arm_app) >= 0x2618)
1103                         ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1104                 else {
1105                         int i, len = dc->x0-dc->color+1;
1106                         u8 __user *colors = (u8 __user *)dc->data;
1107                         u8 r, g, b, blend;
1108                         ret = 0;
1109                         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;
1115                                         break;
1116                                     }
1117                                 ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1118                                 if (ret)
1119                                         break;
1120                         }
1121                 }
1122                 break;
1123         case OSD_SetPixel:
1124                 ret = DrawLine(av7110, av7110->osdwin,
1125                          dc->x0, dc->y0, 0, 0, dc->color);
1126                 break;
1127         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);
1132                 break;
1133         case OSD_FillRow:
1134                 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1135                           dc->x1-dc->x0+1, dc->y1, dc->color);
1136                 break;
1137         case OSD_FillBlock:
1138                 ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1139                           dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1140                 break;
1141         case OSD_Line:
1142                 ret = DrawLine(av7110, av7110->osdwin,
1143                          dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1144                 break;
1145         case OSD_Text:
1146         {
1147                 char textbuf[240];
1148
1149                 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1150                         ret = -EFAULT;
1151                         break;
1152                 }
1153                 textbuf[239] = 0;
1154                 if (dc->x1 > 3)
1155                         dc->x1 = 3;
1156                 ret = SetFont(av7110, av7110->osdwin, dc->x1,
1157                         (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1158                 if (!ret)
1159                         ret = FlushText(av7110);
1160                 if (!ret)
1161                         ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1162                 break;
1163         }
1164         case OSD_SetWindow:
1165                 if (dc->x0 < 1 || dc->x0 > 7)
1166                         ret = -EINVAL;
1167                 else {
1168                         av7110->osdwin = dc->x0;
1169                         ret = 0;
1170                 }
1171                 break;
1172         case OSD_MoveWindow:
1173                 ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1174                 if (!ret)
1175                         ret = SetColorBlend(av7110, av7110->osdwin);
1176                 break;
1177         case OSD_OpenRaw:
1178                 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1179                         ret = -EINVAL;
1180                         break;
1181                 }
1182                 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1183                         av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1184                 else
1185                         av7110->osdbpp[av7110->osdwin] = 0;
1186                 ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1187                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1188                 if (ret)
1189                         break;
1190                 if (!dc->data) {
1191                         ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1192                         if (!ret)
1193                                 ret = SetColorBlend(av7110, av7110->osdwin);
1194                 }
1195                 break;
1196         default:
1197                 ret = -EINVAL;
1198                 break;
1199         }
1200
1201         up(&av7110->osd_sema);
1202         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
1207         return ret;
1208 }
1209
1210 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1211 {
1212         switch (cap->cmd) {
1213         case OSD_CAP_MEMSIZE:
1214                 if (FW_4M_SDRAM(av7110->arm_app))
1215                         cap->val = 1000000;
1216                 else
1217                         cap->val = 92000;
1218                 return 0;
1219         default:
1220                 return -EINVAL;
1221         }
1222 }
1223 #endif /* CONFIG_DVB_AV7110_OSD */