Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / 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 /****************************************************************************
45  * DEBI functions
46  ****************************************************************************/
47
48 /* This DEBI code is based on the Stradis driver
49    by Nathan Laredo <laredo@gnu.org> */
50
51 int av7110_debiwrite(struct av7110 *av7110, u32 config,
52                      int addr, u32 val, int count)
53 {
54         struct saa7146_dev *dev = av7110->dev;
55
56         if (count <= 0 || count > 32764) {
57                 printk("%s: invalid count %d\n", __FUNCTION__, count);
58                 return -1;
59         }
60         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
61                 printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
62                 return -1;
63         }
64         saa7146_write(dev, DEBI_CONFIG, config);
65         if (count <= 4)         /* immediate transfer */
66                 saa7146_write(dev, DEBI_AD, val);
67         else                    /* block transfer */
68                 saa7146_write(dev, DEBI_AD, av7110->debi_bus);
69         saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
70         saa7146_write(dev, MC2, (2 << 16) | 2);
71         return 0;
72 }
73
74 u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
75 {
76         struct saa7146_dev *dev = av7110->dev;
77         u32 result = 0;
78
79         if (count > 32764 || count <= 0) {
80                 printk("%s: invalid count %d\n", __FUNCTION__, count);
81                 return 0;
82         }
83         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
84                 printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
85                 return 0;
86         }
87         saa7146_write(dev, DEBI_AD, av7110->debi_bus);
88         saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
89
90         saa7146_write(dev, DEBI_CONFIG, config);
91         saa7146_write(dev, MC2, (2 << 16) | 2);
92         if (count > 4)
93                 return count;
94         if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
95                 printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
96                 return 0;
97         }
98
99         result = saa7146_read(dev, DEBI_AD);
100         result &= (0xffffffffUL >> ((4 - count) * 8));
101         return result;
102 }
103
104
105
106 /* av7110 ARM core boot stuff */
107
108 void av7110_reset_arm(struct av7110 *av7110)
109 {
110         saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
111
112         /* Disable DEBI and GPIO irq */
113         SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
114         SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
115
116         saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
117         msleep(30);     /* the firmware needs some time to initialize */
118
119         ARM_ResetMailBox(av7110);
120
121         SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
122         SAA7146_IER_ENABLE(av7110->dev, MASK_03);
123
124         av7110->arm_ready = 1;
125         dprintk(1, "reset ARM\n");
126 }
127
128
129 static int waitdebi(struct av7110 *av7110, int adr, int state)
130 {
131         int k;
132
133         dprintk(4, "%p\n", av7110);
134
135         for (k = 0; k < 100; k++) {
136                 if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
137                         return 0;
138                 udelay(5);
139         }
140         return -1;
141 }
142
143 static int load_dram(struct av7110 *av7110, u32 *data, int len)
144 {
145         int i;
146         int blocks, rest;
147         u32 base, bootblock = BOOT_BLOCK;
148
149         dprintk(4, "%p\n", av7110);
150
151         blocks = len / BOOT_MAX_SIZE;
152         rest = len % BOOT_MAX_SIZE;
153         base = DRAM_START_CODE;
154
155         for (i = 0; i < blocks; i++) {
156                 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
157                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
158                         return -1;
159                 }
160                 dprintk(4, "writing DRAM block %d\n", i);
161                 mwdebi(av7110, DEBISWAB, bootblock,
162                        ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE);
163                 bootblock ^= 0x1400;
164                 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
165                 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, BOOT_MAX_SIZE, 2);
166                 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
167                 base += BOOT_MAX_SIZE;
168         }
169
170         if (rest > 0) {
171                 if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
172                         printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
173                         return -1;
174                 }
175                 if (rest > 4)
176                         mwdebi(av7110, DEBISWAB, bootblock,
177                                ((char*)data) + i * BOOT_MAX_SIZE, rest);
178                 else
179                         mwdebi(av7110, DEBISWAB, bootblock,
180                                ((char*)data) + i * BOOT_MAX_SIZE - 4, rest + 4);
181
182                 iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4);
183                 iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2);
184                 iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
185         }
186         if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
187                 printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
188                 return -1;
189         }
190         iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
191         iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
192         if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
193                 printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
194                 return -1;
195         }
196         return 0;
197 }
198
199
200 /* we cannot write av7110 DRAM directly, so load a bootloader into
201  * the DPRAM which implements a simple boot protocol */
202 static u8 bootcode[] = {
203   0xea, 0x00, 0x00, 0x0e, 0xe1, 0xb0, 0xf0, 0x0e, 0xe2, 0x5e, 0xf0, 0x04,
204   0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x08, 0xe2, 0x5e, 0xf0, 0x04,
205   0xe2, 0x5e, 0xf0, 0x04, 0xe2, 0x5e, 0xf0, 0x04, 0x2c, 0x00, 0x00, 0x24,
206   0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x34,
207   0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0x5a, 0x5a, 0x00, 0x1f, 0x15, 0x55,
208   0x00, 0x00, 0x00, 0x09, 0xe5, 0x9f, 0xd0, 0x7c, 0xe5, 0x9f, 0x40, 0x74,
209   0xe3, 0xa0, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x00, 0xe5, 0x84, 0x00, 0x04,
210   0xe5, 0x9f, 0x10, 0x70, 0xe5, 0x9f, 0x20, 0x70, 0xe5, 0x9f, 0x30, 0x64,
211   0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe1, 0x51, 0x00, 0x02,
212   0xda, 0xff, 0xff, 0xfb, 0xe5, 0x9f, 0xf0, 0x50, 0xe1, 0xd4, 0x10, 0xb0,
213   0xe3, 0x51, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xfc, 0xe1, 0xa0, 0x10, 0x0d,
214   0xe5, 0x94, 0x30, 0x04, 0xe1, 0xd4, 0x20, 0xb2, 0xe2, 0x82, 0x20, 0x3f,
215   0xe1, 0xb0, 0x23, 0x22, 0x03, 0xa0, 0x00, 0x02, 0xe1, 0xc4, 0x00, 0xb0,
216   0x0a, 0xff, 0xff, 0xf4, 0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0,
217   0xe8, 0xb1, 0x1f, 0xe0, 0xe8, 0xa3, 0x1f, 0xe0, 0xe2, 0x52, 0x20, 0x01,
218   0x1a, 0xff, 0xff, 0xf9, 0xe2, 0x2d, 0xdb, 0x05, 0xea, 0xff, 0xff, 0xec,
219   0x2c, 0x00, 0x03, 0xf8, 0x2c, 0x00, 0x04, 0x00, 0x9e, 0x00, 0x08, 0x00,
220   0x2c, 0x00, 0x00, 0x74, 0x2c, 0x00, 0x00, 0xc0
221 };
222
223 int av7110_bootarm(struct av7110 *av7110)
224 {
225         struct saa7146_dev *dev = av7110->dev;
226         u32 ret;
227         int i;
228
229         dprintk(4, "%p\n", av7110);
230
231         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
232
233         /* Disable DEBI and GPIO irq */
234         SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
235         SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
236
237         /* enable DEBI */
238         saa7146_write(av7110->dev, MC1, 0x08800880);
239         saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
240         saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
241
242         /* test DEBI */
243         iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
244         if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
245                 printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: "
246                        "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
247                        ret, 0x10325476);
248                 return -1;
249         }
250         for (i = 0; i < 8192; i += 4)
251                 iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
252         dprintk(2, "debi test OK\n");
253
254         /* boot */
255         dprintk(1, "load boot code\n");
256         saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
257         //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
258         //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
259
260         mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
261         iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
262
263         if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
264                 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
265                        "saa7146_wait_for_debi_done() timed out\n");
266                 return -1;
267         }
268         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
269         mdelay(1);
270
271         dprintk(1, "load dram code\n");
272         if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
273                 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
274                        "load_dram() failed\n");
275                 return -1;
276         }
277
278         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
279         mdelay(1);
280
281         dprintk(1, "load dpram code\n");
282         mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
283
284         if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
285                 printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
286                        "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
287                 return -1;
288         }
289         saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
290         msleep(30);     /* the firmware needs some time to initialize */
291
292         //ARM_ClearIrq(av7110);
293         ARM_ResetMailBox(av7110);
294         SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
295         SAA7146_IER_ENABLE(av7110->dev, MASK_03);
296
297         av7110->arm_errors = 0;
298         av7110->arm_ready = 1;
299         return 0;
300 }
301
302
303 /****************************************************************************
304  * DEBI command polling
305  ****************************************************************************/
306
307 int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
308 {
309         unsigned long start;
310         u32 stat;
311
312         if (FW_VERSION(av7110->arm_app) <= 0x261c) {
313                 /* not supported by old firmware */
314                 msleep(50);
315                 return 0;
316         }
317
318         /* new firmware */
319         start = jiffies;
320         for (;;) {
321                 if (down_interruptible(&av7110->dcomlock))
322                         return -ERESTARTSYS;
323                 stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
324                 up(&av7110->dcomlock);
325                 if ((stat & flags) == 0) {
326                         break;
327                 }
328                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
329                         printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
330                                 __FUNCTION__, stat & flags);
331                         return -1;
332                 }
333                 msleep(1);
334         }
335         return 0;
336 }
337
338 int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
339 {
340         int i;
341         unsigned long start;
342         char *type = NULL;
343         u16 flags[2] = {0, 0};
344         u32 stat;
345
346 //      dprintk(4, "%p\n", av7110);
347
348         if (!av7110->arm_ready) {
349                 dprintk(1, "arm not ready.\n");
350                 return -ENXIO;
351         }
352
353         start = jiffies;
354         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
355                 msleep(1);
356                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
357                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
358                         return -ETIMEDOUT;
359                 }
360         }
361
362         wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
363
364 #ifndef _NOHANDSHAKE
365         start = jiffies;
366         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
367                 msleep(1);
368                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
369                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
370                         return -ETIMEDOUT;
371                 }
372         }
373 #endif
374
375         switch ((buf[0] >> 8) & 0xff) {
376         case COMTYPE_PIDFILTER:
377         case COMTYPE_ENCODER:
378         case COMTYPE_REC_PLAY:
379         case COMTYPE_MPEGDECODER:
380                 type = "MSG";
381                 flags[0] = GPMQOver;
382                 flags[1] = GPMQFull;
383                 break;
384         case COMTYPE_OSD:
385                 type = "OSD";
386                 flags[0] = OSDQOver;
387                 flags[1] = OSDQFull;
388                 break;
389         case COMTYPE_MISC:
390                 if (FW_VERSION(av7110->arm_app) >= 0x261d) {
391                         type = "MSG";
392                         flags[0] = GPMQOver;
393                         flags[1] = GPMQBusy;
394                 }
395                 break;
396         default:
397                 break;
398         }
399
400         if (type != NULL) {
401                 /* non-immediate COMMAND type */
402                 start = jiffies;
403                 for (;;) {
404                         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
405                         if (stat & flags[0]) {
406                                 printk(KERN_ERR "%s: %s QUEUE overflow\n",
407                                         __FUNCTION__, type);
408                                 return -1;
409                         }
410                         if ((stat & flags[1]) == 0)
411                                 break;
412                         if (time_after(jiffies, start + ARM_WAIT_FREE)) {
413                                 printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
414                                         __FUNCTION__, type);
415                                 return -1;
416                         }
417                         msleep(1);
418                 }
419         }
420
421         for (i = 2; i < length; i++)
422                 wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
423
424         if (length)
425                 wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
426         else
427                 wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
428
429         wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
430
431         wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
432
433 #ifdef COM_DEBUG
434         start = jiffies;
435         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
436                 msleep(1);
437                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
438                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
439                                __FUNCTION__);
440                         return -ETIMEDOUT;
441                 }
442         }
443
444         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
445         if (stat & GPMQOver) {
446                 printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__);
447                 return -ENOSPC;
448         }
449         else if (stat & OSDQOver) {
450                 printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__);
451                 return -ENOSPC;
452         }
453 #endif
454
455         return 0;
456 }
457
458 int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
459 {
460         int ret;
461
462 //      dprintk(4, "%p\n", av7110);
463
464         if (!av7110->arm_ready) {
465                 dprintk(1, "arm not ready.\n");
466                 return -1;
467         }
468         if (down_interruptible(&av7110->dcomlock))
469                 return -ERESTARTSYS;
470
471         ret = __av7110_send_fw_cmd(av7110, buf, length);
472         up(&av7110->dcomlock);
473         if (ret)
474                 printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
475                        __FUNCTION__, ret);
476         return ret;
477 }
478
479 int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
480 {
481         va_list args;
482         u16 buf[num + 2];
483         int i, ret;
484
485 //      dprintk(4, "%p\n", av7110);
486
487         buf[0] = ((type << 8) | com);
488         buf[1] = num;
489
490         if (num) {
491                 va_start(args, num);
492                 for (i = 0; i < num; i++)
493                         buf[i + 2] = va_arg(args, u32);
494                 va_end(args);
495         }
496
497         ret = av7110_send_fw_cmd(av7110, buf, num + 2);
498         if (ret)
499                 printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
500         return ret;
501 }
502
503 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
504 {
505         int i, ret;
506         u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
507                 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
508
509         dprintk(4, "%p\n", av7110);
510
511         for(i = 0; i < len && i < 32; i++)
512         {
513                 if(i % 2 == 0)
514                         cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
515                 else
516                         cmd[(i / 2) + 2] |= buf[i];
517         }
518
519         ret = av7110_send_fw_cmd(av7110, cmd, 18);
520         if (ret)
521                 printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
522         return ret;
523 }
524
525 int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
526                       int request_buf_len, u16 *reply_buf, int reply_buf_len)
527 {
528         int err;
529         s16 i;
530         unsigned long start;
531 #ifdef COM_DEBUG
532         u32 stat;
533 #endif
534
535         dprintk(4, "%p\n", av7110);
536
537         if (!av7110->arm_ready) {
538                 dprintk(1, "arm not ready.\n");
539                 return -1;
540         }
541
542         if (down_interruptible(&av7110->dcomlock))
543                 return -ERESTARTSYS;
544
545         if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
546                 up(&av7110->dcomlock);
547                 printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
548                 return err;
549         }
550
551         start = jiffies;
552         while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
553 #ifdef _NOHANDSHAKE
554                 msleep(1);
555 #endif
556                 if (time_after(jiffies, start + ARM_WAIT_FREE)) {
557                         printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
558                         up(&av7110->dcomlock);
559                         return -1;
560                 }
561         }
562
563 #ifndef _NOHANDSHAKE
564         start = jiffies;
565         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
566                 msleep(1);
567                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
568                         printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
569                         up(&av7110->dcomlock);
570                         return -1;
571                 }
572         }
573 #endif
574
575 #ifdef COM_DEBUG
576         stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
577         if (stat & GPMQOver) {
578                 printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
579                 up(&av7110->dcomlock);
580                 return -1;
581         }
582         else if (stat & OSDQOver) {
583                 printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
584                 up(&av7110->dcomlock);
585                 return -1;
586         }
587 #endif
588
589         for (i = 0; i < reply_buf_len; i++)
590                 reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
591
592         up(&av7110->dcomlock);
593         return 0;
594 }
595
596 int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
597 {
598         int ret;
599         ret = av7110_fw_request(av7110, &tag, 0, buf, length);
600         if (ret)
601                 printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
602         return ret;
603 }
604
605
606 /****************************************************************************
607  * Firmware commands
608  ****************************************************************************/
609
610 /* get version of the firmware ROM, RTSL, video ucode and ARM application  */
611 int av7110_firmversion(struct av7110 *av7110)
612 {
613         u16 buf[20];
614         u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
615
616         dprintk(4, "%p\n", av7110);
617
618         if (av7110_fw_query(av7110, tag, buf, 16)) {
619                 printk("dvb-ttpci: failed to boot firmware @ card %d\n",
620                        av7110->dvb_adapter->num);
621                 return -EIO;
622         }
623
624         av7110->arm_fw = (buf[0] << 16) + buf[1];
625         av7110->arm_rtsl = (buf[2] << 16) + buf[3];
626         av7110->arm_vid = (buf[4] << 16) + buf[5];
627         av7110->arm_app = (buf[6] << 16) + buf[7];
628         av7110->avtype = (buf[8] << 16) + buf[9];
629
630         printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
631                av7110->dvb_adapter->num, av7110->arm_fw,
632                av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
633
634         /* print firmware capabilities */
635         if (FW_CI_LL_SUPPORT(av7110->arm_app))
636                 printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
637                        av7110->dvb_adapter->num);
638         else
639                 printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
640                        av7110->dvb_adapter->num);
641
642         return 0;
643 }
644
645
646 int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
647 {
648         int i, ret;
649         u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
650                         16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
651
652         dprintk(4, "%p\n", av7110);
653
654         if (len > 10)
655                 len = 10;
656
657         buf[1] = len + 2;
658         buf[2] = len;
659
660         if (burst != -1)
661                 buf[3] = burst ? 0x01 : 0x00;
662         else
663                 buf[3] = 0xffff;
664
665         for (i = 0; i < len; i++)
666                 buf[i + 4] = msg[i];
667
668         if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
669                 printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
670
671         return 0;
672 }
673
674
675 #ifdef CONFIG_DVB_AV7110_OSD
676
677 static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
678 {
679         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
680 }
681
682 static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
683                      enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
684 {
685         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
686                              windownr, colordepth, index, blending);
687 }
688
689 static inline int SetColor_(struct av7110 *av7110, u8 windownr,
690                      enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
691 {
692         return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
693                              windownr, colordepth, index, colorhi, colorlo);
694 }
695
696 static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
697                           u16 colorfg, u16 colorbg)
698 {
699         return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
700                              windownr, fontsize, colorfg, colorbg);
701 }
702
703 static int FlushText(struct av7110 *av7110)
704 {
705         unsigned long start;
706
707         if (down_interruptible(&av7110->dcomlock))
708                 return -ERESTARTSYS;
709         start = jiffies;
710         while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
711                 msleep(1);
712                 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
713                         printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
714                                __FUNCTION__);
715                         up(&av7110->dcomlock);
716                         return -1;
717                 }
718         }
719         up(&av7110->dcomlock);
720         return 0;
721 }
722
723 static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
724 {
725         int i, ret;
726         unsigned long start;
727         int length = strlen(buf) + 1;
728         u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
729
730         if (down_interruptible(&av7110->dcomlock))
731                 return -ERESTARTSYS;
732
733         start = jiffies;
734         while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
735                 msleep(1);
736                 if (time_after(jiffies, start + ARM_WAIT_OSD)) {
737                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
738                                __FUNCTION__);
739                         up(&av7110->dcomlock);
740                         return -1;
741                 }
742         }
743 #ifndef _NOHANDSHAKE
744         start = jiffies;
745         while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
746                 msleep(1);
747                 if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
748                         printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
749                                __FUNCTION__);
750                         up(&av7110->dcomlock);
751                         return -1;
752                 }
753         }
754 #endif
755         for (i = 0; i < length / 2; i++)
756                 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
757                       swab16(*(u16 *)(buf + 2 * i)), 2);
758         if (length & 1)
759                 wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
760         ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
761         up(&av7110->dcomlock);
762         if (ret)
763                 printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
764         return ret;
765 }
766
767 static inline int DrawLine(struct av7110 *av7110, u8 windownr,
768                            u16 x, u16 y, u16 dx, u16 dy, u16 color)
769 {
770         return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
771                              windownr, x, y, dx, dy, color);
772 }
773
774 static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
775                             u16 x, u16 y, u16 dx, u16 dy, u16 color)
776 {
777         return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
778                              windownr, x, y, dx, dy, color);
779 }
780
781 static inline int HideWindow(struct av7110 *av7110, u8 windownr)
782 {
783         return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
784 }
785
786 static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
787 {
788         return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
789 }
790
791 static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
792 {
793         return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
794 }
795
796 static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
797 {
798         return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
799 }
800
801 static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
802                                   osd_raw_window_t disptype,
803                                   u16 width, u16 height)
804 {
805         return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
806                              windownr, disptype, width, height);
807 }
808
809
810 static enum av7110_osd_palette_type bpp2pal[8] = {
811         Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
812 };
813 static osd_raw_window_t bpp2bit[8] = {
814         OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
815 };
816
817 static inline int LoadBitmap(struct av7110 *av7110, u16 format,
818                              u16 dx, u16 dy, int inc, u8 __user * data)
819 {
820         int bpp;
821         int i;
822         int d, delta;
823         u8 c;
824         int ret;
825
826         dprintk(4, "%p\n", av7110);
827
828         ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
829         if (ret == -ERESTARTSYS || ret == 0) {
830                 printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
831                        ret, av7110->bmp_state);
832                 av7110->bmp_state = BMP_NONE;
833                 return -1;
834         }
835         BUG_ON (av7110->bmp_state == BMP_LOADING);
836
837         av7110->bmp_state = BMP_LOADING;
838         if      (format == OSD_BITMAP8) {
839                 bpp=8; delta = 1;
840         } else if (format == OSD_BITMAP4) {
841                 bpp=4; delta = 2;
842         } else if (format == OSD_BITMAP2) {
843                 bpp=2; delta = 4;
844         } else if (format == OSD_BITMAP1) {
845                 bpp=1; delta = 8;
846         } else {
847                 av7110->bmp_state = BMP_NONE;
848                 return -1;
849         }
850         av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
851         av7110->bmpp = 0;
852         if (av7110->bmplen > 32768) {
853                 av7110->bmp_state = BMP_NONE;
854                 return -1;
855         }
856         for (i = 0; i < dy; i++) {
857                 if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
858                         av7110->bmp_state = BMP_NONE;
859                         return -1;
860                 }
861         }
862         if (format != OSD_BITMAP8) {
863                 for (i = 0; i < dx * dy / delta; i++) {
864                         c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
865                         for (d = delta - 2; d >= 0; d--) {
866                                 c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
867                                       << ((delta - d - 1) * bpp));
868                                 ((u8 *)av7110->bmpbuf)[1024 + i] = c;
869                         }
870                 }
871         }
872         av7110->bmplen += 1024;
873         dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
874         return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
875 }
876
877 static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
878 {
879         int ret;
880
881         dprintk(4, "%p\n", av7110);
882
883         BUG_ON (av7110->bmp_state == BMP_NONE);
884
885         ret = wait_event_interruptible_timeout(av7110->bmpq,
886                                 av7110->bmp_state != BMP_LOADING, 10*HZ);
887         if (ret == -ERESTARTSYS || ret == 0) {
888                 printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
889                        ret, av7110->bmp_state);
890                 av7110->bmp_state = BMP_NONE;
891                 return (ret == 0) ? -ETIMEDOUT : ret;
892         }
893
894         BUG_ON (av7110->bmp_state != BMP_LOADED);
895
896         return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
897 }
898
899 static inline int ReleaseBitmap(struct av7110 *av7110)
900 {
901         dprintk(4, "%p\n", av7110);
902
903         if (av7110->bmp_state != BMP_LOADED)
904                 return -1;
905         av7110->bmp_state = BMP_NONE;
906         return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
907 }
908
909 static u32 RGB2YUV(u16 R, u16 G, u16 B)
910 {
911         u16 y, u, v;
912         u16 Y, Cr, Cb;
913
914         y = R * 77 + G * 150 + B * 29;  /* Luma=0.299R+0.587G+0.114B 0..65535 */
915         u = 2048 + B * 8 -(y >> 5);     /* Cr 0..4095 */
916         v = 2048 + R * 8 -(y >> 5);     /* Cb 0..4095 */
917
918         Y = y / 256;
919         Cb = u / 16;
920         Cr = v / 16;
921
922         return Cr | (Cb << 16) | (Y << 8);
923 }
924
925 static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
926 {
927         u16 ch, cl;
928         u32 yuv;
929
930         yuv = blend ? RGB2YUV(r,g,b) : 0;
931         cl = (yuv & 0xffff);
932         ch = ((yuv >> 16) & 0xffff);
933         SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
934                   color, ch, cl);
935         SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
936                   color, ((blend >> 4) & 0x0f));
937 }
938
939 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
940 {
941        int i;
942        int length = last - first + 1;
943
944        if (length * 4 > DATA_BUFF3_SIZE)
945                return -EINVAL;
946
947        for (i = 0; i < length; i++) {
948                u32 color, blend, yuv;
949
950                if (get_user(color, colors + i))
951                        return -EFAULT;
952                blend = (color & 0xF0000000) >> 4;
953                yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
954                                      (color >> 16) & 0xFF) | blend : 0;
955                yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
956                wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
957        }
958        return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
959                             av7110->osdwin,
960                             bpp2pal[av7110->osdbpp[av7110->osdwin]],
961                             first, last);
962 }
963
964 static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
965                        int x1, int y1, int inc, u8 __user * data)
966 {
967         uint w, h, bpp, bpl, size, lpb, bnum, brest;
968         int i;
969         int rc;
970
971         w = x1 - x0 + 1;
972         h = y1 - y0 + 1;
973         if (inc <= 0)
974                 inc = w;
975         if (w <= 0 || w > 720 || h <= 0 || h > 576)
976                 return -1;
977         bpp = av7110->osdbpp[av7110->osdwin] + 1;
978         bpl = ((w * bpp + 7) & ~7) / 8;
979         size = h * bpl;
980         lpb = (32 * 1024) / bpl;
981         bnum = size / (lpb * bpl);
982         brest = size - bnum * lpb * bpl;
983
984         for (i = 0; i < bnum; i++) {
985                 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
986                            w, lpb, inc, data);
987                 if (rc)
988                         return rc;
989                 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
990                 if (rc)
991                         return rc;
992                 data += lpb * inc;
993         }
994         if (brest) {
995                 rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
996                            w, brest / bpl, inc, data);
997                 if (rc)
998                         return rc;
999                 rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
1000                 if (rc)
1001                         return rc;
1002         }
1003         ReleaseBitmap(av7110);
1004         return 0;
1005 }
1006
1007 int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1008 {
1009         int ret;
1010
1011         ret = down_interruptible(&av7110->osd_sema);
1012         if (ret)
1013                 return -ERESTARTSYS;
1014
1015         /* stupid, but OSD functions don't provide a return code anyway */
1016         ret = 0;
1017
1018         switch (dc->cmd) {
1019         case OSD_Close:
1020                 DestroyOSDWindow(av7110, av7110->osdwin);
1021                 goto out;
1022         case OSD_Open:
1023                 av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1024                 CreateOSDWindow(av7110, av7110->osdwin,
1025                                 bpp2bit[av7110->osdbpp[av7110->osdwin]],
1026                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1027                 if (!dc->data) {
1028                         MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1029                         SetColorBlend(av7110, av7110->osdwin);
1030                 }
1031                 goto out;
1032         case OSD_Show:
1033                 MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1034                 goto out;
1035         case OSD_Hide:
1036                 HideWindow(av7110, av7110->osdwin);
1037                 goto out;
1038         case OSD_Clear:
1039                 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1040                 goto out;
1041         case OSD_Fill:
1042                 DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1043                 goto out;
1044         case OSD_SetColor:
1045                 OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1046                 goto out;
1047         case OSD_SetPalette:
1048         {
1049                 if (FW_VERSION(av7110->arm_app) >= 0x2618) {
1050                         ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1051                         goto out;
1052                 } else {
1053                         int i, len = dc->x0-dc->color+1;
1054                         u8 __user *colors = (u8 __user *)dc->data;
1055                         u8 r, g, b, blend;
1056
1057                         for (i = 0; i<len; i++) {
1058                                 if (get_user(r, colors + i * 4) ||
1059                                     get_user(g, colors + i * 4 + 1) ||
1060                                     get_user(b, colors + i * 4 + 2) ||
1061                                     get_user(blend, colors + i * 4 + 3)) {
1062                                         ret = -EFAULT;
1063                                         goto out;
1064                                     }
1065                                 OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1066                         }
1067                 }
1068                 ret = 0;
1069                 goto out;
1070         }
1071         case OSD_SetTrans:
1072                 goto out;
1073         case OSD_SetPixel:
1074                 DrawLine(av7110, av7110->osdwin,
1075                          dc->x0, dc->y0, 0, 0, dc->color);
1076                 goto out;
1077         case OSD_GetPixel:
1078                 goto out;
1079         case OSD_SetRow:
1080                 dc->y1 = dc->y0;
1081                 /* fall through */
1082         case OSD_SetBlock:
1083                 ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1084                 goto out;
1085         case OSD_FillRow:
1086                 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1087                           dc->x1-dc->x0+1, dc->y1, dc->color);
1088                 goto out;
1089         case OSD_FillBlock:
1090                 DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1091                           dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1092                 goto out;
1093         case OSD_Line:
1094                 DrawLine(av7110, av7110->osdwin,
1095                          dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1096                 goto out;
1097         case OSD_Query:
1098                 goto out;
1099         case OSD_Test:
1100                 goto out;
1101         case OSD_Text:
1102         {
1103                 char textbuf[240];
1104
1105                 if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1106                         ret = -EFAULT;
1107                         goto out;
1108                 }
1109                 textbuf[239] = 0;
1110                 if (dc->x1 > 3)
1111                         dc->x1 = 3;
1112                 SetFont(av7110, av7110->osdwin, dc->x1,
1113                         (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
1114                 FlushText(av7110);
1115                 WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1116                 goto out;
1117         }
1118         case OSD_SetWindow:
1119                 if (dc->x0 < 1 || dc->x0 > 7) {
1120                         ret = -EINVAL;
1121                         goto out;
1122                 }
1123                 av7110->osdwin = dc->x0;
1124                 goto out;
1125         case OSD_MoveWindow:
1126                 MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1127                 SetColorBlend(av7110, av7110->osdwin);
1128                 goto out;
1129         case OSD_OpenRaw:
1130                 if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1131                         ret = -EINVAL;
1132                         goto out;
1133                 }
1134                 if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
1135                         av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1136                 }
1137                 else {
1138                         av7110->osdbpp[av7110->osdwin] = 0;
1139                 }
1140                 CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1141                                 dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1142                 if (!dc->data) {
1143                         MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1144                         SetColorBlend(av7110, av7110->osdwin);
1145                 }
1146                 goto out;
1147         default:
1148                 ret = -EINVAL;
1149                 goto out;
1150         }
1151
1152 out:
1153         up(&av7110->osd_sema);
1154         return ret;
1155 }
1156
1157 int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1158 {
1159         switch (cap->cmd) {
1160         case OSD_CAP_MEMSIZE:
1161                 if (FW_4M_SDRAM(av7110->arm_app))
1162                         cap->val = 1000000;
1163                 else
1164                         cap->val = 92000;
1165                 return 0;
1166         default:
1167                 return -EINVAL;
1168         }
1169 }
1170 #endif /* CONFIG_DVB_AV7110_OSD */