aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-01-20 10:51:16 -0500
committerTakashi Iwai <tiwai@suse.de>2014-02-03 03:51:34 -0500
commit400362f1d8dcfda3562e80e88cfc2a92cffaf9bf (patch)
tree05328d792a4a0e7a928da1b3c04f6ba4b2123658 /sound/usb
parent63f4b3a475e84c5aa77f720f0f66989c686a14fb (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.c18
-rw-r--r--sound/usb/mixer.c99
-rw-r--r--sound/usb/mixer.h7
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
699static int usb_audio_resume(struct usb_interface *intf) 699static 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)
723err_out: 723err_out:
724 return err; 724 return err;
725} 725}
726
727static int usb_audio_resume(struct usb_interface *intf)
728{
729 return __usb_audio_resume(intf, false);
730}
731
732static 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
731static struct usb_device_id usb_audio_ids [] = { 742static 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 */
2303void 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
2309int 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 */
2323static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) 2303static 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 */
2403static 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
2409static 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
2422int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
2423{
2424 snd_usb_mixer_inactivate(mixer);
2425 return 0;
2426}
2427
2428static 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
2457int 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
64int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, 64int 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);
66void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
67int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
68 66
69int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, 67int 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,
72int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, 70int 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
74int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
75int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
76#endif
77
75#endif /* __USBMIXER_H */ 78#endif /* __USBMIXER_H */