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