aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/isa/cmi8330.c86
1 files changed, 52 insertions, 34 deletions
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 3ee0269e5bd0..02f79d252718 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Driver for C-Media's CMI8330 soundcards. 2 * Driver for C-Media's CMI8330 and CMI8329 soundcards.
3 * Copyright (c) by George Talusan <gstalusan@uwaterloo.ca> 3 * Copyright (c) by George Talusan <gstalusan@uwaterloo.ca>
4 * http://www.undergrad.math.uwaterloo.ca/~gstalusa 4 * http://www.undergrad.math.uwaterloo.ca/~gstalusa
5 * 5 *
@@ -35,7 +35,7 @@
35 * 35 *
36 * This card has two mixers and two PCM devices. I've cheesed it such 36 * This card has two mixers and two PCM devices. I've cheesed it such
37 * that recording and playback can be done through the same device. 37 * that recording and playback can be done through the same device.
38 * The driver "magically" routes the capturing to the CMI8330 codec, 38 * The driver "magically" routes the capturing to the AD1848 codec,
39 * and playback to the SB16 codec. This allows for full-duplex mode 39 * and playback to the SB16 codec. This allows for full-duplex mode
40 * to some extent. 40 * to some extent.
41 * The utilities in alsa-utils are aware of both devices, so passing 41 * The utilities in alsa-utils are aware of both devices, so passing
@@ -64,7 +64,7 @@
64/* 64/*
65 */ 65 */
66MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>"); 66MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>");
67MODULE_DESCRIPTION("C-Media CMI8330"); 67MODULE_DESCRIPTION("C-Media CMI8330/CMI8329");
68MODULE_LICENSE("GPL"); 68MODULE_LICENSE("GPL");
69MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); 69MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}");
70 70
@@ -86,38 +86,38 @@ static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
86static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 86static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
87 87
88module_param_array(index, int, NULL, 0444); 88module_param_array(index, int, NULL, 0444);
89MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); 89MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard.");
90module_param_array(id, charp, NULL, 0444); 90module_param_array(id, charp, NULL, 0444);
91MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard."); 91MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard.");
92module_param_array(enable, bool, NULL, 0444); 92module_param_array(enable, bool, NULL, 0444);
93MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard."); 93MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard.");
94#ifdef CONFIG_PNP 94#ifdef CONFIG_PNP
95module_param_array(isapnp, bool, NULL, 0444); 95module_param_array(isapnp, bool, NULL, 0444);
96MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); 96MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
97#endif 97#endif
98 98
99module_param_array(sbport, long, NULL, 0444); 99module_param_array(sbport, long, NULL, 0444);
100MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver."); 100MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver.");
101module_param_array(sbirq, int, NULL, 0444); 101module_param_array(sbirq, int, NULL, 0444);
102MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver."); 102MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver.");
103module_param_array(sbdma8, int, NULL, 0444); 103module_param_array(sbdma8, int, NULL, 0444);
104MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver."); 104MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver.");
105module_param_array(sbdma16, int, NULL, 0444); 105module_param_array(sbdma16, int, NULL, 0444);
106MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver."); 106MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver.");
107 107
108module_param_array(wssport, long, NULL, 0444); 108module_param_array(wssport, long, NULL, 0444);
109MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver."); 109MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver.");
110module_param_array(wssirq, int, NULL, 0444); 110module_param_array(wssirq, int, NULL, 0444);
111MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver."); 111MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver.");
112module_param_array(wssdma, int, NULL, 0444); 112module_param_array(wssdma, int, NULL, 0444);
113MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); 113MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver.");
114 114
115module_param_array(fmport, long, NULL, 0444); 115module_param_array(fmport, long, NULL, 0444);
116MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); 116MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver.");
117module_param_array(mpuport, long, NULL, 0444); 117module_param_array(mpuport, long, NULL, 0444);
118MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver."); 118MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver.");
119module_param_array(mpuirq, int, NULL, 0444); 119module_param_array(mpuirq, int, NULL, 0444);
120MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port."); 120MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port.");
121#ifdef CONFIG_PNP 121#ifdef CONFIG_PNP
122static int isa_registered; 122static int isa_registered;
123static int pnp_registered; 123static int pnp_registered;
@@ -156,6 +156,11 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] =
156 156
157typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *); 157typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *);
158 158
159enum card_type {
160 CMI8330,
161 CMI8329
162};
163
159struct snd_cmi8330 { 164struct snd_cmi8330 {
160#ifdef CONFIG_PNP 165#ifdef CONFIG_PNP
161 struct pnp_dev *cap; 166 struct pnp_dev *cap;
@@ -172,11 +177,14 @@ struct snd_cmi8330 {
172 snd_pcm_open_callback_t open; 177 snd_pcm_open_callback_t open;
173 void *private_data; /* sb or wss */ 178 void *private_data; /* sb or wss */
174 } streams[2]; 179 } streams[2];
180
181 enum card_type type;
175}; 182};
176 183
177#ifdef CONFIG_PNP 184#ifdef CONFIG_PNP
178 185
179static struct pnp_card_device_id snd_cmi8330_pnpids[] = { 186static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
187 { .id = "CMI0001", .devs = { { "@X@0001" }, { "@@@0001" }, { "@H@0001" }, { "A@@0001" } } },
180 { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, 188 { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
181 { .id = "" } 189 { .id = "" }
182}; 190};
@@ -304,7 +312,7 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330
304 unsigned int idx; 312 unsigned int idx;
305 int err; 313 int err;
306 314
307 strcpy(card->mixername, "CMI8330/C3D"); 315 strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
308 316
309 for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) { 317 for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
310 err = snd_ctl_add(card, 318 err = snd_ctl_add(card,
@@ -329,6 +337,9 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
329 struct pnp_dev *pdev; 337 struct pnp_dev *pdev;
330 int err; 338 int err;
331 339
340 /* CMI8329 has a device with ID A@@0001, CMI8330 does not */
341 acard->type = (id->devs[3].id[0]) ? CMI8329 : CMI8330;
342
332 acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); 343 acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
333 if (acard->cap == NULL) 344 if (acard->cap == NULL)
334 return -EBUSY; 345 return -EBUSY;
@@ -345,38 +356,45 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
345 356
346 err = pnp_activate_dev(pdev); 357 err = pnp_activate_dev(pdev);
347 if (err < 0) { 358 if (err < 0) {
348 snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n"); 359 snd_printk(KERN_ERR "AD1848 PnP configure failure\n");
349 return -EBUSY; 360 return -EBUSY;
350 } 361 }
351 wssport[dev] = pnp_port_start(pdev, 0); 362 wssport[dev] = pnp_port_start(pdev, 0);
352 wssdma[dev] = pnp_dma(pdev, 0); 363 wssdma[dev] = pnp_dma(pdev, 0);
353 wssirq[dev] = pnp_irq(pdev, 0); 364 wssirq[dev] = pnp_irq(pdev, 0);
354 fmport[dev] = pnp_port_start(pdev, 1); 365 if (pnp_port_start(pdev, 1))
366 fmport[dev] = pnp_port_start(pdev, 1);
355 367
356 /* allocate SB16 resources */ 368 /* allocate SB16 resources */
357 pdev = acard->play; 369 pdev = acard->play;
358 370
359 err = pnp_activate_dev(pdev); 371 err = pnp_activate_dev(pdev);
360 if (err < 0) { 372 if (err < 0) {
361 snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n"); 373 snd_printk(KERN_ERR "SB16 PnP configure failure\n");
362 return -EBUSY; 374 return -EBUSY;
363 } 375 }
364 sbport[dev] = pnp_port_start(pdev, 0); 376 sbport[dev] = pnp_port_start(pdev, 0);
365 sbdma8[dev] = pnp_dma(pdev, 0); 377 sbdma8[dev] = pnp_dma(pdev, 0);
366 sbdma16[dev] = pnp_dma(pdev, 1); 378 sbdma16[dev] = pnp_dma(pdev, 1);
367 sbirq[dev] = pnp_irq(pdev, 0); 379 sbirq[dev] = pnp_irq(pdev, 0);
380 /* On CMI8239, the OPL3 port might be present in SB16 PnP resources */
381 if (fmport[dev] == SNDRV_AUTO_PORT) {
382 if (pnp_port_start(pdev, 1))
383 fmport[dev] = pnp_port_start(pdev, 1);
384 else
385 fmport[dev] = 0x388; /* Or hardwired */
386 }
368 387
369 /* allocate MPU-401 resources */ 388 /* allocate MPU-401 resources */
370 pdev = acard->mpu; 389 pdev = acard->mpu;
371 390
372 err = pnp_activate_dev(pdev); 391 err = pnp_activate_dev(pdev);
373 if (err < 0) { 392 if (err < 0)
374 snd_printk(KERN_ERR 393 snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n");
375 "CMI8330/C3D (MPU-401) PnP configure failure\n"); 394 else {
376 return -EBUSY; 395 mpuport[dev] = pnp_port_start(pdev, 0);
396 mpuirq[dev] = pnp_irq(pdev, 0);
377 } 397 }
378 mpuport[dev] = pnp_port_start(pdev, 0);
379 mpuirq[dev] = pnp_irq(pdev, 0);
380 return 0; 398 return 0;
381} 399}
382#endif 400#endif
@@ -430,9 +448,9 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *
430 snd_cmi8330_capture_open 448 snd_cmi8330_capture_open
431 }; 449 };
432 450
433 if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0) 451 if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0)
434 return err; 452 return err;
435 strcpy(pcm->name, "CMI8330"); 453 strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330");
436 pcm->private_data = chip; 454 pcm->private_data = chip;
437 455
438 /* SB16 */ 456 /* SB16 */
@@ -527,11 +545,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
527 wssdma[dev], -1, 545 wssdma[dev], -1,
528 WSS_HW_DETECT, 0, &acard->wss); 546 WSS_HW_DETECT, 0, &acard->wss);
529 if (err < 0) { 547 if (err < 0) {
530 snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n"); 548 snd_printk(KERN_ERR PFX "AD1848 device busy??\n");
531 return err; 549 return err;
532 } 550 }
533 if (acard->wss->hardware != WSS_HW_CMI8330) { 551 if (acard->wss->hardware != WSS_HW_CMI8330) {
534 snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n"); 552 snd_printk(KERN_ERR PFX "AD1848 not found during probe\n");
535 return -ENODEV; 553 return -ENODEV;
536 } 554 }
537 555
@@ -541,11 +559,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
541 sbdma8[dev], 559 sbdma8[dev],
542 sbdma16[dev], 560 sbdma16[dev],
543 SB_HW_AUTO, &acard->sb)) < 0) { 561 SB_HW_AUTO, &acard->sb)) < 0) {
544 snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); 562 snd_printk(KERN_ERR PFX "SB16 device busy??\n");
545 return err; 563 return err;
546 } 564 }
547 if (acard->sb->hardware != SB_HW_16) { 565 if (acard->sb->hardware != SB_HW_16) {
548 snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); 566 snd_printk(KERN_ERR PFX "SB16 not found during probe\n");
549 return err; 567 return err;
550 } 568 }
551 569
@@ -585,8 +603,8 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
585 mpuport[dev]); 603 mpuport[dev]);
586 } 604 }
587 605
588 strcpy(card->driver, "CMI8330/C3D"); 606 strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
589 strcpy(card->shortname, "C-Media CMI8330/C3D"); 607 strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D");
590 sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", 608 sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
591 card->shortname, 609 card->shortname,
592 acard->wss->port, 610 acard->wss->port,