Commit 178bb7bed5b467463a3861aecdd5361ea9d295b7

Authored by Takashi Iwai
Committed by Peter Chen
1 parent 819efee83b

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

... ... @@ -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 };
... ... @@ -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
... ... @@ -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 */