Skip to content

Commit f5f1654

Browse files
committed
ALSA: usb-audio: Fix missing autopm for MIDI input
The commit [88a8516: 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 <[email protected]> Tested-by: Clemens Ladisch <[email protected]> Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 59866da commit f5f1654

File tree

1 file changed

+46
-42
lines changed

1 file changed

+46
-42
lines changed

sound/usb/midi.c

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,10 @@ struct snd_usb_midi {
126126
struct snd_usb_midi_in_endpoint *in;
127127
} endpoints[MIDI_MAX_ENDPOINTS];
128128
unsigned long input_triggered;
129-
unsigned int opened;
129+
bool autopm_reference;
130+
unsigned int opened[2];
130131
unsigned char disconnected;
132+
unsigned char input_running;
131133

132134
struct snd_kcontrol *roland_load_ctl;
133135
};
@@ -149,7 +151,6 @@ struct snd_usb_midi_out_endpoint {
149151
struct snd_usb_midi_out_endpoint* ep;
150152
struct snd_rawmidi_substream *substream;
151153
int active;
152-
bool autopm_reference;
153154
uint8_t cable; /* cable number << 4 */
154155
uint8_t state;
155156
#define STATE_UNKNOWN 0
@@ -1034,44 +1035,65 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)
10341035
snd_usbmidi_input_start(&umidi->list);
10351036
}
10361037

1037-
static void substream_open(struct snd_rawmidi_substream *substream, int open)
1038+
static int substream_open(struct snd_rawmidi_substream *substream, int dir,
1039+
int open)
10381040
{
10391041
struct snd_usb_midi* umidi = substream->rmidi->private_data;
10401042
struct snd_kcontrol *ctl;
1043+
int err;
10411044

10421045
down_read(&umidi->disc_rwsem);
10431046
if (umidi->disconnected) {
10441047
up_read(&umidi->disc_rwsem);
1045-
return;
1048+
return open ? -ENODEV : 0;
10461049
}
10471050

10481051
mutex_lock(&umidi->mutex);
10491052
if (open) {
1050-
if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
1051-
ctl = umidi->roland_load_ctl;
1052-
ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1053-
snd_ctl_notify(umidi->card,
1053+
if (!umidi->opened[0] && !umidi->opened[1]) {
1054+
err = usb_autopm_get_interface(umidi->iface);
1055+
umidi->autopm_reference = err >= 0;
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,
10541065
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
1055-
update_roland_altsetting(umidi);
1066+
update_roland_altsetting(umidi);
1067+
}
10561068
}
1069+
umidi->opened[dir]++;
1070+
if (umidi->opened[1])
1071+
snd_usbmidi_input_start(&umidi->list);
10571072
} else {
1058-
if (--umidi->opened == 0 && umidi->roland_load_ctl) {
1059-
ctl = umidi->roland_load_ctl;
1060-
ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1061-
snd_ctl_notify(umidi->card,
1073+
umidi->opened[dir]--;
1074+
if (!umidi->opened[1])
1075+
snd_usbmidi_input_stop(&umidi->list);
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,
10621081
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
1082+
}
1083+
if (umidi->autopm_reference)
1084+
usb_autopm_put_interface(umidi->iface);
10631085
}
10641086
}
10651087
mutex_unlock(&umidi->mutex);
10661088
up_read(&umidi->disc_rwsem);
1089+
return 0;
10671090
}
10681091

10691092
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
10701093
{
10711094
struct snd_usb_midi* umidi = substream->rmidi->private_data;
10721095
struct usbmidi_out_port* port = NULL;
10731096
int i, j;
1074-
int err;
10751097

10761098
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
10771099
if (umidi->endpoints[i].out)
@@ -1085,33 +1107,14 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
10851107
return -ENXIO;
10861108
}
10871109

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;
10981110
substream->runtime->private_data = port;
10991111
port->state = STATE_UNKNOWN;
1100-
substream_open(substream, 1);
1101-
return 0;
1112+
return substream_open(substream, 0, 1);
11021113
}
11031114

11041115
static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
11051116
{
1106-
struct snd_usb_midi* umidi = substream->rmidi->private_data;
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;
1117+
return substream_open(substream, 0, 0);
11151118
}
11161119

11171120
static 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)
11641167

11651168
static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
11661169
{
1167-
substream_open(substream, 1);
1168-
return 0;
1170+
return substream_open(substream, 1, 1);
11691171
}
11701172

11711173
static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
11721174
{
1173-
substream_open(substream, 0);
1174-
return 0;
1175+
return substream_open(substream, 1, 0);
11751176
}
11761177

11771178
static 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)
20802081
unsigned int i, j;
20812082

20822083
umidi = list_entry(p, struct snd_usb_midi, list);
2084+
if (!umidi->input_running)
2085+
return;
20832086
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
20842087
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
20852088
if (ep->in)
20862089
for (j = 0; j < INPUT_URBS; ++j)
20872090
usb_kill_urb(ep->in->urbs[j]);
20882091
}
2092+
umidi->input_running = 0;
20892093
}
20902094

20912095
static 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)
21102114
int i;
21112115

21122116
umidi = list_entry(p, struct snd_usb_midi, list);
2117+
if (umidi->input_running || !umidi->opened[1])
2118+
return;
21132119
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
21142120
snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
2121+
umidi->input_running = 1;
21152122
}
21162123

21172124
/*
@@ -2250,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card,
22502257
}
22512258

22522259
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);
22562260
return 0;
22572261
}
22582262

0 commit comments

Comments
 (0)