aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-12-03 05:12:46 -0500
committerTakashi Iwai <tiwai@suse.de>2012-12-04 01:27:27 -0500
commit59866da9e4ae54819e3c4e0a8f426bdb0c2ef993 (patch)
tree345bf3e8be9d6f0ad9a19c18a531a68ee3dcd55d /sound
parent467b10350525e53ddeea0b8de5b8b386a830d2a9 (diff)
ALSA: usb-audio: Avoid autopm calls after disconnection
Add a similar protection against the disconnection race and the invalid use of usb instance after disconnection, as well as we've done for the USB audio PCM. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51201 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')
-rw-r--r--sound/usb/midi.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index eeefbce3873c..c0054ee9389b 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;
@@ -1038,6 +1039,12 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
1038 struct snd_usb_midi* umidi = substream->rmidi->private_data; 1039 struct snd_usb_midi* umidi = substream->rmidi->private_data;
1039 struct snd_kcontrol *ctl; 1040 struct snd_kcontrol *ctl;
1040 1041
1042 down_read(&umidi->disc_rwsem);
1043 if (umidi->disconnected) {
1044 up_read(&umidi->disc_rwsem);
1045 return;
1046 }
1047
1041 mutex_lock(&umidi->mutex); 1048 mutex_lock(&umidi->mutex);
1042 if (open) { 1049 if (open) {
1043 if (umidi->opened++ == 0 && umidi->roland_load_ctl) { 1050 if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
@@ -1056,6 +1063,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
1056 } 1063 }
1057 } 1064 }
1058 mutex_unlock(&umidi->mutex); 1065 mutex_unlock(&umidi->mutex);
1066 up_read(&umidi->disc_rwsem);
1059} 1067}
1060 1068
1061static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) 1069static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@ -1076,8 +1084,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
1076 snd_BUG(); 1084 snd_BUG();
1077 return -ENXIO; 1085 return -ENXIO;
1078 } 1086 }
1087
1088 down_read(&umidi->disc_rwsem);
1089 if (umidi->disconnected) {
1090 up_read(&umidi->disc_rwsem);
1091 return -ENODEV;
1092 }
1079 err = usb_autopm_get_interface(umidi->iface); 1093 err = usb_autopm_get_interface(umidi->iface);
1080 port->autopm_reference = err >= 0; 1094 port->autopm_reference = err >= 0;
1095 up_read(&umidi->disc_rwsem);
1081 if (err < 0 && err != -EACCES) 1096 if (err < 0 && err != -EACCES)
1082 return -EIO; 1097 return -EIO;
1083 substream->runtime->private_data = port; 1098 substream->runtime->private_data = port;
@@ -1092,8 +1107,10 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
1092 struct usbmidi_out_port *port = substream->runtime->private_data; 1107 struct usbmidi_out_port *port = substream->runtime->private_data;
1093 1108
1094 substream_open(substream, 0); 1109 substream_open(substream, 0);
1095 if (port->autopm_reference) 1110 down_read(&umidi->disc_rwsem);
1111 if (!umidi->disconnected && port->autopm_reference)
1096 usb_autopm_put_interface(umidi->iface); 1112 usb_autopm_put_interface(umidi->iface);
1113 up_read(&umidi->disc_rwsem);
1097 return 0; 1114 return 0;
1098} 1115}
1099 1116
@@ -1403,9 +1420,12 @@ void snd_usbmidi_disconnect(struct list_head* p)
1403 * a timer may submit an URB. To reliably break the cycle 1420 * a timer may submit an URB. To reliably break the cycle
1404 * a flag under lock must be used 1421 * a flag under lock must be used
1405 */ 1422 */
1423 down_write(&umidi->disc_rwsem);
1406 spin_lock_irq(&umidi->disc_lock); 1424 spin_lock_irq(&umidi->disc_lock);
1407 umidi->disconnected = 1; 1425 umidi->disconnected = 1;
1408 spin_unlock_irq(&umidi->disc_lock); 1426 spin_unlock_irq(&umidi->disc_lock);
1427 up_write(&umidi->disc_rwsem);
1428
1409 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 1429 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
1410 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; 1430 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
1411 if (ep->out) 1431 if (ep->out)
@@ -2117,6 +2137,7 @@ int snd_usbmidi_create(struct snd_card *card,
2117 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; 2137 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
2118 init_timer(&umidi->error_timer); 2138 init_timer(&umidi->error_timer);
2119 spin_lock_init(&umidi->disc_lock); 2139 spin_lock_init(&umidi->disc_lock);
2140 init_rwsem(&umidi->disc_rwsem);
2120 mutex_init(&umidi->mutex); 2141 mutex_init(&umidi->mutex);
2121 umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), 2142 umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
2122 le16_to_cpu(umidi->dev->descriptor.idProduct)); 2143 le16_to_cpu(umidi->dev->descriptor.idProduct));