From 74a0094cd9d030d7a684e6ce1cbd1658eb63bd7d Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 27 Jun 2009 16:26:35 +0200 Subject: [PATCH 1/4] ALSA: cmi8330: revert comments about AD1848 back In ALSA 1.0.20, the comments were changed to say CMI8330 instead of AD1848. The CMI8330 chip includes two codecs - AD1848 and SB16, so the comments were correct and are misleading now. Revert them back. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/isa/cmi8330.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 3ee0269e5bd..d510c76c537 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -35,7 +35,7 @@ * * This card has two mixers and two PCM devices. I've cheesed it such * that recording and playback can be done through the same device. - * The driver "magically" routes the capturing to the CMI8330 codec, + * The driver "magically" routes the capturing to the AD1848 codec, * and playback to the SB16 codec. This allows for full-duplex mode * to some extent. * The utilities in alsa-utils are aware of both devices, so passing @@ -345,7 +345,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n"); + snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); return -EBUSY; } wssport[dev] = pnp_port_start(pdev, 0); @@ -527,11 +527,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) wssdma[dev], -1, WSS_HW_DETECT, 0, &acard->wss); if (err < 0) { - snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n"); + snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); return err; } if (acard->wss->hardware != WSS_HW_CMI8330) { - snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n"); + snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); return -ENODEV; } From 69eb88825a7a562ee3564bdae20c35b0238307b0 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 4 Jul 2009 22:25:44 +0200 Subject: [PATCH 2/4] cmi8330: Add basic CMI8329 support Add basic support for CMI8329 cards. Makes PCM and OPL3 work. Does not break CMI8330 (tested). Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/isa/cmi8330.c | 71 +++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index d510c76c537..33e63faf6aa 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -1,5 +1,5 @@ /* - * Driver for C-Media's CMI8330 soundcards. + * Driver for C-Media's CMI8330 and CMI8329 soundcards. * Copyright (c) by George Talusan * http://www.undergrad.math.uwaterloo.ca/~gstalusa * @@ -64,7 +64,7 @@ /* */ MODULE_AUTHOR("George Talusan "); -MODULE_DESCRIPTION("C-Media CMI8330"); +MODULE_DESCRIPTION("C-Media CMI8330/CMI8329"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); @@ -86,38 +86,38 @@ static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); +MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard."); module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard."); +MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard."); module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard."); +MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard."); #ifdef CONFIG_PNP module_param_array(isapnp, bool, NULL, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); #endif module_param_array(sbport, long, NULL, 0444); -MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver."); +MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver."); module_param_array(sbirq, int, NULL, 0444); -MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver."); +MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver."); module_param_array(sbdma8, int, NULL, 0444); -MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver."); +MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver."); module_param_array(sbdma16, int, NULL, 0444); -MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver."); +MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver."); module_param_array(wssport, long, NULL, 0444); -MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver."); module_param_array(wssirq, int, NULL, 0444); -MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver."); module_param_array(wssdma, int, NULL, 0444); -MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver."); module_param_array(fmport, long, NULL, 0444); -MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); +MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver."); module_param_array(mpuport, long, NULL, 0444); -MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver."); +MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver."); module_param_array(mpuirq, int, NULL, 0444); -MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port."); +MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port."); #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; @@ -156,6 +156,11 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] = typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *); +enum card_type { + CMI8330, + CMI8329 +}; + struct snd_cmi8330 { #ifdef CONFIG_PNP struct pnp_dev *cap; @@ -172,11 +177,14 @@ struct snd_cmi8330 { snd_pcm_open_callback_t open; void *private_data; /* sb or wss */ } streams[2]; + + enum card_type type; }; #ifdef CONFIG_PNP static struct pnp_card_device_id snd_cmi8330_pnpids[] = { + { .id = "CMI0001", .devs = { { "@X@0001" }, { "@@@0001" }, { "@H@0001" }, { "A@@0001" } } }, { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, { .id = "" } }; @@ -304,7 +312,7 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 unsigned int idx; int err; - strcpy(card->mixername, "CMI8330/C3D"); + strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) { err = snd_ctl_add(card, @@ -329,6 +337,9 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, struct pnp_dev *pdev; int err; + /* CMI8329 has a device with ID A@@0001, CMI8330 does not */ + acard->type = (id->devs[3].id[0]) ? CMI8329 : CMI8330; + acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); if (acard->cap == NULL) return -EBUSY; @@ -345,34 +356,36 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); + snd_printk(KERN_ERR "AD1848 PnP configure failure\n"); return -EBUSY; } wssport[dev] = pnp_port_start(pdev, 0); wssdma[dev] = pnp_dma(pdev, 0); wssirq[dev] = pnp_irq(pdev, 0); - fmport[dev] = pnp_port_start(pdev, 1); + if (acard->type == CMI8330) + fmport[dev] = pnp_port_start(pdev, 1); /* allocate SB16 resources */ pdev = acard->play; err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n"); + snd_printk(KERN_ERR "SB16 PnP configure failure\n"); return -EBUSY; } sbport[dev] = pnp_port_start(pdev, 0); sbdma8[dev] = pnp_dma(pdev, 0); sbdma16[dev] = pnp_dma(pdev, 1); sbirq[dev] = pnp_irq(pdev, 0); + if (acard->type == CMI8329) + fmport[dev] = pnp_port_start(pdev, 1); /* allocate MPU-401 resources */ pdev = acard->mpu; err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR - "CMI8330/C3D (MPU-401) PnP configure failure\n"); + snd_printk(KERN_ERR "MPU-401 PnP configure failure\n"); return -EBUSY; } mpuport[dev] = pnp_port_start(pdev, 0); @@ -430,9 +443,9 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 * snd_cmi8330_capture_open }; - if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0) + if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0) return err; - strcpy(pcm->name, "CMI8330"); + strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330"); pcm->private_data = chip; /* SB16 */ @@ -527,11 +540,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) wssdma[dev], -1, WSS_HW_DETECT, 0, &acard->wss); if (err < 0) { - snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); + snd_printk(KERN_ERR PFX "AD1848 device busy??\n"); return err; } if (acard->wss->hardware != WSS_HW_CMI8330) { - snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); + snd_printk(KERN_ERR PFX "AD1848 not found during probe\n"); return -ENODEV; } @@ -541,11 +554,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) sbdma8[dev], sbdma16[dev], SB_HW_AUTO, &acard->sb)) < 0) { - snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); + snd_printk(KERN_ERR PFX "SB16 device busy??\n"); return err; } if (acard->sb->hardware != SB_HW_16) { - snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); + snd_printk(KERN_ERR PFX "SB16 not found during probe\n"); return err; } @@ -585,8 +598,8 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) mpuport[dev]); } - strcpy(card->driver, "CMI8330/C3D"); - strcpy(card->shortname, "C-Media CMI8330/C3D"); + strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); + strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D"); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", card->shortname, acard->wss->port, From 0b959167237208bc1a811e30bf866cd29bff1652 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 6 Jul 2009 22:08:04 +0200 Subject: [PATCH 3/4] ALSA: cmi8330: find OPL3 port automatically My CMI8329 had OPL3 port specified in SB16 resources. But now I found out that it was my modification of the card's PnP EEPROM a couple of years ago (can be done using C9SETROM.EXE utility). I did it because the OPL3 port was completely missing from PnP data. It seems to be hardwired to 0x388 on CMI8329. Find OPL3 port automatically by searching in WSS and SB16 resources. If not found, assume that it's hardwired to 0x388. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/isa/cmi8330.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 33e63faf6aa..f7acb8dac18 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -362,7 +362,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, wssport[dev] = pnp_port_start(pdev, 0); wssdma[dev] = pnp_dma(pdev, 0); wssirq[dev] = pnp_irq(pdev, 0); - if (acard->type == CMI8330) + if (pnp_port_start(pdev, 1)) fmport[dev] = pnp_port_start(pdev, 1); /* allocate SB16 resources */ @@ -377,8 +377,13 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, sbdma8[dev] = pnp_dma(pdev, 0); sbdma16[dev] = pnp_dma(pdev, 1); sbirq[dev] = pnp_irq(pdev, 0); - if (acard->type == CMI8329) - fmport[dev] = pnp_port_start(pdev, 1); + /* On CMI8239, the OPL3 port might be present in SB16 PnP resources */ + if (fmport[dev] == SNDRV_AUTO_PORT) { + if (pnp_port_start(pdev, 1)) + fmport[dev] = pnp_port_start(pdev, 1); + else + fmport[dev] = 0x388; /* Or hardwired */ + } /* allocate MPU-401 resources */ pdev = acard->mpu; From 72b43cf1402169e8bc088838a6db91d613c35627 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 7 Jul 2009 18:09:48 +0200 Subject: [PATCH 4/4] ALSA: cmi8330: Allow MPU-401-less operation Adding MPU-401 support to cmi8330 driver could cause a regression (non-working sound) on a system where there is no free IRQ for the MPU-401 device (which is not very uncommon as this card requires two separate IRQs plus a third one for MPU-401). When MPU-401 PnP configuration fails (mostly because of unavailable IRQ), just ignore MPU-401 and continue without it. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/isa/cmi8330.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index f7acb8dac18..02f79d25271 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -389,12 +389,12 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, pdev = acard->mpu; err = pnp_activate_dev(pdev); - if (err < 0) { - snd_printk(KERN_ERR "MPU-401 PnP configure failure\n"); - return -EBUSY; + if (err < 0) + snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n"); + else { + mpuport[dev] = pnp_port_start(pdev, 0); + mpuirq[dev] = pnp_irq(pdev, 0); } - mpuport[dev] = pnp_port_start(pdev, 0); - mpuirq[dev] = pnp_irq(pdev, 0); return 0; } #endif