blob: c2cdbafdb77b34ae3b06b723f5e963e61854f92b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
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>
Mauro Carvalho Chehab98f30ed2005-11-08 21:37:17 -080034#include <linux/videodev2.h>
Ingo Molnar1e4baed2006-01-15 07:52:23 -020035#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include "cx88.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020038#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
41MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
42MODULE_LICENSE("GPL");
43
44/* ------------------------------------------------------------------ */
45
46static unsigned int core_debug = 0;
47module_param(core_debug,int,0644);
48MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
49
50static unsigned int latency = UNSET;
51module_param(latency,int,0444);
52MODULE_PARM_DESC(latency,"pci latency timer");
53
54static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070055static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Linus Torvalds1da177e2005-04-16 15:20:36 -070056static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
57
58module_param_array(tuner, int, NULL, 0444);
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070059module_param_array(radio, int, NULL, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060module_param_array(card, int, NULL, 0444);
61
62MODULE_PARM_DESC(tuner,"tuner type");
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070063MODULE_PARM_DESC(radio,"radio tuner type");
Linus Torvalds1da177e2005-04-16 15:20:36 -070064MODULE_PARM_DESC(card,"card type");
65
66static unsigned int nicam = 0;
67module_param(nicam,int,0644);
68MODULE_PARM_DESC(nicam,"tv audio is nicam");
69
70static unsigned int nocomb = 0;
71module_param(nocomb,int,0644);
72MODULE_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
77static unsigned int cx88_devcount;
78static LIST_HEAD(cx88_devlist);
Ingo Molnar1e4baed2006-01-15 07:52:23 -020079static DEFINE_MUTEX(devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define NO_SYNC_LINE (-1U)
82
83static 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 */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800104 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
105 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
106 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 } else {
108 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800109 todo = bpl;
110 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800112 *(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)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800117 *(rp++)=cpu_to_le32(RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800119 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 todo -= sg_dma_len(sg);
121 sg++;
122 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800123 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 *(rp++)=cpu_to_le32(sg_dma_address(sg));
125 offset += todo;
126 }
127 offset += padding;
128 }
129
130 return rp;
131}
132
133int 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;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300166 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 return 0;
168}
169
170int 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;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300191 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 return 0;
193}
194
195int 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
215void
216cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
217{
Eric Sesterhennae246012006-03-13 13:17:11 -0300218 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 videobuf_waiton(&buf->vb,0,0);
220 videobuf_dma_pci_unmap(pci, &buf->vb.dma);
221 videobuf_dma_free(&buf->vb.dma);
222 btcx_riscmem_free(pci, &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
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200241 * channels 25+26 (audio) - 4.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 * channel 28 (mpeg) - 4.0k
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200243 * TOTAL = 29.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 *
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
254struct sram_channel cx88_sram_channels[] = {
255 [SRAM_CH21] = {
256 .name = "video y / packed",
257 .cmds_start = 0x180040,
258 .ctrl_start = 0x180400,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800259 .cdt = 0x180400 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 .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,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800271 .cdt = 0x1804a0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .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,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800283 .cdt = 0x180540 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 .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,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800295 .cdt = 0x1805e0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 .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,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800307 .cdt = 0x180680 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 .fifo_start = 0x185400,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200309 .fifo_size = 0x001000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 .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,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800319 .cdt = 0x180680 + 64, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 .fifo_start = 0x185400, /* same as audio IN */
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200321 .fifo_size = 0x001000, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 .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,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200332 .fifo_start = 0x186400,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 .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
341int 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
Peter Hagervallf9e7a022005-11-08 21:36:29 -0800381static int cx88_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420void 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
Adrian Bunk408b6642005-05-01 08:59:29 -0700475static char *cx88_pci_irqs[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 "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};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482void 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
504int 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
519void 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 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
551void 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
575int 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
630static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
631{
632 return (norm->id & V4L2_STD_625_50) ? 922 : 754;
633}
634
635static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
636{
637 return (norm->id & V4L2_STD_625_50) ? 186 : 135;
638}
639
640static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
641{
642 return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
643}
644
645static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
646{
647 static const unsigned int ntsc = 28636360;
648 static const unsigned int pal = 35468950;
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700649 static const unsigned int palm = 28604892;
650
651 if (norm->id & V4L2_STD_PAL_M)
652 return palm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
655}
656
657static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
658{
659 return (norm->id & V4L2_STD_625_50)
660 ? HLNotchFilter135PAL
661 : HLNotchFilter135NTSC;
662}
663
664static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
665{
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700666 /* Should always be Line Draw Time / (4*FSC) */
667
668 if (norm->id & V4L2_STD_PAL_M)
669 return 909;
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
672}
673
674static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
675{
676 return (norm->id & V4L2_STD_625_50) ? 511 : 288;
677}
678
679int 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
748static const u32 xtal = 28636363;
749
750static 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
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800787int cx88_start_audio_dma(struct cx88_core *core)
788{
Marcin Rudowski17801f52006-02-06 09:15:14 -0200789 /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
790 int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800791 /* setup fifo + format */
Marcin Rudowski17801f52006-02-06 09:15:14 -0200792 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);
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800794
Marcin Rudowski17801f52006-02-06 09:15:14 -0200795 cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
796 cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800797
798 /* start dma */
799 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800800 return 0;
801}
802
803int 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811static 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) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800819 core->tvaudio = WW_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 } else if (V4L2_STD_PAL_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800822 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 } else if (V4L2_STD_PAL_I & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800825 core->tvaudio = WW_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827 } else if (V4L2_STD_SECAM_L & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800828 core->tvaudio = WW_L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 } else if (V4L2_STD_SECAM_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800831 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
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);
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -0700849 /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800851/*
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return 0;
857}
858
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800859
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861int 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 // 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 // done
945 return 0;
946}
947
948/* ------------------------------------------------------------------ */
949
950static 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
1005struct 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
1024static 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
1035struct cx88_core* cx88_core_get(struct pci_dev *pci)
1036{
1037 struct cx88_core *core;
1038 struct list_head *item;
1039 int i;
1040
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001041 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 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);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001052 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 return core;
1054 }
Panagiotis Issaris74081872006-01-11 19:40:56 -02001055 core = kzalloc(sizeof(*core),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 if (NULL == core)
1057 goto fail_unlock;
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 atomic_inc(&core->refcount);
1060 core->pci_bus = pci->bus->number;
1061 core->pci_slot = PCI_SLOT(pci->devfn);
1062 core->pci_irqmask = 0x00fc00;
Ingo Molnar3593cab2006-02-07 06:49:14 -02001063 mutex_init(&core->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 core->nr = cx88_devcount++;
1066 sprintf(core->name,"cx88[%d]",core->nr);
1067 if (0 != get_ressources(core,pci)) {
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001068 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 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 }
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001097 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 core->tuner_type = tuner[core->nr];
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001104 core->radio_type = radio[core->nr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (UNSET == core->tuner_type)
1106 core->tuner_type = cx88_boards[core->board].tuner_type;
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001107 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
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001114 printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001115 core->tuner_type, core->tuner_addr<<1,
1116 core->radio_type, core->radio_addr<<1);
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1119
1120 /* init hardware */
1121 cx88_reset(core);
1122 cx88_i2c_init(core,pci);
Michael Krufky87f07832005-11-08 21:36:19 -08001123 cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 cx88_card_setup(core);
1125 cx88_ir_init(core,pci);
1126
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001127 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 return core;
1129
1130fail_free:
1131 kfree(core);
1132fail_unlock:
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001133 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return NULL;
1135}
1136
1137void 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
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001145 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 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--;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001152 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 kfree(core);
1154}
1155
1156/* ------------------------------------------------------------------ */
1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158EXPORT_SYMBOL(cx88_print_irqbits);
1159
1160EXPORT_SYMBOL(cx88_core_irq);
1161EXPORT_SYMBOL(cx88_wakeup);
1162EXPORT_SYMBOL(cx88_reset);
1163EXPORT_SYMBOL(cx88_shutdown);
1164
1165EXPORT_SYMBOL(cx88_risc_buffer);
1166EXPORT_SYMBOL(cx88_risc_databuffer);
1167EXPORT_SYMBOL(cx88_risc_stopper);
1168EXPORT_SYMBOL(cx88_free_buffer);
1169
1170EXPORT_SYMBOL(cx88_sram_channels);
1171EXPORT_SYMBOL(cx88_sram_channel_setup);
1172EXPORT_SYMBOL(cx88_sram_channel_dump);
1173
1174EXPORT_SYMBOL(cx88_set_tvnorm);
1175EXPORT_SYMBOL(cx88_set_scale);
1176
1177EXPORT_SYMBOL(cx88_vdev_init);
1178EXPORT_SYMBOL(cx88_core_get);
1179EXPORT_SYMBOL(cx88_core_put);
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -08001180EXPORT_SYMBOL(cx88_start_audio_dma);
1181EXPORT_SYMBOL(cx88_stop_audio_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183/*
1184 * Local variables:
1185 * c-basic-offset: 8
1186 * End:
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001187 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 */