Commit 830f4021a8d5ce97c6bed267132e5e90fb166192

Authored by Oliver Neukum
Committed by Greg Kroah-Hartman
1 parent 62ad296b6c

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);