aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/card.c66
-rw-r--r--sound/usb/midi.c8
-rw-r--r--sound/usb/mixer.c23
-rw-r--r--sound/usb/pcm.c20
-rw-r--r--sound/usb/power.h17
-rw-r--r--sound/usb/usbaudio.h6
6 files changed, 118 insertions, 22 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 7fa53d91e73b..40722f8711ad 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -65,6 +65,7 @@
65#include "pcm.h" 65#include "pcm.h"
66#include "urb.h" 66#include "urb.h"
67#include "format.h" 67#include "format.h"
68#include "power.h"
68 69
69MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 70MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
70MODULE_DESCRIPTION("USB Audio"); 71MODULE_DESCRIPTION("USB Audio");
@@ -330,6 +331,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
330 chip->setup = device_setup[idx]; 331 chip->setup = device_setup[idx];
331 chip->nrpacks = nrpacks; 332 chip->nrpacks = nrpacks;
332 chip->async_unlink = async_unlink; 333 chip->async_unlink = async_unlink;
334 chip->probing = 1;
333 335
334 chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), 336 chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
335 le16_to_cpu(dev->descriptor.idProduct)); 337 le16_to_cpu(dev->descriptor.idProduct));
@@ -451,6 +453,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
451 goto __error; 453 goto __error;
452 } 454 }
453 chip = usb_chip[i]; 455 chip = usb_chip[i];
456 chip->probing = 1;
454 break; 457 break;
455 } 458 }
456 } 459 }
@@ -466,6 +469,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
466 goto __error; 469 goto __error;
467 } 470 }
468 snd_card_set_dev(chip->card, &intf->dev); 471 snd_card_set_dev(chip->card, &intf->dev);
472 chip->pm_intf = intf;
469 break; 473 break;
470 } 474 }
471 if (!chip) { 475 if (!chip) {
@@ -505,6 +509,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
505 509
506 usb_chip[chip->index] = chip; 510 usb_chip[chip->index] = chip;
507 chip->num_interfaces++; 511 chip->num_interfaces++;
512 chip->probing = 0;
508 mutex_unlock(&register_mutex); 513 mutex_unlock(&register_mutex);
509 return chip; 514 return chip;
510 515
@@ -581,6 +586,23 @@ static void usb_audio_disconnect(struct usb_interface *intf)
581} 586}
582 587
583#ifdef CONFIG_PM 588#ifdef CONFIG_PM
589
590int snd_usb_autoresume(struct snd_usb_audio *chip)
591{
592 int err = -ENODEV;
593
594 if (!chip->shutdown && !chip->probing)
595 err = usb_autopm_get_interface(chip->pm_intf);
596
597 return err;
598}
599
600void snd_usb_autosuspend(struct snd_usb_audio *chip)
601{
602 if (!chip->shutdown && !chip->probing)
603 usb_autopm_put_interface(chip->pm_intf);
604}
605
584static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) 606static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
585{ 607{
586 struct snd_usb_audio *chip = usb_get_intfdata(intf); 608 struct snd_usb_audio *chip = usb_get_intfdata(intf);
@@ -591,18 +613,26 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
591 if (chip == (void *)-1L) 613 if (chip == (void *)-1L)
592 return 0; 614 return 0;
593 615
594 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); 616 if (!(message.event & PM_EVENT_AUTO)) {
595 if (!chip->num_suspended_intf++) { 617 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
596 list_for_each(p, &chip->pcm_list) { 618 if (!chip->num_suspended_intf++) {
597 as = list_entry(p, struct snd_usb_stream, list); 619 list_for_each(p, &chip->pcm_list) {
598 snd_pcm_suspend_all(as->pcm); 620 as = list_entry(p, struct snd_usb_stream, list);
599 } 621 snd_pcm_suspend_all(as->pcm);
600 622 }
601 list_for_each_entry(mixer, &chip->mixer_list, list) { 623 }
602 snd_usb_mixer_inactivate(mixer); 624 } else {
603 } 625 /*
626 * otherwise we keep the rest of the system in the dark
627 * to keep this transparent
628 */
629 if (!chip->num_suspended_intf++)
630 chip->autosuspended = 1;
604 } 631 }
605 632
633 list_for_each_entry(mixer, &chip->mixer_list, list)
634 snd_usb_mixer_inactivate(mixer);
635
606 return 0; 636 return 0;
607} 637}
608 638
@@ -610,6 +640,7 @@ static int usb_audio_resume(struct usb_interface *intf)
610{ 640{
611 struct snd_usb_audio *chip = usb_get_intfdata(intf); 641 struct snd_usb_audio *chip = usb_get_intfdata(intf);
612 struct usb_mixer_interface *mixer; 642 struct usb_mixer_interface *mixer;
643 int err = 0;
613 644
614 if (chip == (void *)-1L) 645 if (chip == (void *)-1L)
615 return 0; 646 return 0;
@@ -619,12 +650,18 @@ static int usb_audio_resume(struct usb_interface *intf)
619 * ALSA leaves material resumption to user space 650 * ALSA leaves material resumption to user space
620 * we just notify and restart the mixers 651 * we just notify and restart the mixers
621 */ 652 */
622 list_for_each_entry(mixer, &chip->mixer_list, list) 653 list_for_each_entry(mixer, &chip->mixer_list, list) {
623 snd_usb_mixer_activate(mixer); 654 err = snd_usb_mixer_activate(mixer);
655 if (err < 0)
656 goto err_out;
657 }
624 658
625 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); 659 if (!chip->autosuspended)
660 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
661 chip->autosuspended = 0;
626 662
627 return 0; 663err_out:
664 return err;
628} 665}
629#else 666#else
630#define usb_audio_suspend NULL 667#define usb_audio_suspend NULL
@@ -652,6 +689,7 @@ static struct usb_driver usb_audio_driver = {
652 .suspend = usb_audio_suspend, 689 .suspend = usb_audio_suspend,
653 .resume = usb_audio_resume, 690 .resume = usb_audio_resume,
654 .id_table = usb_audio_ids, 691 .id_table = usb_audio_ids,
692 .supports_autosuspend = 1,
655}; 693};
656 694
657static int __init snd_usb_audio_init(void) 695static int __init snd_usb_audio_init(void)
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index db2dc5ffe6dd..b4b39c0b6c9e 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -54,6 +54,7 @@
54#include <sound/asequencer.h> 54#include <sound/asequencer.h>
55#include "usbaudio.h" 55#include "usbaudio.h"
56#include "midi.h" 56#include "midi.h"
57#include "power.h"
57#include "helper.h" 58#include "helper.h"
58 59
59/* 60/*
@@ -1044,6 +1045,7 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1044 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1045 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1045 struct usbmidi_out_port* port = NULL; 1046 struct usbmidi_out_port* port = NULL;
1046 int i, j; 1047 int i, j;
1048 int err;
1047 1049
1048 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) 1050 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
1049 if (umidi->endpoints[i].out) 1051 if (umidi->endpoints[i].out)
@@ -1056,6 +1058,9 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1056 snd_BUG(); 1058 snd_BUG();
1057 return -ENXIO; 1059 return -ENXIO;
1058 } 1060 }
1061 err = usb_autopm_get_interface(umidi->iface);
1062 if (err < 0)
1063 return -EIO;
1059 substream->runtime->private_data = port; 1064 substream->runtime->private_data = port;
1060 port->state = STATE_UNKNOWN; 1065 port->state = STATE_UNKNOWN;
1061 substream_open(substream, 1); 1066 substream_open(substream, 1);
@@ -1064,7 +1069,10 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1064 1069
1065static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) 1070static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
1066{ 1071{
1072 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1073
1067 substream_open(substream, 0); 1074 substream_open(substream, 0);
1075 usb_autopm_put_interface(umidi->iface);
1068 return 0; 1076 return 0;
1069} 1077}
1070 1078
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 09e59345bb6d..5e4775716607 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -61,6 +61,7 @@
61#include "mixer.h" 61#include "mixer.h"
62#include "helper.h" 62#include "helper.h"
63#include "mixer_quirks.h" 63#include "mixer_quirks.h"
64#include "power.h"
64 65
65#define MAX_ID_ELEMS 256 66#define MAX_ID_ELEMS 256
66 67
@@ -295,16 +296,22 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
295 unsigned char buf[2]; 296 unsigned char buf[2];
296 int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; 297 int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
297 int timeout = 10; 298 int timeout = 10;
299 int err;
298 300
301 err = snd_usb_autoresume(cval->mixer->chip);
302 if (err < 0)
303 return -EIO;
299 while (timeout-- > 0) { 304 while (timeout-- > 0) {
300 if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, 305 if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
301 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 306 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
302 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), 307 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
303 buf, val_len, 100) >= val_len) { 308 buf, val_len, 100) >= val_len) {
304 *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); 309 *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
310 snd_usb_autosuspend(cval->mixer->chip);
305 return 0; 311 return 0;
306 } 312 }
307 } 313 }
314 snd_usb_autosuspend(cval->mixer->chip);
308 snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", 315 snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
309 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); 316 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
310 return -EINVAL; 317 return -EINVAL;
@@ -328,12 +335,18 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
328 335
329 memset(buf, 0, sizeof(buf)); 336 memset(buf, 0, sizeof(buf));
330 337
338 ret = snd_usb_autoresume(chip) ? -EIO : 0;
339 if (ret)
340 goto error;
341
331 ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, 342 ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
332 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 343 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
333 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), 344 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
334 buf, size, 1000); 345 buf, size, 1000);
346 snd_usb_autosuspend(chip);
335 347
336 if (ret < 0) { 348 if (ret < 0) {
349error:
337 snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", 350 snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
338 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); 351 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
339 return ret; 352 return ret;
@@ -413,7 +426,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
413{ 426{
414 struct snd_usb_audio *chip = cval->mixer->chip; 427 struct snd_usb_audio *chip = cval->mixer->chip;
415 unsigned char buf[2]; 428 unsigned char buf[2];
416 int val_len, timeout = 10; 429 int val_len, err, timeout = 10;
417 430
418 if (cval->mixer->protocol == UAC_VERSION_1) { 431 if (cval->mixer->protocol == UAC_VERSION_1) {
419 val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; 432 val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
@@ -433,13 +446,19 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
433 value_set = convert_bytes_value(cval, value_set); 446 value_set = convert_bytes_value(cval, value_set);
434 buf[0] = value_set & 0xff; 447 buf[0] = value_set & 0xff;
435 buf[1] = (value_set >> 8) & 0xff; 448 buf[1] = (value_set >> 8) & 0xff;
449 err = snd_usb_autoresume(chip);
450 if (err < 0)
451 return -EIO;
436 while (timeout-- > 0) 452 while (timeout-- > 0)
437 if (snd_usb_ctl_msg(chip->dev, 453 if (snd_usb_ctl_msg(chip->dev,
438 usb_sndctrlpipe(chip->dev, 0), request, 454 usb_sndctrlpipe(chip->dev, 0), request,
439 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 455 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
440 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), 456 validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
441 buf, val_len, 100) >= 0) 457 buf, val_len, 100) >= 0) {
458 snd_usb_autosuspend(chip);
442 return 0; 459 return 0;
460 }
461 snd_usb_autosuspend(chip);
443 snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", 462 snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
444 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); 463 request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
445 return -EINVAL; 464 return -EINVAL;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index e3f680526cb5..b8dcbf407bbb 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -32,6 +32,7 @@
32#include "helper.h" 32#include "helper.h"
33#include "pcm.h" 33#include "pcm.h"
34#include "clock.h" 34#include "clock.h"
35#include "power.h"
35 36
36/* 37/*
37 * return the current pcm pointer. just based on the hwptr_done value. 38 * return the current pcm pointer. just based on the hwptr_done value.
@@ -739,6 +740,9 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
739 pt = 125 * (1 << fp->datainterval); 740 pt = 125 * (1 << fp->datainterval);
740 ptmin = min(ptmin, pt); 741 ptmin = min(ptmin, pt);
741 } 742 }
743 err = snd_usb_autoresume(subs->stream->chip);
744 if (err < 0)
745 return err;
742 746
743 param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; 747 param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
744 if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) 748 if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -756,21 +760,21 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
756 SNDRV_PCM_HW_PARAM_CHANNELS, 760 SNDRV_PCM_HW_PARAM_CHANNELS,
757 param_period_time_if_needed, 761 param_period_time_if_needed,
758 -1)) < 0) 762 -1)) < 0)
759 return err; 763 goto rep_err;
760 if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 764 if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
761 hw_rule_channels, subs, 765 hw_rule_channels, subs,
762 SNDRV_PCM_HW_PARAM_FORMAT, 766 SNDRV_PCM_HW_PARAM_FORMAT,
763 SNDRV_PCM_HW_PARAM_RATE, 767 SNDRV_PCM_HW_PARAM_RATE,
764 param_period_time_if_needed, 768 param_period_time_if_needed,
765 -1)) < 0) 769 -1)) < 0)
766 return err; 770 goto rep_err;
767 if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, 771 if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
768 hw_rule_format, subs, 772 hw_rule_format, subs,
769 SNDRV_PCM_HW_PARAM_RATE, 773 SNDRV_PCM_HW_PARAM_RATE,
770 SNDRV_PCM_HW_PARAM_CHANNELS, 774 SNDRV_PCM_HW_PARAM_CHANNELS,
771 param_period_time_if_needed, 775 param_period_time_if_needed,
772 -1)) < 0) 776 -1)) < 0)
773 return err; 777 goto rep_err;
774 if (param_period_time_if_needed >= 0) { 778 if (param_period_time_if_needed >= 0) {
775 err = snd_pcm_hw_rule_add(runtime, 0, 779 err = snd_pcm_hw_rule_add(runtime, 0,
776 SNDRV_PCM_HW_PARAM_PERIOD_TIME, 780 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
@@ -780,11 +784,15 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
780 SNDRV_PCM_HW_PARAM_RATE, 784 SNDRV_PCM_HW_PARAM_RATE,
781 -1); 785 -1);
782 if (err < 0) 786 if (err < 0)
783 return err; 787 goto rep_err;
784 } 788 }
785 if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) 789 if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
786 return err; 790 goto rep_err;
787 return 0; 791 return 0;
792
793rep_err:
794 snd_usb_autosuspend(subs->stream->chip);
795 return err;
788} 796}
789 797
790static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) 798static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
@@ -798,6 +806,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
798 runtime->hw = snd_usb_hardware; 806 runtime->hw = snd_usb_hardware;
799 runtime->private_data = subs; 807 runtime->private_data = subs;
800 subs->pcm_substream = substream; 808 subs->pcm_substream = substream;
809 /* runtime PM is also done there */
801 return setup_hw_info(runtime, subs); 810 return setup_hw_info(runtime, subs);
802} 811}
803 812
@@ -811,6 +820,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
811 subs->interface = -1; 820 subs->interface = -1;
812 } 821 }
813 subs->pcm_substream = NULL; 822 subs->pcm_substream = NULL;
823 snd_usb_autosuspend(subs->stream->chip);
814 return 0; 824 return 0;
815} 825}
816 826
diff --git a/sound/usb/power.h b/sound/usb/power.h
new file mode 100644
index 000000000000..48ee51dcb71e
--- /dev/null
+++ b/sound/usb/power.h
@@ -0,0 +1,17 @@
1#ifndef __USBAUDIO_POWER_H
2#define __USBAUDIO_POWER_H
3
4#ifdef CONFIG_PM
5int snd_usb_autoresume(struct snd_usb_audio *chip);
6void snd_usb_autosuspend(struct snd_usb_audio *chip);
7#else
8static inline int snd_usb_autoresume(struct snd_usb_audio *chip)
9{
10 return 0;
11}
12static inline void snd_usb_autosuspend(struct snd_usb_audio *chip)
13{
14}
15#endif
16
17#endif /* __USBAUDIO_POWER_H */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 6e66fffe87f5..32f2a97f2f14 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -34,10 +34,14 @@ struct snd_usb_audio {
34 int index; 34 int index;
35 struct usb_device *dev; 35 struct usb_device *dev;
36 struct snd_card *card; 36 struct snd_card *card;
37 struct usb_interface *pm_intf;
37 u32 usb_id; 38 u32 usb_id;
38 int shutdown;
39 struct mutex shutdown_mutex; 39 struct mutex shutdown_mutex;
40 unsigned int shutdown:1;
41 unsigned int probing:1;
42 unsigned int autosuspended:1;
40 unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ 43 unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
44
41 int num_interfaces; 45 int num_interfaces;
42 int num_suspended_intf; 46 int num_suspended_intf;
43 47