Pull icc-cleanup into release branch
[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         /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
791         int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
792         /* setup fifo + format */
793         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
794         cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
795
796         cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
797         cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
798
799         /* start dma */
800         cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
801         return 0;
802 }
803
804 int cx88_stop_audio_dma(struct cx88_core *core)
805 {
806         /* stop dma */
807         cx_write(MO_AUD_DMACNTRL, 0x0000);
808
809         return 0;
810 }
811
812 static int set_tvaudio(struct cx88_core *core)
813 {
814         struct cx88_tvnorm *norm = core->tvnorm;
815
816         if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
817                 return 0;
818
819         if (V4L2_STD_PAL_BG & norm->id) {
820                 core->tvaudio = WW_BG;
821
822         } else if (V4L2_STD_PAL_DK & norm->id) {
823                 core->tvaudio = WW_DK;
824
825         } else if (V4L2_STD_PAL_I & norm->id) {
826                 core->tvaudio = WW_I;
827
828         } else if (V4L2_STD_SECAM_L & norm->id) {
829                 core->tvaudio = WW_L;
830
831         } else if (V4L2_STD_SECAM_DK & norm->id) {
832                 core->tvaudio = WW_DK;
833
834         } else if ((V4L2_STD_NTSC_M & norm->id) ||
835                    (V4L2_STD_PAL_M  & norm->id)) {
836                 core->tvaudio = WW_BTSC;
837
838         } else if (V4L2_STD_NTSC_M_JP & norm->id) {
839                 core->tvaudio = WW_EIAJ;
840
841         } else {
842                 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
843                        core->name, norm->name);
844                 core->tvaudio = 0;
845                 return 0;
846         }
847
848         cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
849         cx88_set_tvaudio(core);
850         /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
851
852 /*
853    This should be needed only on cx88-alsa. It seems that some cx88 chips have
854    bugs and does require DMA enabled for it to work.
855  */
856         cx88_start_audio_dma(core);
857         return 0;
858 }
859
860
861
862 int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
863 {
864         u32 fsc8;
865         u32 adc_clock;
866         u32 vdec_clock;
867         u32 step_db,step_dr;
868         u64 tmp64;
869         u32 bdelay,agcdelay,htotal;
870
871         core->tvnorm = norm;
872         fsc8       = norm_fsc8(norm);
873         adc_clock  = xtal;
874         vdec_clock = fsc8;
875         step_db    = fsc8;
876         step_dr    = fsc8;
877
878         if (norm->id & V4L2_STD_SECAM) {
879                 step_db = 4250000 * 8;
880                 step_dr = 4406250 * 8;
881         }
882
883         dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
884                 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
885         set_pll(core,2,vdec_clock);
886
887         dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",
888                 norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
889         cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
890
891         // FIXME: as-is from DScaler
892         dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
893                 norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
894         cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
895
896         // MO_SCONV_REG = adc clock / video dec clock * 2^17
897         tmp64  = adc_clock * (u64)(1 << 17);
898         do_div(tmp64, vdec_clock);
899         dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",
900                 (u32)tmp64, cx_read(MO_SCONV_REG));
901         cx_write(MO_SCONV_REG, (u32)tmp64);
902
903         // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
904         tmp64  = step_db * (u64)(1 << 22);
905         do_div(tmp64, vdec_clock);
906         dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",
907                 (u32)tmp64, cx_read(MO_SUB_STEP));
908         cx_write(MO_SUB_STEP, (u32)tmp64);
909
910         // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
911         tmp64  = step_dr * (u64)(1 << 22);
912         do_div(tmp64, vdec_clock);
913         dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",
914                 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
915         cx_write(MO_SUB_STEP_DR, (u32)tmp64);
916
917         // bdelay + agcdelay
918         bdelay   = vdec_clock * 65 / 20000000 + 21;
919         agcdelay = vdec_clock * 68 / 20000000 + 15;
920         dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
921                 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
922         cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
923
924         // htotal
925         tmp64 = norm_htotal(norm) * (u64)vdec_clock;
926         do_div(tmp64, fsc8);
927         htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
928         dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
929                 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
930         cx_write(MO_HTOTAL, htotal);
931
932         // vbi stuff
933         cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
934                                  norm_vbipack(norm)));
935
936         // this is needed as well to set all tvnorm parameter
937         cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
938
939         // audio
940         set_tvaudio(core);
941
942         // tell i2c chips
943         cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
944
945         // done
946         return 0;
947 }
948
949 /* ------------------------------------------------------------------ */
950
951 static int cx88_pci_quirks(char *name, struct pci_dev *pci)
952 {
953         unsigned int lat = UNSET;
954         u8 ctrl = 0;
955         u8 value;
956
957         /* check pci quirks */
958         if (pci_pci_problems & PCIPCI_TRITON) {
959                 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
960                        name);
961                 ctrl |= CX88X_EN_TBFX;
962         }
963         if (pci_pci_problems & PCIPCI_NATOMA) {
964                 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
965                        name);
966                 ctrl |= CX88X_EN_TBFX;
967         }
968         if (pci_pci_problems & PCIPCI_VIAETBF) {
969                 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
970                        name);
971                 ctrl |= CX88X_EN_TBFX;
972         }
973         if (pci_pci_problems & PCIPCI_VSFX) {
974                 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
975                        name);
976                 ctrl |= CX88X_EN_VSFX;
977         }
978 #ifdef PCIPCI_ALIMAGIK
979         if (pci_pci_problems & PCIPCI_ALIMAGIK) {
980                 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
981                        name);
982                 lat = 0x0A;
983         }
984 #endif
985
986         /* check insmod options */
987         if (UNSET != latency)
988                 lat = latency;
989
990         /* apply stuff */
991         if (ctrl) {
992                 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
993                 value |= ctrl;
994                 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
995         }
996         if (UNSET != lat) {
997                 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
998                        name, latency);
999                 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1000         }
1001         return 0;
1002 }
1003
1004 /* ------------------------------------------------------------------ */
1005
1006 struct video_device *cx88_vdev_init(struct cx88_core *core,
1007                                     struct pci_dev *pci,
1008                                     struct video_device *template,
1009                                     char *type)
1010 {
1011         struct video_device *vfd;
1012
1013         vfd = video_device_alloc();
1014         if (NULL == vfd)
1015                 return NULL;
1016         *vfd = *template;
1017         vfd->minor   = -1;
1018         vfd->dev     = &pci->dev;
1019         vfd->release = video_device_release;
1020         snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1021                  core->name, type, cx88_boards[core->board].name);
1022         return vfd;
1023 }
1024
1025 static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1026 {
1027         if (request_mem_region(pci_resource_start(pci,0),
1028                                pci_resource_len(pci,0),
1029                                core->name))
1030                 return 0;
1031         printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
1032                core->name,pci_resource_start(pci,0));
1033         return -EBUSY;
1034 }
1035
1036 struct cx88_core* cx88_core_get(struct pci_dev *pci)
1037 {
1038         struct cx88_core *core;
1039         struct list_head *item;
1040         int i;
1041
1042         mutex_lock(&devlist);
1043         list_for_each(item,&cx88_devlist) {
1044                 core = list_entry(item, struct cx88_core, devlist);
1045                 if (pci->bus->number != core->pci_bus)
1046                         continue;
1047                 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1048                         continue;
1049
1050                 if (0 != get_ressources(core,pci))
1051                         goto fail_unlock;
1052                 atomic_inc(&core->refcount);
1053                 mutex_unlock(&devlist);
1054                 return core;
1055         }
1056         core = kzalloc(sizeof(*core),GFP_KERNEL);
1057         if (NULL == core)
1058                 goto fail_unlock;
1059
1060         atomic_inc(&core->refcount);
1061         core->pci_bus  = pci->bus->number;
1062         core->pci_slot = PCI_SLOT(pci->devfn);
1063         core->pci_irqmask = 0x00fc00;
1064         init_MUTEX(&core->lock);
1065
1066         core->nr = cx88_devcount++;
1067         sprintf(core->name,"cx88[%d]",core->nr);
1068         if (0 != get_ressources(core,pci)) {
1069                 printk(KERN_ERR "CORE %s No more PCI ressources for "
1070                         "subsystem: %04x:%04x, board: %s\n",
1071                         core->name,pci->subsystem_vendor,
1072                         pci->subsystem_device,
1073                         cx88_boards[core->board].name);
1074
1075                 cx88_devcount--;
1076                 goto fail_free;
1077         }
1078         list_add_tail(&core->devlist,&cx88_devlist);
1079
1080         /* PCI stuff */
1081         cx88_pci_quirks(core->name, pci);
1082         core->lmmio = ioremap(pci_resource_start(pci,0),
1083                               pci_resource_len(pci,0));
1084         core->bmmio = (u8 __iomem *)core->lmmio;
1085
1086         /* board config */
1087         core->board = UNSET;
1088         if (card[core->nr] < cx88_bcount)
1089                 core->board = card[core->nr];
1090         for (i = 0; UNSET == core->board  &&  i < cx88_idcount; i++)
1091                 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1092                     pci->subsystem_device == cx88_subids[i].subdevice)
1093                         core->board = cx88_subids[i].card;
1094         if (UNSET == core->board) {
1095                 core->board = CX88_BOARD_UNKNOWN;
1096                 cx88_card_list(core,pci);
1097         }
1098         printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1099                 core->name,pci->subsystem_vendor,
1100                 pci->subsystem_device,cx88_boards[core->board].name,
1101                 core->board, card[core->nr] == core->board ?
1102                 "insmod option" : "autodetected");
1103
1104         core->tuner_type = tuner[core->nr];
1105         core->radio_type = radio[core->nr];
1106         if (UNSET == core->tuner_type)
1107                 core->tuner_type = cx88_boards[core->board].tuner_type;
1108         if (UNSET == core->radio_type)
1109                 core->radio_type = cx88_boards[core->board].radio_type;
1110         if (!core->tuner_addr)
1111                 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1112         if (!core->radio_addr)
1113                 core->radio_addr = cx88_boards[core->board].radio_addr;
1114
1115         printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
1116                 core->tuner_type, core->tuner_addr<<1,
1117                 core->radio_type, core->radio_addr<<1);
1118
1119         core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1120
1121         /* init hardware */
1122         cx88_reset(core);
1123         cx88_i2c_init(core,pci);
1124         cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
1125         cx88_card_setup(core);
1126         cx88_ir_init(core,pci);
1127
1128         mutex_unlock(&devlist);
1129         return core;
1130
1131 fail_free:
1132         kfree(core);
1133 fail_unlock:
1134         mutex_unlock(&devlist);
1135         return NULL;
1136 }
1137
1138 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1139 {
1140         release_mem_region(pci_resource_start(pci,0),
1141                            pci_resource_len(pci,0));
1142
1143         if (!atomic_dec_and_test(&core->refcount))
1144                 return;
1145
1146         mutex_lock(&devlist);
1147         cx88_ir_fini(core);
1148         if (0 == core->i2c_rc)
1149                 i2c_bit_del_bus(&core->i2c_adap);
1150         list_del(&core->devlist);
1151         iounmap(core->lmmio);
1152         cx88_devcount--;
1153         mutex_unlock(&devlist);
1154         kfree(core);
1155 }
1156
1157 /* ------------------------------------------------------------------ */
1158
1159 EXPORT_SYMBOL(cx88_print_irqbits);
1160
1161 EXPORT_SYMBOL(cx88_core_irq);
1162 EXPORT_SYMBOL(cx88_wakeup);
1163 EXPORT_SYMBOL(cx88_reset);
1164 EXPORT_SYMBOL(cx88_shutdown);
1165
1166 EXPORT_SYMBOL(cx88_risc_buffer);
1167 EXPORT_SYMBOL(cx88_risc_databuffer);
1168 EXPORT_SYMBOL(cx88_risc_stopper);
1169 EXPORT_SYMBOL(cx88_free_buffer);
1170
1171 EXPORT_SYMBOL(cx88_sram_channels);
1172 EXPORT_SYMBOL(cx88_sram_channel_setup);
1173 EXPORT_SYMBOL(cx88_sram_channel_dump);
1174
1175 EXPORT_SYMBOL(cx88_set_tvnorm);
1176 EXPORT_SYMBOL(cx88_set_scale);
1177
1178 EXPORT_SYMBOL(cx88_vdev_init);
1179 EXPORT_SYMBOL(cx88_core_get);
1180 EXPORT_SYMBOL(cx88_core_put);
1181 EXPORT_SYMBOL(cx88_start_audio_dma);
1182 EXPORT_SYMBOL(cx88_stop_audio_dma);
1183
1184 /*
1185  * Local variables:
1186  * c-basic-offset: 8
1187  * End:
1188  * 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
1189  */