Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / media / video / cx88 / cx88-core.c
blob26a6138015cb7baedac59458a62cd7e35688b613
1 /*
2 * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $
4 * device driver for Conexant 2388x based TV cards
5 * driver core
7 * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <linux/init.h>
25 #include <linux/list.h>
26 #include <linux/module.h>
27 #include <linux/moduleparam.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
30 #include <linux/kmod.h>
31 #include <linux/sound.h>
32 #include <linux/interrupt.h>
33 #include <linux/pci.h>
34 #include <linux/delay.h>
35 #include <linux/videodev.h>
37 #include "cx88.h"
39 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
40 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
41 MODULE_LICENSE("GPL");
43 /* ------------------------------------------------------------------ */
45 static unsigned int core_debug = 0;
46 module_param(core_debug,int,0644);
47 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
49 static unsigned int latency = UNSET;
50 module_param(latency,int,0444);
51 MODULE_PARM_DESC(latency,"pci latency timer");
53 static unsigned int tuner[] = {[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(card, int, NULL, 0444);
59 MODULE_PARM_DESC(tuner,"tuner type");
60 MODULE_PARM_DESC(card,"card type");
62 static unsigned int nicam = 0;
63 module_param(nicam,int,0644);
64 MODULE_PARM_DESC(nicam,"tv audio is nicam");
66 static unsigned int nocomb = 0;
67 module_param(nocomb,int,0644);
68 MODULE_PARM_DESC(nocomb,"disable comb filter");
70 #define dprintk(level,fmt, arg...) if (core_debug >= level) \
71 printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
73 static unsigned int cx88_devcount;
74 static LIST_HEAD(cx88_devlist);
75 static DECLARE_MUTEX(devlist);
77 /* ------------------------------------------------------------------ */
78 /* debug help functions */
80 static const char *v4l1_ioctls[] = {
81 "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
82 "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
83 "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
84 "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
85 "SMICROCODE", "GVBIFMT", "SVBIFMT" };
86 #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
88 static const char *v4l2_ioctls[] = {
89 "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
90 "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
91 "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
92 "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
93 "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
94 "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
95 "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
96 "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
97 "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
98 "S_MODULATOR"
100 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
102 void cx88_print_ioctl(char *name, unsigned int cmd)
104 char *dir;
106 switch (_IOC_DIR(cmd)) {
107 case _IOC_NONE: dir = "--"; break;
108 case _IOC_READ: dir = "r-"; break;
109 case _IOC_WRITE: dir = "-w"; break;
110 case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
111 default: dir = "??"; break;
113 switch (_IOC_TYPE(cmd)) {
114 case 'v':
115 printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
116 name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
117 v4l1_ioctls[_IOC_NR(cmd)] : "???");
118 break;
119 case 'V':
120 printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
121 name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
122 v4l2_ioctls[_IOC_NR(cmd)] : "???");
123 break;
124 default:
125 printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
126 name, cmd, dir, _IOC_NR(cmd));
130 /* ------------------------------------------------------------------ */
131 #define NO_SYNC_LINE (-1U)
133 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
134 unsigned int offset, u32 sync_line,
135 unsigned int bpl, unsigned int padding,
136 unsigned int lines)
138 struct scatterlist *sg;
139 unsigned int line,todo;
141 /* sync instruction */
142 if (sync_line != NO_SYNC_LINE)
143 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
145 /* scan lines */
146 sg = sglist;
147 for (line = 0; line < lines; line++) {
148 while (offset && offset >= sg_dma_len(sg)) {
149 offset -= sg_dma_len(sg);
150 sg++;
152 if (bpl <= sg_dma_len(sg)-offset) {
153 /* fits into current chunk */
154 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
155 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
156 offset+=bpl;
157 } else {
158 /* scanline needs to be splitted */
159 todo = bpl;
160 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
161 (sg_dma_len(sg)-offset));
162 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
163 todo -= (sg_dma_len(sg)-offset);
164 offset = 0;
165 sg++;
166 while (todo > sg_dma_len(sg)) {
167 *(rp++)=cpu_to_le32(RISC_WRITE|
168 sg_dma_len(sg));
169 *(rp++)=cpu_to_le32(sg_dma_address(sg));
170 todo -= sg_dma_len(sg);
171 sg++;
173 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
174 *(rp++)=cpu_to_le32(sg_dma_address(sg));
175 offset += todo;
177 offset += padding;
180 return rp;
183 int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
184 struct scatterlist *sglist,
185 unsigned int top_offset, unsigned int bottom_offset,
186 unsigned int bpl, unsigned int padding, unsigned int lines)
188 u32 instructions,fields;
189 u32 *rp;
190 int rc;
192 fields = 0;
193 if (UNSET != top_offset)
194 fields++;
195 if (UNSET != bottom_offset)
196 fields++;
198 /* estimate risc mem: worst case is one write per page border +
199 one write per scan line + syncs + jump (all 2 dwords) */
200 instructions = (bpl * lines * fields) / PAGE_SIZE + lines * fields;
201 instructions += 3 + 4;
202 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
203 return rc;
205 /* write risc instructions */
206 rp = risc->cpu;
207 if (UNSET != top_offset)
208 rp = cx88_risc_field(rp, sglist, top_offset, 0,
209 bpl, padding, lines);
210 if (UNSET != bottom_offset)
211 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
212 bpl, padding, lines);
214 /* save pointer to jmp instruction address */
215 risc->jmp = rp;
216 BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
217 return 0;
220 int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
221 struct scatterlist *sglist, unsigned int bpl,
222 unsigned int lines)
224 u32 instructions;
225 u32 *rp;
226 int rc;
228 /* estimate risc mem: worst case is one write per page border +
229 one write per scan line + syncs + jump (all 2 dwords) */
230 instructions = (bpl * lines) / PAGE_SIZE + lines;
231 instructions += 3 + 4;
232 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
233 return rc;
235 /* write risc instructions */
236 rp = risc->cpu;
237 rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
239 /* save pointer to jmp instruction address */
240 risc->jmp = rp;
241 BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
242 return 0;
245 int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
246 u32 reg, u32 mask, u32 value)
248 u32 *rp;
249 int rc;
251 if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
252 return rc;
254 /* write risc instructions */
255 rp = risc->cpu;
256 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
257 *(rp++) = cpu_to_le32(reg);
258 *(rp++) = cpu_to_le32(value);
259 *(rp++) = cpu_to_le32(mask);
260 *(rp++) = cpu_to_le32(RISC_JUMP);
261 *(rp++) = cpu_to_le32(risc->dma);
262 return 0;
265 void
266 cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
268 if (in_interrupt())
269 BUG();
270 videobuf_waiton(&buf->vb,0,0);
271 videobuf_dma_pci_unmap(pci, &buf->vb.dma);
272 videobuf_dma_free(&buf->vb.dma);
273 btcx_riscmem_free(pci, &buf->risc);
274 buf->vb.state = STATE_NEEDS_INIT;
277 /* ------------------------------------------------------------------ */
278 /* our SRAM memory layout */
280 /* we are going to put all thr risc programs into host memory, so we
281 * can use the whole SDRAM for the DMA fifos. To simplify things, we
282 * use a static memory layout. That surely will waste memory in case
283 * we don't use all DMA channels at the same time (which will be the
284 * case most of the time). But that still gives us enougth FIFO space
285 * to be able to deal with insane long pci latencies ...
287 * FIFO space allocations:
288 * channel 21 (y video) - 10.0k
289 * channel 22 (u video) - 2.0k
290 * channel 23 (v video) - 2.0k
291 * channel 24 (vbi) - 4.0k
292 * channels 25+26 (audio) - 0.5k
293 * channel 28 (mpeg) - 4.0k
294 * TOTAL = 25.5k
296 * Every channel has 160 bytes control data (64 bytes instruction
297 * queue and 6 CDT entries), which is close to 2k total.
299 * Address layout:
300 * 0x0000 - 0x03ff CMDs / reserved
301 * 0x0400 - 0x0bff instruction queues + CDs
302 * 0x0c00 - FIFOs
305 struct sram_channel cx88_sram_channels[] = {
306 [SRAM_CH21] = {
307 .name = "video y / packed",
308 .cmds_start = 0x180040,
309 .ctrl_start = 0x180400,
310 .cdt = 0x180400 + 64,
311 .fifo_start = 0x180c00,
312 .fifo_size = 0x002800,
313 .ptr1_reg = MO_DMA21_PTR1,
314 .ptr2_reg = MO_DMA21_PTR2,
315 .cnt1_reg = MO_DMA21_CNT1,
316 .cnt2_reg = MO_DMA21_CNT2,
318 [SRAM_CH22] = {
319 .name = "video u",
320 .cmds_start = 0x180080,
321 .ctrl_start = 0x1804a0,
322 .cdt = 0x1804a0 + 64,
323 .fifo_start = 0x183400,
324 .fifo_size = 0x000800,
325 .ptr1_reg = MO_DMA22_PTR1,
326 .ptr2_reg = MO_DMA22_PTR2,
327 .cnt1_reg = MO_DMA22_CNT1,
328 .cnt2_reg = MO_DMA22_CNT2,
330 [SRAM_CH23] = {
331 .name = "video v",
332 .cmds_start = 0x1800c0,
333 .ctrl_start = 0x180540,
334 .cdt = 0x180540 + 64,
335 .fifo_start = 0x183c00,
336 .fifo_size = 0x000800,
337 .ptr1_reg = MO_DMA23_PTR1,
338 .ptr2_reg = MO_DMA23_PTR2,
339 .cnt1_reg = MO_DMA23_CNT1,
340 .cnt2_reg = MO_DMA23_CNT2,
342 [SRAM_CH24] = {
343 .name = "vbi",
344 .cmds_start = 0x180100,
345 .ctrl_start = 0x1805e0,
346 .cdt = 0x1805e0 + 64,
347 .fifo_start = 0x184400,
348 .fifo_size = 0x001000,
349 .ptr1_reg = MO_DMA24_PTR1,
350 .ptr2_reg = MO_DMA24_PTR2,
351 .cnt1_reg = MO_DMA24_CNT1,
352 .cnt2_reg = MO_DMA24_CNT2,
354 [SRAM_CH25] = {
355 .name = "audio from",
356 .cmds_start = 0x180140,
357 .ctrl_start = 0x180680,
358 .cdt = 0x180680 + 64,
359 .fifo_start = 0x185400,
360 .fifo_size = 0x000200,
361 .ptr1_reg = MO_DMA25_PTR1,
362 .ptr2_reg = MO_DMA25_PTR2,
363 .cnt1_reg = MO_DMA25_CNT1,
364 .cnt2_reg = MO_DMA25_CNT2,
366 [SRAM_CH26] = {
367 .name = "audio to",
368 .cmds_start = 0x180180,
369 .ctrl_start = 0x180720,
370 .cdt = 0x180680 + 64, /* same as audio IN */
371 .fifo_start = 0x185400, /* same as audio IN */
372 .fifo_size = 0x000200, /* same as audio IN */
373 .ptr1_reg = MO_DMA26_PTR1,
374 .ptr2_reg = MO_DMA26_PTR2,
375 .cnt1_reg = MO_DMA26_CNT1,
376 .cnt2_reg = MO_DMA26_CNT2,
378 [SRAM_CH28] = {
379 .name = "mpeg",
380 .cmds_start = 0x180200,
381 .ctrl_start = 0x1807C0,
382 .cdt = 0x1807C0 + 64,
383 .fifo_start = 0x185600,
384 .fifo_size = 0x001000,
385 .ptr1_reg = MO_DMA28_PTR1,
386 .ptr2_reg = MO_DMA28_PTR2,
387 .cnt1_reg = MO_DMA28_CNT1,
388 .cnt2_reg = MO_DMA28_CNT2,
392 int cx88_sram_channel_setup(struct cx88_core *core,
393 struct sram_channel *ch,
394 unsigned int bpl, u32 risc)
396 unsigned int i,lines;
397 u32 cdt;
399 bpl = (bpl + 7) & ~7; /* alignment */
400 cdt = ch->cdt;
401 lines = ch->fifo_size / bpl;
402 if (lines > 6)
403 lines = 6;
404 BUG_ON(lines < 2);
406 /* write CDT */
407 for (i = 0; i < lines; i++)
408 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
410 /* write CMDS */
411 cx_write(ch->cmds_start + 0, risc);
412 cx_write(ch->cmds_start + 4, cdt);
413 cx_write(ch->cmds_start + 8, (lines*16) >> 3);
414 cx_write(ch->cmds_start + 12, ch->ctrl_start);
415 cx_write(ch->cmds_start + 16, 64 >> 2);
416 for (i = 20; i < 64; i += 4)
417 cx_write(ch->cmds_start + i, 0);
419 /* fill registers */
420 cx_write(ch->ptr1_reg, ch->fifo_start);
421 cx_write(ch->ptr2_reg, cdt);
422 cx_write(ch->cnt1_reg, (bpl >> 3) -1);
423 cx_write(ch->cnt2_reg, (lines*16) >> 3);
425 dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
426 return 0;
429 /* ------------------------------------------------------------------ */
430 /* debug helper code */
432 int cx88_risc_decode(u32 risc)
434 static char *instr[16] = {
435 [ RISC_SYNC >> 28 ] = "sync",
436 [ RISC_WRITE >> 28 ] = "write",
437 [ RISC_WRITEC >> 28 ] = "writec",
438 [ RISC_READ >> 28 ] = "read",
439 [ RISC_READC >> 28 ] = "readc",
440 [ RISC_JUMP >> 28 ] = "jump",
441 [ RISC_SKIP >> 28 ] = "skip",
442 [ RISC_WRITERM >> 28 ] = "writerm",
443 [ RISC_WRITECM >> 28 ] = "writecm",
444 [ RISC_WRITECR >> 28 ] = "writecr",
446 static int incr[16] = {
447 [ RISC_WRITE >> 28 ] = 2,
448 [ RISC_JUMP >> 28 ] = 2,
449 [ RISC_WRITERM >> 28 ] = 3,
450 [ RISC_WRITECM >> 28 ] = 3,
451 [ RISC_WRITECR >> 28 ] = 4,
453 static char *bits[] = {
454 "12", "13", "14", "resync",
455 "cnt0", "cnt1", "18", "19",
456 "20", "21", "22", "23",
457 "irq1", "irq2", "eol", "sol",
459 int i;
461 printk("0x%08x [ %s", risc,
462 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
463 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
464 if (risc & (1 << (i + 12)))
465 printk(" %s",bits[i]);
466 printk(" count=%d ]\n", risc & 0xfff);
467 return incr[risc >> 28] ? incr[risc >> 28] : 1;
470 #if 0 /* currently unused, but useful for debugging */
471 void cx88_risc_disasm(struct cx88_core *core,
472 struct btcx_riscmem *risc)
474 unsigned int i,j,n;
476 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
477 core->name, risc->cpu, (unsigned long)risc->dma);
478 for (i = 0; i < (risc->size >> 2); i += n) {
479 printk("%s: %04d: ", core->name, i);
480 n = cx88_risc_decode(risc->cpu[i]);
481 for (j = 1; j < n; j++)
482 printk("%s: %04d: 0x%08x [ arg #%d ]\n",
483 core->name, i+j, risc->cpu[i+j], j);
484 if (risc->cpu[i] == RISC_JUMP)
485 break;
488 #endif
490 void cx88_sram_channel_dump(struct cx88_core *core,
491 struct sram_channel *ch)
493 static char *name[] = {
494 "initial risc",
495 "cdt base",
496 "cdt size",
497 "iq base",
498 "iq size",
499 "risc pc",
500 "iq wr ptr",
501 "iq rd ptr",
502 "cdt current",
503 "pci target",
504 "line / byte",
506 u32 risc;
507 unsigned int i,j,n;
509 printk("%s: %s - dma channel status dump\n",
510 core->name,ch->name);
511 for (i = 0; i < ARRAY_SIZE(name); i++)
512 printk("%s: cmds: %-12s: 0x%08x\n",
513 core->name,name[i],
514 cx_read(ch->cmds_start + 4*i));
515 for (i = 0; i < 4; i++) {
516 risc = cx_read(ch->cmds_start + 4 * (i+11));
517 printk("%s: risc%d: ", core->name, i);
518 cx88_risc_decode(risc);
520 for (i = 0; i < 16; i += n) {
521 risc = cx_read(ch->ctrl_start + 4 * i);
522 printk("%s: iq %x: ", core->name, i);
523 n = cx88_risc_decode(risc);
524 for (j = 1; j < n; j++) {
525 risc = cx_read(ch->ctrl_start + 4 * (i+j));
526 printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
527 core->name, i+j, risc, j);
531 printk("%s: fifo: 0x%08x -> 0x%x\n",
532 core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
533 printk("%s: ctrl: 0x%08x -> 0x%x\n",
534 core->name, ch->ctrl_start, ch->ctrl_start+6*16);
535 printk("%s: ptr1_reg: 0x%08x\n",
536 core->name,cx_read(ch->ptr1_reg));
537 printk("%s: ptr2_reg: 0x%08x\n",
538 core->name,cx_read(ch->ptr2_reg));
539 printk("%s: cnt1_reg: 0x%08x\n",
540 core->name,cx_read(ch->cnt1_reg));
541 printk("%s: cnt2_reg: 0x%08x\n",
542 core->name,cx_read(ch->cnt2_reg));
545 char *cx88_pci_irqs[32] = {
546 "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
547 "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
548 "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
549 "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
551 char *cx88_vid_irqs[32] = {
552 "y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
553 "y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
554 "y_oflow", "u_oflow", "v_oflow", "vbi_oflow",
555 "y_sync", "u_sync", "v_sync", "vbi_sync",
556 "opc_err", "par_err", "rip_err", "pci_abort",
558 char *cx88_mpeg_irqs[32] = {
559 "ts_risci1", NULL, NULL, NULL,
560 "ts_risci2", NULL, NULL, NULL,
561 "ts_oflow", NULL, NULL, NULL,
562 "ts_sync", NULL, NULL, NULL,
563 "opc_err", "par_err", "rip_err", "pci_abort",
564 "ts_err?",
567 void cx88_print_irqbits(char *name, char *tag, char **strings,
568 u32 bits, u32 mask)
570 unsigned int i;
572 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
573 for (i = 0; i < 32; i++) {
574 if (!(bits & (1 << i)))
575 continue;
576 if (strings[i])
577 printk(" %s", strings[i]);
578 else
579 printk(" %d", i);
580 if (!(mask & (1 << i)))
581 continue;
582 printk("*");
584 printk("\n");
587 /* ------------------------------------------------------------------ */
589 int cx88_core_irq(struct cx88_core *core, u32 status)
591 int handled = 0;
593 if (status & (1<<18)) {
594 cx88_ir_irq(core);
595 handled++;
597 if (!handled)
598 cx88_print_irqbits(core->name, "irq pci",
599 cx88_pci_irqs, status,
600 core->pci_irqmask);
601 return handled;
604 void cx88_wakeup(struct cx88_core *core,
605 struct cx88_dmaqueue *q, u32 count)
607 struct cx88_buffer *buf;
608 int bc;
610 for (bc = 0;; bc++) {
611 if (list_empty(&q->active))
612 break;
613 buf = list_entry(q->active.next,
614 struct cx88_buffer, vb.queue);
615 #if 0
616 if (buf->count > count)
617 break;
618 #else
619 /* count comes from the hw and is is 16bit wide --
620 * this trick handles wrap-arounds correctly for
621 * up to 32767 buffers in flight... */
622 if ((s16) (count - buf->count) < 0)
623 break;
624 #endif
625 do_gettimeofday(&buf->vb.ts);
626 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
627 count, buf->count);
628 buf->vb.state = STATE_DONE;
629 list_del(&buf->vb.queue);
630 wake_up(&buf->vb.done);
632 if (list_empty(&q->active)) {
633 del_timer(&q->timeout);
634 } else {
635 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
637 if (bc != 1)
638 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
641 void cx88_shutdown(struct cx88_core *core)
643 /* disable RISC controller + IRQs */
644 cx_write(MO_DEV_CNTRL2, 0);
646 /* stop dma transfers */
647 cx_write(MO_VID_DMACNTRL, 0x0);
648 cx_write(MO_AUD_DMACNTRL, 0x0);
649 cx_write(MO_TS_DMACNTRL, 0x0);
650 cx_write(MO_VIP_DMACNTRL, 0x0);
651 cx_write(MO_GPHST_DMACNTRL, 0x0);
653 /* stop interrupts */
654 cx_write(MO_PCI_INTMSK, 0x0);
655 cx_write(MO_VID_INTMSK, 0x0);
656 cx_write(MO_AUD_INTMSK, 0x0);
657 cx_write(MO_TS_INTMSK, 0x0);
658 cx_write(MO_VIP_INTMSK, 0x0);
659 cx_write(MO_GPHST_INTMSK, 0x0);
661 /* stop capturing */
662 cx_write(VID_CAPTURE_CONTROL, 0);
665 int cx88_reset(struct cx88_core *core)
667 dprintk(1,"%s\n",__FUNCTION__);
668 cx88_shutdown(core);
670 /* clear irq status */
671 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
672 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
673 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
675 /* wait a bit */
676 msleep(100);
678 /* init sram */
679 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
680 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
681 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
682 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
683 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
684 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
685 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
687 /* misc init ... */
688 cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
689 (1 << 12) | // agc gain
690 (1 << 11) | // adaptibe agc
691 (0 << 10) | // chroma agc
692 (0 << 9) | // ckillen
693 (7)));
695 /* setup image format */
696 cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
698 /* setup FIFO Threshholds */
699 cx_write(MO_PDMA_STHRSH, 0x0807);
700 cx_write(MO_PDMA_DTHRSH, 0x0807);
702 /* fixes flashing of image */
703 cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
704 cx_write(MO_AGC_BACK_VBI, 0x00E00555);
706 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
707 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
708 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
710 /* Reset on-board parts */
711 cx_write(MO_SRST_IO, 0);
712 msleep(10);
713 cx_write(MO_SRST_IO, 1);
715 return 0;
718 /* ------------------------------------------------------------------ */
720 static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
722 return (norm->id & V4L2_STD_625_50) ? 922 : 754;
725 static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
727 return (norm->id & V4L2_STD_625_50) ? 186 : 135;
730 static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
732 return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
735 static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
737 static const unsigned int ntsc = 28636360;
738 static const unsigned int pal = 35468950;
740 return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
743 static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
745 return (norm->id & V4L2_STD_625_50)
746 ? HLNotchFilter135PAL
747 : HLNotchFilter135NTSC;
750 static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
752 return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
755 static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
757 return (norm->id & V4L2_STD_625_50) ? 511 : 288;
760 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
761 enum v4l2_field field)
763 unsigned int swidth = norm_swidth(core->tvnorm);
764 unsigned int sheight = norm_maxh(core->tvnorm);
765 u32 value;
767 dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
768 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
769 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
770 core->tvnorm->name);
771 if (!V4L2_FIELD_HAS_BOTH(field))
772 height *= 2;
774 // recalc H delay and scale registers
775 value = (width * norm_hdelay(core->tvnorm)) / swidth;
776 value &= 0x3fe;
777 cx_write(MO_HDELAY_EVEN, value);
778 cx_write(MO_HDELAY_ODD, value);
779 dprintk(1,"set_scale: hdelay 0x%04x\n", value);
781 value = (swidth * 4096 / width) - 4096;
782 cx_write(MO_HSCALE_EVEN, value);
783 cx_write(MO_HSCALE_ODD, value);
784 dprintk(1,"set_scale: hscale 0x%04x\n", value);
786 cx_write(MO_HACTIVE_EVEN, width);
787 cx_write(MO_HACTIVE_ODD, width);
788 dprintk(1,"set_scale: hactive 0x%04x\n", width);
790 // recalc V scale Register (delay is constant)
791 cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
792 cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
793 dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
795 value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
796 cx_write(MO_VSCALE_EVEN, value);
797 cx_write(MO_VSCALE_ODD, value);
798 dprintk(1,"set_scale: vscale 0x%04x\n", value);
800 cx_write(MO_VACTIVE_EVEN, sheight);
801 cx_write(MO_VACTIVE_ODD, sheight);
802 dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
804 // setup filters
805 value = 0;
806 value |= (1 << 19); // CFILT (default)
807 if (core->tvnorm->id & V4L2_STD_SECAM) {
808 value |= (1 << 15);
809 value |= (1 << 16);
811 if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
812 value |= (1 << 13) | (1 << 5);
813 if (V4L2_FIELD_INTERLACED == field)
814 value |= (1 << 3); // VINT (interlaced vertical scaling)
815 if (width < 385)
816 value |= (1 << 0); // 3-tap interpolation
817 if (width < 193)
818 value |= (1 << 1); // 5-tap interpolation
819 if (nocomb)
820 value |= (3 << 5); // disable comb filter
822 cx_write(MO_FILTER_EVEN, value);
823 cx_write(MO_FILTER_ODD, value);
824 dprintk(1,"set_scale: filter 0x%04x\n", value);
826 return 0;
829 static const u32 xtal = 28636363;
831 static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
833 static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
834 u64 pll;
835 u32 reg;
836 int i;
838 if (prescale < 2)
839 prescale = 2;
840 if (prescale > 5)
841 prescale = 5;
843 pll = ofreq * 8 * prescale * (u64)(1 << 20);
844 do_div(pll,xtal);
845 reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
846 if (((reg >> 20) & 0x3f) < 14) {
847 printk("%s/0: pll out of range\n",core->name);
848 return -1;
851 dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
852 reg, cx_read(MO_PLL_REG), ofreq);
853 cx_write(MO_PLL_REG, reg);
854 for (i = 0; i < 100; i++) {
855 reg = cx_read(MO_DEVICE_STATUS);
856 if (reg & (1<<2)) {
857 dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
858 prescale,ofreq);
859 return 0;
861 dprintk(1,"pll not locked yet, waiting ...\n");
862 msleep(10);
864 dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
865 return -1;
868 static int set_tvaudio(struct cx88_core *core)
870 struct cx88_tvnorm *norm = core->tvnorm;
872 if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
873 return 0;
875 if (V4L2_STD_PAL_BG & norm->id) {
876 core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
878 } else if (V4L2_STD_PAL_DK & norm->id) {
879 core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
881 } else if (V4L2_STD_PAL_I & norm->id) {
882 core->tvaudio = WW_NICAM_I;
884 } else if (V4L2_STD_SECAM_L & norm->id) {
885 core->tvaudio = WW_SYSTEM_L_AM;
887 } else if (V4L2_STD_SECAM_DK & norm->id) {
888 core->tvaudio = WW_A2_DK;
890 } else if ((V4L2_STD_NTSC_M & norm->id) ||
891 (V4L2_STD_PAL_M & norm->id)) {
892 core->tvaudio = WW_BTSC;
894 } else if (V4L2_STD_NTSC_M_JP & norm->id) {
895 core->tvaudio = WW_EIAJ;
897 } else {
898 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
899 core->name, norm->name);
900 core->tvaudio = 0;
901 return 0;
904 cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
905 cx88_set_tvaudio(core);
906 // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
908 cx_write(MO_AUDD_LNGTH, 128); /* fifo size */
909 cx_write(MO_AUDR_LNGTH, 128); /* fifo size */
910 cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
911 return 0;
914 int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
916 u32 fsc8;
917 u32 adc_clock;
918 u32 vdec_clock;
919 u32 step_db,step_dr;
920 u64 tmp64;
921 u32 bdelay,agcdelay,htotal;
923 core->tvnorm = norm;
924 fsc8 = norm_fsc8(norm);
925 adc_clock = xtal;
926 vdec_clock = fsc8;
927 step_db = fsc8;
928 step_dr = fsc8;
930 if (norm->id & V4L2_STD_SECAM) {
931 step_db = 4250000 * 8;
932 step_dr = 4406250 * 8;
935 dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
936 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
937 set_pll(core,2,vdec_clock);
939 dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
940 norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
941 cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
943 #if 1
944 // FIXME: as-is from DScaler
945 dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
946 norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
947 cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
948 #endif
950 // MO_SCONV_REG = adc clock / video dec clock * 2^17
951 tmp64 = adc_clock * (u64)(1 << 17);
952 do_div(tmp64, vdec_clock);
953 dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
954 (u32)tmp64, cx_read(MO_SCONV_REG));
955 cx_write(MO_SCONV_REG, (u32)tmp64);
957 // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
958 tmp64 = step_db * (u64)(1 << 22);
959 do_div(tmp64, vdec_clock);
960 dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
961 (u32)tmp64, cx_read(MO_SUB_STEP));
962 cx_write(MO_SUB_STEP, (u32)tmp64);
964 // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
965 tmp64 = step_dr * (u64)(1 << 22);
966 do_div(tmp64, vdec_clock);
967 dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
968 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
969 cx_write(MO_SUB_STEP_DR, (u32)tmp64);
971 // bdelay + agcdelay
972 bdelay = vdec_clock * 65 / 20000000 + 21;
973 agcdelay = vdec_clock * 68 / 20000000 + 15;
974 dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
975 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
976 cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
978 // htotal
979 tmp64 = norm_htotal(norm) * (u64)vdec_clock;
980 do_div(tmp64, fsc8);
981 htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
982 dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
983 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
984 cx_write(MO_HTOTAL, htotal);
986 // vbi stuff
987 cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
988 norm_vbipack(norm)));
990 // this is needed as well to set all tvnorm parameter
991 cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
993 // audio
994 set_tvaudio(core);
996 // tell i2c chips
997 #ifdef V4L2_I2C_CLIENTS
998 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
999 #else
1001 struct video_channel c;
1002 memset(&c,0,sizeof(c));
1003 c.channel = core->input;
1004 c.norm = VIDEO_MODE_PAL;
1005 if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
1006 c.norm = VIDEO_MODE_NTSC;
1007 if (norm->id & V4L2_STD_SECAM)
1008 c.norm = VIDEO_MODE_SECAM;
1009 cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
1011 #endif
1013 // done
1014 return 0;
1017 /* ------------------------------------------------------------------ */
1019 static int cx88_pci_quirks(char *name, struct pci_dev *pci)
1021 unsigned int lat = UNSET;
1022 u8 ctrl = 0;
1023 u8 value;
1025 /* check pci quirks */
1026 if (pci_pci_problems & PCIPCI_TRITON) {
1027 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
1028 name);
1029 ctrl |= CX88X_EN_TBFX;
1031 if (pci_pci_problems & PCIPCI_NATOMA) {
1032 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
1033 name);
1034 ctrl |= CX88X_EN_TBFX;
1036 if (pci_pci_problems & PCIPCI_VIAETBF) {
1037 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
1038 name);
1039 ctrl |= CX88X_EN_TBFX;
1041 if (pci_pci_problems & PCIPCI_VSFX) {
1042 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
1043 name);
1044 ctrl |= CX88X_EN_VSFX;
1046 #ifdef PCIPCI_ALIMAGIK
1047 if (pci_pci_problems & PCIPCI_ALIMAGIK) {
1048 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
1049 name);
1050 lat = 0x0A;
1052 #endif
1054 /* check insmod options */
1055 if (UNSET != latency)
1056 lat = latency;
1058 /* apply stuff */
1059 if (ctrl) {
1060 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
1061 value |= ctrl;
1062 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
1064 if (UNSET != lat) {
1065 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
1066 name, latency);
1067 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1069 return 0;
1072 /* ------------------------------------------------------------------ */
1074 struct video_device *cx88_vdev_init(struct cx88_core *core,
1075 struct pci_dev *pci,
1076 struct video_device *template,
1077 char *type)
1079 struct video_device *vfd;
1081 vfd = video_device_alloc();
1082 if (NULL == vfd)
1083 return NULL;
1084 *vfd = *template;
1085 vfd->minor = -1;
1086 vfd->dev = &pci->dev;
1087 vfd->release = video_device_release;
1088 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1089 core->name, type, cx88_boards[core->board].name);
1090 return vfd;
1093 static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1095 if (request_mem_region(pci_resource_start(pci,0),
1096 pci_resource_len(pci,0),
1097 core->name))
1098 return 0;
1099 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
1100 core->name,pci_resource_start(pci,0));
1101 return -EBUSY;
1104 struct cx88_core* cx88_core_get(struct pci_dev *pci)
1106 struct cx88_core *core;
1107 struct list_head *item;
1108 int i;
1110 down(&devlist);
1111 list_for_each(item,&cx88_devlist) {
1112 core = list_entry(item, struct cx88_core, devlist);
1113 if (pci->bus->number != core->pci_bus)
1114 continue;
1115 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1116 continue;
1118 if (0 != get_ressources(core,pci))
1119 goto fail_unlock;
1120 atomic_inc(&core->refcount);
1121 up(&devlist);
1122 return core;
1124 core = kmalloc(sizeof(*core),GFP_KERNEL);
1125 if (NULL == core)
1126 goto fail_unlock;
1128 memset(core,0,sizeof(*core));
1129 atomic_inc(&core->refcount);
1130 core->pci_bus = pci->bus->number;
1131 core->pci_slot = PCI_SLOT(pci->devfn);
1132 core->pci_irqmask = 0x00fc00;
1134 core->nr = cx88_devcount++;
1135 sprintf(core->name,"cx88[%d]",core->nr);
1136 if (0 != get_ressources(core,pci)) {
1137 cx88_devcount--;
1138 goto fail_free;
1140 list_add_tail(&core->devlist,&cx88_devlist);
1142 /* PCI stuff */
1143 cx88_pci_quirks(core->name, pci);
1144 core->lmmio = ioremap(pci_resource_start(pci,0),
1145 pci_resource_len(pci,0));
1146 core->bmmio = (u8 __iomem *)core->lmmio;
1148 /* board config */
1149 core->board = UNSET;
1150 if (card[core->nr] < cx88_bcount)
1151 core->board = card[core->nr];
1152 for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
1153 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1154 pci->subsystem_device == cx88_subids[i].subdevice)
1155 core->board = cx88_subids[i].card;
1156 if (UNSET == core->board) {
1157 core->board = CX88_BOARD_UNKNOWN;
1158 cx88_card_list(core,pci);
1160 printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1161 core->name,pci->subsystem_vendor,
1162 pci->subsystem_device,cx88_boards[core->board].name,
1163 core->board, card[core->nr] == core->board ?
1164 "insmod option" : "autodetected");
1166 core->tuner_type = tuner[core->nr];
1167 if (UNSET == core->tuner_type)
1168 core->tuner_type = cx88_boards[core->board].tuner_type;
1169 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1171 /* init hardware */
1172 cx88_reset(core);
1173 cx88_i2c_init(core,pci);
1174 cx88_card_setup(core);
1175 cx88_ir_init(core,pci);
1177 up(&devlist);
1178 return core;
1180 fail_free:
1181 kfree(core);
1182 fail_unlock:
1183 up(&devlist);
1184 return NULL;
1187 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1189 release_mem_region(pci_resource_start(pci,0),
1190 pci_resource_len(pci,0));
1192 if (!atomic_dec_and_test(&core->refcount))
1193 return;
1195 down(&devlist);
1196 cx88_ir_fini(core);
1197 if (0 == core->i2c_rc)
1198 i2c_bit_del_bus(&core->i2c_adap);
1199 list_del(&core->devlist);
1200 iounmap(core->lmmio);
1201 cx88_devcount--;
1202 up(&devlist);
1203 kfree(core);
1206 /* ------------------------------------------------------------------ */
1208 EXPORT_SYMBOL(cx88_print_ioctl);
1209 EXPORT_SYMBOL(cx88_pci_irqs);
1210 EXPORT_SYMBOL(cx88_vid_irqs);
1211 EXPORT_SYMBOL(cx88_mpeg_irqs);
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);
1236 * Local variables:
1237 * c-basic-offset: 8
1238 * End: