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