aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-12-03 05:30:50 -0500
committerTakashi Iwai <tiwai@suse.de>2012-12-04 01:27:44 -0500
commitf5f165418cabf2218eb466c0e94693b8b1aee88b (patch)
treecc5bb9658be8d83c1f4c0533468f52ac2a5348be /sound/usb
parent59866da9e4ae54819e3c4e0a8f426bdb0c2ef993 (diff)
ALSA: usb-audio: Fix missing autopm for MIDI input
The commit [88a8516a: ALSA: usbaudio: implement USB autosuspend] added the support of autopm for USB MIDI output, but it didn't take the MIDI input into account. This patch adds the following for fixing the autopm: - Manage the URB start at the first MIDI input stream open, instead of the time of instance creation - Move autopm code to the common substream_open() - Make snd_usbmidi_input_start/_stop() more robust and add the running state check Reviewd-by: Clemens Ladisch <clemens@ladisch.de> Tested-by: Clemens Ladisch <clemens@ladisch.de> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/midi.c88
1 files changed, 46 insertions, 42 deletions
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index c0054ee9389b..34b9bb7fe87c 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -126,8 +126,10 @@ struct snd_usb_midi {
126 struct snd_usb_midi_in_endpoint *in; 126 struct snd_usb_midi_in_endpoint *in;
127 } endpoints[MIDI_MAX_ENDPOINTS]; 127 } endpoints[MIDI_MAX_ENDPOINTS];
128 unsigned long input_triggered; 128 unsigned long input_triggered;
129 unsigned int opened; 129 bool autopm_reference;
130 unsigned int opened[2];
130 unsigned char disconnected; 131 unsigned char disconnected;
132 unsigned char input_running;
131 133
132 struct snd_kcontrol *roland_load_ctl; 134 struct snd_kcontrol *roland_load_ctl;
133}; 135};
@@ -149,7 +151,6 @@ struct snd_usb_midi_out_endpoint {
149 struct snd_usb_midi_out_endpoint* ep; 151 struct snd_usb_midi_out_endpoint* ep;
150 struct snd_rawmidi_substream *substream; 152 struct snd_rawmidi_substream *substream;
151 int active; 153 int active;
152 bool autopm_reference;
153 uint8_t cable; /* cable number << 4 */ 154 uint8_t cable; /* cable number << 4 */
154 uint8_t state; 155 uint8_t state;
155#define STATE_UNKNOWN 0 156#define STATE_UNKNOWN 0
@@ -1034,36 +1035,58 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)
1034 snd_usbmidi_input_start(&umidi->list); 1035 snd_usbmidi_input_start(&umidi->list);
1035} 1036}
1036 1037
1037static void substream_open(struct snd_rawmidi_substream *substream, int open) 1038static int substream_open(struct snd_rawmidi_substream *substream, int dir,
1039 int open)
1038{ 1040{
1039 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1041 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1040 struct snd_kcontrol *ctl; 1042 struct snd_kcontrol *ctl;
1043 int err;
1041 1044
1042 down_read(&umidi->disc_rwsem); 1045 down_read(&umidi->disc_rwsem);
1043 if (umidi->disconnected) { 1046 if (umidi->disconnected) {
1044 up_read(&umidi->disc_rwsem); 1047 up_read(&umidi->disc_rwsem);
1045 return; 1048 return open ? -ENODEV : 0;
1046 } 1049 }
1047 1050
1048 mutex_lock(&umidi->mutex); 1051 mutex_lock(&umidi->mutex);
1049 if (open) { 1052 if (open) {
1050 if (umidi->opened++ == 0 && umidi->roland_load_ctl) { 1053 if (!umidi->opened[0] && !umidi->opened[1]) {
1051 ctl = umidi->roland_load_ctl; 1054 err = usb_autopm_get_interface(umidi->iface);
1052 ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 1055 umidi->autopm_reference = err >= 0;
1053 snd_ctl_notify(umidi->card, 1056 if (err < 0 && err != -EACCES) {
1057 mutex_unlock(&umidi->mutex);
1058 up_read(&umidi->disc_rwsem);
1059 return -EIO;
1060 }
1061 if (umidi->roland_load_ctl) {
1062 ctl = umidi->roland_load_ctl;
1063 ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1064 snd_ctl_notify(umidi->card,
1054 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); 1065 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
1055 update_roland_altsetting(umidi); 1066 update_roland_altsetting(umidi);
1067 }
1056 } 1068 }
1069 umidi->opened[dir]++;
1070 if (umidi->opened[1])
1071 snd_usbmidi_input_start(&umidi->list);
1057 } else { 1072 } else {
1058 if (--umidi->opened == 0 && umidi->roland_load_ctl) { 1073 umidi->opened[dir]--;
1059 ctl = umidi->roland_load_ctl; 1074 if (!umidi->opened[1])
1060 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 1075 snd_usbmidi_input_stop(&umidi->list);
1061 snd_ctl_notify(umidi->card, 1076 if (!umidi->opened[0] && !umidi->opened[1]) {
1077 if (umidi->roland_load_ctl) {
1078 ctl = umidi->roland_load_ctl;
1079 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1080 snd_ctl_notify(umidi->card,
1062 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); 1081 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
1082 }
1083 if (umidi->autopm_reference)
1084 usb_autopm_put_interface(umidi->iface);
1063 } 1085 }
1064 } 1086 }
1065 mutex_unlock(&umidi->mutex); 1087 mutex_unlock(&umidi->mutex);
1066 up_read(&umidi->disc_rwsem); 1088 up_read(&umidi->disc_rwsem);
1089 return 0;
1067} 1090}
1068 1091
1069static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) 1092static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@ -1071,7 +1094,6 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1071 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1094 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1072 struct usbmidi_out_port* port = NULL; 1095 struct usbmidi_out_port* port = NULL;
1073 int i, j; 1096 int i, j;
1074 int err;
1075 1097
1076 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) 1098 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
1077 if (umidi->endpoints[i].out) 1099 if (umidi->endpoints[i].out)
@@ -1085,33 +1107,14 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1085 return -ENXIO; 1107 return -ENXIO;
1086 } 1108 }
1087 1109
1088 down_read(&umidi->disc_rwsem);
1089 if (umidi->disconnected) {
1090 up_read(&umidi->disc_rwsem);
1091 return -ENODEV;
1092 }
1093 err = usb_autopm_get_interface(umidi->iface);
1094 port->autopm_reference = err >= 0;
1095 up_read(&umidi->disc_rwsem);
1096 if (err < 0 && err != -EACCES)
1097 return -EIO;
1098 substream->runtime->private_data = port; 1110 substream->runtime->private_data = port;
1099 port->state = STATE_UNKNOWN; 1111 port->state = STATE_UNKNOWN;
1100 substream_open(substream, 1); 1112 return substream_open(substream, 0, 1);
1101 return 0;
1102} 1113}
1103 1114
1104static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) 1115static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
1105{ 1116{
1106 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1117 return substream_open(substream, 0, 0);
1107 struct usbmidi_out_port *port = substream->runtime->private_data;
1108
1109 substream_open(substream, 0);
1110 down_read(&umidi->disc_rwsem);
1111 if (!umidi->disconnected && port->autopm_reference)
1112 usb_autopm_put_interface(umidi->iface);
1113 up_read(&umidi->disc_rwsem);
1114 return 0;
1115} 1118}
1116 1119
1117static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) 1120static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -1164,14 +1167,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
1164 1167
1165static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) 1168static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
1166{ 1169{
1167 substream_open(substream, 1); 1170 return substream_open(substream, 1, 1);
1168 return 0;
1169} 1171}
1170 1172
1171static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) 1173static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
1172{ 1174{
1173 substream_open(substream, 0); 1175 return substream_open(substream, 1, 0);
1174 return 0;
1175} 1176}
1176 1177
1177static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) 1178static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -2080,12 +2081,15 @@ void snd_usbmidi_input_stop(struct list_head* p)
2080 unsigned int i, j; 2081 unsigned int i, j;
2081 2082
2082 umidi = list_entry(p, struct snd_usb_midi, list); 2083 umidi = list_entry(p, struct snd_usb_midi, list);
2084 if (!umidi->input_running)
2085 return;
2083 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 2086 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
2084 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; 2087 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
2085 if (ep->in) 2088 if (ep->in)
2086 for (j = 0; j < INPUT_URBS; ++j) 2089 for (j = 0; j < INPUT_URBS; ++j)
2087 usb_kill_urb(ep->in->urbs[j]); 2090 usb_kill_urb(ep->in->urbs[j]);
2088 } 2091 }
2092 umidi->input_running = 0;
2089} 2093}
2090 2094
2091static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) 2095static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
@@ -2110,8 +2114,11 @@ void snd_usbmidi_input_start(struct list_head* p)
2110 int i; 2114 int i;
2111 2115
2112 umidi = list_entry(p, struct snd_usb_midi, list); 2116 umidi = list_entry(p, struct snd_usb_midi, list);
2117 if (umidi->input_running || !umidi->opened[1])
2118 return;
2113 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) 2119 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
2114 snd_usbmidi_input_start_ep(umidi->endpoints[i].in); 2120 snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
2121 umidi->input_running = 1;
2115} 2122}
2116 2123
2117/* 2124/*
@@ -2250,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card,
2250 } 2257 }
2251 2258
2252 list_add_tail(&umidi->list, midi_list); 2259 list_add_tail(&umidi->list, midi_list);
2253
2254 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
2255 snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
2256 return 0; 2260 return 0;
2257} 2261}
2258 2262