diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 66 | ||||
-rw-r--r-- | sound/usb/midi.c | 8 | ||||
-rw-r--r-- | sound/usb/mixer.c | 23 | ||||
-rw-r--r-- | sound/usb/pcm.c | 20 | ||||
-rw-r--r-- | sound/usb/power.h | 17 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 6 |
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 | ||
69 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 70 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
70 | MODULE_DESCRIPTION("USB Audio"); | 71 | MODULE_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(®ister_mutex); | 513 | mutex_unlock(®ister_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 | |||
590 | int 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 | |||
600 | void 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 | |||
584 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 606 | static 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; | 663 | err_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 | ||
657 | static int __init snd_usb_audio_init(void) | 695 | static 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 | ||
1065 | static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) | 1070 | static 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) { |
349 | error: | ||
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 | |||
793 | rep_err: | ||
794 | snd_usb_autosuspend(subs->stream->chip); | ||
795 | return err; | ||
788 | } | 796 | } |
789 | 797 | ||
790 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | 798 | static 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 | ||
5 | int snd_usb_autoresume(struct snd_usb_audio *chip); | ||
6 | void snd_usb_autosuspend(struct snd_usb_audio *chip); | ||
7 | #else | ||
8 | static inline int snd_usb_autoresume(struct snd_usb_audio *chip) | ||
9 | { | ||
10 | return 0; | ||
11 | } | ||
12 | static 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 | ||