diff options
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/dummy.c | 106 |
1 files changed, 80 insertions, 26 deletions
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 9c827b154458..a276f7c80360 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #include <sound/driver.h> | 21 | #include <sound/driver.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/err.h> | ||
24 | #include <linux/platform_device.h> | ||
23 | #include <linux/jiffies.h> | 25 | #include <linux/jiffies.h> |
24 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 27 | #include <linux/time.h> |
@@ -151,6 +153,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); | |||
151 | 153 | ||
152 | struct snd_dummy { | 154 | struct snd_dummy { |
153 | struct snd_card *card; | 155 | struct snd_card *card; |
156 | struct snd_pcm *pcm; | ||
154 | spinlock_t mixer_lock; | 157 | spinlock_t mixer_lock; |
155 | int mixer_volume[MIXER_ADDR_LAST+1][2]; | 158 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
156 | int capture_source[MIXER_ADDR_LAST+1][2]; | 159 | int capture_source[MIXER_ADDR_LAST+1][2]; |
@@ -169,8 +172,6 @@ struct snd_dummy_pcm { | |||
169 | struct snd_pcm_substream *substream; | 172 | struct snd_pcm_substream *substream; |
170 | }; | 173 | }; |
171 | 174 | ||
172 | static struct snd_card *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
173 | |||
174 | 175 | ||
175 | static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm) | 176 | static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm) |
176 | { | 177 | { |
@@ -190,15 +191,21 @@ static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int c | |||
190 | int err = 0; | 191 | int err = 0; |
191 | 192 | ||
192 | spin_lock(&dpcm->lock); | 193 | spin_lock(&dpcm->lock); |
193 | if (cmd == SNDRV_PCM_TRIGGER_START) { | 194 | switch (cmd) { |
195 | case SNDRV_PCM_TRIGGER_START: | ||
196 | case SNDRV_PCM_TRIGGER_RESUME: | ||
194 | snd_card_dummy_pcm_timer_start(dpcm); | 197 | snd_card_dummy_pcm_timer_start(dpcm); |
195 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { | 198 | break; |
199 | case SNDRV_PCM_TRIGGER_STOP: | ||
200 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
196 | snd_card_dummy_pcm_timer_stop(dpcm); | 201 | snd_card_dummy_pcm_timer_stop(dpcm); |
197 | } else { | 202 | break; |
203 | default: | ||
198 | err = -EINVAL; | 204 | err = -EINVAL; |
205 | break; | ||
199 | } | 206 | } |
200 | spin_unlock(&dpcm->lock); | 207 | spin_unlock(&dpcm->lock); |
201 | return err; | 208 | return 0; |
202 | } | 209 | } |
203 | 210 | ||
204 | static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) | 211 | static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) |
@@ -251,7 +258,7 @@ static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *su | |||
251 | static struct snd_pcm_hardware snd_card_dummy_playback = | 258 | static struct snd_pcm_hardware snd_card_dummy_playback = |
252 | { | 259 | { |
253 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 260 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
254 | SNDRV_PCM_INFO_MMAP_VALID), | 261 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
255 | .formats = USE_FORMATS, | 262 | .formats = USE_FORMATS, |
256 | .rates = USE_RATE, | 263 | .rates = USE_RATE, |
257 | .rate_min = USE_RATE_MIN, | 264 | .rate_min = USE_RATE_MIN, |
@@ -269,7 +276,7 @@ static struct snd_pcm_hardware snd_card_dummy_playback = | |||
269 | static struct snd_pcm_hardware snd_card_dummy_capture = | 276 | static struct snd_pcm_hardware snd_card_dummy_capture = |
270 | { | 277 | { |
271 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 278 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
272 | SNDRV_PCM_INFO_MMAP_VALID), | 279 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
273 | .formats = USE_FORMATS, | 280 | .formats = USE_FORMATS, |
274 | .rates = USE_RATE, | 281 | .rates = USE_RATE, |
275 | .rate_min = USE_RATE_MIN, | 282 | .rate_min = USE_RATE_MIN, |
@@ -405,6 +412,7 @@ static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int su | |||
405 | if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, | 412 | if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, |
406 | substreams, substreams, &pcm)) < 0) | 413 | substreams, substreams, &pcm)) < 0) |
407 | return err; | 414 | return err; |
415 | dummy->pcm = pcm; | ||
408 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops); | 416 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops); |
409 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); | 417 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); |
410 | pcm->private_data = dummy; | 418 | pcm->private_data = dummy; |
@@ -547,14 +555,13 @@ static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) | |||
547 | return 0; | 555 | return 0; |
548 | } | 556 | } |
549 | 557 | ||
550 | static int __init snd_card_dummy_probe(int dev) | 558 | static int __init snd_dummy_probe(struct platform_device *devptr) |
551 | { | 559 | { |
552 | struct snd_card *card; | 560 | struct snd_card *card; |
553 | struct snd_dummy *dummy; | 561 | struct snd_dummy *dummy; |
554 | int idx, err; | 562 | int idx, err; |
563 | int dev = devptr->id; | ||
555 | 564 | ||
556 | if (!enable[dev]) | ||
557 | return -ENODEV; | ||
558 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, | 565 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, |
559 | sizeof(struct snd_dummy)); | 566 | sizeof(struct snd_dummy)); |
560 | if (card == NULL) | 567 | if (card == NULL) |
@@ -575,11 +582,10 @@ static int __init snd_card_dummy_probe(int dev) | |||
575 | strcpy(card->shortname, "Dummy"); | 582 | strcpy(card->shortname, "Dummy"); |
576 | sprintf(card->longname, "Dummy %i", dev + 1); | 583 | sprintf(card->longname, "Dummy %i", dev + 1); |
577 | 584 | ||
578 | if ((err = snd_card_set_generic_dev(card)) < 0) | 585 | snd_card_set_dev(card, &devptr->dev); |
579 | goto __nodev; | ||
580 | 586 | ||
581 | if ((err = snd_card_register(card)) == 0) { | 587 | if ((err = snd_card_register(card)) == 0) { |
582 | snd_dummy_cards[dev] = card; | 588 | platform_set_drvdata(devptr, card); |
583 | return 0; | 589 | return 0; |
584 | } | 590 | } |
585 | __nodev: | 591 | __nodev: |
@@ -587,16 +593,62 @@ static int __init snd_card_dummy_probe(int dev) | |||
587 | return err; | 593 | return err; |
588 | } | 594 | } |
589 | 595 | ||
590 | static int __init alsa_card_dummy_init(void) | 596 | static int snd_dummy_remove(struct platform_device *devptr) |
597 | { | ||
598 | snd_card_free(platform_get_drvdata(devptr)); | ||
599 | platform_set_drvdata(devptr, NULL); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | #ifdef CONFIG_PM | ||
604 | static int snd_dummy_suspend(struct platform_device *pdev, pm_message_t state) | ||
591 | { | 605 | { |
592 | int dev, cards; | 606 | struct snd_card *card = platform_get_drvdata(pdev); |
607 | struct snd_dummy *dummy = card->private_data; | ||
593 | 608 | ||
594 | for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) { | 609 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
595 | if (snd_card_dummy_probe(dev) < 0) { | 610 | snd_pcm_suspend_all(dummy->pcm); |
596 | #ifdef MODULE | 611 | return 0; |
597 | printk(KERN_ERR "Dummy soundcard #%i not found or device busy\n", dev + 1); | 612 | } |
613 | |||
614 | static int snd_dummy_resume(struct platform_device *pdev) | ||
615 | { | ||
616 | struct snd_card *card = platform_get_drvdata(pdev); | ||
617 | |||
618 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
619 | return 0; | ||
620 | } | ||
621 | #endif | ||
622 | |||
623 | #define SND_DUMMY_DRIVER "snd_dummy" | ||
624 | |||
625 | static struct platform_driver snd_dummy_driver = { | ||
626 | .probe = snd_dummy_probe, | ||
627 | .remove = snd_dummy_remove, | ||
628 | #ifdef CONFIG_PM | ||
629 | .suspend = snd_dummy_suspend, | ||
630 | .resume = snd_dummy_resume, | ||
598 | #endif | 631 | #endif |
599 | break; | 632 | .driver = { |
633 | .name = SND_DUMMY_DRIVER | ||
634 | }, | ||
635 | }; | ||
636 | |||
637 | static int __init alsa_card_dummy_init(void) | ||
638 | { | ||
639 | int i, cards, err; | ||
640 | |||
641 | if ((err = platform_driver_register(&snd_dummy_driver)) < 0) | ||
642 | return err; | ||
643 | |||
644 | cards = 0; | ||
645 | for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { | ||
646 | struct platform_device *device; | ||
647 | device = platform_device_register_simple(SND_DUMMY_DRIVER, | ||
648 | i, NULL, 0); | ||
649 | if (IS_ERR(device)) { | ||
650 | err = PTR_ERR(device); | ||
651 | goto errout; | ||
600 | } | 652 | } |
601 | cards++; | 653 | cards++; |
602 | } | 654 | } |
@@ -604,17 +656,19 @@ static int __init alsa_card_dummy_init(void) | |||
604 | #ifdef MODULE | 656 | #ifdef MODULE |
605 | printk(KERN_ERR "Dummy soundcard not found or device busy\n"); | 657 | printk(KERN_ERR "Dummy soundcard not found or device busy\n"); |
606 | #endif | 658 | #endif |
607 | return -ENODEV; | 659 | err = -ENODEV; |
660 | goto errout; | ||
608 | } | 661 | } |
609 | return 0; | 662 | return 0; |
663 | |||
664 | errout: | ||
665 | platform_driver_unregister(&snd_dummy_driver); | ||
666 | return err; | ||
610 | } | 667 | } |
611 | 668 | ||
612 | static void __exit alsa_card_dummy_exit(void) | 669 | static void __exit alsa_card_dummy_exit(void) |
613 | { | 670 | { |
614 | int idx; | 671 | platform_driver_unregister(&snd_dummy_driver); |
615 | |||
616 | for (idx = 0; idx < SNDRV_CARDS; idx++) | ||
617 | snd_card_free(snd_dummy_cards[idx]); | ||
618 | } | 672 | } |
619 | 673 | ||
620 | module_init(alsa_card_dummy_init) | 674 | module_init(alsa_card_dummy_init) |