@@ -116,6 +116,7 @@ struct snd_usb_midi {
116
116
struct list_head list ;
117
117
struct timer_list error_timer ;
118
118
spinlock_t disc_lock ;
119
+ struct rw_semaphore disc_rwsem ;
119
120
struct mutex mutex ;
120
121
u32 usb_id ;
121
122
int next_midi_device ;
@@ -1038,6 +1039,12 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
1038
1039
struct snd_usb_midi * umidi = substream -> rmidi -> private_data ;
1039
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
1048
mutex_lock (& umidi -> mutex );
1042
1049
if (open ) {
1043
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
1065
mutex_unlock (& umidi -> mutex );
1066
+ up_read (& umidi -> disc_rwsem );
1059
1067
}
1060
1068
1061
1069
static 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
1084
snd_BUG ();
1077
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
1093
err = usb_autopm_get_interface (umidi -> iface );
1080
1094
port -> autopm_reference = err >= 0 ;
1095
+ up_read (& umidi -> disc_rwsem );
1081
1096
if (err < 0 && err != - EACCES )
1082
1097
return - EIO ;
1083
1098
substream -> runtime -> private_data = port ;
@@ -1092,8 +1107,10 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
1092
1107
struct usbmidi_out_port * port = substream -> runtime -> private_data ;
1093
1108
1094
1109
substream_open (substream , 0 );
1095
- if (port -> autopm_reference )
1110
+ down_read (& umidi -> disc_rwsem );
1111
+ if (!umidi -> disconnected && port -> autopm_reference )
1096
1112
usb_autopm_put_interface (umidi -> iface );
1113
+ up_read (& umidi -> disc_rwsem );
1097
1114
return 0 ;
1098
1115
}
1099
1116
@@ -1403,9 +1420,12 @@ void snd_usbmidi_disconnect(struct list_head* p)
1403
1420
* a timer may submit an URB. To reliably break the cycle
1404
1421
* a flag under lock must be used
1405
1422
*/
1423
+ down_write (& umidi -> disc_rwsem );
1406
1424
spin_lock_irq (& umidi -> disc_lock );
1407
1425
umidi -> disconnected = 1 ;
1408
1426
spin_unlock_irq (& umidi -> disc_lock );
1427
+ up_write (& umidi -> disc_rwsem );
1428
+
1409
1429
for (i = 0 ; i < MIDI_MAX_ENDPOINTS ; ++ i ) {
1410
1430
struct snd_usb_midi_endpoint * ep = & umidi -> endpoints [i ];
1411
1431
if (ep -> out )
@@ -2117,6 +2137,7 @@ int snd_usbmidi_create(struct snd_card *card,
2117
2137
umidi -> usb_protocol_ops = & snd_usbmidi_standard_ops ;
2118
2138
init_timer (& umidi -> error_timer );
2119
2139
spin_lock_init (& umidi -> disc_lock );
2140
+ init_rwsem (& umidi -> disc_rwsem );
2120
2141
mutex_init (& umidi -> mutex );
2121
2142
umidi -> usb_id = USB_ID (le16_to_cpu (umidi -> dev -> descriptor .idVendor ),
2122
2143
le16_to_cpu (umidi -> dev -> descriptor .idProduct ));
0 commit comments