Commit 178bb7bed5b467463a3861aecdd5361ea9d295b7
Committed by
Peter Chen
1 parent
819efee83b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
2 other branches
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>
Showing 3 changed files with 99 additions and 25 deletions Side-by-side Diff
sound/usb/card.c
... | ... | @@ -694,12 +694,12 @@ |
694 | 694 | } |
695 | 695 | |
696 | 696 | list_for_each_entry(mixer, &chip->mixer_list, list) |
697 | - snd_usb_mixer_inactivate(mixer); | |
697 | + snd_usb_mixer_suspend(mixer); | |
698 | 698 | |
699 | 699 | return 0; |
700 | 700 | } |
701 | 701 | |
702 | -static int usb_audio_resume(struct usb_interface *intf) | |
702 | +static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) | |
703 | 703 | { |
704 | 704 | struct snd_usb_audio *chip = usb_get_intfdata(intf); |
705 | 705 | struct usb_mixer_interface *mixer; |
... | ... | @@ -714,7 +714,7 @@ |
714 | 714 | * we just notify and restart the mixers |
715 | 715 | */ |
716 | 716 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
717 | - err = snd_usb_mixer_activate(mixer); | |
717 | + err = snd_usb_mixer_resume(mixer, reset_resume); | |
718 | 718 | if (err < 0) |
719 | 719 | goto err_out; |
720 | 720 | } |
721 | 721 | |
... | ... | @@ -726,9 +726,20 @@ |
726 | 726 | err_out: |
727 | 727 | return err; |
728 | 728 | } |
729 | + | |
730 | +static int usb_audio_resume(struct usb_interface *intf) | |
731 | +{ | |
732 | + return __usb_audio_resume(intf, false); | |
733 | +} | |
734 | + | |
735 | +static int usb_audio_reset_resume(struct usb_interface *intf) | |
736 | +{ | |
737 | + return __usb_audio_resume(intf, true); | |
738 | +} | |
729 | 739 | #else |
730 | 740 | #define usb_audio_suspend NULL |
731 | 741 | #define usb_audio_resume NULL |
742 | +#define usb_audio_reset_resume NULL | |
732 | 743 | #endif /* CONFIG_PM */ |
733 | 744 | |
734 | 745 | static struct usb_device_id usb_audio_ids [] = { |
... | ... | @@ -750,6 +761,7 @@ |
750 | 761 | .disconnect = usb_audio_disconnect, |
751 | 762 | .suspend = usb_audio_suspend, |
752 | 763 | .resume = usb_audio_resume, |
764 | + .reset_resume = usb_audio_reset_resume, | |
753 | 765 | .id_table = usb_audio_ids, |
754 | 766 | .supports_autosuspend = 1, |
755 | 767 | }; |
sound/usb/mixer.c
... | ... | @@ -2300,26 +2300,6 @@ |
2300 | 2300 | } |
2301 | 2301 | } |
2302 | 2302 | |
2303 | -/* stop any bus activity of a mixer */ | |
2304 | -void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) | |
2305 | -{ | |
2306 | - usb_kill_urb(mixer->urb); | |
2307 | - usb_kill_urb(mixer->rc_urb); | |
2308 | -} | |
2309 | - | |
2310 | -int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) | |
2311 | -{ | |
2312 | - int err; | |
2313 | - | |
2314 | - if (mixer->urb) { | |
2315 | - err = usb_submit_urb(mixer->urb, GFP_NOIO); | |
2316 | - if (err < 0) | |
2317 | - return err; | |
2318 | - } | |
2319 | - | |
2320 | - return 0; | |
2321 | -} | |
2322 | - | |
2323 | 2303 | /* create the handler for the optional status interrupt endpoint */ |
2324 | 2304 | static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) |
2325 | 2305 | { |
... | ... | @@ -2418,4 +2398,83 @@ |
2418 | 2398 | usb_kill_urb(mixer->urb); |
2419 | 2399 | usb_kill_urb(mixer->rc_urb); |
2420 | 2400 | } |
2401 | + | |
2402 | +#ifdef CONFIG_PM | |
2403 | +/* stop any bus activity of a mixer */ | |
2404 | +static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) | |
2405 | +{ | |
2406 | + usb_kill_urb(mixer->urb); | |
2407 | + usb_kill_urb(mixer->rc_urb); | |
2408 | +} | |
2409 | + | |
2410 | +static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) | |
2411 | +{ | |
2412 | + int err; | |
2413 | + | |
2414 | + if (mixer->urb) { | |
2415 | + err = usb_submit_urb(mixer->urb, GFP_NOIO); | |
2416 | + if (err < 0) | |
2417 | + return err; | |
2418 | + } | |
2419 | + | |
2420 | + return 0; | |
2421 | +} | |
2422 | + | |
2423 | +int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) | |
2424 | +{ | |
2425 | + snd_usb_mixer_inactivate(mixer); | |
2426 | + return 0; | |
2427 | +} | |
2428 | + | |
2429 | +static int restore_mixer_value(struct usb_mixer_elem_info *cval) | |
2430 | +{ | |
2431 | + int c, err, idx; | |
2432 | + | |
2433 | + if (cval->cmask) { | |
2434 | + idx = 0; | |
2435 | + for (c = 0; c < MAX_CHANNELS; c++) { | |
2436 | + if (!(cval->cmask & (1 << c))) | |
2437 | + continue; | |
2438 | + if (cval->cached & (1 << c)) { | |
2439 | + err = set_cur_mix_value(cval, c + 1, idx, | |
2440 | + cval->cache_val[idx]); | |
2441 | + if (err < 0) | |
2442 | + return err; | |
2443 | + } | |
2444 | + idx++; | |
2445 | + } | |
2446 | + } else { | |
2447 | + /* master */ | |
2448 | + if (cval->cached) { | |
2449 | + err = set_cur_mix_value(cval, 0, 0, *cval->cache_val); | |
2450 | + if (err < 0) | |
2451 | + return err; | |
2452 | + } | |
2453 | + } | |
2454 | + | |
2455 | + return 0; | |
2456 | +} | |
2457 | + | |
2458 | +int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) | |
2459 | +{ | |
2460 | + struct usb_mixer_elem_info *cval; | |
2461 | + int id, err; | |
2462 | + | |
2463 | + /* FIXME: any mixer quirks? */ | |
2464 | + | |
2465 | + if (reset_resume) { | |
2466 | + /* restore cached mixer values */ | |
2467 | + for (id = 0; id < MAX_ID_ELEMS; id++) { | |
2468 | + for (cval = mixer->id_elems[id]; cval; | |
2469 | + cval = cval->next_id_elem) { | |
2470 | + err = restore_mixer_value(cval); | |
2471 | + if (err < 0) | |
2472 | + return err; | |
2473 | + } | |
2474 | + } | |
2475 | + } | |
2476 | + | |
2477 | + return snd_usb_mixer_activate(mixer); | |
2478 | +} | |
2479 | +#endif |
sound/usb/mixer.h
... | ... | @@ -63,14 +63,17 @@ |
63 | 63 | |
64 | 64 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, |
65 | 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 | 67 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, |
70 | 68 | struct snd_kcontrol *kctl); |
71 | 69 | |
72 | 70 | int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, |
73 | 71 | unsigned int size, unsigned int __user *_tlv); |
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 | |
74 | 77 | |
75 | 78 | #endif /* __USBMIXER_H */ |