diff options
-rw-r--r-- | sound/isa/cmi8330.c | 241 |
1 files changed, 163 insertions, 78 deletions
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index cf160062beb0..ba0114ebafde 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c | |||
@@ -45,6 +45,8 @@ | |||
45 | 45 | ||
46 | #include <sound/driver.h> | 46 | #include <sound/driver.h> |
47 | #include <linux/init.h> | 47 | #include <linux/init.h> |
48 | #include <linux/err.h> | ||
49 | #include <linux/platform_device.h> | ||
48 | #include <linux/slab.h> | 50 | #include <linux/slab.h> |
49 | #include <linux/pnp.h> | 51 | #include <linux/pnp.h> |
50 | #include <linux/moduleparam.h> | 52 | #include <linux/moduleparam.h> |
@@ -156,8 +158,6 @@ struct snd_cmi8330 { | |||
156 | } streams[2]; | 158 | } streams[2]; |
157 | }; | 159 | }; |
158 | 160 | ||
159 | static struct snd_card *snd_cmi8330_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
160 | |||
161 | #ifdef CONFIG_PNP | 161 | #ifdef CONFIG_PNP |
162 | 162 | ||
163 | static struct pnp_card_device_id snd_cmi8330_pnpids[] = { | 163 | static struct pnp_card_device_id snd_cmi8330_pnpids[] = { |
@@ -429,6 +429,31 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 * | |||
429 | } | 429 | } |
430 | 430 | ||
431 | 431 | ||
432 | #ifdef CONFIG_PM | ||
433 | static int snd_cmi8330_suspend(struct snd_card *card) | ||
434 | { | ||
435 | struct snd_cmi8330 *acard = card->private_data; | ||
436 | |||
437 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
438 | snd_pcm_suspend_all(acard->pcm); | ||
439 | acard->wss->suspend(acard->wss); | ||
440 | snd_sbmixer_suspend(acard->sb); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int snd_cmi8330_resume(struct snd_card *card) | ||
445 | { | ||
446 | struct snd_cmi8330 *acard = card->private_data; | ||
447 | |||
448 | snd_sbdsp_reset(acard->sb); | ||
449 | snd_sbmixer_suspend(acard->sb); | ||
450 | acard->wss->resume(acard->wss); | ||
451 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
452 | return 0; | ||
453 | } | ||
454 | #endif | ||
455 | |||
456 | |||
432 | /* | 457 | /* |
433 | */ | 458 | */ |
434 | 459 | ||
@@ -440,44 +465,28 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 * | |||
440 | 465 | ||
441 | #define PFX "cmi8330: " | 466 | #define PFX "cmi8330: " |
442 | 467 | ||
443 | static int __devinit snd_cmi8330_probe(int dev, | 468 | static struct snd_card *snd_cmi8330_card_new(int dev) |
444 | struct pnp_card_link *pcard, | ||
445 | const struct pnp_card_device_id *pid) | ||
446 | { | 469 | { |
447 | struct snd_card *card; | 470 | struct snd_card *card; |
448 | struct snd_cmi8330 *acard; | 471 | struct snd_cmi8330 *acard; |
449 | int i, err; | ||
450 | |||
451 | if (! is_isapnp_selected(dev)) { | ||
452 | if (wssport[dev] == SNDRV_AUTO_PORT) { | ||
453 | snd_printk(KERN_ERR PFX "specify wssport\n"); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | if (sbport[dev] == SNDRV_AUTO_PORT) { | ||
457 | snd_printk(KERN_ERR PFX "specify sbport\n"); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | } | ||
461 | 472 | ||
462 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, | 473 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, |
463 | sizeof(struct snd_cmi8330)); | 474 | sizeof(struct snd_cmi8330)); |
464 | if (card == NULL) { | 475 | if (card == NULL) { |
465 | snd_printk(KERN_ERR PFX "could not get a new card\n"); | 476 | snd_printk(KERN_ERR PFX "could not get a new card\n"); |
466 | return -ENOMEM; | 477 | return NULL; |
467 | } | 478 | } |
468 | acard = (struct snd_cmi8330 *)card->private_data; | 479 | acard = card->private_data; |
469 | acard->card = card; | 480 | acard->card = card; |
481 | return card; | ||
482 | } | ||
470 | 483 | ||
471 | #ifdef CONFIG_PNP | 484 | static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) |
472 | if (isapnp[dev]) { | 485 | { |
473 | if ((err = snd_cmi8330_pnp(dev, acard, pcard, pid)) < 0) { | 486 | struct snd_cmi8330 *acard; |
474 | snd_printk(KERN_ERR PFX "PnP detection failed\n"); | 487 | int i, err; |
475 | goto _err; | ||
476 | } | ||
477 | snd_card_set_dev(card, &pcard->card->dev); | ||
478 | } | ||
479 | #endif | ||
480 | 488 | ||
489 | acard = card->private_data; | ||
481 | if ((err = snd_ad1848_create(card, | 490 | if ((err = snd_ad1848_create(card, |
482 | wssport[dev] + 4, | 491 | wssport[dev] + 4, |
483 | wssirq[dev], | 492 | wssirq[dev], |
@@ -485,12 +494,11 @@ static int __devinit snd_cmi8330_probe(int dev, | |||
485 | AD1848_HW_DETECT, | 494 | AD1848_HW_DETECT, |
486 | &acard->wss)) < 0) { | 495 | &acard->wss)) < 0) { |
487 | snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); | 496 | snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); |
488 | goto _err; | 497 | return err; |
489 | } | 498 | } |
490 | if (acard->wss->hardware != AD1848_HW_CMI8330) { | 499 | if (acard->wss->hardware != AD1848_HW_CMI8330) { |
491 | snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); | 500 | snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); |
492 | err = -ENODEV; | 501 | return -ENODEV; |
493 | goto _err; | ||
494 | } | 502 | } |
495 | 503 | ||
496 | if ((err = snd_sbdsp_create(card, sbport[dev], | 504 | if ((err = snd_sbdsp_create(card, sbport[dev], |
@@ -500,11 +508,11 @@ static int __devinit snd_cmi8330_probe(int dev, | |||
500 | sbdma16[dev], | 508 | sbdma16[dev], |
501 | SB_HW_AUTO, &acard->sb)) < 0) { | 509 | SB_HW_AUTO, &acard->sb)) < 0) { |
502 | snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); | 510 | snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); |
503 | goto _err; | 511 | return err; |
504 | } | 512 | } |
505 | if (acard->sb->hardware != SB_HW_16) { | 513 | if (acard->sb->hardware != SB_HW_16) { |
506 | snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); | 514 | snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); |
507 | goto _err; | 515 | return err; |
508 | } | 516 | } |
509 | 517 | ||
510 | snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */ | 518 | snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */ |
@@ -513,12 +521,12 @@ static int __devinit snd_cmi8330_probe(int dev, | |||
513 | 521 | ||
514 | if ((err = snd_cmi8330_mixer(card, acard)) < 0) { | 522 | if ((err = snd_cmi8330_mixer(card, acard)) < 0) { |
515 | snd_printk(KERN_ERR PFX "failed to create mixers\n"); | 523 | snd_printk(KERN_ERR PFX "failed to create mixers\n"); |
516 | goto _err; | 524 | return err; |
517 | } | 525 | } |
518 | 526 | ||
519 | if ((err = snd_cmi8330_pcm(card, acard)) < 0) { | 527 | if ((err = snd_cmi8330_pcm(card, acard)) < 0) { |
520 | snd_printk(KERN_ERR PFX "failed to create pcms\n"); | 528 | snd_printk(KERN_ERR PFX "failed to create pcms\n"); |
521 | goto _err; | 529 | return err; |
522 | } | 530 | } |
523 | 531 | ||
524 | strcpy(card->driver, "CMI8330/C3D"); | 532 | strcpy(card->driver, "CMI8330/C3D"); |
@@ -529,79 +537,162 @@ static int __devinit snd_cmi8330_probe(int dev, | |||
529 | wssirq[dev], | 537 | wssirq[dev], |
530 | wssdma[dev]); | 538 | wssdma[dev]); |
531 | 539 | ||
532 | if ((err = snd_card_set_generic_dev(card)) < 0) | 540 | return snd_card_register(card); |
533 | goto _err; | 541 | } |
542 | |||
543 | static int __init snd_cmi8330_nonpnp_probe(struct platform_device *pdev) | ||
544 | { | ||
545 | struct snd_card *card; | ||
546 | int err; | ||
547 | int dev = pdev->id; | ||
534 | 548 | ||
535 | if ((err = snd_card_register(card)) < 0) | 549 | if (wssport[dev] == SNDRV_AUTO_PORT) { |
536 | goto _err; | 550 | snd_printk(KERN_ERR PFX "specify wssport\n"); |
551 | return -EINVAL; | ||
552 | } | ||
553 | if (sbport[dev] == SNDRV_AUTO_PORT) { | ||
554 | snd_printk(KERN_ERR PFX "specify sbport\n"); | ||
555 | return -EINVAL; | ||
556 | } | ||
537 | 557 | ||
538 | if (pcard) | 558 | card = snd_cmi8330_card_new(dev); |
539 | pnp_set_card_drvdata(pcard, card); | 559 | if (! card) |
540 | else | 560 | return -ENOMEM; |
541 | snd_cmi8330_legacy[dev] = card; | 561 | snd_card_set_dev(card, &pdev->dev); |
562 | if ((err = snd_cmi8330_probe(card, dev)) < 0) { | ||
563 | snd_card_free(card); | ||
564 | return err; | ||
565 | } | ||
566 | platform_set_drvdata(pdev, card); | ||
542 | return 0; | 567 | return 0; |
568 | } | ||
569 | |||
570 | static int snd_cmi8330_nonpnp_remove(struct platform_device *devptr) | ||
571 | { | ||
572 | snd_card_free(platform_get_drvdata(devptr)); | ||
573 | platform_set_drvdata(devptr, NULL); | ||
574 | return 0; | ||
575 | } | ||
543 | 576 | ||
544 | _err: | 577 | #ifdef CONFIG_PM |
545 | snd_card_free(card); | 578 | static int snd_cmi8330_nonpnp_suspend(struct platform_device *dev, pm_message_t state) |
546 | return err; | 579 | { |
580 | return snd_cmi8330_suspend(platform_get_drvdata(dev)); | ||
547 | } | 581 | } |
548 | 582 | ||
583 | static int snd_cmi8330_nonpnp_resume(struct platform_device *dev) | ||
584 | { | ||
585 | return snd_cmi8330_resume(platform_get_drvdata(dev)); | ||
586 | } | ||
587 | #endif | ||
588 | |||
589 | #define CMI8330_DRIVER "snd_cmi8330" | ||
590 | |||
591 | static struct platform_driver snd_cmi8330_driver = { | ||
592 | .probe = snd_cmi8330_nonpnp_probe, | ||
593 | .remove = snd_cmi8330_nonpnp_remove, | ||
594 | #ifdef CONFIG_PM | ||
595 | .suspend = snd_cmi8330_nonpnp_suspend, | ||
596 | .resume = snd_cmi8330_nonpnp_resume, | ||
597 | #endif | ||
598 | .driver = { | ||
599 | .name = CMI8330_DRIVER | ||
600 | }, | ||
601 | }; | ||
602 | |||
603 | |||
549 | #ifdef CONFIG_PNP | 604 | #ifdef CONFIG_PNP |
550 | static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *card, | 605 | static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, |
551 | const struct pnp_card_device_id *id) | 606 | const struct pnp_card_device_id *pid) |
552 | { | 607 | { |
553 | static int dev; | 608 | static int dev; |
609 | struct snd_card *card; | ||
554 | int res; | 610 | int res; |
555 | 611 | ||
556 | for ( ; dev < SNDRV_CARDS; dev++) { | 612 | for ( ; dev < SNDRV_CARDS; dev++) { |
557 | if (!enable[dev] || !isapnp[dev]) | 613 | if (enable[dev] && isapnp[dev]) |
558 | continue; | 614 | break; |
559 | res = snd_cmi8330_probe(dev, card, id); | 615 | } |
560 | if (res < 0) | 616 | if (dev >= SNDRV_CARDS) |
561 | return res; | 617 | return -ENODEV; |
562 | dev++; | 618 | |
563 | return 0; | 619 | card = snd_cmi8330_card_new(dev); |
620 | if (! card) | ||
621 | return -ENOMEM; | ||
622 | if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) { | ||
623 | snd_printk(KERN_ERR PFX "PnP detection failed\n"); | ||
624 | snd_card_free(card); | ||
625 | return res; | ||
626 | } | ||
627 | snd_card_set_dev(card, &pcard->card->dev); | ||
628 | if ((res = snd_cmi8330_probe(card, dev)) < 0) { | ||
629 | snd_card_free(card); | ||
630 | return res; | ||
564 | } | 631 | } |
565 | return -ENODEV; | 632 | pnp_set_card_drvdata(pcard, card); |
633 | dev++; | ||
634 | return 0; | ||
566 | } | 635 | } |
567 | 636 | ||
568 | static void __devexit snd_cmi8330_pnp_remove(struct pnp_card_link * pcard) | 637 | static void __devexit snd_cmi8330_pnp_remove(struct pnp_card_link * pcard) |
569 | { | 638 | { |
570 | struct snd_card *card = (struct snd_card *) pnp_get_card_drvdata(pcard); | 639 | snd_card_free(pnp_get_card_drvdata(pcard)); |
640 | pnp_set_card_drvdata(pcard, NULL); | ||
641 | } | ||
571 | 642 | ||
572 | snd_card_disconnect(card); | 643 | #ifdef CONFIG_PM |
573 | snd_card_free_in_thread(card); | 644 | static int snd_cmi8330_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) |
645 | { | ||
646 | return snd_cmi8330_suspend(pnp_get_card_drvdata(pcard)); | ||
574 | } | 647 | } |
575 | 648 | ||
649 | static int snd_cmi8330_pnp_resume(struct pnp_card_link *pcard) | ||
650 | { | ||
651 | return snd_cmi8330_resume(pnp_get_card_drvdata(pcard)); | ||
652 | } | ||
653 | #endif | ||
654 | |||
576 | static struct pnp_card_driver cmi8330_pnpc_driver = { | 655 | static struct pnp_card_driver cmi8330_pnpc_driver = { |
577 | .flags = PNP_DRIVER_RES_DISABLE, | 656 | .flags = PNP_DRIVER_RES_DISABLE, |
578 | .name = "cmi8330", | 657 | .name = "cmi8330", |
579 | .id_table = snd_cmi8330_pnpids, | 658 | .id_table = snd_cmi8330_pnpids, |
580 | .probe = snd_cmi8330_pnp_detect, | 659 | .probe = snd_cmi8330_pnp_detect, |
581 | .remove = __devexit_p(snd_cmi8330_pnp_remove), | 660 | .remove = __devexit_p(snd_cmi8330_pnp_remove), |
661 | #ifdef CONFIG_PM | ||
662 | .suspend = snd_cmi8330_pnp_suspend, | ||
663 | .resume = snd_cmi8330_pnp_resume, | ||
664 | #endif | ||
582 | }; | 665 | }; |
583 | #endif /* CONFIG_PNP */ | 666 | #endif /* CONFIG_PNP */ |
584 | 667 | ||
585 | static int __init alsa_card_cmi8330_init(void) | 668 | static int __init alsa_card_cmi8330_init(void) |
586 | { | 669 | { |
587 | int dev, cards = 0; | 670 | int i, err, cards = 0; |
588 | 671 | ||
589 | for (dev = 0; dev < SNDRV_CARDS; dev++) { | 672 | if ((err = platform_driver_register(&snd_cmi8330_driver)) < 0) |
590 | if (!enable[dev]) | 673 | return err; |
591 | continue; | 674 | |
592 | if (is_isapnp_selected(dev)) | 675 | for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { |
676 | struct platform_device *device; | ||
677 | if (is_isapnp_selected(i)) | ||
593 | continue; | 678 | continue; |
594 | if (snd_cmi8330_probe(dev, NULL, NULL) >= 0) | 679 | device = platform_device_register_simple(CMI8330_DRIVER, |
595 | cards++; | 680 | i, NULL, 0); |
681 | if (IS_ERR(device)) { | ||
682 | err = PTR_ERR(device); | ||
683 | platform_driver_unregister(&snd_cmi8330_driver); | ||
684 | return err; | ||
685 | } | ||
686 | cards++; | ||
596 | } | 687 | } |
597 | #ifdef CONFIG_PNP | 688 | |
598 | cards += pnp_register_card_driver(&cmi8330_pnpc_driver); | 689 | err = pnp_register_card_driver(&cmi8330_pnpc_driver); |
599 | #endif | 690 | if (err > 0) |
691 | cards += err; | ||
600 | 692 | ||
601 | if (!cards) { | 693 | if (!cards) { |
602 | #ifdef CONFIG_PNP | ||
603 | pnp_unregister_card_driver(&cmi8330_pnpc_driver); | 694 | pnp_unregister_card_driver(&cmi8330_pnpc_driver); |
604 | #endif | 695 | platform_driver_unregister(&snd_cmi8330_driver); |
605 | #ifdef MODULE | 696 | #ifdef MODULE |
606 | snd_printk(KERN_ERR "CMI8330 not found or device busy\n"); | 697 | snd_printk(KERN_ERR "CMI8330 not found or device busy\n"); |
607 | #endif | 698 | #endif |
@@ -612,14 +703,8 @@ static int __init alsa_card_cmi8330_init(void) | |||
612 | 703 | ||
613 | static void __exit alsa_card_cmi8330_exit(void) | 704 | static void __exit alsa_card_cmi8330_exit(void) |
614 | { | 705 | { |
615 | int i; | ||
616 | |||
617 | #ifdef CONFIG_PNP | ||
618 | /* PnP cards first */ | ||
619 | pnp_unregister_card_driver(&cmi8330_pnpc_driver); | 706 | pnp_unregister_card_driver(&cmi8330_pnpc_driver); |
620 | #endif | 707 | platform_driver_unregister(&snd_cmi8330_driver); |
621 | for (i = 0; i < SNDRV_CARDS; i++) | ||
622 | snd_card_free(snd_cmi8330_legacy[i]); | ||
623 | } | 708 | } |
624 | 709 | ||
625 | module_init(alsa_card_cmi8330_init) | 710 | module_init(alsa_card_cmi8330_init) |