diff options
| author | Takashi Iwai <tiwai@suse.de> | 2005-11-17 11:11:35 -0500 |
|---|---|---|
| committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:28:25 -0500 |
| commit | acdcbc15426b91b0041756a92ea4932c60def189 (patch) | |
| tree | 07116cab00cfa6e935187af677059a7f5b8fb139 /sound | |
| parent | 175cdcfb113e2a72f9d1a2ced4b80e0ff17fcaae (diff) | |
[ALSA] cmi8330 - Use platform_device, add PM support
Modules: CMI8330 driver
Rewrite the probe/remove with platform_device.
Also, add the PM support.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
| -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) |
