aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/midi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/midi.c')
-rw-r--r--sound/usb/midi.c91
1 files changed, 58 insertions, 33 deletions
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index eeefbce3873c..34b9bb7fe87c 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -116,6 +116,7 @@ struct snd_usb_midi {
116 struct list_head list; 116 struct list_head list;
117 struct timer_list error_timer; 117 struct timer_list error_timer;
118 spinlock_t disc_lock; 118 spinlock_t disc_lock;
119 struct rw_semaphore disc_rwsem;
119 struct mutex mutex; 120 struct mutex mutex;
120 u32 usb_id; 121 u32 usb_id;
121 int next_midi_device; 122 int next_midi_device;
@@ -125,8 +126,10 @@ struct snd_usb_midi {
125 struct snd_usb_midi_in_endpoint *in; 126 struct snd_usb_midi_in_endpoint *in;
126 } endpoints[MIDI_MAX_ENDPOINTS]; 127 } endpoints[MIDI_MAX_ENDPOINTS];
127 unsigned long input_triggered; 128 unsigned long input_triggered;
128 unsigned int opened; 129 bool autopm_reference;
130 unsigned int opened[2];
129 unsigned char disconnected; 131 unsigned char disconnected;
132 unsigned char input_running;
130 133
131 struct snd_kcontrol *roland_load_ctl; 134 struct snd_kcontrol *roland_load_ctl;
132}; 135};
@@ -148,7 +151,6 @@ struct snd_usb_midi_out_endpoint {
148 struct snd_usb_midi_out_endpoint* ep; 151 struct snd_usb_midi_out_endpoint* ep;
149 struct snd_rawmidi_substream *substream; 152 struct snd_rawmidi_substream *substream;
150 int active; 153 int active;
151 bool autopm_reference;
152 uint8_t cable; /* cable number << 4 */ 154 uint8_t cable; /* cable number << 4 */
153 uint8_t state; 155 uint8_t state;
154#define STATE_UNKNOWN 0 156#define STATE_UNKNOWN 0
@@ -1033,29 +1035,58 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)
1033 snd_usbmidi_input_start(&umidi->list); 1035 snd_usbmidi_input_start(&umidi->list);
1034} 1036}
1035 1037
1036static void substream_open(struct snd_rawmidi_substream *substream, int open) 1038static int substream_open(struct snd_rawmidi_substream *substream, int dir,
1039 int open)
1037{ 1040{
1038 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1041 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1039 struct snd_kcontrol *ctl; 1042 struct snd_kcontrol *ctl;
1043 int err;
1044
1045 down_read(&umidi->disc_rwsem);
1046 if (umidi->disconnected) {
1047 up_read(&umidi->disc_rwsem);
1048 return open ? -ENODEV : 0;
1049 }
1040 1050
1041 mutex_lock(&umidi->mutex); 1051 mutex_lock(&umidi->mutex);
1042 if (open) { 1052 if (open) {
1043 if (umidi->opened++ == 0 && umidi->roland_load_ctl) { 1053 if (!umidi->opened[0] && !umidi->opened[1]) {
1044 ctl = umidi->roland_load_ctl; 1054 err = usb_autopm_get_interface(umidi->iface);
1045 ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 1055 umidi->autopm_reference = err >= 0;
1046 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,
1047 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); 1065 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
1048 update_roland_altsetting(umidi); 1066 update_roland_altsetting(umidi);
1067 }
1049 } 1068 }
1069 umidi->opened[dir]++;
1070 if (umidi->opened[1])
1071 snd_usbmidi_input_start(&umidi->list);
1050 } else { 1072 } else {
1051 if (--umidi->opened == 0 && umidi->roland_load_ctl) { 1073 umidi->opened[dir]--;
1052 ctl = umidi->roland_load_ctl; 1074 if (!umidi->opened[1])
1053 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 1075 snd_usbmidi_input_stop(&umidi->list);
1054 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,
1055 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);
1056 } 1085 }
1057 } 1086 }
1058 mutex_unlock(&umidi->mutex); 1087 mutex_unlock(&umidi->mutex);
1088 up_read(&umidi->disc_rwsem);
1089 return 0;
1059} 1090}
1060 1091
1061static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) 1092static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@ -1063,7 +1094,6 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1063 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1094 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1064 struct usbmidi_out_port* port = NULL; 1095 struct usbmidi_out_port* port = NULL;
1065 int i, j; 1096 int i, j;
1066 int err;
1067 1097
1068 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) 1098 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
1069 if (umidi->endpoints[i].out) 1099 if (umidi->endpoints[i].out)
@@ -1076,25 +1106,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1076 snd_BUG(); 1106 snd_BUG();
1077 return -ENXIO; 1107 return -ENXIO;
1078 } 1108 }
1079 err = usb_autopm_get_interface(umidi->iface); 1109
1080 port->autopm_reference = err >= 0;
1081 if (err < 0 && err != -EACCES)
1082 return -EIO;
1083 substream->runtime->private_data = port; 1110 substream->runtime->private_data = port;
1084 port->state = STATE_UNKNOWN; 1111 port->state = STATE_UNKNOWN;
1085 substream_open(substream, 1); 1112 return substream_open(substream, 0, 1);
1086 return 0;
1087} 1113}
1088 1114
1089static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) 1115static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
1090{ 1116{
1091 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1117 return substream_open(substream, 0, 0);
1092 struct usbmidi_out_port *port = substream->runtime->private_data;
1093
1094 substream_open(substream, 0);
1095 if (port->autopm_reference)
1096 usb_autopm_put_interface(umidi->iface);
1097 return 0;
1098} 1118}
1099 1119
1100static 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)
@@ -1147,14 +1167,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
1147 1167
1148static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) 1168static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
1149{ 1169{
1150 substream_open(substream, 1); 1170 return substream_open(substream, 1, 1);
1151 return 0;
1152} 1171}
1153 1172
1154static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) 1173static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
1155{ 1174{
1156 substream_open(substream, 0); 1175 return substream_open(substream, 1, 0);
1157 return 0;
1158} 1176}
1159 1177
1160static 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)
@@ -1403,9 +1421,12 @@ void snd_usbmidi_disconnect(struct list_head* p)
1403 * a timer may submit an URB. To reliably break the cycle 1421 * a timer may submit an URB. To reliably break the cycle
1404 * a flag under lock must be used 1422 * a flag under lock must be used
1405 */ 1423 */
1424 down_write(&umidi->disc_rwsem);
1406 spin_lock_irq(&umidi->disc_lock); 1425 spin_lock_irq(&umidi->disc_lock);
1407 umidi->disconnected = 1; 1426 umidi->disconnected = 1;
1408 spin_unlock_irq(&umidi->disc_lock); 1427 spin_unlock_irq(&umidi->disc_lock);
1428 up_write(&umidi->disc_rwsem);
1429
1409 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 1430 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
1410 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; 1431 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
1411 if (ep->out) 1432 if (ep->out)
@@ -2060,12 +2081,15 @@ void snd_usbmidi_input_stop(struct list_head* p)
2060 unsigned int i, j; 2081 unsigned int i, j;
2061 2082
2062 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;
2063 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 2086 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
2064 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; 2087 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
2065 if (ep->in) 2088 if (ep->in)
2066 for (j = 0; j < INPUT_URBS; ++j) 2089 for (j = 0; j < INPUT_URBS; ++j)
2067 usb_kill_urb(ep->in->urbs[j]); 2090 usb_kill_urb(ep->in->urbs[j]);
2068 } 2091 }
2092 umidi->input_running = 0;
2069} 2093}
2070 2094
2071static 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)
@@ -2090,8 +2114,11 @@ void snd_usbmidi_input_start(struct list_head* p)
2090 int i; 2114 int i;
2091 2115
2092 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;
2093 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) 2119 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
2094 snd_usbmidi_input_start_ep(umidi->endpoints[i].in); 2120 snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
2121 umidi->input_running = 1;
2095} 2122}
2096 2123
2097/* 2124/*
@@ -2117,6 +2144,7 @@ int snd_usbmidi_create(struct snd_card *card,
2117 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; 2144 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
2118 init_timer(&umidi->error_timer); 2145 init_timer(&umidi->error_timer);
2119 spin_lock_init(&umidi->disc_lock); 2146 spin_lock_init(&umidi->disc_lock);
2147 init_rwsem(&umidi->disc_rwsem);
2120 mutex_init(&umidi->mutex); 2148 mutex_init(&umidi->mutex);
2121 umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), 2149 umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
2122 le16_to_cpu(umidi->dev->descriptor.idProduct)); 2150 le16_to_cpu(umidi->dev->descriptor.idProduct));
@@ -2229,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card,
2229 } 2257 }
2230 2258
2231 list_add_tail(&umidi->list, midi_list); 2259 list_add_tail(&umidi->list, midi_list);
2232
2233 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
2234 snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
2235 return 0; 2260 return 0;
2236} 2261}
2237 2262