diff options
Diffstat (limited to 'sound/isa/sb/sb16.c')
-rw-r--r-- | sound/isa/sb/sb16.c | 369 |
1 files changed, 234 insertions, 135 deletions
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index c2fa451bc8f0..c0be7a5a3425 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/pnp.h> | 26 | #include <linux/pnp.h> |
27 | #include <linux/err.h> | ||
28 | #include <linux/platform_device.h> | ||
27 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
28 | #include <sound/core.h> | 30 | #include <sound/core.h> |
29 | #include <sound/sb.h> | 31 | #include <sound/sb.h> |
@@ -32,7 +34,6 @@ | |||
32 | #include <sound/opl3.h> | 34 | #include <sound/opl3.h> |
33 | #include <sound/emu8000.h> | 35 | #include <sound/emu8000.h> |
34 | #include <sound/seq_device.h> | 36 | #include <sound/seq_device.h> |
35 | #define SNDRV_LEGACY_AUTO_PROBE | ||
36 | #define SNDRV_LEGACY_FIND_FREE_IRQ | 37 | #define SNDRV_LEGACY_FIND_FREE_IRQ |
37 | #define SNDRV_LEGACY_FIND_FREE_DMA | 38 | #define SNDRV_LEGACY_FIND_FREE_DMA |
38 | #include <sound/initval.h> | 39 | #include <sound/initval.h> |
@@ -127,8 +128,14 @@ module_param_array(seq_ports, int, NULL, 0444); | |||
127 | MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth."); | 128 | MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth."); |
128 | #endif | 129 | #endif |
129 | 130 | ||
131 | static struct platform_device *platform_devices[SNDRV_CARDS]; | ||
132 | #ifdef CONFIG_PNP | ||
133 | static int pnp_registered; | ||
134 | #endif | ||
135 | |||
130 | struct snd_card_sb16 { | 136 | struct snd_card_sb16 { |
131 | struct resource *fm_res; /* used to block FM i/o region for legacy cards */ | 137 | struct resource *fm_res; /* used to block FM i/o region for legacy cards */ |
138 | struct snd_sb *chip; | ||
132 | #ifdef CONFIG_PNP | 139 | #ifdef CONFIG_PNP |
133 | int dev_no; | 140 | int dev_no; |
134 | struct pnp_dev *dev; | 141 | struct pnp_dev *dev; |
@@ -138,8 +145,6 @@ struct snd_card_sb16 { | |||
138 | #endif | 145 | #endif |
139 | }; | 146 | }; |
140 | 147 | ||
141 | static snd_card_t *snd_sb16_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
142 | |||
143 | #ifdef CONFIG_PNP | 148 | #ifdef CONFIG_PNP |
144 | 149 | ||
145 | static struct pnp_card_device_id snd_sb16_pnpids[] = { | 150 | static struct pnp_card_device_id snd_sb16_pnpids[] = { |
@@ -339,9 +344,9 @@ __wt_error: | |||
339 | 344 | ||
340 | #endif /* CONFIG_PNP */ | 345 | #endif /* CONFIG_PNP */ |
341 | 346 | ||
342 | static void snd_sb16_free(snd_card_t *card) | 347 | static void snd_sb16_free(struct snd_card *card) |
343 | { | 348 | { |
344 | struct snd_card_sb16 *acard = (struct snd_card_sb16 *)card->private_data; | 349 | struct snd_card_sb16 *acard = card->private_data; |
345 | 350 | ||
346 | if (acard == NULL) | 351 | if (acard == NULL) |
347 | return; | 352 | return; |
@@ -354,73 +359,32 @@ static void snd_sb16_free(snd_card_t *card) | |||
354 | #define is_isapnp_selected(dev) 0 | 359 | #define is_isapnp_selected(dev) 0 |
355 | #endif | 360 | #endif |
356 | 361 | ||
357 | static int __init snd_sb16_probe(int dev, | 362 | static struct snd_card *snd_sb16_card_new(int dev) |
358 | struct pnp_card_link *pcard, | 363 | { |
359 | const struct pnp_card_device_id *pid) | 364 | struct snd_card *card = snd_card_new(index[dev], id[dev], THIS_MODULE, |
365 | sizeof(struct snd_card_sb16)); | ||
366 | if (card == NULL) | ||
367 | return NULL; | ||
368 | card->private_free = snd_sb16_free; | ||
369 | return card; | ||
370 | } | ||
371 | |||
372 | static int __init snd_sb16_probe(struct snd_card *card, int dev) | ||
360 | { | 373 | { |
361 | static int possible_irqs[] = {5, 9, 10, 7, -1}; | ||
362 | static int possible_dmas8[] = {1, 3, 0, -1}; | ||
363 | static int possible_dmas16[] = {5, 6, 7, -1}; | ||
364 | int xirq, xdma8, xdma16; | 374 | int xirq, xdma8, xdma16; |
365 | sb_t *chip; | 375 | struct snd_sb *chip; |
366 | snd_card_t *card; | 376 | struct snd_card_sb16 *acard = card->private_data; |
367 | struct snd_card_sb16 *acard; | 377 | struct snd_opl3 *opl3; |
368 | opl3_t *opl3; | 378 | struct snd_hwdep *synth = NULL; |
369 | snd_hwdep_t *synth = NULL; | ||
370 | #ifdef CONFIG_SND_SB16_CSP | 379 | #ifdef CONFIG_SND_SB16_CSP |
371 | snd_hwdep_t *xcsp = NULL; | 380 | struct snd_hwdep *xcsp = NULL; |
372 | #endif | 381 | #endif |
373 | unsigned long flags; | 382 | unsigned long flags; |
374 | int err; | 383 | int err; |
375 | 384 | ||
376 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, | ||
377 | sizeof(struct snd_card_sb16)); | ||
378 | if (card == NULL) | ||
379 | return -ENOMEM; | ||
380 | acard = (struct snd_card_sb16 *) card->private_data; | ||
381 | card->private_free = snd_sb16_free; | ||
382 | #ifdef CONFIG_PNP | ||
383 | if (isapnp[dev]) { | ||
384 | if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) | ||
385 | goto _err; | ||
386 | snd_card_set_dev(card, &pcard->card->dev); | ||
387 | } | ||
388 | #endif | ||
389 | |||
390 | xirq = irq[dev]; | 385 | xirq = irq[dev]; |
391 | xdma8 = dma8[dev]; | 386 | xdma8 = dma8[dev]; |
392 | xdma16 = dma16[dev]; | 387 | xdma16 = dma16[dev]; |
393 | if (! is_isapnp_selected(dev)) { | ||
394 | if (xirq == SNDRV_AUTO_IRQ) { | ||
395 | if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { | ||
396 | snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); | ||
397 | err = -EBUSY; | ||
398 | goto _err; | ||
399 | } | ||
400 | } | ||
401 | if (xdma8 == SNDRV_AUTO_DMA) { | ||
402 | if ((xdma8 = snd_legacy_find_free_dma(possible_dmas8)) < 0) { | ||
403 | snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); | ||
404 | err = -EBUSY; | ||
405 | goto _err; | ||
406 | } | ||
407 | } | ||
408 | if (xdma16 == SNDRV_AUTO_DMA) { | ||
409 | if ((xdma16 = snd_legacy_find_free_dma(possible_dmas16)) < 0) { | ||
410 | snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); | ||
411 | err = -EBUSY; | ||
412 | goto _err; | ||
413 | } | ||
414 | } | ||
415 | /* non-PnP FM port address is hardwired with base port address */ | ||
416 | fm_port[dev] = port[dev]; | ||
417 | /* block the 0x388 port to avoid PnP conflicts */ | ||
418 | acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); | ||
419 | #ifdef SNDRV_SBAWE_EMU8000 | ||
420 | /* non-PnP AWE port address is hardwired with base port address */ | ||
421 | awe_port[dev] = port[dev] + 0x400; | ||
422 | #endif | ||
423 | } | ||
424 | 388 | ||
425 | if ((err = snd_sbdsp_create(card, | 389 | if ((err = snd_sbdsp_create(card, |
426 | port[dev], | 390 | port[dev], |
@@ -430,19 +394,19 @@ static int __init snd_sb16_probe(int dev, | |||
430 | xdma16, | 394 | xdma16, |
431 | SB_HW_AUTO, | 395 | SB_HW_AUTO, |
432 | &chip)) < 0) | 396 | &chip)) < 0) |
433 | goto _err; | 397 | return err; |
434 | 398 | ||
399 | acard->chip = chip; | ||
435 | if (chip->hardware != SB_HW_16) { | 400 | if (chip->hardware != SB_HW_16) { |
436 | snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]); | 401 | snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]); |
437 | err = -ENODEV; | 402 | return -ENODEV; |
438 | goto _err; | ||
439 | } | 403 | } |
440 | chip->mpu_port = mpu_port[dev]; | 404 | chip->mpu_port = mpu_port[dev]; |
441 | if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) | 405 | if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) |
442 | goto _err; | 406 | return err; |
443 | 407 | ||
444 | if ((err = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) | 408 | if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) |
445 | goto _err; | 409 | return err; |
446 | 410 | ||
447 | strcpy(card->driver, | 411 | strcpy(card->driver, |
448 | #ifdef SNDRV_SBAWE_EMU8000 | 412 | #ifdef SNDRV_SBAWE_EMU8000 |
@@ -464,7 +428,7 @@ static int __init snd_sb16_probe(int dev, | |||
464 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, | 428 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, |
465 | chip->mpu_port, 0, | 429 | chip->mpu_port, 0, |
466 | xirq, 0, &chip->rmidi)) < 0) | 430 | xirq, 0, &chip->rmidi)) < 0) |
467 | goto _err; | 431 | return err; |
468 | chip->rmidi_callback = snd_mpu401_uart_interrupt; | 432 | chip->rmidi_callback = snd_mpu401_uart_interrupt; |
469 | } | 433 | } |
470 | 434 | ||
@@ -487,12 +451,12 @@ static int __init snd_sb16_probe(int dev, | |||
487 | int seqdev = 1; | 451 | int seqdev = 1; |
488 | #endif | 452 | #endif |
489 | if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) | 453 | if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) |
490 | goto _err; | 454 | return err; |
491 | } | 455 | } |
492 | } | 456 | } |
493 | 457 | ||
494 | if ((err = snd_sbmixer_new(chip)) < 0) | 458 | if ((err = snd_sbmixer_new(chip)) < 0) |
495 | goto _err; | 459 | return err; |
496 | 460 | ||
497 | #ifdef CONFIG_SND_SB16_CSP | 461 | #ifdef CONFIG_SND_SB16_CSP |
498 | /* CSP chip on SB16ASP/AWE32 */ | 462 | /* CSP chip on SB16ASP/AWE32 */ |
@@ -512,7 +476,7 @@ static int __init snd_sb16_probe(int dev, | |||
512 | seq_ports[dev], NULL)) < 0) { | 476 | seq_ports[dev], NULL)) < 0) { |
513 | snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]); | 477 | snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]); |
514 | 478 | ||
515 | goto _err; | 479 | return err; |
516 | } | 480 | } |
517 | } | 481 | } |
518 | #endif | 482 | #endif |
@@ -524,56 +488,168 @@ static int __init snd_sb16_probe(int dev, | |||
524 | (mic_agc[dev] ? 0x00 : 0x01)); | 488 | (mic_agc[dev] ? 0x00 : 0x01)); |
525 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | 489 | spin_unlock_irqrestore(&chip->mixer_lock, flags); |
526 | 490 | ||
527 | if ((err = snd_card_set_generic_dev(card)) < 0) | ||
528 | goto _err; | ||
529 | |||
530 | if ((err = snd_card_register(card)) < 0) | 491 | if ((err = snd_card_register(card)) < 0) |
531 | goto _err; | 492 | return err; |
532 | 493 | ||
533 | if (pcard) | ||
534 | pnp_set_card_drvdata(pcard, card); | ||
535 | else | ||
536 | snd_sb16_legacy[dev] = card; | ||
537 | return 0; | 494 | return 0; |
495 | } | ||
538 | 496 | ||
539 | _err: | 497 | #ifdef CONFIG_PM |
540 | snd_card_free(card); | 498 | static int snd_sb16_suspend(struct snd_card *card, pm_message_t state) |
541 | return err; | 499 | { |
500 | struct snd_card_sb16 *acard = card->private_data; | ||
501 | struct snd_sb *chip = acard->chip; | ||
502 | |||
503 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
504 | snd_pcm_suspend_all(chip->pcm); | ||
505 | snd_sbmixer_suspend(chip); | ||
506 | return 0; | ||
542 | } | 507 | } |
543 | 508 | ||
544 | static int __init snd_sb16_probe_legacy_port(unsigned long xport) | 509 | static int snd_sb16_resume(struct snd_card *card) |
545 | { | 510 | { |
546 | static int dev; | 511 | struct snd_card_sb16 *acard = card->private_data; |
547 | int res; | 512 | struct snd_sb *chip = acard->chip; |
548 | 513 | ||
549 | for ( ; dev < SNDRV_CARDS; dev++) { | 514 | snd_sbdsp_reset(chip); |
550 | if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT) | 515 | snd_sbmixer_resume(chip); |
551 | continue; | 516 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
552 | if (is_isapnp_selected(dev)) | 517 | return 0; |
553 | continue; | 518 | } |
554 | port[dev] = xport; | 519 | #endif |
555 | res = snd_sb16_probe(dev, NULL, NULL); | 520 | |
556 | if (res < 0) | 521 | static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr) |
557 | port[dev] = SNDRV_AUTO_PORT; | 522 | { |
558 | return res; | 523 | struct snd_card_sb16 *acard; |
524 | struct snd_card *card; | ||
525 | int err; | ||
526 | |||
527 | card = snd_sb16_card_new(dev); | ||
528 | if (! card) | ||
529 | return -ENOMEM; | ||
530 | |||
531 | acard = card->private_data; | ||
532 | /* non-PnP FM port address is hardwired with base port address */ | ||
533 | fm_port[dev] = port[dev]; | ||
534 | /* block the 0x388 port to avoid PnP conflicts */ | ||
535 | acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); | ||
536 | #ifdef SNDRV_SBAWE_EMU8000 | ||
537 | /* non-PnP AWE port address is hardwired with base port address */ | ||
538 | awe_port[dev] = port[dev] + 0x400; | ||
539 | #endif | ||
540 | |||
541 | snd_card_set_dev(card, &devptr->dev); | ||
542 | if ((err = snd_sb16_probe(card, dev)) < 0) { | ||
543 | snd_card_free(card); | ||
544 | return err; | ||
559 | } | 545 | } |
560 | return -ENODEV; | 546 | platform_set_drvdata(devptr, card); |
547 | return 0; | ||
561 | } | 548 | } |
562 | 549 | ||
550 | |||
551 | static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev) | ||
552 | { | ||
553 | int dev = pdev->id; | ||
554 | int err; | ||
555 | static int possible_irqs[] = {5, 9, 10, 7, -1}; | ||
556 | static int possible_dmas8[] = {1, 3, 0, -1}; | ||
557 | static int possible_dmas16[] = {5, 6, 7, -1}; | ||
558 | |||
559 | if (irq[dev] == SNDRV_AUTO_IRQ) { | ||
560 | if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) { | ||
561 | snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); | ||
562 | return -EBUSY; | ||
563 | } | ||
564 | } | ||
565 | if (dma8[dev] == SNDRV_AUTO_DMA) { | ||
566 | if ((dma8[dev] = snd_legacy_find_free_dma(possible_dmas8)) < 0) { | ||
567 | snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); | ||
568 | return -EBUSY; | ||
569 | } | ||
570 | } | ||
571 | if (dma16[dev] == SNDRV_AUTO_DMA) { | ||
572 | if ((dma16[dev] = snd_legacy_find_free_dma(possible_dmas16)) < 0) { | ||
573 | snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); | ||
574 | return -EBUSY; | ||
575 | } | ||
576 | } | ||
577 | |||
578 | if (port[dev] != SNDRV_AUTO_PORT) | ||
579 | return snd_sb16_nonpnp_probe1(dev, pdev); | ||
580 | else { | ||
581 | static int possible_ports[] = {0x220, 0x240, 0x260, 0x280}; | ||
582 | int i; | ||
583 | for (i = 0; i < ARRAY_SIZE(possible_ports); i++) { | ||
584 | port[dev] = possible_ports[i]; | ||
585 | err = snd_sb16_nonpnp_probe1(dev, pdev); | ||
586 | if (! err) | ||
587 | return 0; | ||
588 | } | ||
589 | return err; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | static int __devexit snd_sb16_nonpnp_remove(struct platform_device *devptr) | ||
594 | { | ||
595 | snd_card_free(platform_get_drvdata(devptr)); | ||
596 | platform_set_drvdata(devptr, NULL); | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | #ifdef CONFIG_PM | ||
601 | static int snd_sb16_nonpnp_suspend(struct platform_device *dev, pm_message_t state) | ||
602 | { | ||
603 | return snd_sb16_suspend(platform_get_drvdata(dev), state); | ||
604 | } | ||
605 | |||
606 | static int snd_sb16_nonpnp_resume(struct platform_device *dev) | ||
607 | { | ||
608 | return snd_sb16_resume(platform_get_drvdata(dev)); | ||
609 | } | ||
610 | #endif | ||
611 | |||
612 | #ifdef SNDRV_SBAWE | ||
613 | #define SND_SB16_DRIVER "snd_sbawe" | ||
614 | #else | ||
615 | #define SND_SB16_DRIVER "snd_sb16" | ||
616 | #endif | ||
617 | |||
618 | static struct platform_driver snd_sb16_nonpnp_driver = { | ||
619 | .probe = snd_sb16_nonpnp_probe, | ||
620 | .remove = __devexit_p(snd_sb16_nonpnp_remove), | ||
621 | #ifdef CONFIG_PM | ||
622 | .suspend = snd_sb16_nonpnp_suspend, | ||
623 | .resume = snd_sb16_nonpnp_resume, | ||
624 | #endif | ||
625 | .driver = { | ||
626 | .name = SND_SB16_DRIVER | ||
627 | }, | ||
628 | }; | ||
629 | |||
630 | |||
563 | #ifdef CONFIG_PNP | 631 | #ifdef CONFIG_PNP |
564 | 632 | ||
565 | static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *card, | 633 | static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, |
566 | const struct pnp_card_device_id *id) | 634 | const struct pnp_card_device_id *pid) |
567 | { | 635 | { |
568 | static int dev; | 636 | static int dev; |
637 | struct snd_card *card; | ||
569 | int res; | 638 | int res; |
570 | 639 | ||
571 | for ( ; dev < SNDRV_CARDS; dev++) { | 640 | for ( ; dev < SNDRV_CARDS; dev++) { |
572 | if (!enable[dev] || !isapnp[dev]) | 641 | if (!enable[dev] || !isapnp[dev]) |
573 | continue; | 642 | continue; |
574 | res = snd_sb16_probe(dev, card, id); | 643 | card = snd_sb16_card_new(dev); |
575 | if (res < 0) | 644 | if (! card) |
645 | return -ENOMEM; | ||
646 | snd_card_set_dev(card, &pcard->card->dev); | ||
647 | if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 || | ||
648 | (res = snd_sb16_probe(card, dev)) < 0) { | ||
649 | snd_card_free(card); | ||
576 | return res; | 650 | return res; |
651 | } | ||
652 | pnp_set_card_drvdata(pcard, card); | ||
577 | dev++; | 653 | dev++; |
578 | return 0; | 654 | return 0; |
579 | } | 655 | } |
@@ -583,57 +659,82 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *card, | |||
583 | 659 | ||
584 | static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard) | 660 | static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard) |
585 | { | 661 | { |
586 | snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard); | 662 | snd_card_free(pnp_get_card_drvdata(pcard)); |
663 | pnp_set_card_drvdata(pcard, NULL); | ||
664 | } | ||
587 | 665 | ||
588 | snd_card_disconnect(card); | 666 | #ifdef CONFIG_PM |
589 | snd_card_free_in_thread(card); | 667 | static int snd_sb16_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) |
668 | { | ||
669 | return snd_sb16_suspend(pnp_get_card_drvdata(pcard), state); | ||
590 | } | 670 | } |
671 | static int snd_sb16_pnp_resume(struct pnp_card_link *pcard) | ||
672 | { | ||
673 | return snd_sb16_resume(pnp_get_card_drvdata(pcard)); | ||
674 | } | ||
675 | #endif | ||
591 | 676 | ||
592 | static struct pnp_card_driver sb16_pnpc_driver = { | 677 | static struct pnp_card_driver sb16_pnpc_driver = { |
593 | .flags = PNP_DRIVER_RES_DISABLE, | 678 | .flags = PNP_DRIVER_RES_DISABLE, |
679 | #ifdef SNDRV_SBAWE | ||
680 | .name = "sbawe", | ||
681 | #else | ||
594 | .name = "sb16", | 682 | .name = "sb16", |
683 | #endif | ||
595 | .id_table = snd_sb16_pnpids, | 684 | .id_table = snd_sb16_pnpids, |
596 | .probe = snd_sb16_pnp_detect, | 685 | .probe = snd_sb16_pnp_detect, |
597 | .remove = __devexit_p(snd_sb16_pnp_remove), | 686 | .remove = __devexit_p(snd_sb16_pnp_remove), |
687 | #ifdef CONFIG_PM | ||
688 | .suspend = snd_sb16_pnp_suspend, | ||
689 | .resume = snd_sb16_pnp_resume, | ||
690 | #endif | ||
598 | }; | 691 | }; |
599 | 692 | ||
600 | #endif /* CONFIG_PNP */ | 693 | #endif /* CONFIG_PNP */ |
601 | 694 | ||
695 | static void __init_or_module snd_sb16_unregister_all(void) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | #ifdef CONFIG_PNP | ||
700 | if (pnp_registered) | ||
701 | pnp_unregister_card_driver(&sb16_pnpc_driver); | ||
702 | #endif | ||
703 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) | ||
704 | platform_device_unregister(platform_devices[i]); | ||
705 | platform_driver_unregister(&snd_sb16_nonpnp_driver); | ||
706 | } | ||
707 | |||
602 | static int __init alsa_card_sb16_init(void) | 708 | static int __init alsa_card_sb16_init(void) |
603 | { | 709 | { |
604 | int dev, cards = 0, i; | 710 | int i, err, cards = 0; |
605 | static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280, -1}; | ||
606 | 711 | ||
607 | /* legacy non-auto cards at first */ | 712 | if ((err = platform_driver_register(&snd_sb16_nonpnp_driver)) < 0) |
608 | for (dev = 0; dev < SNDRV_CARDS; dev++) { | 713 | return err; |
609 | if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT) | 714 | |
610 | continue; | 715 | for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { |
611 | if (is_isapnp_selected(dev)) | 716 | struct platform_device *device; |
612 | continue; | 717 | if (is_isapnp_selected(i)) |
613 | if (!snd_sb16_probe(dev, NULL, NULL)) { | ||
614 | cards++; | ||
615 | continue; | 718 | continue; |
719 | device = platform_device_register_simple(SND_SB16_DRIVER, | ||
720 | i, NULL, 0); | ||
721 | if (IS_ERR(device)) { | ||
722 | err = PTR_ERR(device); | ||
723 | goto errout; | ||
616 | } | 724 | } |
617 | #ifdef MODULE | 725 | platform_devices[i] = device; |
618 | snd_printk(KERN_ERR "Sound Blaster 16+ soundcard #%i not found at 0x%lx or device busy\n", dev, port[dev]); | 726 | cards++; |
619 | #endif | ||
620 | } | 727 | } |
621 | /* legacy auto configured cards */ | ||
622 | i = snd_legacy_auto_probe(possible_ports, snd_sb16_probe_legacy_port); | ||
623 | if (i > 0) | ||
624 | cards += i; | ||
625 | |||
626 | #ifdef CONFIG_PNP | 728 | #ifdef CONFIG_PNP |
627 | /* PnP cards at last */ | 729 | /* PnP cards at last */ |
628 | i = pnp_register_card_driver(&sb16_pnpc_driver); | 730 | i = pnp_register_card_driver(&sb16_pnpc_driver); |
629 | if (i >0) | 731 | if (i >= 0) { |
732 | pnp_registered = 1; | ||
630 | cards += i; | 733 | cards += i; |
734 | } | ||
631 | #endif | 735 | #endif |
632 | 736 | ||
633 | if (!cards) { | 737 | if (!cards) { |
634 | #ifdef CONFIG_PNP | ||
635 | pnp_unregister_card_driver(&sb16_pnpc_driver); | ||
636 | #endif | ||
637 | #ifdef MODULE | 738 | #ifdef MODULE |
638 | snd_printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n"); | 739 | snd_printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n"); |
639 | #ifdef SNDRV_SBAWE_EMU8000 | 740 | #ifdef SNDRV_SBAWE_EMU8000 |
@@ -642,21 +743,19 @@ static int __init alsa_card_sb16_init(void) | |||
642 | snd_printk(KERN_ERR "In case, if you have AWE card, try snd-sbawe module\n"); | 743 | snd_printk(KERN_ERR "In case, if you have AWE card, try snd-sbawe module\n"); |
643 | #endif | 744 | #endif |
644 | #endif | 745 | #endif |
645 | return -ENODEV; | 746 | err = -ENODEV; |
747 | goto errout; | ||
646 | } | 748 | } |
647 | return 0; | 749 | return 0; |
750 | |||
751 | errout: | ||
752 | snd_sb16_unregister_all(); | ||
753 | return err; | ||
648 | } | 754 | } |
649 | 755 | ||
650 | static void __exit alsa_card_sb16_exit(void) | 756 | static void __exit alsa_card_sb16_exit(void) |
651 | { | 757 | { |
652 | int dev; | 758 | snd_sb16_unregister_all(); |
653 | |||
654 | #ifdef CONFIG_PNP | ||
655 | /* PnP cards first */ | ||
656 | pnp_unregister_card_driver(&sb16_pnpc_driver); | ||
657 | #endif | ||
658 | for (dev = 0; dev < SNDRV_CARDS; dev++) | ||
659 | snd_card_free(snd_sb16_legacy[dev]); | ||
660 | } | 759 | } |
661 | 760 | ||
662 | module_init(alsa_card_sb16_init) | 761 | module_init(alsa_card_sb16_init) |