Commit 830f4021a8d5ce97c6bed267132e5e90fb166192
Committed by
Greg Kroah-Hartman
1 parent
62ad296b6c
Exists in
master
and in
20 other branches
USB: fix disconnect bug in cdc-acm
cdc-acm must give up secondary interfaces if the primary is disconnected and vice versa. This wasn't done correctly. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 1 changed file with 15 additions and 13 deletions Side-by-side Diff
drivers/usb/class/cdc-acm.c
... | ... | @@ -838,7 +838,7 @@ |
838 | 838 | * USB probe and disconnect routines. |
839 | 839 | */ |
840 | 840 | |
841 | -/* Little helper: write buffers free */ | |
841 | +/* Little helpers: write/read buffers free */ | |
842 | 842 | static void acm_write_buffers_free(struct acm *acm) |
843 | 843 | { |
844 | 844 | int i; |
... | ... | @@ -849,6 +849,15 @@ |
849 | 849 | } |
850 | 850 | } |
851 | 851 | |
852 | +static void acm_read_buffers_free(struct acm *acm) | |
853 | +{ | |
854 | + struct usb_device *usb_dev = interface_to_usbdev(acm->control); | |
855 | + int i, n = acm->rx_buflimit; | |
856 | + | |
857 | + for (i = 0; i < n; i++) | |
858 | + usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | |
859 | +} | |
860 | + | |
852 | 861 | /* Little helper: write buffers allocate */ |
853 | 862 | static int acm_write_buffers_alloc(struct acm *acm) |
854 | 863 | { |
855 | 864 | |
... | ... | @@ -1171,9 +1180,8 @@ |
1171 | 1180 | for (i = 0; i < ACM_NW; i++) |
1172 | 1181 | usb_free_urb(acm->wb[i].urb); |
1173 | 1182 | alloc_fail7: |
1183 | + acm_read_buffers_free(acm); | |
1174 | 1184 | for (i = 0; i < num_rx_buf; i++) |
1175 | - usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | |
1176 | - for (i = 0; i < num_rx_buf; i++) | |
1177 | 1185 | usb_free_urb(acm->ru[i].urb); |
1178 | 1186 | usb_free_urb(acm->ctrlurb); |
1179 | 1187 | alloc_fail5: |
1180 | 1188 | |
1181 | 1189 | |
... | ... | @@ -1209,15 +1217,9 @@ |
1209 | 1217 | { |
1210 | 1218 | struct acm *acm = usb_get_intfdata(intf); |
1211 | 1219 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1212 | - int i; | |
1213 | 1220 | |
1214 | - if (!acm || !acm->dev) { | |
1215 | - dbg("disconnect on nonexisting interface"); | |
1216 | - return; | |
1217 | - } | |
1218 | - | |
1219 | 1221 | mutex_lock(&open_mutex); |
1220 | - if (!usb_get_intfdata(intf)) { | |
1222 | + if (!acm || !acm->dev) { | |
1221 | 1223 | mutex_unlock(&open_mutex); |
1222 | 1224 | return; |
1223 | 1225 | } |
1224 | 1226 | |
... | ... | @@ -1236,10 +1238,10 @@ |
1236 | 1238 | |
1237 | 1239 | acm_write_buffers_free(acm); |
1238 | 1240 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1239 | - for (i = 0; i < acm->rx_buflimit; i++) | |
1240 | - usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | |
1241 | + acm_read_buffers_free(acm); | |
1241 | 1242 | |
1242 | - usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); | |
1243 | + usb_driver_release_interface(&acm_driver, intf == acm->control ? | |
1244 | + acm->data : acm->control); | |
1243 | 1245 | |
1244 | 1246 | if (!acm->used) { |
1245 | 1247 | acm_tty_unregister(acm); |