Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / media / video / cx88 / cx88-core.c
1 /*
2  *
3  * device driver for Conexant 2388x based TV cards
4  * driver core
5  *
6  * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include <linux/init.h>
24 #include <linux/list.h>
25 #include <linux/module.h>
26 #include <linux/moduleparam.h>
27 #include <linux/kernel.h>
28 #include <linux/slab.h>
29 #include <linux/kmod.h>
30 #include <linux/sound.h>
31 #include <linux/interrupt.h>
32 #include <linux/pci.h>
33 #include <linux/delay.h>
34 #include <linux/videodev2.h>
35 #include <linux/mutex.h>
36
37 #include "cx88.h"
38 #include <media/v4l2-common.h>
39
40 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
41 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
42 MODULE_LICENSE("GPL");
43
44 /* ------------------------------------------------------------------ */
45
46 static unsigned int core_debug = 0;
47 module_param(core_debug,int,0644);
48 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
49
50 static unsigned int latency = UNSET;
51 module_param(latency,int,0444);
52 MODULE_PARM_DESC(latency,"pci latency timer");
53
54 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
55 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
56 static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
57
58 module_param_array(tuner, int, NULL, 0444);
59 module_param_array(radio, int, NULL, 0444);
60 module_param_array(card,  int, NULL, 0444);
61
62 MODULE_PARM_DESC(tuner,"tuner type");
63 MODULE_PARM_DESC(radio,"radio tuner type");
64 MODULE_PARM_DESC(card,"card type");
65
66 static unsigned int nicam = 0;
67 module_param(nicam,int,0644);
68 MODULE_PARM_DESC(nicam,"tv audio is nicam");
69
70 static unsigned int nocomb = 0;
71 module_param(nocomb,int,0644);
72 MODULE_PARM_DESC(nocomb,"disable comb filter");
73
74 #define dprintk(level,fmt, arg...)      if (core_debug >= level)        \
75         printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
76
77 static unsigned int cx88_devcount;
78 static LIST_HEAD(cx88_devlist);
79 static DEFINE_MUTEX(devlist);
80
81 #define NO_SYNC_LINE (-1U)
82
83 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
84                             unsigned int offset, u32 sync_line,
85                             unsigned int bpl, unsigned int padding,
86                             unsigned int lines)
87 {
88         struct scatterlist *sg;
89         unsigned int line,todo;
90
91         /* sync instruction */
92         if (sync_line != NO_SYNC_LINE)
93                 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
94
95         /* scan lines */
96         sg = sglist;
97         for (line = 0; line < lines; line++) {
98                 while (offset && offset >= sg_dma_len(sg)) {
99                         offset -= sg_dma_len(sg);
100                         sg++;
101                 }
102                 if (bpl <= sg_dma_len(sg)-offset) {
103                         /* fits into current chunk */
104                         *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
105                         *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
106                         offset+=bpl;
107                 } else {
108                         /* scanline needs to be splitted */
109                         todo = bpl;
110                         *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
111                                             (sg_dma_len(sg)-offset));
112                         *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
113                         todo -= (sg_dma_len(sg)-offset);
114                         offset = 0;
115                         sg++;
116                         while (todo > sg_dma_len(sg)) {
117                                 *(rp++)=cpu_to_le32(RISC_WRITE|
118                                                     sg_dma_len(sg));
119                                 *(rp++)=cpu_to_le32(sg_dma_address(sg));
120                                 todo -= sg_dma_len(sg);
121                                 sg++;
122                         }
123                         *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
124                         *(rp++)=cpu_to_le32(sg_dma_address(sg));
125                         offset += todo;
126                 }
127                 offset += padding;
128         }
129
130         return rp;
131 }
132
133 int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
134                      struct scatterlist *sglist,
135                      unsigned int top_offset, unsigned int bottom_offset,
136                      unsigned int bpl, unsigned int padding, unsigned int lines)
137 {
138         u32 instructions,fields;
139         u32 *rp;
140         int rc;
141
142         fields = 0;
143         if (UNSET != top_offset)
144                 fields++;
145         if (UNSET != bottom_offset)
146                 fields++;
147
148         /* estimate risc mem: worst case is one write per page border +
149            one write per scan line + syncs + jump (all 2 dwords) */
150         instructions  = (bpl * lines * fields) / PAGE_SIZE + lines * fields;
151         instructions += 3 + 4;
152         if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
153                 return rc;
154
155         /* write risc instructions */
156         rp = risc->cpu;
157         if (UNSET != top_offset)
158                 rp = cx88_risc_field(rp, sglist, top_offset, 0,
159                                      bpl, padding, lines);
160         if (UNSET != bottom_offset)
161                 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
162                                      bpl, padding, lines);
163
164         /* save pointer to jmp instruction address */
165         risc->jmp = rp;
166         BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
167         return 0;
168 }
169
170 int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
171                          struct scatterlist *sglist, unsigned int bpl,
172                          unsigned int lines)
173 {
174         u32 instructions;
175         u32 *rp;
176         int rc;
177
178         /* estimate risc mem: worst case is one write per page border +
179            one write per scan line + syncs + jump (all 2 dwords) */
180         instructions  = (bpl * lines) / PAGE_SIZE + lines;
181         instructions += 3 + 4;
182         if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
183                 return rc;
184
185         /* write risc instructions */
186         rp = risc->cpu;
187         rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
188
189         /* save pointer to jmp instruction address */
190         risc->jmp = rp;
191         BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
192         return 0;
193 }
194
195 int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
196                       u32 reg, u32 mask, u32 value)
197 {
198         u32 *rp;
199         int rc;
200
201         if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
202                 return rc;
203
204         /* write risc instructions */
205         rp = risc->cpu;
206         *(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2 | RISC_IMM);
207         *(rp++) = cpu_to_le32(reg);
208         *(rp++) = cpu_to_le32(value);
209         *(rp++) = cpu_to_le32(mask);
210         *(rp++) = cpu_to_le32(RISC_JUMP);
211         *(rp++) = cpu_to_le32(risc->dma);
212         return 0;
213 }
214
215 void
216 cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
217 {
218         if (in_interrupt())
219                 BUG();
220         videobuf_waiton(&buf->vb,0,0);
221         videobuf_dma_pci_unmap(pci, &buf->vb.dma);
222         videobuf_dma_free(&buf->vb.dma);
223         btcx_riscmem_free(pci, &buf->risc);
224         buf->vb.state = STATE_NEEDS_INIT;
225 }
226
227 /* ------------------------------------------------------------------ */
228 /* our SRAM memory layout                                             */
229
230 /* we are going to put all thr risc programs into host memory, so we
231  * can use the whole SDRAM for the DMA fifos.  To simplify things, we
232  * use a static memory layout.  That surely will waste memory in case
233  * we don't use all DMA channels at the same time (which will be the
234  * case most of the time).  But that still gives us enougth FIFO space
235  * to be able to deal with insane long pci latencies ...
236  *
237  * FIFO space allocations:
238  *    channel  21    (y video)  - 10.0k
239  *    channel  22    (u video)  -  2.0k
240  *    channel  23    (v video)  -  2.0k
241  *    channel  24    (vbi)      -  4.0k
242  *    channels 25+26 (audio)    -  4.0k
243  *    channel  28    (mpeg)     -  4.0k
244  *    TOTAL                     = 29.0k
245  *
246  * Every channel has 160 bytes control data (64 bytes instruction
247  * queue and 6 CDT entries), which is close to 2k total.
248  *
249  * Address layout:
250  *    0x0000 - 0x03ff    CMDs / reserved
251  *    0x0400 - 0x0bff    instruction queues + CDs
252  *    0x0c00 -           FIFOs
253  */
254
255 struct sram_channel cx88_sram_channels[] = {
256         [SRAM_CH21] = {
257                 .name       = "video y / packed",
258                 .cmds_start = 0x180040,
259                 .ctrl_start = 0x180400,
260                 .cdt        = 0x180400 + 64,
261                 .fifo_start = 0x180c00,
262                 .fifo_size  = 0x002800,
263                 .ptr1_reg   = MO_DMA21_PTR1,
264                 .ptr2_reg   = MO_DMA21_PTR2,
265                 .cnt1_reg   = MO_DMA21_CNT1,
266                 .cnt2_reg   = MO_DMA21_CNT2,
267         },
268         [SRAM_CH22] = {
269                 .name       = "video u",
270                 .cmds_start = 0x180080,
271                 .ctrl_start = 0x1804a0,
272                 .cdt        = 0x1804a0 + 64,
273                 .fifo_start = 0x183400,
274                 .fifo_size  = 0x000800,
275                 .ptr1_reg   = MO_DMA22_PTR1,
276                 .ptr2_reg   = MO_DMA22_PTR2,
277                 .cnt1_reg   = MO_DMA22_CNT1,
278                 .cnt2_reg   = MO_DMA22_CNT2,
279         },
280         [SRAM_CH23] = {
281                 .name       = "video v",
282                 .cmds_start = 0x1800c0,
283                 .ctrl_start = 0x180540,
284                 .cdt        = 0x180540 + 64,
285                 .fifo_start = 0x183c00,
286                 .fifo_size  = 0x000800,
287                 .ptr1_reg   = MO_DMA23_PTR1,
288                 .ptr2_reg   = MO_DMA23_PTR2,
289                 .cnt1_reg   = MO_DMA23_CNT1,
290                 .cnt2_reg   = MO_DMA23_CNT2,
291         },
292         [SRAM_CH24] = {
293                 .name       = "vbi",
294                 .cmds_start = 0x180100,
295                 .ctrl_start = 0x1805e0,
296                 .cdt        = 0x1805e0 + 64,
297                 .fifo_start = 0x184400,
298                 .fifo_size  = 0x001000,
299                 .ptr1_reg   = MO_DMA24_PTR1,
300                 .ptr2_reg   = MO_DMA24_PTR2,
301                 .cnt1_reg   = MO_DMA24_CNT1,
302                 .cnt2_reg   = MO_DMA24_CNT2,
303         },
304         [SRAM_CH25] = {
305                 .name       = "audio from",
306                 .cmds_start = 0x180140,
307                 .ctrl_start = 0x180680,
308                 .cdt        = 0x180680 + 64,
309                 .fifo_start = 0x185400,
310                 .fifo_size  = 0x001000,
311                 .ptr1_reg   = MO_DMA25_PTR1,
312                 .ptr2_reg   = MO_DMA25_PTR2,
313                 .cnt1_reg   = MO_DMA25_CNT1,
314                 .cnt2_reg   = MO_DMA25_CNT2,
315         },
316         [SRAM_CH26] = {
317                 .name       = "audio to",
318                 .cmds_start = 0x180180,
319                 .ctrl_start = 0x180720,
320                 .cdt        = 0x180680 + 64,  /* same as audio IN */
321                 .fifo_start = 0x185400,       /* same as audio IN */
322                 .fifo_size  = 0x001000,       /* same as audio IN */
323                 .ptr1_reg   = MO_DMA26_PTR1,
324                 .ptr2_reg   = MO_DMA26_PTR2,
325                 .cnt1_reg   = MO_DMA26_CNT1,
326                 .cnt2_reg   = MO_DMA26_CNT2,
327         },
328         [SRAM_CH28] = {
329                 .name       = "mpeg",
330                 .cmds_start = 0x180200,
331                 .ctrl_start = 0x1807C0,
332                 .cdt        = 0x1807C0 + 64,
333                 .fifo_start = 0x186400,
334                 .fifo_size  = 0x001000,
335                 .ptr1_reg   = MO_DMA28_PTR1,
336                 .ptr2_reg   = MO_DMA28_PTR2,
337                 .cnt1_reg   = MO_DMA28_CNT1,
338                 .cnt2_reg   = MO_DMA28_CNT2,
339         },
340 };
341
342 int cx88_sram_channel_setup(struct cx88_core *core,
343                             struct sram_channel *ch,
344                             unsigned int bpl, u32 risc)
345 {
346         unsigned int i,lines;
347         u32 cdt;
348
349         bpl   = (bpl + 7) & ~7; /* alignment */
350         cdt   = ch->cdt;
351         lines = ch->fifo_size / bpl;
352         if (lines > 6)
353                 lines = 6;
354         BUG_ON(lines < 2);
355
356         /* write CDT */
357         for (i = 0; i < lines; i++)
358                 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
359
360         /* write CMDS */
361         cx_write(ch->cmds_start +  0, risc);
362         cx_write(ch->cmds_start +  4, cdt);
363         cx_write(ch->cmds_start +  8, (lines*16) >> 3);
364         cx_write(ch->cmds_start + 12, ch->ctrl_start);
365         cx_write(ch->cmds_start + 16, 64 >> 2);
366         for (i = 20; i < 64; i += 4)
367                 cx_write(ch->cmds_start + i, 0);
368
369         /* fill registers */
370         cx_write(ch->ptr1_reg, ch->fifo_start);
371         cx_write(ch->ptr2_reg, cdt);
372         cx_write(ch->cnt1_reg, (bpl >> 3) -1);
373         cx_write(ch->cnt2_reg, (lines*16) >> 3);
374
375         dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
376         return 0;
377 }
378
379 /* ------------------------------------------------------------------ */
380 /* debug helper code                                                  */
381
382 static int cx88_risc_decode(u32 risc)
383 {
384         static char *instr[16] = {
385                 [ RISC_SYNC    >> 28 ] = "sync",
386                 [ RISC_WRITE   >> 28 ] = "write",
387                 [ RISC_WRITEC  >> 28 ] = "writec",
388                 [ RISC_READ    >> 28 ] = "read",
389                 [ RISC_READC   >> 28 ] = "readc",
390                 [ RISC_JUMP    >> 28 ] = "jump",
391                 [ RISC_SKIP    >> 28 ] = "skip",
392                 [ RISC_WRITERM >> 28 ] = "writerm",
393                 [ RISC_WRITECM >> 28 ] = "writecm",
394                 [ RISC_WRITECR >> 28 ] = "writecr",
395         };
396         static int incr[16] = {
397                 [ RISC_WRITE   >> 28 ] = 2,
398                 [ RISC_JUMP    >> 28 ] = 2,
399                 [ RISC_WRITERM >> 28 ] = 3,
400                 [ RISC_WRITECM >> 28 ] = 3,
401                 [ RISC_WRITECR >> 28 ] = 4,
402         };
403         static char *bits[] = {
404                 "12",   "13",   "14",   "resync",
405                 "cnt0", "cnt1", "18",   "19",
406                 "20",   "21",   "22",   "23",
407                 "irq1", "irq2", "eol",  "sol",
408         };
409         int i;
410
411         printk("0x%08x [ %s", risc,
412                instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
413         for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
414                 if (risc & (1 << (i + 12)))
415                         printk(" %s",bits[i]);
416         printk(" count=%d ]\n", risc & 0xfff);
417         return incr[risc >> 28] ? incr[risc >> 28] : 1;
418 }
419
420
421 void cx88_sram_channel_dump(struct cx88_core *core,
422                             struct sram_channel *ch)
423 {
424         static char *name[] = {
425                 "initial risc",
426                 "cdt base",
427                 "cdt size",
428                 "iq base",
429                 "iq size",
430                 "risc pc",
431                 "iq wr ptr",
432                 "iq rd ptr",
433                 "cdt current",
434                 "pci target",
435                 "line / byte",
436         };
437         u32 risc;
438         unsigned int i,j,n;
439
440         printk("%s: %s - dma channel status dump\n",
441                core->name,ch->name);
442         for (i = 0; i < ARRAY_SIZE(name); i++)
443                 printk("%s:   cmds: %-12s: 0x%08x\n",
444                        core->name,name[i],
445                        cx_read(ch->cmds_start + 4*i));
446         for (i = 0; i < 4; i++) {
447                 risc = cx_read(ch->cmds_start + 4 * (i+11));
448                 printk("%s:   risc%d: ", core->name, i);
449                 cx88_risc_decode(risc);
450         }
451         for (i = 0; i < 16; i += n) {
452                 risc = cx_read(ch->ctrl_start + 4 * i);
453                 printk("%s:   iq %x: ", core->name, i);
454                 n = cx88_risc_decode(risc);
455                 for (j = 1; j < n; j++) {
456                         risc = cx_read(ch->ctrl_start + 4 * (i+j));
457                         printk("%s:   iq %x: 0x%08x [ arg #%d ]\n",
458                                core->name, i+j, risc, j);
459                 }
460         }
461
462         printk("%s: fifo: 0x%08x -> 0x%x\n",
463                core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
464         printk("%s: ctrl: 0x%08x -> 0x%x\n",
465                core->name, ch->ctrl_start, ch->ctrl_start+6*16);
466         printk("%s:   ptr1_reg: 0x%08x\n",
467                core->name,cx_read(ch->ptr1_reg));
468         printk("%s:   ptr2_reg: 0x%08x\n",
469                core->name,cx_read(ch->ptr2_reg));
470         printk("%s:   cnt1_reg: 0x%08x\n",
471                core->name,cx_read(ch->cnt1_reg));
472         printk("%s:   cnt2_reg: 0x%08x\n",
473                core->name,cx_read(ch->cnt2_reg));
474 }
475
476 static char *cx88_pci_irqs[32] = {
477         "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
478         "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
479         "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
480         "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
481 };
482
483 void cx88_print_irqbits(char *name, char *tag, char **strings,
484                         u32 bits, u32 mask)
485 {
486         unsigned int i;
487
488         printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
489         for (i = 0; i < 32; i++) {
490                 if (!(bits & (1 << i)))
491                         continue;
492                 if (strings[i])
493                         printk(" %s", strings[i]);
494                 else
495                         printk(" %d", i);
496                 if (!(mask & (1 << i)))
497                         continue;
498                 printk("*");
499         }
500         printk("\n");
501 }
502
503 /* ------------------------------------------------------------------ */
504
505 int cx88_core_irq(struct cx88_core *core, u32 status)
506 {
507         int handled = 0;
508
509         if (status & (1<<18)) {
510                 cx88_ir_irq(core);
511                 handled++;
512         }
513         if (!handled)
514                 cx88_print_irqbits(core->name, "irq pci",
515                                    cx88_pci_irqs, status,
516                                    core->pci_irqmask);
517         return handled;
518 }
519
520 void cx88_wakeup(struct cx88_core *core,
521                  struct cx88_dmaqueue *q, u32 count)
522 {
523         struct cx88_buffer *buf;
524         int bc;
525
526         for (bc = 0;; bc++) {
527                 if (list_empty(&q->active))
528                         break;
529                 buf = list_entry(q->active.next,
530                                  struct cx88_buffer, vb.queue);
531                 /* count comes from the hw and is is 16bit wide --
532                  * this trick handles wrap-arounds correctly for
533                  * up to 32767 buffers in flight... */
534                 if ((s16) (count - buf->count) < 0)
535                         break;
536                 do_gettimeofday(&buf->vb.ts);
537                 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
538                         count, buf->count);
539                 buf->vb.state = STATE_DONE;
540                 list_del(&buf->vb.queue);
541                 wake_up(&buf->vb.done);
542         }
543         if (list_empty(&q->active)) {
544                 del_timer(&q->timeout);
545         } else {
546                 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
547         }
548         if (bc != 1)
549                 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
550 }
551
552 void cx88_shutdown(struct cx88_core *core)
553 {
554         /* disable RISC controller + IRQs */
555         cx_write(MO_DEV_CNTRL2, 0);
556
557         /* stop dma transfers */
558         cx_write(MO_VID_DMACNTRL, 0x0);
559         cx_write(MO_AUD_DMACNTRL, 0x0);
560         cx_write(MO_TS_DMACNTRL, 0x0);
561         cx_write(MO_VIP_DMACNTRL, 0x0);
562         cx_write(MO_GPHST_DMACNTRL, 0x0);
563
564         /* stop interrupts */
565         cx_write(MO_PCI_INTMSK, 0x0);
566         cx_write(MO_VID_INTMSK, 0x0);
567         cx_write(MO_AUD_INTMSK, 0x0);
568         cx_write(MO_TS_INTMSK, 0x0);
569         cx_write(MO_VIP_INTMSK, 0x0);
570         cx_write(MO_GPHST_INTMSK, 0x0);
571
572         /* stop capturing */
573         cx_write(VID_CAPTURE_CONTROL, 0);
574 }
575
576 int cx88_reset(struct cx88_core *core)
577 {
578         dprintk(1,"%s\n",__FUNCTION__);
579         cx88_shutdown(core);
580
581         /* clear irq status */
582         cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
583         cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
584         cx_write(MO_INT1_STAT,   0xFFFFFFFF); // Clear RISC int
585
586         /* wait a bit */
587         msleep(100);
588
589         /* init sram */
590         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
591         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
592         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
593         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
594         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
595         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
596         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
597
598         /* misc init ... */
599         cx_write(MO_INPUT_FORMAT, ((1 << 13) |   // agc enable
600                                    (1 << 12) |   // agc gain
601                                    (1 << 11) |   // adaptibe agc
602                                    (0 << 10) |   // chroma agc
603                                    (0 <<  9) |   // ckillen
604                                    (7)));
605
606         /* setup image format */
607         cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
608
609         /* setup FIFO Threshholds */
610         cx_write(MO_PDMA_STHRSH,   0x0807);
611         cx_write(MO_PDMA_DTHRSH,   0x0807);
612
613         /* fixes flashing of image */
614         cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
615         cx_write(MO_AGC_BACK_VBI,  0x00E00555);
616
617         cx_write(MO_VID_INTSTAT,   0xFFFFFFFF); // Clear PIV int
618         cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
619         cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
620
621         /* Reset on-board parts */
622         cx_write(MO_SRST_IO, 0);
623         msleep(10);
624         cx_write(MO_SRST_IO, 1);
625
626         return 0;
627 }
628
629 /* ------------------------------------------------------------------ */
630
631 static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
632 {
633         return (norm->id & V4L2_STD_625_50) ? 922 : 754;
634 }
635
636 static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
637 {
638         return (norm->id & V4L2_STD_625_50) ? 186 : 135;
639 }
640
641 static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
642 {
643         return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
644 }
645
646 static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
647 {
648         static const unsigned int ntsc = 28636360;
649         static const unsigned int pal  = 35468950;
650         static const unsigned int palm  = 28604892;
651
652         if (norm->id & V4L2_STD_PAL_M)
653                 return palm;
654
655         return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
656 }
657
658 static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
659 {
660         return (norm->id & V4L2_STD_625_50)
661                 ? HLNotchFilter135PAL
662                 : HLNotchFilter135NTSC;
663 }
664
665 static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
666 {
667         /* Should always be Line Draw Time / (4*FSC) */
668
669         if (norm->id & V4L2_STD_PAL_M)
670                 return 909;
671
672         return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
673 }
674
675 static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
676 {
677         return (norm->id & V4L2_STD_625_50) ? 511 : 288;
678 }
679
680 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
681                    enum v4l2_field field)
682 {
683         unsigned int swidth  = norm_swidth(core->tvnorm);
684         unsigned int sheight = norm_maxh(core->tvnorm);
685         u32 value;
686
687         dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
688                 V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
689                 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
690                 core->tvnorm->name);
691         if (!V4L2_FIELD_HAS_BOTH(field))
692                 height *= 2;
693
694         // recalc H delay and scale registers
695         value = (width * norm_hdelay(core->tvnorm)) / swidth;
696         value &= 0x3fe;
697         cx_write(MO_HDELAY_EVEN,  value);
698         cx_write(MO_HDELAY_ODD,   value);
699         dprintk(1,"set_scale: hdelay  0x%04x\n", value);
700
701         value = (swidth * 4096 / width) - 4096;
702         cx_write(MO_HSCALE_EVEN,  value);
703         cx_write(MO_HSCALE_ODD,   value);
704         dprintk(1,"set_scale: hscale  0x%04x\n", value);
705
706         cx_write(MO_HACTIVE_EVEN, width);
707         cx_write(MO_HACTIVE_ODD,  width);
708         dprintk(1,"set_scale: hactive 0x%04x\n", width);
709
710         // recalc V scale Register (delay is constant)
711         cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
712         cx_write(MO_VDELAY_ODD,  norm_vdelay(core->tvnorm));
713         dprintk(1,"set_scale: vdelay  0x%04x\n", norm_vdelay(core->tvnorm));
714
715         value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
716         cx_write(MO_VSCALE_EVEN,  value);
717         cx_write(MO_VSCALE_ODD,   value);
718         dprintk(1,"set_scale: vscale  0x%04x\n", value);
719
720         cx_write(MO_VACTIVE_EVEN, sheight);
721         cx_write(MO_VACTIVE_ODD,  sheight);
722         dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
723
724         // setup filters
725         value = 0;
726         value |= (1 << 19);        // CFILT (default)
727         if (core->tvnorm->id & V4L2_STD_SECAM) {
728                 value |= (1 << 15);
729                 value |= (1 << 16);
730         }
731         if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
732                 value |= (1 << 13) | (1 << 5);
733         if (V4L2_FIELD_INTERLACED == field)
734                 value |= (1 << 3); // VINT (interlaced vertical scaling)
735         if (width < 385)
736                 value |= (1 << 0); // 3-tap interpolation
737         if (width < 193)
738                 value |= (1 << 1); // 5-tap interpolation
739         if (nocomb)
740                 value |= (3 << 5); // disable comb filter
741
742         cx_write(MO_FILTER_EVEN,  value);
743         cx_write(MO_FILTER_ODD,   value);
744         dprintk(1,"set_scale: filter  0x%04x\n", value);
745
746         return 0;
747 }
748
749 static const u32 xtal = 28636363;
750
751 static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
752 {
753         static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
754         u64 pll;
755         u32 reg;
756         int i;
757
758         if (prescale < 2)
759                 prescale = 2;
760         if (prescale > 5)
761                 prescale = 5;
762
763         pll = ofreq * 8 * prescale * (u64)(1 << 20);
764         do_div(pll,xtal);
765         reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
766         if (((reg >> 20) & 0x3f) < 14) {
767                 printk("%s/0: pll out of range\n",core->name);
768                 return -1;
769         }
770
771         dprintk(1,"set_pll:    MO_PLL_REG       0x%08x [old=0x%08x,freq=%d]\n",
772                 reg, cx_read(MO_PLL_REG), ofreq);
773         cx_write(MO_PLL_REG, reg);
774         for (i = 0; i < 100; i++) {
775                 reg = cx_read(MO_DEVICE_STATUS);
776                 if (reg & (1<<2)) {
777                         dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
778                                 prescale,ofreq);
779                         return 0;
780                 }
781                 dprintk(1,"pll not locked yet, waiting ...\n");
782                 msleep(10);
783         }
784         dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
785         return -1;
786 }
787
788 int cx88_start_audio_dma(struct cx88_core *core)
789 {
790         /* setup fifo + format */
791         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
792         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
793
794         cx_write(MO_AUDD_LNGTH,    128); /* fifo bpl size */
795         cx_write(MO_AUDR_LNGTH,    128); /* fifo bpl size */
796
797         /* start dma */
798         cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
799         return 0;
800 }
801
802 int cx88_stop_audio_dma(struct cx88_core *core)
803 {
804         /* stop dma */
805         cx_write(MO_AUD_DMACNTRL, 0x0000);
806
807         return 0;
808 }
809
810 static int set_tvaudio(struct cx88_core *core)
811 {
812         struct cx88_tvnorm *norm = core->tvnorm;
813
814         if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
815                 return 0;
816
817         if (V4L2_STD_PAL_BG & norm->id) {
818                 core->tvaudio = WW_BG;
819
820         } else if (V4L2_STD_PAL_DK & norm->id) {
821                 core->tvaudio = WW_DK;
822
823         } else if (V4L2_STD_PAL_I & norm->id) {
824                 core->tvaudio = WW_I;
825
826         } else if (V4L2_STD_SECAM_L & norm->id) {
827                 core->tvaudio = WW_L;
828
829         } else if (V4L2_STD_SECAM_DK & norm->id) {
830                 core->tvaudio = WW_DK;
831
832         } else if ((V4L2_STD_NTSC_M & norm->id) ||
833                    (V4L2_STD_PAL_M  & norm->id)) {
834                 core->tvaudio = WW_BTSC;
835
836         } else if (V4L2_STD_NTSC_M_JP & norm->id) {
837                 core->tvaudio = WW_EIAJ;
838
839         } else {
840                 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
841                        core->name, norm->name);
842                 core->tvaudio = 0;
843                 return 0;
844         }
845
846         cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
847         cx88_set_tvaudio(core);
848         /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
849
850 /*
851    This should be needed only on cx88-alsa. It seems that some cx88 chips have
852    bugs and does require DMA enabled for it to work.
853  */
854         cx88_start_audio_dma(core);
855         return 0;
856 }
857
858
859
860 int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
861 {
862         u32 fsc8;
863         u32 adc_clock;
864         u32 vdec_clock;
865         u32 step_db,step_dr;
866         u64 tmp64;
867         u32 bdelay,agcdelay,htotal;
868
869         core->tvnorm = norm;
870         fsc8       = norm_fsc8(norm);
871         adc_clock  = xtal;
872         vdec_clock = fsc8;
873         step_db    = fsc8;
874         step_dr    = fsc8;
875
876         if (norm->id & V4L2_STD_SECAM) {
877                 step_db = 4250000 * 8;
878                 step_dr = 4406250 * 8;
879         }
880
881         dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
882                 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
883         set_pll(core,2,vdec_clock);
884
885         dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
886                 norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
887         cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
888
889         // FIXME: as-is from DScaler
890         dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
891                 norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
892         cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
893
894         // MO_SCONV_REG = adc clock / video dec clock * 2^17
895         tmp64  = adc_clock * (u64)(1 << 17);
896         do_div(tmp64, vdec_clock);
897         dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",
898                 (u32)tmp64, cx_read(MO_SCONV_REG));
899         cx_write(MO_SCONV_REG, (u32)tmp64);
900
901         // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
902         tmp64  = step_db * (u64)(1 << 22);
903         do_div(tmp64, vdec_clock);
904         dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",
905                 (u32)tmp64, cx_read(MO_SUB_STEP));
906         cx_write(MO_SUB_STEP, (u32)tmp64);
907
908         // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
909         tmp64  = step_dr * (u64)(1 << 22);
910         do_div(tmp64, vdec_clock);
911         dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",
912                 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
913         cx_write(MO_SUB_STEP_DR, (u32)tmp64);
914
915         // bdelay + agcdelay
916         bdelay   = vdec_clock * 65 / 20000000 + 21;
917         agcdelay = vdec_clock * 68 / 20000000 + 15;
918         dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
919                 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
920         cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
921
922         // htotal
923         tmp64 = norm_htotal(norm) * (u64)vdec_clock;
924         do_div(tmp64, fsc8);
925         htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
926         dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
927                 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
928         cx_write(MO_HTOTAL, htotal);
929
930         // vbi stuff
931         cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
932                                  norm_vbipack(norm)));
933
934         // this is needed as well to set all tvnorm parameter
935         cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
936
937         // audio
938         set_tvaudio(core);
939
940         // tell i2c chips
941         cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
942
943         // done
944         return 0;
945 }
946
947 /* ------------------------------------------------------------------ */
948
949 static int cx88_pci_quirks(char *name, struct pci_dev *pci)
950 {
951         unsigned int lat = UNSET;
952         u8 ctrl = 0;
953         u8 value;
954
955         /* check pci quirks */
956         if (pci_pci_problems & PCIPCI_TRITON) {
957                 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
958                        name);
959                 ctrl |= CX88X_EN_TBFX;
960         }
961         if (pci_pci_problems & PCIPCI_NATOMA) {
962                 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
963                        name);
964                 ctrl |= CX88X_EN_TBFX;
965         }
966         if (pci_pci_problems & PCIPCI_VIAETBF) {
967                 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
968                        name);
969                 ctrl |= CX88X_EN_TBFX;
970         }
971         if (pci_pci_problems & PCIPCI_VSFX) {
972                 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
973                        name);
974                 ctrl |= CX88X_EN_VSFX;
975         }
976 #ifdef PCIPCI_ALIMAGIK
977         if (pci_pci_problems & PCIPCI_ALIMAGIK) {
978                 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
979                        name);
980                 lat = 0x0A;
981         }
982 #endif
983
984         /* check insmod options */
985         if (UNSET != latency)
986                 lat = latency;
987
988         /* apply stuff */
989         if (ctrl) {
990                 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
991                 value |= ctrl;
992                 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
993         }
994         if (UNSET != lat) {
995                 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
996                        name, latency);
997                 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
998         }
999         return 0;
1000 }
1001
1002 /* ------------------------------------------------------------------ */
1003
1004 struct video_device *cx88_vdev_init(struct cx88_core *core,
1005                                     struct pci_dev *pci,
1006                                     struct video_device *template,
1007                                     char *type)
1008 {
1009         struct video_device *vfd;
1010
1011         vfd = video_device_alloc();
1012         if (NULL == vfd)
1013                 return NULL;
1014         *vfd = *template;
1015         vfd->minor   = -1;
1016         vfd->dev     = &pci->dev;
1017         vfd->release = video_device_release;
1018         snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1019                  core->name, type, cx88_boards[core->board].name);
1020         return vfd;
1021 }
1022
1023 static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1024 {
1025         if (request_mem_region(pci_resource_start(pci,0),
1026                                pci_resource_len(pci,0),
1027                                core->name))
1028                 return 0;
1029         printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
1030                core->name,pci_resource_start(pci,0));
1031         return -EBUSY;
1032 }
1033
1034 struct cx88_core* cx88_core_get(struct pci_dev *pci)
1035 {
1036         struct cx88_core *core;
1037         struct list_head *item;
1038         int i;
1039
1040         mutex_lock(&devlist);
1041         list_for_each(item,&cx88_devlist) {
1042                 core = list_entry(item, struct cx88_core, devlist);
1043                 if (pci->bus->number != core->pci_bus)
1044                         continue;
1045                 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1046                         continue;
1047
1048                 if (0 != get_ressources(core,pci))
1049                         goto fail_unlock;
1050                 atomic_inc(&core->refcount);
1051                 mutex_unlock(&devlist);
1052                 return core;
1053         }
1054         core = kzalloc(sizeof(*core),GFP_KERNEL);
1055         if (NULL == core)
1056                 goto fail_unlock;
1057
1058         atomic_inc(&core->refcount);
1059         core->pci_bus  = pci->bus->number;
1060         core->pci_slot = PCI_SLOT(pci->devfn);
1061         core->pci_irqmask = 0x00fc00;
1062         init_MUTEX(&core->lock);
1063
1064         core->nr = cx88_devcount++;
1065         sprintf(core->name,"cx88[%d]",core->nr);
1066         if (0 != get_ressources(core,pci)) {
1067                 printk(KERN_ERR "CORE %s No more PCI ressources for "
1068                         "subsystem: %04x:%04x, board: %s\n",
1069                         core->name,pci->subsystem_vendor,
1070                         pci->subsystem_device,
1071                         cx88_boards[core->board].name);
1072
1073                 cx88_devcount--;
1074                 goto fail_free;
1075         }
1076         list_add_tail(&core->devlist,&cx88_devlist);
1077
1078         /* PCI stuff */
1079         cx88_pci_quirks(core->name, pci);
1080         core->lmmio = ioremap(pci_resource_start(pci,0),
1081                               pci_resource_len(pci,0));
1082         core->bmmio = (u8 __iomem *)core->lmmio;
1083
1084         /* board config */
1085         core->board = UNSET;
1086         if (card[core->nr] < cx88_bcount)
1087                 core->board = card[core->nr];
1088         for (i = 0; UNSET == core->board  &&  i < cx88_idcount; i++)
1089                 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1090                     pci->subsystem_device == cx88_subids[i].subdevice)
1091                         core->board = cx88_subids[i].card;
1092         if (UNSET == core->board) {
1093                 core->board = CX88_BOARD_UNKNOWN;
1094                 cx88_card_list(core,pci);
1095         }
1096         printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1097                 core->name,pci->subsystem_vendor,
1098                 pci->subsystem_device,cx88_boards[core->board].name,
1099                 core->board, card[core->nr] == core->board ?
1100                 "insmod option" : "autodetected");
1101
1102         core->tuner_type = tuner[core->nr];
1103         core->radio_type = radio[core->nr];
1104         if (UNSET == core->tuner_type)
1105                 core->tuner_type = cx88_boards[core->board].tuner_type;
1106         if (UNSET == core->radio_type)
1107                 core->radio_type = cx88_boards[core->board].radio_type;
1108         if (!core->tuner_addr)
1109                 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1110         if (!core->radio_addr)
1111                 core->radio_addr = cx88_boards[core->board].radio_addr;
1112
1113         printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
1114                 core->tuner_type, core->tuner_addr<<1,
1115                 core->radio_type, core->radio_addr<<1);
1116
1117         core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1118
1119         /* init hardware */
1120         cx88_reset(core);
1121         cx88_i2c_init(core,pci);
1122         cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
1123         cx88_card_setup(core);
1124         cx88_ir_init(core,pci);
1125
1126         mutex_unlock(&devlist);
1127         return core;
1128
1129 fail_free:
1130         kfree(core);
1131 fail_unlock:
1132         mutex_unlock(&devlist);
1133         return NULL;
1134 }
1135
1136 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1137 {
1138         release_mem_region(pci_resource_start(pci,0),
1139                            pci_resource_len(pci,0));
1140
1141         if (!atomic_dec_and_test(&core->refcount))
1142                 return;
1143
1144         mutex_lock(&devlist);
1145         cx88_ir_fini(core);
1146         if (0 == core->i2c_rc)
1147                 i2c_bit_del_bus(&core->i2c_adap);
1148         list_del(&core->devlist);
1149         iounmap(core->lmmio);
1150         cx88_devcount--;
1151         mutex_unlock(&devlist);
1152         kfree(core);
1153 }
1154
1155 /* ------------------------------------------------------------------ */
1156
1157 EXPORT_SYMBOL(cx88_print_irqbits);
1158
1159 EXPORT_SYMBOL(cx88_core_irq);
1160 EXPORT_SYMBOL(cx88_wakeup);
1161 EXPORT_SYMBOL(cx88_reset);
1162 EXPORT_SYMBOL(cx88_shutdown);
1163
1164 EXPORT_SYMBOL(cx88_risc_buffer);
1165 EXPORT_SYMBOL(cx88_risc_databuffer);
1166 EXPORT_SYMBOL(cx88_risc_stopper);
1167 EXPORT_SYMBOL(cx88_free_buffer);
1168
1169 EXPORT_SYMBOL(cx88_sram_channels);
1170 EXPORT_SYMBOL(cx88_sram_channel_setup);
1171 EXPORT_SYMBOL(cx88_sram_channel_dump);
1172
1173 EXPORT_SYMBOL(cx88_set_tvnorm);
1174 EXPORT_SYMBOL(cx88_set_scale);
1175
1176 EXPORT_SYMBOL(cx88_vdev_init);
1177 EXPORT_SYMBOL(cx88_core_get);
1178 EXPORT_SYMBOL(cx88_core_put);
1179 EXPORT_SYMBOL(cx88_start_audio_dma);
1180 EXPORT_SYMBOL(cx88_stop_audio_dma);
1181
1182 /*
1183  * Local variables:
1184  * c-basic-offset: 8
1185  * End:
1186  * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
1187  */