diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-01-20 10:51:16 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-02-03 03:51:34 -0500 |
commit | 400362f1d8dcfda3562e80e88cfc2a92cffaf9bf (patch) | |
tree | 05328d792a4a0e7a928da1b3c04f6ba4b2123658 /sound/usb | |
parent | 63f4b3a475e84c5aa77f720f0f66989c686a14fb (diff) |
ALSA: usb-audio: Resume mixer values properly
Implement reset_resume callback so that the mixer values are properly
restored. Still no boot quirks are called, so it might not work well
on some devices.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 18 | ||||
-rw-r--r-- | sound/usb/mixer.c | 99 | ||||
-rw-r--r-- | sound/usb/mixer.h | 7 |
3 files changed, 99 insertions, 25 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index d979050e6a6a..025224136129 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -691,12 +691,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | |||
691 | } | 691 | } |
692 | 692 | ||
693 | list_for_each_entry(mixer, &chip->mixer_list, list) | 693 | list_for_each_entry(mixer, &chip->mixer_list, list) |
694 | snd_usb_mixer_inactivate(mixer); | 694 | snd_usb_mixer_suspend(mixer); |
695 | 695 | ||
696 | return 0; | 696 | return 0; |
697 | } | 697 | } |
698 | 698 | ||
699 | static int usb_audio_resume(struct usb_interface *intf) | 699 | static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) |
700 | { | 700 | { |
701 | struct snd_usb_audio *chip = usb_get_intfdata(intf); | 701 | struct snd_usb_audio *chip = usb_get_intfdata(intf); |
702 | struct usb_mixer_interface *mixer; | 702 | struct usb_mixer_interface *mixer; |
@@ -711,7 +711,7 @@ static int usb_audio_resume(struct usb_interface *intf) | |||
711 | * we just notify and restart the mixers | 711 | * we just notify and restart the mixers |
712 | */ | 712 | */ |
713 | list_for_each_entry(mixer, &chip->mixer_list, list) { | 713 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
714 | err = snd_usb_mixer_activate(mixer); | 714 | err = snd_usb_mixer_resume(mixer, reset_resume); |
715 | if (err < 0) | 715 | if (err < 0) |
716 | goto err_out; | 716 | goto err_out; |
717 | } | 717 | } |
@@ -723,9 +723,20 @@ static int usb_audio_resume(struct usb_interface *intf) | |||
723 | err_out: | 723 | err_out: |
724 | return err; | 724 | return err; |
725 | } | 725 | } |
726 | |||
727 | static int usb_audio_resume(struct usb_interface *intf) | ||
728 | { | ||
729 | return __usb_audio_resume(intf, false); | ||
730 | } | ||
731 | |||
732 | static int usb_audio_reset_resume(struct usb_interface *intf) | ||
733 | { | ||
734 | return __usb_audio_resume(intf, true); | ||
735 | } | ||
726 | #else | 736 | #else |
727 | #define usb_audio_suspend NULL | 737 | #define usb_audio_suspend NULL |
728 | #define usb_audio_resume NULL | 738 | #define usb_audio_resume NULL |
739 | #define usb_audio_reset_resume NULL | ||
729 | #endif /* CONFIG_PM */ | 740 | #endif /* CONFIG_PM */ |
730 | 741 | ||
731 | static struct usb_device_id usb_audio_ids [] = { | 742 | static struct usb_device_id usb_audio_ids [] = { |
@@ -747,6 +758,7 @@ static struct usb_driver usb_audio_driver = { | |||
747 | .disconnect = usb_audio_disconnect, | 758 | .disconnect = usb_audio_disconnect, |
748 | .suspend = usb_audio_suspend, | 759 | .suspend = usb_audio_suspend, |
749 | .resume = usb_audio_resume, | 760 | .resume = usb_audio_resume, |
761 | .reset_resume = usb_audio_reset_resume, | ||
750 | .id_table = usb_audio_ids, | 762 | .id_table = usb_audio_ids, |
751 | .supports_autosuspend = 1, | 763 | .supports_autosuspend = 1, |
752 | }; | 764 | }; |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 44b0ba4feab3..aa9bc19aae68 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -2299,26 +2299,6 @@ requeue: | |||
2299 | } | 2299 | } |
2300 | } | 2300 | } |
2301 | 2301 | ||
2302 | /* stop any bus activity of a mixer */ | ||
2303 | void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) | ||
2304 | { | ||
2305 | usb_kill_urb(mixer->urb); | ||
2306 | usb_kill_urb(mixer->rc_urb); | ||
2307 | } | ||
2308 | |||
2309 | int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) | ||
2310 | { | ||
2311 | int err; | ||
2312 | |||
2313 | if (mixer->urb) { | ||
2314 | err = usb_submit_urb(mixer->urb, GFP_NOIO); | ||
2315 | if (err < 0) | ||
2316 | return err; | ||
2317 | } | ||
2318 | |||
2319 | return 0; | ||
2320 | } | ||
2321 | |||
2322 | /* create the handler for the optional status interrupt endpoint */ | 2302 | /* create the handler for the optional status interrupt endpoint */ |
2323 | static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) | 2303 | static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) |
2324 | { | 2304 | { |
@@ -2417,3 +2397,82 @@ void snd_usb_mixer_disconnect(struct list_head *p) | |||
2417 | usb_kill_urb(mixer->urb); | 2397 | usb_kill_urb(mixer->urb); |
2418 | usb_kill_urb(mixer->rc_urb); | 2398 | usb_kill_urb(mixer->rc_urb); |
2419 | } | 2399 | } |
2400 | |||
2401 | #ifdef CONFIG_PM | ||
2402 | /* stop any bus activity of a mixer */ | ||
2403 | static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) | ||
2404 | { | ||
2405 | usb_kill_urb(mixer->urb); | ||
2406 | usb_kill_urb(mixer->rc_urb); | ||
2407 | } | ||
2408 | |||
2409 | static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) | ||
2410 | { | ||
2411 | int err; | ||
2412 | |||
2413 | if (mixer->urb) { | ||
2414 | err = usb_submit_urb(mixer->urb, GFP_NOIO); | ||
2415 | if (err < 0) | ||
2416 | return err; | ||
2417 | } | ||
2418 | |||
2419 | return 0; | ||
2420 | } | ||
2421 | |||
2422 | int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) | ||
2423 | { | ||
2424 | snd_usb_mixer_inactivate(mixer); | ||
2425 | return 0; | ||
2426 | } | ||
2427 | |||
2428 | static int restore_mixer_value(struct usb_mixer_elem_info *cval) | ||
2429 | { | ||
2430 | int c, err, idx; | ||
2431 | |||
2432 | if (cval->cmask) { | ||
2433 | idx = 0; | ||
2434 | for (c = 0; c < MAX_CHANNELS; c++) { | ||
2435 | if (!(cval->cmask & (1 << c))) | ||
2436 | continue; | ||
2437 | if (cval->cached & (1 << c)) { | ||
2438 | err = set_cur_mix_value(cval, c + 1, idx, | ||
2439 | cval->cache_val[idx]); | ||
2440 | if (err < 0) | ||
2441 | return err; | ||
2442 | } | ||
2443 | idx++; | ||
2444 | } | ||
2445 | } else { | ||
2446 | /* master */ | ||
2447 | if (cval->cached) { | ||
2448 | err = set_cur_mix_value(cval, 0, 0, *cval->cache_val); | ||
2449 | if (err < 0) | ||
2450 | return err; | ||
2451 | } | ||
2452 | } | ||
2453 | |||
2454 | return 0; | ||
2455 | } | ||
2456 | |||
2457 | int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) | ||
2458 | { | ||
2459 | struct usb_mixer_elem_info *cval; | ||
2460 | int id, err; | ||
2461 | |||
2462 | /* FIXME: any mixer quirks? */ | ||
2463 | |||
2464 | if (reset_resume) { | ||
2465 | /* restore cached mixer values */ | ||
2466 | for (id = 0; id < MAX_ID_ELEMS; id++) { | ||
2467 | for (cval = mixer->id_elems[id]; cval; | ||
2468 | cval = cval->next_id_elem) { | ||
2469 | err = restore_mixer_value(cval); | ||
2470 | if (err < 0) | ||
2471 | return err; | ||
2472 | } | ||
2473 | } | ||
2474 | } | ||
2475 | |||
2476 | return snd_usb_mixer_activate(mixer); | ||
2477 | } | ||
2478 | #endif | ||
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index aab80df201bd..73b1f649447b 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); | |||
63 | 63 | ||
64 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | 64 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, |
65 | int request, int validx, int value_set); | 65 | int request, int validx, int value_set); |
66 | void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer); | ||
67 | int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); | ||
68 | 66 | ||
69 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, | 67 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, |
70 | struct snd_kcontrol *kctl); | 68 | struct snd_kcontrol *kctl); |
@@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, | |||
72 | int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | 70 | int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, |
73 | unsigned int size, unsigned int __user *_tlv); | 71 | unsigned int size, unsigned int __user *_tlv); |
74 | 72 | ||
73 | #ifdef CONFIG_PM | ||
74 | int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer); | ||
75 | int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume); | ||
76 | #endif | ||
77 | |||
75 | #endif /* __USBMIXER_H */ | 78 | #endif /* __USBMIXER_H */ |