aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@brturbo.com.br>2006-01-09 12:32:44 -0500
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>2006-01-09 12:32:44 -0500
commitb7f355d23c34399ccfd54fd613c306ab4a788234 (patch)
tree3e55c0b49918bb82f97650b281ad8feca7ad8007 /drivers
parent0de71224d17f43101fa20696a8d7a78fb599557e (diff)
V4L/DVB (3293): Added digital support for cx88 (cx88-alsa)
- This module is co-authored by Ricardo Cerqueira <v4l@cerqueira.org>. - Added digital audio support for cx88-based boards that have function 01 enabled. These boards can be identified by having PCI id 1471:8801 or 1471:8811. - Increased DMA buffer from 512 to 4096 seems to fix audio distortion. - Existing audio DMA uses conflict with cx88-alsa. Should be disabled when cx88-alsa module is compiled. Signed-off-by: Ricardo Cerqueira <v4l@cerqueira.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/cx88/Kconfig15
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c848
-rw-r--r--drivers/media/video/cx88/cx88-core.c11
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c4
4 files changed, 872 insertions, 6 deletions
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index ec6201a32aca..76fcb4e995c9 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -29,6 +29,21 @@ config VIDEO_CX88_DVB
29 You must also select one or more DVB/ATSC demodulators. 29 You must also select one or more DVB/ATSC demodulators.
30 If you are unsure which you need, choose all of them. 30 If you are unsure which you need, choose all of them.
31 31
32config VIDEO_CX88_ALSA
33 tristate "ALSA DMA audio support"
34 depends on VIDEO_CX88 && SND
35 select SND_PCM_OSS
36 ---help---
37 This is a video4linux driver for direct (DMA) audio on
38 Conexant 2388x based TV cards.
39 It only works with boards with function 01 enabled.
40 To check if your board supports, use lspci -n.
41 If supported, you should see 1471:8801 or 1471:8811
42 PCI device.
43
44 To compile this driver as a module, choose M here: the
45 module will be called cx88-alsa.
46
32config VIDEO_CX88_DVB_ALL_FRONTENDS 47config VIDEO_CX88_DVB_ALL_FRONTENDS
33 bool "Build all supported frontends for cx2388x based TV cards" 48 bool "Build all supported frontends for cx2388x based TV cards"
34 default y 49 default y
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
new file mode 100644
index 000000000000..7695b521eb35
--- /dev/null
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -0,0 +1,848 @@
1/*
2 *
3 * Support for audio capture
4 * PCI function #1 of the cx2388x.
5 *
6 * (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
7 * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
8 * Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
9 * Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/device.h>
29#include <linux/interrupt.h>
30#include <asm/delay.h>
31#include <sound/driver.h>
32#include <sound/core.h>
33#include <sound/pcm.h>
34#include <sound/pcm_params.h>
35#include <sound/control.h>
36#include <sound/initval.h>
37
38#include "cx88.h"
39#include "cx88-reg.h"
40
41#define dprintk(level,fmt, arg...) if (debug >= level) \
42 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg)
43
44#define dprintk_core(level,fmt, arg...) if (debug >= level) \
45 printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
46
47
48/****************************************************************************
49 Data type declarations - Can be moded to a header file later
50 ****************************************************************************/
51
52/* These can be replaced after done */
53#define MIXER_ADDR_LAST MAX_CX88_INPUT
54
55struct cx88_audio_dev {
56 struct cx88_core *core;
57 struct cx88_dmaqueue q;
58
59 /* pci i/o */
60 struct pci_dev *pci;
61 unsigned char pci_rev,pci_lat;
62
63 /* audio controls */
64 int irq;
65
66 snd_card_t *card;
67
68 spinlock_t reg_lock;
69
70 unsigned int dma_size;
71 unsigned int period_size;
72 unsigned int num_periods;
73
74 struct videobuf_dmabuf dma_risc;
75
76 int mixer_volume[MIXER_ADDR_LAST+1][2];
77 int capture_source[MIXER_ADDR_LAST+1][2];
78
79 long int read_count;
80 long int read_offset;
81
82 struct cx88_buffer *buf;
83
84 long opened;
85 snd_pcm_substream_t *substream;
86
87};
88typedef struct cx88_audio_dev snd_cx88_card_t;
89
90
91
92/****************************************************************************
93 Module global static vars
94 ****************************************************************************/
95
96static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
97static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
98static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
99static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
100
101module_param_array(enable, bool, NULL, 0444);
102MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
103
104module_param_array(index, int, NULL, 0444);
105MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
106
107
108/****************************************************************************
109 Module macros
110 ****************************************************************************/
111
112MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
113MODULE_AUTHOR("Ricardo Cerqueira");
114MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
115MODULE_LICENSE("GPL");
116MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
117 "{{Conexant,23882},"
118 "{{Conexant,23883}");
119static unsigned int debug = 0;
120module_param(debug,int,0644);
121MODULE_PARM_DESC(debug,"enable debug messages");
122
123/****************************************************************************
124 Module specific funtions
125 ****************************************************************************/
126
127/*
128 * BOARD Specific: Sets audio DMA
129 */
130
131int _cx88_start_audio_dma(snd_cx88_card_t *chip)
132{
133 struct cx88_buffer *buf = chip->buf;
134 struct cx88_core *core=chip->core;
135 struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
136
137
138 dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
139
140 /* setup fifo + format - out channel */
141 cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
142 buf->bpl, buf->risc.dma);
143
144 /* sets bpl size */
145 cx_write(MO_AUDD_LNGTH, buf->bpl);
146
147 /* reset counter */
148 cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
149
150 dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
151 /* enable irqs */
152 cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
153
154
155 /* Enables corresponding bits at AUD_INT_STAT */
156 cx_write(MO_AUD_INTMSK,
157 (1<<16)|
158 (1<<12)|
159 (1<<4)|
160 (1<<0)
161 );
162
163 /* start dma */
164 cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
165 cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
166
167 if (debug)
168 cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
169
170 return 0;
171}
172
173/*
174 * BOARD Specific: Resets audio DMA
175 */
176int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
177{
178 struct cx88_core *core=chip->core;
179 dprintk(1, "Stopping audio DMA\n");
180
181 /* stop dma */
182 cx_clear(MO_AUD_DMACNTRL, 0x11);
183
184 /* disable irqs */
185 cx_clear(MO_PCI_INTMSK, 0x02);
186 cx_clear(MO_AUD_INTMSK,
187 (1<<16)|
188 (1<<12)|
189 (1<<4)|
190 (1<<0)
191 );
192
193 if (debug)
194 cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
195
196 return 0;
197}
198
199#define MAX_IRQ_LOOP 10
200
201/*
202 * BOARD Specific: IRQ dma bits
203 */
204static char *cx88_aud_irqs[32] = {
205 "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
206 NULL, /* reserved */
207 "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
208 NULL, /* reserved */
209 "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
210 NULL, /* reserved */
211 "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
212 NULL, /* reserved */
213 "opc_err", "par_err", "rip_err", /* 16-18 */
214 "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
215};
216
217/*
218 * BOARD Specific: Threats IRQ audio specific calls
219 */
220static void cx8801_aud_irq(snd_cx88_card_t *chip)
221{
222 struct cx88_core *core = chip->core;
223 u32 status, mask;
224 u32 count;
225
226 status = cx_read(MO_AUD_INTSTAT);
227 mask = cx_read(MO_AUD_INTMSK);
228 if (0 == (status & mask)) {
229 spin_unlock(&chip->reg_lock);
230 return;
231 }
232 cx_write(MO_AUD_INTSTAT, status);
233 if (debug > 1 || (status & mask & ~0xff))
234 cx88_print_irqbits(core->name, "irq aud",
235 cx88_aud_irqs, status, mask);
236 /* risc op code error */
237 if (status & (1 << 16)) {
238 printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
239 cx_clear(MO_AUD_DMACNTRL, 0x11);
240 cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
241 }
242
243 /* risc1 downstream */
244 if (status & 0x01) {
245 spin_lock(&chip->reg_lock);
246 count = cx_read(MO_AUDD_GPCNT);
247 spin_unlock(&chip->reg_lock);
248 if (chip->read_count == 0)
249 chip->read_count += chip->dma_size;
250 }
251
252 if (chip->read_count >= chip->period_size) {
253 dprintk(2, "Elapsing period\n");
254 snd_pcm_period_elapsed(chip->substream);
255 }
256
257 dprintk(3,"Leaving audio IRQ handler...\n");
258
259 /* FIXME: Any other status should deserve a special handling? */
260}
261
262/*
263 * BOARD Specific: Handles IRQ calls
264 */
265static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
266{
267 snd_cx88_card_t *chip = dev_id;
268 struct cx88_core *core = chip->core;
269 u32 status;
270 int loop, handled = 0;
271
272 for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
273 status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
274 if (0 == status)
275 goto out;
276 dprintk( 3, "cx8801_irq\n" );
277 dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
278 dprintk( 3, " status: %d\n", status );
279 handled = 1;
280 cx_write(MO_PCI_INTSTAT, status);
281
282 if (status & 0x02)
283 {
284 dprintk( 2, " ALSA IRQ handling\n" );
285 cx8801_aud_irq(chip);
286 }
287 };
288
289 if (MAX_IRQ_LOOP == loop) {
290 dprintk( 0, "clearing mask\n" );
291 dprintk(1,"%s/0: irq loop -- clearing mask\n",
292 core->name);
293 cx_clear(MO_PCI_INTMSK,0x02);
294 }
295
296 out:
297 return IRQ_RETVAL(handled);
298}
299
300
301static int dsp_buffer_free(snd_cx88_card_t *chip)
302{
303 BUG_ON(!chip->dma_size);
304
305 dprintk(2,"Freeing buffer\n");
306 videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc);
307 videobuf_dma_free(&chip->dma_risc);
308 btcx_riscmem_free(chip->pci,&chip->buf->risc);
309 kfree(chip->buf);
310
311 chip->dma_size = 0;
312
313 return 0;
314}
315
316/****************************************************************************
317 ALSA PCM Interface
318 ****************************************************************************/
319
320/*
321 * Digital hardware definition
322 */
323static snd_pcm_hardware_t snd_cx88_digital_hw = {
324 .info = SNDRV_PCM_INFO_MMAP |
325 SNDRV_PCM_INFO_INTERLEAVED |
326 SNDRV_PCM_INFO_BLOCK_TRANSFER |
327 SNDRV_PCM_INFO_MMAP_VALID,
328 .formats = SNDRV_PCM_FMTBIT_S16_LE,
329
330 .rates = SNDRV_PCM_RATE_48000,
331 .rate_min = 48000,
332 .rate_max = 48000,
333 .channels_min = 1,
334 .channels_max = 2,
335 .buffer_bytes_max = (2*2048),
336 .period_bytes_min = 256,
337 .period_bytes_max = 2048,
338 .periods_min = 2,
339 .periods_max = 16,
340};
341
342/*
343 * audio pcm capture runtime free
344 */
345static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
346{
347}
348/*
349 * audio pcm capture open callback
350 */
351static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
352{
353 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
354 snd_pcm_runtime_t *runtime = substream->runtime;
355 int err;
356
357 if (test_and_set_bit(0, &chip->opened))
358 return -EBUSY;
359
360 err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
361 if (err < 0)
362 goto _error;
363
364 chip->substream = substream;
365
366 chip->read_count = 0;
367 chip->read_offset = 0;
368
369 runtime->private_free = snd_card_cx88_runtime_free;
370 runtime->hw = snd_cx88_digital_hw;
371
372 return 0;
373_error:
374 dprintk(1,"Error opening PCM!\n");
375 clear_bit(0, &chip->opened);
376 smp_mb__after_clear_bit();
377 return err;
378}
379
380/*
381 * audio close callback
382 */
383static int snd_cx88_close(snd_pcm_substream_t *substream)
384{
385 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
386
387 clear_bit(0, &chip->opened);
388 smp_mb__after_clear_bit();
389
390 return 0;
391}
392
393/*
394 * hw_params callback
395 */
396static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
397 snd_pcm_hw_params_t * hw_params)
398{
399 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
400 struct cx88_buffer *buf;
401
402 if (substream->runtime->dma_area) {
403 dsp_buffer_free(chip);
404 substream->runtime->dma_area = NULL;
405 }
406
407
408 chip->period_size = params_period_bytes(hw_params);
409 chip->num_periods = params_periods(hw_params);
410 chip->dma_size = chip->period_size * params_periods(hw_params);
411
412 BUG_ON(!chip->dma_size);
413
414 dprintk(1,"Setting buffer\n");
415
416 buf = kmalloc(sizeof(*buf),GFP_KERNEL);
417 if (NULL == buf)
418 return -ENOMEM;
419 memset(buf,0,sizeof(*buf));
420
421
422 buf->vb.memory = V4L2_MEMORY_MMAP;
423 buf->vb.width = chip->period_size;
424 buf->vb.height = chip->num_periods;
425 buf->vb.size = chip->dma_size;
426 buf->vb.field = V4L2_FIELD_NONE;
427
428 videobuf_dma_init(&buf->vb.dma);
429 videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
430 (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
431
432 videobuf_dma_pci_map(chip->pci,&buf->vb.dma);
433
434
435 cx88_risc_databuffer(chip->pci, &buf->risc,
436 buf->vb.dma.sglist,
437 buf->vb.width, buf->vb.height);
438
439 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
440 buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
441
442 buf->vb.state = STATE_PREPARED;
443
444 buf->bpl = chip->period_size;
445 chip->buf = buf;
446 chip->dma_risc = buf->vb.dma;
447
448 dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
449 substream->runtime->dma_area = chip->dma_risc.vmalloc;
450 return 0;
451}
452
453/*
454 * hw free callback
455 */
456static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
457{
458
459 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
460
461 if (substream->runtime->dma_area) {
462 dsp_buffer_free(chip);
463 substream->runtime->dma_area = NULL;
464 }
465
466 return 0;
467}
468
469/*
470 * prepare callback
471 */
472static int snd_cx88_prepare(snd_pcm_substream_t *substream)
473{
474 return 0;
475}
476
477
478/*
479 * trigger callback
480 */
481static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
482{
483 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
484 int err;
485
486 spin_lock(&chip->reg_lock);
487
488 switch (cmd) {
489 case SNDRV_PCM_TRIGGER_START:
490 err=_cx88_start_audio_dma(chip);
491 break;
492 case SNDRV_PCM_TRIGGER_STOP:
493 err=_cx88_stop_audio_dma(chip);
494 break;
495 default:
496 err=-EINVAL;
497 break;
498 }
499
500 spin_unlock(&chip->reg_lock);
501
502 return err;
503}
504
505/*
506 * pointer callback
507 */
508static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
509{
510 snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
511 snd_pcm_runtime_t *runtime = substream->runtime;
512
513 if (chip->read_count) {
514 chip->read_count -= snd_pcm_lib_period_bytes(substream);
515 chip->read_offset += snd_pcm_lib_period_bytes(substream);
516 if (chip->read_offset == chip->dma_size)
517 chip->read_offset = 0;
518 }
519
520 dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
521 return bytes_to_frames(runtime, chip->read_offset);
522
523}
524
525/*
526 * operators
527 */
528static snd_pcm_ops_t snd_cx88_pcm_ops = {
529 .open = snd_cx88_pcm_open,
530 .close = snd_cx88_close,
531 .ioctl = snd_pcm_lib_ioctl,
532 .hw_params = snd_cx88_hw_params,
533 .hw_free = snd_cx88_hw_free,
534 .prepare = snd_cx88_prepare,
535 .trigger = snd_cx88_card_trigger,
536 .pointer = snd_cx88_pointer,
537};
538
539/*
540 * create a PCM device
541 */
542static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
543{
544 int err;
545 snd_pcm_t *pcm;
546
547 err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
548 if (err < 0)
549 return err;
550 pcm->private_data = chip;
551 strcpy(pcm->name, name);
552 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
553
554 return 0;
555}
556
557/****************************************************************************
558 CONTROL INTERFACE
559 ****************************************************************************/
560static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
561{
562 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
563 info->count = 1;
564 info->value.integer.min = 0;
565 info->value.integer.max = 0x3f;
566
567 return 0;
568}
569
570/* OK - TODO: test it */
571static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
572{
573 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
574 struct cx88_core *core=chip->core;
575
576 value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
577
578 return 0;
579}
580
581/* OK - TODO: test it */
582static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
583{
584 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
585 struct cx88_core *core=chip->core;
586 int v;
587 u32 old_control;
588
589 spin_lock_irq(&chip->reg_lock);
590 old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
591 v = 0x3f - (value->value.integer.value[0] & 0x3f);
592 cx_andor(AUD_VOL_CTL, 0x3f, v);
593 spin_unlock_irq(&chip->reg_lock);
594
595 return v != old_control;
596}
597
598static snd_kcontrol_new_t snd_cx88_capture_volume = {
599 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
600 .name = "Capture Volume",
601 .info = snd_cx88_capture_volume_info,
602 .get = snd_cx88_capture_volume_get,
603 .put = snd_cx88_capture_volume_put,
604};
605
606
607/****************************************************************************
608 Basic Flow for Sound Devices
609 ****************************************************************************/
610
611/*
612 * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
613 * Only boards with eeprom and byte 1 at eeprom=1 have it
614 */
615
616struct pci_device_id cx88_audio_pci_tbl[] = {
617 {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
618 {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
619 {0, }
620};
621MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
622
623/*
624 * Chip-specific destructor
625 */
626
627static int snd_cx88_free(snd_cx88_card_t *chip)
628{
629
630 if (chip->irq >= 0){
631 synchronize_irq(chip->irq);
632 free_irq(chip->irq, chip);
633 }
634
635 cx88_core_put(chip->core,chip->pci);
636
637 pci_disable_device(chip->pci);
638 return 0;
639}
640
641/*
642 * Component Destructor
643 */
644static void snd_cx88_dev_free(snd_card_t * card)
645{
646 snd_cx88_card_t *chip = card->private_data;
647
648 snd_cx88_free(chip);
649}
650
651
652/*
653 * Alsa Constructor - Component probe
654 */
655
656static int devno=0;
657static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
658 snd_cx88_card_t **rchip)
659{
660 snd_cx88_card_t *chip;
661 struct cx88_core *core;
662 int err;
663
664 *rchip = NULL;
665
666 err = pci_enable_device(pci);
667 if (err < 0)
668 return err;
669
670 pci_set_master(pci);
671
672 chip = (snd_cx88_card_t *) card->private_data;
673
674 core = cx88_core_get(pci);
675
676 if (!pci_dma_supported(pci,0xffffffff)) {
677 dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
678 err = -EIO;
679 cx88_core_put(core,pci);
680 return err;
681 }
682
683
684 /* pci init */
685 chip->card = card;
686 chip->pci = pci;
687 chip->irq = -1;
688 spin_lock_init(&chip->reg_lock);
689
690 cx88_reset(core);
691 if (NULL == core) {
692 err = -EINVAL;
693 kfree (chip);
694 return err;
695 }
696 chip->core = core;
697
698 /* get irq */
699 err = request_irq(chip->pci->irq, cx8801_irq,
700 SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip);
701 if (err < 0) {
702 dprintk(0, "%s: can't get IRQ %d\n",
703 chip->core->name, chip->pci->irq);
704 return err;
705 }
706
707 /* print pci info */
708 pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
709 pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat);
710
711 dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
712 "latency: %d, mmio: 0x%lx\n", core->name, devno,
713 pci_name(pci), chip->pci_rev, pci->irq,
714 chip->pci_lat,pci_resource_start(pci,0));
715
716 chip->irq = pci->irq;
717 synchronize_irq(chip->irq);
718
719 snd_card_set_dev(card, &pci->dev);
720
721 *rchip = chip;
722
723 return 0;
724}
725
726static int __devinit cx88_audio_initdev(struct pci_dev *pci,
727 const struct pci_device_id *pci_id)
728{
729 snd_card_t *card;
730 snd_cx88_card_t *chip;
731 int err;
732
733 if (devno >= SNDRV_CARDS)
734 return (-ENODEV);
735
736 if (!enable[devno]) {
737 ++devno;
738 return (-ENOENT);
739 }
740
741 card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t));
742 if (!card)
743 return (-ENOMEM);
744
745 card->private_free = snd_cx88_dev_free;
746
747 err = snd_cx88_create(card, pci, &chip);
748 if (err < 0)
749 return (err);
750
751 err = snd_cx88_pcm(chip, 0, "CX88 Digital");
752
753 if (err < 0) {
754 snd_card_free(card);
755 return (err);
756 }
757
758 err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
759 if (err < 0) {
760 snd_card_free(card);
761 return (err);
762 }
763
764 strcpy (card->driver, "CX88x");
765 sprintf(card->shortname, "Conexant CX%x", pci->device);
766 sprintf(card->longname, "%s at %#lx",
767 card->shortname, pci_resource_start(pci, 0));
768 strcpy (card->mixername, "CX88");
769
770 dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
771 card->driver,devno);
772
773 err = snd_card_register(card);
774 if (err < 0) {
775 snd_card_free(card);
776 return (err);
777 }
778 snd_cx88_cards[devno] = card;
779
780 pci_set_drvdata(pci,card);
781
782 devno++;
783 return 0;
784}
785/*
786 * ALSA destructor
787 */
788static void __devexit cx88_audio_finidev(struct pci_dev *pci)
789{
790 struct cx88_audio_dev *card = pci_get_drvdata(pci);
791
792 snd_card_free((void *)card);
793
794 pci_set_drvdata(pci, NULL);
795
796 devno--;
797}
798
799/*
800 * PCI driver definition
801 */
802
803static struct pci_driver cx88_audio_pci_driver = {
804 .name = "cx88_audio",
805 .id_table = cx88_audio_pci_tbl,
806 .probe = cx88_audio_initdev,
807 .remove = cx88_audio_finidev,
808 SND_PCI_PM_CALLBACKS
809};
810
811/****************************************************************************
812 LINUX MODULE INIT
813 ****************************************************************************/
814
815/*
816 * module init
817 */
818static int cx88_audio_init(void)
819{
820 printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
821 (CX88_VERSION_CODE >> 16) & 0xff,
822 (CX88_VERSION_CODE >> 8) & 0xff,
823 CX88_VERSION_CODE & 0xff);
824#ifdef SNAPSHOT
825 printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
826 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
827#endif
828 return pci_register_driver(&cx88_audio_pci_driver);
829}
830
831/*
832 * module remove
833 */
834static void cx88_audio_fini(void)
835{
836
837 pci_unregister_driver(&cx88_audio_pci_driver);
838}
839
840module_init(cx88_audio_init);
841module_exit(cx88_audio_fini);
842
843/* ----------------------------------------------------------- */
844/*
845 * Local variables:
846 * c-basic-offset: 8
847 * End:
848 */
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index fc814d198694..9975be1aca38 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -238,9 +238,9 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
238 * channel 22 (u video) - 2.0k 238 * channel 22 (u video) - 2.0k
239 * channel 23 (v video) - 2.0k 239 * channel 23 (v video) - 2.0k
240 * channel 24 (vbi) - 4.0k 240 * channel 24 (vbi) - 4.0k
241 * channels 25+26 (audio) - 0.5k 241 * channels 25+26 (audio) - 4.0k
242 * channel 28 (mpeg) - 4.0k 242 * channel 28 (mpeg) - 4.0k
243 * TOTAL = 25.5k 243 * TOTAL = 29.0k
244 * 244 *
245 * Every channel has 160 bytes control data (64 bytes instruction 245 * Every channel has 160 bytes control data (64 bytes instruction
246 * queue and 6 CDT entries), which is close to 2k total. 246 * queue and 6 CDT entries), which is close to 2k total.
@@ -306,7 +306,7 @@ struct sram_channel cx88_sram_channels[] = {
306 .ctrl_start = 0x180680, 306 .ctrl_start = 0x180680,
307 .cdt = 0x180680 + 64, 307 .cdt = 0x180680 + 64,
308 .fifo_start = 0x185400, 308 .fifo_start = 0x185400,
309 .fifo_size = 0x000200, 309 .fifo_size = 0x001000,
310 .ptr1_reg = MO_DMA25_PTR1, 310 .ptr1_reg = MO_DMA25_PTR1,
311 .ptr2_reg = MO_DMA25_PTR2, 311 .ptr2_reg = MO_DMA25_PTR2,
312 .cnt1_reg = MO_DMA25_CNT1, 312 .cnt1_reg = MO_DMA25_CNT1,
@@ -318,7 +318,7 @@ struct sram_channel cx88_sram_channels[] = {
318 .ctrl_start = 0x180720, 318 .ctrl_start = 0x180720,
319 .cdt = 0x180680 + 64, /* same as audio IN */ 319 .cdt = 0x180680 + 64, /* same as audio IN */
320 .fifo_start = 0x185400, /* same as audio IN */ 320 .fifo_start = 0x185400, /* same as audio IN */
321 .fifo_size = 0x000200, /* same as audio IN */ 321 .fifo_size = 0x001000, /* same as audio IN */
322 .ptr1_reg = MO_DMA26_PTR1, 322 .ptr1_reg = MO_DMA26_PTR1,
323 .ptr2_reg = MO_DMA26_PTR2, 323 .ptr2_reg = MO_DMA26_PTR2,
324 .cnt1_reg = MO_DMA26_CNT1, 324 .cnt1_reg = MO_DMA26_CNT1,
@@ -329,7 +329,7 @@ struct sram_channel cx88_sram_channels[] = {
329 .cmds_start = 0x180200, 329 .cmds_start = 0x180200,
330 .ctrl_start = 0x1807C0, 330 .ctrl_start = 0x1807C0,
331 .cdt = 0x1807C0 + 64, 331 .cdt = 0x1807C0 + 64,
332 .fifo_start = 0x185600, 332 .fifo_start = 0x186400,
333 .fifo_size = 0x001000, 333 .fifo_size = 0x001000,
334 .ptr1_reg = MO_DMA28_PTR1, 334 .ptr1_reg = MO_DMA28_PTR1,
335 .ptr2_reg = MO_DMA28_PTR2, 335 .ptr2_reg = MO_DMA28_PTR2,
@@ -795,7 +795,6 @@ int cx88_start_audio_dma(struct cx88_core *core)
795 795
796 /* start dma */ 796 /* start dma */
797 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ 797 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
798
799 return 0; 798 return 0;
800} 799}
801 800
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 00051a4c1dc2..24118e43e73a 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -132,10 +132,14 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
132{ 132{
133 u32 volume; 133 u32 volume;
134 134
135#ifndef USING_CX88_ALSA
135 /* restart dma; This avoids buzz in NICAM and is good in others */ 136 /* restart dma; This avoids buzz in NICAM and is good in others */
136 cx88_stop_audio_dma(core); 137 cx88_stop_audio_dma(core);
138#endif
137 cx_write(AUD_RATE_THRES_DMD, 0x000000C0); 139 cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
140#ifndef USING_CX88_ALSA
138 cx88_start_audio_dma(core); 141 cx88_start_audio_dma(core);
142#endif
139 143
140 if (cx88_boards[core->board].blackbird) { 144 if (cx88_boards[core->board].blackbird) {
141 /* sets sound input from external adc */ 145 /* sets sound input from external adc */