diff options
Diffstat (limited to 'sound/isa/cmi8330.c')
-rw-r--r-- | sound/isa/cmi8330.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 115437957413..9ca8122f7ba2 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c | |||
@@ -31,11 +31,11 @@ | |||
31 | * To quickly load the module, | 31 | * To quickly load the module, |
32 | * | 32 | * |
33 | * modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1 | 33 | * modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1 |
34 | * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 | 34 | * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 fmport=0x388 |
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 AD1848 codec, | 38 | * The driver "magically" routes the capturing to the CMI8330 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 |
@@ -52,6 +52,7 @@ | |||
52 | #include <sound/core.h> | 52 | #include <sound/core.h> |
53 | #include <sound/wss.h> | 53 | #include <sound/wss.h> |
54 | #include <sound/opl3.h> | 54 | #include <sound/opl3.h> |
55 | #include <sound/mpu401.h> | ||
55 | #include <sound/sb.h> | 56 | #include <sound/sb.h> |
56 | #include <sound/initval.h> | 57 | #include <sound/initval.h> |
57 | 58 | ||
@@ -81,6 +82,8 @@ static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | |||
81 | static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | 82 | static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; |
82 | static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | 83 | static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; |
83 | static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 84 | static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
85 | static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
86 | static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
84 | 87 | ||
85 | module_param_array(index, int, NULL, 0444); | 88 | module_param_array(index, int, NULL, 0444); |
86 | MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); | 89 | MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); |
@@ -111,6 +114,10 @@ MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); | |||
111 | 114 | ||
112 | module_param_array(fmport, long, NULL, 0444); | 115 | module_param_array(fmport, long, NULL, 0444); |
113 | MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); | 116 | MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); |
117 | module_param_array(mpuport, long, NULL, 0444); | ||
118 | MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver."); | ||
119 | module_param_array(mpuirq, int, NULL, 0444); | ||
120 | MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port."); | ||
114 | #ifdef CONFIG_PNP | 121 | #ifdef CONFIG_PNP |
115 | static int isa_registered; | 122 | static int isa_registered; |
116 | static int pnp_registered; | 123 | static int pnp_registered; |
@@ -153,6 +160,7 @@ struct snd_cmi8330 { | |||
153 | #ifdef CONFIG_PNP | 160 | #ifdef CONFIG_PNP |
154 | struct pnp_dev *cap; | 161 | struct pnp_dev *cap; |
155 | struct pnp_dev *play; | 162 | struct pnp_dev *play; |
163 | struct pnp_dev *mpu; | ||
156 | #endif | 164 | #endif |
157 | struct snd_card *card; | 165 | struct snd_card *card; |
158 | struct snd_wss *wss; | 166 | struct snd_wss *wss; |
@@ -169,7 +177,7 @@ struct snd_cmi8330 { | |||
169 | #ifdef CONFIG_PNP | 177 | #ifdef CONFIG_PNP |
170 | 178 | ||
171 | static struct pnp_card_device_id snd_cmi8330_pnpids[] = { | 179 | static struct pnp_card_device_id snd_cmi8330_pnpids[] = { |
172 | { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" } } }, | 180 | { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, |
173 | { .id = "" } | 181 | { .id = "" } |
174 | }; | 182 | }; |
175 | 183 | ||
@@ -329,11 +337,15 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, | |||
329 | if (acard->play == NULL) | 337 | if (acard->play == NULL) |
330 | return -EBUSY; | 338 | return -EBUSY; |
331 | 339 | ||
340 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); | ||
341 | if (acard->play == NULL) | ||
342 | return -EBUSY; | ||
343 | |||
332 | pdev = acard->cap; | 344 | pdev = acard->cap; |
333 | 345 | ||
334 | err = pnp_activate_dev(pdev); | 346 | err = pnp_activate_dev(pdev); |
335 | if (err < 0) { | 347 | if (err < 0) { |
336 | snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); | 348 | snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n"); |
337 | return -EBUSY; | 349 | return -EBUSY; |
338 | } | 350 | } |
339 | wssport[dev] = pnp_port_start(pdev, 0); | 351 | wssport[dev] = pnp_port_start(pdev, 0); |
@@ -354,6 +366,17 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, | |||
354 | sbdma16[dev] = pnp_dma(pdev, 1); | 366 | sbdma16[dev] = pnp_dma(pdev, 1); |
355 | sbirq[dev] = pnp_irq(pdev, 0); | 367 | sbirq[dev] = pnp_irq(pdev, 0); |
356 | 368 | ||
369 | /* allocate MPU-401 resources */ | ||
370 | pdev = acard->mpu; | ||
371 | |||
372 | err = pnp_activate_dev(pdev); | ||
373 | if (err < 0) { | ||
374 | snd_printk(KERN_ERR | ||
375 | "CMI8330/C3D (MPU-401) PnP configure failure\n"); | ||
376 | return -EBUSY; | ||
377 | } | ||
378 | mpuport[dev] = pnp_port_start(pdev, 0); | ||
379 | mpuirq[dev] = pnp_irq(pdev, 0); | ||
357 | return 0; | 380 | return 0; |
358 | } | 381 | } |
359 | #endif | 382 | #endif |
@@ -502,11 +525,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) | |||
502 | wssdma[dev], -1, | 525 | wssdma[dev], -1, |
503 | WSS_HW_DETECT, 0, &acard->wss); | 526 | WSS_HW_DETECT, 0, &acard->wss); |
504 | if (err < 0) { | 527 | if (err < 0) { |
505 | snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); | 528 | snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n"); |
506 | return err; | 529 | return err; |
507 | } | 530 | } |
508 | if (acard->wss->hardware != WSS_HW_CMI8330) { | 531 | if (acard->wss->hardware != WSS_HW_CMI8330) { |
509 | snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); | 532 | snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n"); |
510 | return -ENODEV; | 533 | return -ENODEV; |
511 | } | 534 | } |
512 | 535 | ||
@@ -552,6 +575,13 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) | |||
552 | } | 575 | } |
553 | } | 576 | } |
554 | 577 | ||
578 | if (mpuport[dev] != SNDRV_AUTO_PORT) { | ||
579 | if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | ||
580 | mpuport[dev], 0, mpuirq[dev], | ||
581 | IRQF_DISABLED, NULL) < 0) | ||
582 | printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", | ||
583 | mpuport[dev]); | ||
584 | } | ||
555 | 585 | ||
556 | strcpy(card->driver, "CMI8330/C3D"); | 586 | strcpy(card->driver, "CMI8330/C3D"); |
557 | strcpy(card->shortname, "C-Media CMI8330/C3D"); | 587 | strcpy(card->shortname, "C-Media CMI8330/C3D"); |