diff options
Diffstat (limited to 'sound/isa/cmi8330.c')
| -rw-r--r-- | sound/isa/cmi8330.c | 86 |
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 | */ |
| 66 | MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>"); | 66 | MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>"); |
| 67 | MODULE_DESCRIPTION("C-Media CMI8330"); | 67 | MODULE_DESCRIPTION("C-Media CMI8330/CMI8329"); |
| 68 | MODULE_LICENSE("GPL"); | 68 | MODULE_LICENSE("GPL"); |
| 69 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); | 69 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); |
| 70 | 70 | ||
| @@ -86,38 +86,38 @@ static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | |||
| 86 | static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | 86 | static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; |
| 87 | 87 | ||
| 88 | module_param_array(index, int, NULL, 0444); | 88 | module_param_array(index, int, NULL, 0444); |
| 89 | MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); | 89 | MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard."); |
| 90 | module_param_array(id, charp, NULL, 0444); | 90 | module_param_array(id, charp, NULL, 0444); |
| 91 | MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard."); | 91 | MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard."); |
| 92 | module_param_array(enable, bool, NULL, 0444); | 92 | module_param_array(enable, bool, NULL, 0444); |
| 93 | MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard."); | 93 | MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard."); |
| 94 | #ifdef CONFIG_PNP | 94 | #ifdef CONFIG_PNP |
| 95 | module_param_array(isapnp, bool, NULL, 0444); | 95 | module_param_array(isapnp, bool, NULL, 0444); |
| 96 | MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); | 96 | MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); |
| 97 | #endif | 97 | #endif |
| 98 | 98 | ||
| 99 | module_param_array(sbport, long, NULL, 0444); | 99 | module_param_array(sbport, long, NULL, 0444); |
| 100 | MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver."); | 100 | MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver."); |
| 101 | module_param_array(sbirq, int, NULL, 0444); | 101 | module_param_array(sbirq, int, NULL, 0444); |
| 102 | MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver."); | 102 | MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver."); |
| 103 | module_param_array(sbdma8, int, NULL, 0444); | 103 | module_param_array(sbdma8, int, NULL, 0444); |
| 104 | MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver."); | 104 | MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver."); |
| 105 | module_param_array(sbdma16, int, NULL, 0444); | 105 | module_param_array(sbdma16, int, NULL, 0444); |
| 106 | MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver."); | 106 | MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver."); |
| 107 | 107 | ||
| 108 | module_param_array(wssport, long, NULL, 0444); | 108 | module_param_array(wssport, long, NULL, 0444); |
| 109 | MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver."); | 109 | MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver."); |
| 110 | module_param_array(wssirq, int, NULL, 0444); | 110 | module_param_array(wssirq, int, NULL, 0444); |
| 111 | MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver."); | 111 | MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver."); |
| 112 | module_param_array(wssdma, int, NULL, 0444); | 112 | module_param_array(wssdma, int, NULL, 0444); |
| 113 | MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); | 113 | MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver."); |
| 114 | 114 | ||
| 115 | module_param_array(fmport, long, NULL, 0444); | 115 | module_param_array(fmport, long, NULL, 0444); |
| 116 | MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); | 116 | MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver."); |
| 117 | module_param_array(mpuport, long, NULL, 0444); | 117 | module_param_array(mpuport, long, NULL, 0444); |
| 118 | MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver."); | 118 | MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver."); |
| 119 | module_param_array(mpuirq, int, NULL, 0444); | 119 | module_param_array(mpuirq, int, NULL, 0444); |
| 120 | MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port."); | 120 | MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port."); |
| 121 | #ifdef CONFIG_PNP | 121 | #ifdef CONFIG_PNP |
| 122 | static int isa_registered; | 122 | static int isa_registered; |
| 123 | static int pnp_registered; | 123 | static int pnp_registered; |
| @@ -156,6 +156,11 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] = | |||
| 156 | 156 | ||
| 157 | typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *); | 157 | typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *); |
| 158 | 158 | ||
| 159 | enum card_type { | ||
| 160 | CMI8330, | ||
| 161 | CMI8329 | ||
| 162 | }; | ||
| 163 | |||
| 159 | struct snd_cmi8330 { | 164 | struct 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 | ||
| 179 | static struct pnp_card_device_id snd_cmi8330_pnpids[] = { | 186 | static 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, |
