Linux v2.6.15-rc7
[pohmelfs.git] / drivers / media / video / cx88 / cx88-core.c
blobbb6eb54e19ceddcb4726ee9dfc5117baa8c73ef1
1 /*
3 * device driver for Conexant 2388x based TV cards
4 * driver core
6 * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
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.
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.
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.
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>
36 #include "cx88.h"
38 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
39 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
40 MODULE_LICENSE("GPL");
42 /* ------------------------------------------------------------------ */
44 static unsigned int core_debug = 0;
45 module_param(core_debug,int,0644);
46 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
48 static unsigned int latency = UNSET;
49 module_param(latency,int,0444);
50 MODULE_PARM_DESC(latency,"pci latency timer");
52 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
53 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
54 static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
56 module_param_array(tuner, int, NULL, 0444);
57 module_param_array(radio, int, NULL, 0444);
58 module_param_array(card, int, NULL, 0444);
60 MODULE_PARM_DESC(tuner,"tuner type");
61 MODULE_PARM_DESC(radio,"radio tuner type");
62 MODULE_PARM_DESC(card,"card type");
64 static unsigned int nicam = 0;
65 module_param(nicam,int,0644);
66 MODULE_PARM_DESC(nicam,"tv audio is nicam");
68 static unsigned int nocomb = 0;
69 module_param(nocomb,int,0644);
70 MODULE_PARM_DESC(nocomb,"disable comb filter");
72 #define dprintk(level,fmt, arg...) if (core_debug >= level) \
73 printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
75 static unsigned int cx88_devcount;
76 static LIST_HEAD(cx88_devlist);
77 static DECLARE_MUTEX(devlist);
79 /* ------------------------------------------------------------------ */
80 /* debug help functions */
82 static const char *v4l1_ioctls[] = {
83 "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
84 "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
85 "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
86 "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
87 "SMICROCODE", "GVBIFMT", "SVBIFMT" };
88 #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
90 static const char *v4l2_ioctls[] = {
91 "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
92 "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
93 "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
94 "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
95 "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
96 "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
97 "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
98 "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
99 "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
100 "S_MODULATOR"
102 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
104 void cx88_print_ioctl(char *name, unsigned int cmd)
106 char *dir;
108 switch (_IOC_DIR(cmd)) {
109 case _IOC_NONE: dir = "--"; break;
110 case _IOC_READ: dir = "r-"; break;
111 case _IOC_WRITE: dir = "-w"; break;
112 case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
113 default: dir = "??"; break;
115 switch (_IOC_TYPE(cmd)) {
116 case 'v':
117 printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
118 name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
119 v4l1_ioctls[_IOC_NR(cmd)] : "???");
120 break;
121 case 'V':
122 printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
123 name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
124 v4l2_ioctls[_IOC_NR(cmd)] : "???");
125 break;
126 default:
127 printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
128 name, cmd, dir, _IOC_NR(cmd));
132 /* ------------------------------------------------------------------ */
133 #define NO_SYNC_LINE (-1U)
135 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
136 unsigned int offset, u32 sync_line,
137 unsigned int bpl, unsigned int padding,
138 unsigned int lines)
140 struct scatterlist *sg;
141 unsigned int line,todo;
143 /* sync instruction */
144 if (sync_line != NO_SYNC_LINE)
145 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
147 /* scan lines */
148 sg = sglist;
149 for (line = 0; line < lines; line++) {
150 while (offset && offset >= sg_dma_len(sg)) {
151 offset -= sg_dma_len(sg);
152 sg++;
154 if (bpl <= sg_dma_len(sg)-offset) {
155 /* fits into current chunk */
156 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
157 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
158 offset+=bpl;
159 } else {
160 /* scanline needs to be splitted */
161 todo = bpl;
162 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
163 (sg_dma_len(sg)-offset));
164 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
165 todo -= (sg_dma_len(sg)-offset);
166 offset = 0;
167 sg++;
168 while (todo > sg_dma_len(sg)) {
169 *(rp++)=cpu_to_le32(RISC_WRITE|
170 sg_dma_len(sg));
171 *(rp++)=cpu_to_le32(sg_dma_address(sg));
172 todo -= sg_dma_len(sg);
173 sg++;
175 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
176 *(rp++)=cpu_to_le32(sg_dma_address(sg));
177 offset += todo;
179 offset += padding;
182 return rp;
185 int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
186 struct scatterlist *sglist,
187 unsigned int top_offset, unsigned int bottom_offset,
188 unsigned int bpl, unsigned int padding, unsigned int lines)
190 u32 instructions,fields;
191 u32 *rp;
192 int rc;
194 fields = 0;
195 if (UNSET != top_offset)
196 fields++;
197 if (UNSET != bottom_offset)
198 fields++;
200 /* estimate risc mem: worst case is one write per page border +
201 one write per scan line + syncs + jump (all 2 dwords) */
202 instructions = (bpl * lines * fields) / PAGE_SIZE + lines * fields;
203 instructions += 3 + 4;
204 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
205 return rc;
207 /* write risc instructions */
208 rp = risc->cpu;
209 if (UNSET != top_offset)
210 rp = cx88_risc_field(rp, sglist, top_offset, 0,
211 bpl, padding, lines);
212 if (UNSET != bottom_offset)
213 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
214 bpl, padding, lines);
216 /* save pointer to jmp instruction address */
217 risc->jmp = rp;
218 BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
219 return 0;
222 int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
223 struct scatterlist *sglist, unsigned int bpl,
224 unsigned int lines)
226 u32 instructions;
227 u32 *rp;
228 int rc;
230 /* estimate risc mem: worst case is one write per page border +
231 one write per scan line + syncs + jump (all 2 dwords) */
232 instructions = (bpl * lines) / PAGE_SIZE + lines;
233 instructions += 3 + 4;
234 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
235 return rc;
237 /* write risc instructions */
238 rp = risc->cpu;
239 rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
241 /* save pointer to jmp instruction address */
242 risc->jmp = rp;
243 BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
244 return 0;
247 int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
248 u32 reg, u32 mask, u32 value)
250 u32 *rp;
251 int rc;
253 if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
254 return rc;
256 /* write risc instructions */
257 rp = risc->cpu;
258 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
259 *(rp++) = cpu_to_le32(reg);
260 *(rp++) = cpu_to_le32(value);
261 *(rp++) = cpu_to_le32(mask);
262 *(rp++) = cpu_to_le32(RISC_JUMP);
263 *(rp++) = cpu_to_le32(risc->dma);
264 return 0;
267 void
268 cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
270 if (in_interrupt())
271 BUG();
272 videobuf_waiton(&buf->vb,0,0);
273 videobuf_dma_pci_unmap(pci, &buf->vb.dma);
274 videobuf_dma_free(&buf->vb.dma);
275 btcx_riscmem_free(pci, &buf->risc);
276 buf->vb.state = STATE_NEEDS_INIT;
279 /* ------------------------------------------------------------------ */
280 /* our SRAM memory layout */
282 /* we are going to put all thr risc programs into host memory, so we
283 * can use the whole SDRAM for the DMA fifos. To simplify things, we
284 * use a static memory layout. That surely will waste memory in case
285 * we don't use all DMA channels at the same time (which will be the
286 * case most of the time). But that still gives us enougth FIFO space
287 * to be able to deal with insane long pci latencies ...
289 * FIFO space allocations:
290 * channel 21 (y video) - 10.0k
291 * channel 22 (u video) - 2.0k
292 * channel 23 (v video) - 2.0k
293 * channel 24 (vbi) - 4.0k
294 * channels 25+26 (audio) - 0.5k
295 * channel 28 (mpeg) - 4.0k
296 * TOTAL = 25.5k
298 * Every channel has 160 bytes control data (64 bytes instruction
299 * queue and 6 CDT entries), which is close to 2k total.
301 * Address layout:
302 * 0x0000 - 0x03ff CMDs / reserved
303 * 0x0400 - 0x0bff instruction queues + CDs
304 * 0x0c00 - FIFOs
307 struct sram_channel cx88_sram_channels[] = {
308 [SRAM_CH21] = {
309 .name = "video y / packed",
310 .cmds_start = 0x180040,
311 .ctrl_start = 0x180400,
312 .cdt = 0x180400 + 64,
313 .fifo_start = 0x180c00,
314 .fifo_size = 0x002800,
315 .ptr1_reg = MO_DMA21_PTR1,
316 .ptr2_reg = MO_DMA21_PTR2,
317 .cnt1_reg = MO_DMA21_CNT1,
318 .cnt2_reg = MO_DMA21_CNT2,
320 [SRAM_CH22] = {
321 .name = "video u",
322 .cmds_start = 0x180080,
323 .ctrl_start = 0x1804a0,
324 .cdt = 0x1804a0 + 64,
325 .fifo_start = 0x183400,
326 .fifo_size = 0x000800,
327 .ptr1_reg = MO_DMA22_PTR1,
328 .ptr2_reg = MO_DMA22_PTR2,
329 .cnt1_reg = MO_DMA22_CNT1,
330 .cnt2_reg = MO_DMA22_CNT2,
332 [SRAM_CH23] = {
333 .name = "video v",
334 .cmds_start = 0x1800c0,
335 .ctrl_start = 0x180540,
336 .cdt = 0x180540 + 64,
337 .fifo_start = 0x183c00,
338 .fifo_size = 0x000800,
339 .ptr1_reg = MO_DMA23_PTR1,
340 .ptr2_reg = MO_DMA23_PTR2,
341 .cnt1_reg = MO_DMA23_CNT1,
342 .cnt2_reg = MO_DMA23_CNT2,
344 [SRAM_CH24] = {
345 .name = "vbi",
346 .cmds_start = 0x180100,
347 .ctrl_start = 0x1805e0,
348 .cdt = 0x1805e0 + 64,
349 .fifo_start = 0x184400,
350 .fifo_size = 0x001000,
351 .ptr1_reg = MO_DMA24_PTR1,
352 .ptr2_reg = MO_DMA24_PTR2,
353 .cnt1_reg = MO_DMA24_CNT1,
354 .cnt2_reg = MO_DMA24_CNT2,
356 [SRAM_CH25] = {
357 .name = "audio from",
358 .cmds_start = 0x180140,
359 .ctrl_start = 0x180680,
360 .cdt = 0x180680 + 64,
361 .fifo_start = 0x185400,
362 .fifo_size = 0x000200,
363 .ptr1_reg = MO_DMA25_PTR1,
364 .ptr2_reg = MO_DMA25_PTR2,
365 .cnt1_reg = MO_DMA25_CNT1,
366 .cnt2_reg = MO_DMA25_CNT2,
368 [SRAM_CH26] = {
369 .name = "audio to",
370 .cmds_start = 0x180180,
371 .ctrl_start = 0x180720,
372 .cdt = 0x180680 + 64, /* same as audio IN */
373 .fifo_start = 0x185400, /* same as audio IN */
374 .fifo_size = 0x000200, /* same as audio IN */
375 .ptr1_reg = MO_DMA26_PTR1,
376 .ptr2_reg = MO_DMA26_PTR2,
377 .cnt1_reg = MO_DMA26_CNT1,
378 .cnt2_reg = MO_DMA26_CNT2,
380 [SRAM_CH28] = {
381 .name = "mpeg",
382 .cmds_start = 0x180200,
383 .ctrl_start = 0x1807C0,
384 .cdt = 0x1807C0 + 64,
385 .fifo_start = 0x185600,
386 .fifo_size = 0x001000,
387 .ptr1_reg = MO_DMA28_PTR1,
388 .ptr2_reg = MO_DMA28_PTR2,
389 .cnt1_reg = MO_DMA28_CNT1,
390 .cnt2_reg = MO_DMA28_CNT2,
394 int cx88_sram_channel_setup(struct cx88_core *core,
395 struct sram_channel *ch,
396 unsigned int bpl, u32 risc)
398 unsigned int i,lines;
399 u32 cdt;
401 bpl = (bpl + 7) & ~7; /* alignment */
402 cdt = ch->cdt;
403 lines = ch->fifo_size / bpl;
404 if (lines > 6)
405 lines = 6;
406 BUG_ON(lines < 2);
408 /* write CDT */
409 for (i = 0; i < lines; i++)
410 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
412 /* write CMDS */
413 cx_write(ch->cmds_start + 0, risc);
414 cx_write(ch->cmds_start + 4, cdt);
415 cx_write(ch->cmds_start + 8, (lines*16) >> 3);
416 cx_write(ch->cmds_start + 12, ch->ctrl_start);
417 cx_write(ch->cmds_start + 16, 64 >> 2);
418 for (i = 20; i < 64; i += 4)
419 cx_write(ch->cmds_start + i, 0);
421 /* fill registers */
422 cx_write(ch->ptr1_reg, ch->fifo_start);
423 cx_write(ch->ptr2_reg, cdt);
424 cx_write(ch->cnt1_reg, (bpl >> 3) -1);
425 cx_write(ch->cnt2_reg, (lines*16) >> 3);
427 dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
428 return 0;
431 /* ------------------------------------------------------------------ */
432 /* debug helper code */
434 static int cx88_risc_decode(u32 risc)
436 static char *instr[16] = {
437 [ RISC_SYNC >> 28 ] = "sync",
438 [ RISC_WRITE >> 28 ] = "write",
439 [ RISC_WRITEC >> 28 ] = "writec",
440 [ RISC_READ >> 28 ] = "read",
441 [ RISC_READC >> 28 ] = "readc",
442 [ RISC_JUMP >> 28 ] = "jump",
443 [ RISC_SKIP >> 28 ] = "skip",
444 [ RISC_WRITERM >> 28 ] = "writerm",
445 [ RISC_WRITECM >> 28 ] = "writecm",
446 [ RISC_WRITECR >> 28 ] = "writecr",
448 static int incr[16] = {
449 [ RISC_WRITE >> 28 ] = 2,
450 [ RISC_JUMP >> 28 ] = 2,
451 [ RISC_WRITERM >> 28 ] = 3,
452 [ RISC_WRITECM >> 28 ] = 3,
453 [ RISC_WRITECR >> 28 ] = 4,
455 static char *bits[] = {
456 "12", "13", "14", "resync",
457 "cnt0", "cnt1", "18", "19",
458 "20", "21", "22", "23",
459 "irq1", "irq2", "eol", "sol",
461 int i;
463 printk("0x%08x [ %s", risc,
464 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
465 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
466 if (risc & (1 << (i + 12)))
467 printk(" %s",bits[i]);
468 printk(" count=%d ]\n", risc & 0xfff);
469 return incr[risc >> 28] ? incr[risc >> 28] : 1;
473 void cx88_sram_channel_dump(struct cx88_core *core,
474 struct sram_channel *ch)
476 static char *name[] = {
477 "initial risc",
478 "cdt base",
479 "cdt size",
480 "iq base",
481 "iq size",
482 "risc pc",
483 "iq wr ptr",
484 "iq rd ptr",
485 "cdt current",
486 "pci target",
487 "line / byte",
489 u32 risc;
490 unsigned int i,j,n;
492 printk("%s: %s - dma channel status dump\n",
493 core->name,ch->name);
494 for (i = 0; i < ARRAY_SIZE(name); i++)
495 printk("%s: cmds: %-12s: 0x%08x\n",
496 core->name,name[i],
497 cx_read(ch->cmds_start + 4*i));
498 for (i = 0; i < 4; i++) {
499 risc = cx_read(ch->cmds_start + 4 * (i+11));
500 printk("%s: risc%d: ", core->name, i);
501 cx88_risc_decode(risc);
503 for (i = 0; i < 16; i += n) {
504 risc = cx_read(ch->ctrl_start + 4 * i);
505 printk("%s: iq %x: ", core->name, i);
506 n = cx88_risc_decode(risc);
507 for (j = 1; j < n; j++) {
508 risc = cx_read(ch->ctrl_start + 4 * (i+j));
509 printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
510 core->name, i+j, risc, j);
514 printk("%s: fifo: 0x%08x -> 0x%x\n",
515 core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
516 printk("%s: ctrl: 0x%08x -> 0x%x\n",
517 core->name, ch->ctrl_start, ch->ctrl_start+6*16);
518 printk("%s: ptr1_reg: 0x%08x\n",
519 core->name,cx_read(ch->ptr1_reg));
520 printk("%s: ptr2_reg: 0x%08x\n",
521 core->name,cx_read(ch->ptr2_reg));
522 printk("%s: cnt1_reg: 0x%08x\n",
523 core->name,cx_read(ch->cnt1_reg));
524 printk("%s: cnt2_reg: 0x%08x\n",
525 core->name,cx_read(ch->cnt2_reg));
528 static char *cx88_pci_irqs[32] = {
529 "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
530 "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
531 "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
532 "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
535 void cx88_print_irqbits(char *name, char *tag, char **strings,
536 u32 bits, u32 mask)
538 unsigned int i;
540 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
541 for (i = 0; i < 32; i++) {
542 if (!(bits & (1 << i)))
543 continue;
544 if (strings[i])
545 printk(" %s", strings[i]);
546 else
547 printk(" %d", i);
548 if (!(mask & (1 << i)))
549 continue;
550 printk("*");
552 printk("\n");
555 /* ------------------------------------------------------------------ */
557 int cx88_core_irq(struct cx88_core *core, u32 status)
559 int handled = 0;
561 if (status & (1<<18)) {
562 cx88_ir_irq(core);
563 handled++;
565 if (!handled)
566 cx88_print_irqbits(core->name, "irq pci",
567 cx88_pci_irqs, status,
568 core->pci_irqmask);
569 return handled;
572 void cx88_wakeup(struct cx88_core *core,
573 struct cx88_dmaqueue *q, u32 count)
575 struct cx88_buffer *buf;
576 int bc;
578 for (bc = 0;; bc++) {
579 if (list_empty(&q->active))
580 break;
581 buf = list_entry(q->active.next,
582 struct cx88_buffer, vb.queue);
583 /* count comes from the hw and is is 16bit wide --
584 * this trick handles wrap-arounds correctly for
585 * up to 32767 buffers in flight... */
586 if ((s16) (count - buf->count) < 0)
587 break;
588 do_gettimeofday(&buf->vb.ts);
589 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
590 count, buf->count);
591 buf->vb.state = STATE_DONE;
592 list_del(&buf->vb.queue);
593 wake_up(&buf->vb.done);
595 if (list_empty(&q->active)) {
596 del_timer(&q->timeout);
597 } else {
598 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
600 if (bc != 1)
601 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
604 void cx88_shutdown(struct cx88_core *core)
606 /* disable RISC controller + IRQs */
607 cx_write(MO_DEV_CNTRL2, 0);
609 /* stop dma transfers */
610 cx_write(MO_VID_DMACNTRL, 0x0);
611 cx_write(MO_AUD_DMACNTRL, 0x0);
612 cx_write(MO_TS_DMACNTRL, 0x0);
613 cx_write(MO_VIP_DMACNTRL, 0x0);
614 cx_write(MO_GPHST_DMACNTRL, 0x0);
616 /* stop interrupts */
617 cx_write(MO_PCI_INTMSK, 0x0);
618 cx_write(MO_VID_INTMSK, 0x0);
619 cx_write(MO_AUD_INTMSK, 0x0);
620 cx_write(MO_TS_INTMSK, 0x0);
621 cx_write(MO_VIP_INTMSK, 0x0);
622 cx_write(MO_GPHST_INTMSK, 0x0);
624 /* stop capturing */
625 cx_write(VID_CAPTURE_CONTROL, 0);
628 int cx88_reset(struct cx88_core *core)
630 dprintk(1,"%s\n",__FUNCTION__);
631 cx88_shutdown(core);
633 /* clear irq status */
634 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
635 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
636 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
638 /* wait a bit */
639 msleep(100);
641 /* init sram */
642 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
643 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
644 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
645 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
646 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
647 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
648 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
650 /* misc init ... */
651 cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
652 (1 << 12) | // agc gain
653 (1 << 11) | // adaptibe agc
654 (0 << 10) | // chroma agc
655 (0 << 9) | // ckillen
656 (7)));
658 /* setup image format */
659 cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
661 /* setup FIFO Threshholds */
662 cx_write(MO_PDMA_STHRSH, 0x0807);
663 cx_write(MO_PDMA_DTHRSH, 0x0807);
665 /* fixes flashing of image */
666 cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
667 cx_write(MO_AGC_BACK_VBI, 0x00E00555);
669 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
670 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
671 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
673 /* Reset on-board parts */
674 cx_write(MO_SRST_IO, 0);
675 msleep(10);
676 cx_write(MO_SRST_IO, 1);
678 return 0;
681 /* ------------------------------------------------------------------ */
683 static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
685 return (norm->id & V4L2_STD_625_50) ? 922 : 754;
688 static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
690 return (norm->id & V4L2_STD_625_50) ? 186 : 135;
693 static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
695 return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
698 static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
700 static const unsigned int ntsc = 28636360;
701 static const unsigned int pal = 35468950;
702 static const unsigned int palm = 28604892;
704 if (norm->id & V4L2_STD_PAL_M)
705 return palm;
707 return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
710 static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
712 return (norm->id & V4L2_STD_625_50)
713 ? HLNotchFilter135PAL
714 : HLNotchFilter135NTSC;
717 static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
719 /* Should always be Line Draw Time / (4*FSC) */
721 if (norm->id & V4L2_STD_PAL_M)
722 return 909;
724 return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
727 static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
729 return (norm->id & V4L2_STD_625_50) ? 511 : 288;
732 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
733 enum v4l2_field field)
735 unsigned int swidth = norm_swidth(core->tvnorm);
736 unsigned int sheight = norm_maxh(core->tvnorm);
737 u32 value;
739 dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
740 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
741 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
742 core->tvnorm->name);
743 if (!V4L2_FIELD_HAS_BOTH(field))
744 height *= 2;
746 // recalc H delay and scale registers
747 value = (width * norm_hdelay(core->tvnorm)) / swidth;
748 value &= 0x3fe;
749 cx_write(MO_HDELAY_EVEN, value);
750 cx_write(MO_HDELAY_ODD, value);
751 dprintk(1,"set_scale: hdelay 0x%04x\n", value);
753 value = (swidth * 4096 / width) - 4096;
754 cx_write(MO_HSCALE_EVEN, value);
755 cx_write(MO_HSCALE_ODD, value);
756 dprintk(1,"set_scale: hscale 0x%04x\n", value);
758 cx_write(MO_HACTIVE_EVEN, width);
759 cx_write(MO_HACTIVE_ODD, width);
760 dprintk(1,"set_scale: hactive 0x%04x\n", width);
762 // recalc V scale Register (delay is constant)
763 cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
764 cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
765 dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
767 value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
768 cx_write(MO_VSCALE_EVEN, value);
769 cx_write(MO_VSCALE_ODD, value);
770 dprintk(1,"set_scale: vscale 0x%04x\n", value);
772 cx_write(MO_VACTIVE_EVEN, sheight);
773 cx_write(MO_VACTIVE_ODD, sheight);
774 dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
776 // setup filters
777 value = 0;
778 value |= (1 << 19); // CFILT (default)
779 if (core->tvnorm->id & V4L2_STD_SECAM) {
780 value |= (1 << 15);
781 value |= (1 << 16);
783 if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
784 value |= (1 << 13) | (1 << 5);
785 if (V4L2_FIELD_INTERLACED == field)
786 value |= (1 << 3); // VINT (interlaced vertical scaling)
787 if (width < 385)
788 value |= (1 << 0); // 3-tap interpolation
789 if (width < 193)
790 value |= (1 << 1); // 5-tap interpolation
791 if (nocomb)
792 value |= (3 << 5); // disable comb filter
794 cx_write(MO_FILTER_EVEN, value);
795 cx_write(MO_FILTER_ODD, value);
796 dprintk(1,"set_scale: filter 0x%04x\n", value);
798 return 0;
801 static const u32 xtal = 28636363;
803 static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
805 static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
806 u64 pll;
807 u32 reg;
808 int i;
810 if (prescale < 2)
811 prescale = 2;
812 if (prescale > 5)
813 prescale = 5;
815 pll = ofreq * 8 * prescale * (u64)(1 << 20);
816 do_div(pll,xtal);
817 reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
818 if (((reg >> 20) & 0x3f) < 14) {
819 printk("%s/0: pll out of range\n",core->name);
820 return -1;
823 dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
824 reg, cx_read(MO_PLL_REG), ofreq);
825 cx_write(MO_PLL_REG, reg);
826 for (i = 0; i < 100; i++) {
827 reg = cx_read(MO_DEVICE_STATUS);
828 if (reg & (1<<2)) {
829 dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
830 prescale,ofreq);
831 return 0;
833 dprintk(1,"pll not locked yet, waiting ...\n");
834 msleep(10);
836 dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
837 return -1;
840 int cx88_start_audio_dma(struct cx88_core *core)
842 /* setup fifo + format */
843 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
844 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
846 cx_write(MO_AUDD_LNGTH, 128); /* fifo bpl size */
847 cx_write(MO_AUDR_LNGTH, 128); /* fifo bpl size */
849 /* start dma */
850 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
852 return 0;
855 int cx88_stop_audio_dma(struct cx88_core *core)
857 /* stop dma */
858 cx_write(MO_AUD_DMACNTRL, 0x0000);
860 return 0;
863 static int set_tvaudio(struct cx88_core *core)
865 struct cx88_tvnorm *norm = core->tvnorm;
867 if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
868 return 0;
870 if (V4L2_STD_PAL_BG & norm->id) {
871 core->tvaudio = WW_BG;
873 } else if (V4L2_STD_PAL_DK & norm->id) {
874 core->tvaudio = WW_DK;
876 } else if (V4L2_STD_PAL_I & norm->id) {
877 core->tvaudio = WW_I;
879 } else if (V4L2_STD_SECAM_L & norm->id) {
880 core->tvaudio = WW_L;
882 } else if (V4L2_STD_SECAM_DK & norm->id) {
883 core->tvaudio = WW_DK;
885 } else if ((V4L2_STD_NTSC_M & norm->id) ||
886 (V4L2_STD_PAL_M & norm->id)) {
887 core->tvaudio = WW_BTSC;
889 } else if (V4L2_STD_NTSC_M_JP & norm->id) {
890 core->tvaudio = WW_EIAJ;
892 } else {
893 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
894 core->name, norm->name);
895 core->tvaudio = 0;
896 return 0;
899 cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
900 cx88_set_tvaudio(core);
901 /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
904 This should be needed only on cx88-alsa. It seems that some cx88 chips have
905 bugs and does require DMA enabled for it to work.
907 cx88_start_audio_dma(core);
908 return 0;
913 int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
915 u32 fsc8;
916 u32 adc_clock;
917 u32 vdec_clock;
918 u32 step_db,step_dr;
919 u64 tmp64;
920 u32 bdelay,agcdelay,htotal;
922 core->tvnorm = norm;
923 fsc8 = norm_fsc8(norm);
924 adc_clock = xtal;
925 vdec_clock = fsc8;
926 step_db = fsc8;
927 step_dr = fsc8;
929 if (norm->id & V4L2_STD_SECAM) {
930 step_db = 4250000 * 8;
931 step_dr = 4406250 * 8;
934 dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
935 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
936 set_pll(core,2,vdec_clock);
938 dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
939 norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
940 cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
942 // FIXME: as-is from DScaler
943 dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
944 norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
945 cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
947 // MO_SCONV_REG = adc clock / video dec clock * 2^17
948 tmp64 = adc_clock * (u64)(1 << 17);
949 do_div(tmp64, vdec_clock);
950 dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
951 (u32)tmp64, cx_read(MO_SCONV_REG));
952 cx_write(MO_SCONV_REG, (u32)tmp64);
954 // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
955 tmp64 = step_db * (u64)(1 << 22);
956 do_div(tmp64, vdec_clock);
957 dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
958 (u32)tmp64, cx_read(MO_SUB_STEP));
959 cx_write(MO_SUB_STEP, (u32)tmp64);
961 // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
962 tmp64 = step_dr * (u64)(1 << 22);
963 do_div(tmp64, vdec_clock);
964 dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
965 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
966 cx_write(MO_SUB_STEP_DR, (u32)tmp64);
968 // bdelay + agcdelay
969 bdelay = vdec_clock * 65 / 20000000 + 21;
970 agcdelay = vdec_clock * 68 / 20000000 + 15;
971 dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
972 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
973 cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
975 // htotal
976 tmp64 = norm_htotal(norm) * (u64)vdec_clock;
977 do_div(tmp64, fsc8);
978 htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
979 dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
980 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
981 cx_write(MO_HTOTAL, htotal);
983 // vbi stuff
984 cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
985 norm_vbipack(norm)));
987 // this is needed as well to set all tvnorm parameter
988 cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
990 // audio
991 set_tvaudio(core);
993 // tell i2c chips
994 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
996 // done
997 return 0;
1000 /* ------------------------------------------------------------------ */
1002 static int cx88_pci_quirks(char *name, struct pci_dev *pci)
1004 unsigned int lat = UNSET;
1005 u8 ctrl = 0;
1006 u8 value;
1008 /* check pci quirks */
1009 if (pci_pci_problems & PCIPCI_TRITON) {
1010 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
1011 name);
1012 ctrl |= CX88X_EN_TBFX;
1014 if (pci_pci_problems & PCIPCI_NATOMA) {
1015 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
1016 name);
1017 ctrl |= CX88X_EN_TBFX;
1019 if (pci_pci_problems & PCIPCI_VIAETBF) {
1020 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
1021 name);
1022 ctrl |= CX88X_EN_TBFX;
1024 if (pci_pci_problems & PCIPCI_VSFX) {
1025 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
1026 name);
1027 ctrl |= CX88X_EN_VSFX;
1029 #ifdef PCIPCI_ALIMAGIK
1030 if (pci_pci_problems & PCIPCI_ALIMAGIK) {
1031 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
1032 name);
1033 lat = 0x0A;
1035 #endif
1037 /* check insmod options */
1038 if (UNSET != latency)
1039 lat = latency;
1041 /* apply stuff */
1042 if (ctrl) {
1043 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
1044 value |= ctrl;
1045 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
1047 if (UNSET != lat) {
1048 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
1049 name, latency);
1050 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1052 return 0;
1055 /* ------------------------------------------------------------------ */
1057 struct video_device *cx88_vdev_init(struct cx88_core *core,
1058 struct pci_dev *pci,
1059 struct video_device *template,
1060 char *type)
1062 struct video_device *vfd;
1064 vfd = video_device_alloc();
1065 if (NULL == vfd)
1066 return NULL;
1067 *vfd = *template;
1068 vfd->minor = -1;
1069 vfd->dev = &pci->dev;
1070 vfd->release = video_device_release;
1071 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1072 core->name, type, cx88_boards[core->board].name);
1073 return vfd;
1076 static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1078 if (request_mem_region(pci_resource_start(pci,0),
1079 pci_resource_len(pci,0),
1080 core->name))
1081 return 0;
1082 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
1083 core->name,pci_resource_start(pci,0));
1084 return -EBUSY;
1087 struct cx88_core* cx88_core_get(struct pci_dev *pci)
1089 struct cx88_core *core;
1090 struct list_head *item;
1091 int i;
1093 down(&devlist);
1094 list_for_each(item,&cx88_devlist) {
1095 core = list_entry(item, struct cx88_core, devlist);
1096 if (pci->bus->number != core->pci_bus)
1097 continue;
1098 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1099 continue;
1101 if (0 != get_ressources(core,pci))
1102 goto fail_unlock;
1103 atomic_inc(&core->refcount);
1104 up(&devlist);
1105 return core;
1107 core = kmalloc(sizeof(*core),GFP_KERNEL);
1108 if (NULL == core)
1109 goto fail_unlock;
1111 memset(core,0,sizeof(*core));
1112 atomic_inc(&core->refcount);
1113 core->pci_bus = pci->bus->number;
1114 core->pci_slot = PCI_SLOT(pci->devfn);
1115 core->pci_irqmask = 0x00fc00;
1116 init_MUTEX(&core->lock);
1118 core->nr = cx88_devcount++;
1119 sprintf(core->name,"cx88[%d]",core->nr);
1120 if (0 != get_ressources(core,pci)) {
1121 printk(KERN_ERR "CORE %s No more PCI ressources for "
1122 "subsystem: %04x:%04x, board: %s\n",
1123 core->name,pci->subsystem_vendor,
1124 pci->subsystem_device,
1125 cx88_boards[core->board].name);
1127 cx88_devcount--;
1128 goto fail_free;
1130 list_add_tail(&core->devlist,&cx88_devlist);
1132 /* PCI stuff */
1133 cx88_pci_quirks(core->name, pci);
1134 core->lmmio = ioremap(pci_resource_start(pci,0),
1135 pci_resource_len(pci,0));
1136 core->bmmio = (u8 __iomem *)core->lmmio;
1138 /* board config */
1139 core->board = UNSET;
1140 if (card[core->nr] < cx88_bcount)
1141 core->board = card[core->nr];
1142 for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
1143 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1144 pci->subsystem_device == cx88_subids[i].subdevice)
1145 core->board = cx88_subids[i].card;
1146 if (UNSET == core->board) {
1147 core->board = CX88_BOARD_UNKNOWN;
1148 cx88_card_list(core,pci);
1150 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1151 core->name,pci->subsystem_vendor,
1152 pci->subsystem_device,cx88_boards[core->board].name,
1153 core->board, card[core->nr] == core->board ?
1154 "insmod option" : "autodetected");
1156 core->tuner_type = tuner[core->nr];
1157 core->radio_type = radio[core->nr];
1158 if (UNSET == core->tuner_type)
1159 core->tuner_type = cx88_boards[core->board].tuner_type;
1160 if (UNSET == core->radio_type)
1161 core->radio_type = cx88_boards[core->board].radio_type;
1162 if (!core->tuner_addr)
1163 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1164 if (!core->radio_addr)
1165 core->radio_addr = cx88_boards[core->board].radio_addr;
1167 printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
1168 core->tuner_type, core->tuner_addr<<1,
1169 core->radio_type, core->radio_addr<<1);
1171 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1173 /* init hardware */
1174 cx88_reset(core);
1175 cx88_i2c_init(core,pci);
1176 cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
1177 cx88_card_setup(core);
1178 cx88_ir_init(core,pci);
1180 up(&devlist);
1181 return core;
1183 fail_free:
1184 kfree(core);
1185 fail_unlock:
1186 up(&devlist);
1187 return NULL;
1190 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1192 release_mem_region(pci_resource_start(pci,0),
1193 pci_resource_len(pci,0));
1195 if (!atomic_dec_and_test(&core->refcount))
1196 return;
1198 down(&devlist);
1199 cx88_ir_fini(core);
1200 if (0 == core->i2c_rc)
1201 i2c_bit_del_bus(&core->i2c_adap);
1202 list_del(&core->devlist);
1203 iounmap(core->lmmio);
1204 cx88_devcount--;
1205 up(&devlist);
1206 kfree(core);
1209 /* ------------------------------------------------------------------ */
1211 EXPORT_SYMBOL(cx88_print_ioctl);
1212 EXPORT_SYMBOL(cx88_print_irqbits);
1214 EXPORT_SYMBOL(cx88_core_irq);
1215 EXPORT_SYMBOL(cx88_wakeup);
1216 EXPORT_SYMBOL(cx88_reset);
1217 EXPORT_SYMBOL(cx88_shutdown);
1219 EXPORT_SYMBOL(cx88_risc_buffer);
1220 EXPORT_SYMBOL(cx88_risc_databuffer);
1221 EXPORT_SYMBOL(cx88_risc_stopper);
1222 EXPORT_SYMBOL(cx88_free_buffer);
1224 EXPORT_SYMBOL(cx88_sram_channels);
1225 EXPORT_SYMBOL(cx88_sram_channel_setup);
1226 EXPORT_SYMBOL(cx88_sram_channel_dump);
1228 EXPORT_SYMBOL(cx88_set_tvnorm);
1229 EXPORT_SYMBOL(cx88_set_scale);
1231 EXPORT_SYMBOL(cx88_vdev_init);
1232 EXPORT_SYMBOL(cx88_core_get);
1233 EXPORT_SYMBOL(cx88_core_put);
1234 EXPORT_SYMBOL(cx88_start_audio_dma);
1235 EXPORT_SYMBOL(cx88_stop_audio_dma);
1238 * Local variables:
1239 * c-basic-offset: 8
1240 * End:
1241 * 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