diff options
author | Oliver Neukum <oliver@neukum.org> | 2008-06-25 08:17:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-07-21 18:16:37 -0400 |
commit | 830f4021a8d5ce97c6bed267132e5e90fb166192 (patch) | |
tree | a07956625a505ebfd808f39ce8cb698db3dc358d | |
parent | 62ad296b6ca78bd123864c138814c0a597873693 (diff) |
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>
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 28 |
1 files changed, 15 insertions, 13 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ba86fec872b4..93b28ee8e8bd 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -838,7 +838,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios | |||
838 | * USB probe and disconnect routines. | 838 | * USB probe and disconnect routines. |
839 | */ | 839 | */ |
840 | 840 | ||
841 | /* Little helper: write buffers free */ | 841 | /* Little helpers: write/read buffers free */ |
842 | static void acm_write_buffers_free(struct acm *acm) | 842 | static void acm_write_buffers_free(struct acm *acm) |
843 | { | 843 | { |
844 | int i; | 844 | int i; |
@@ -849,6 +849,15 @@ static void acm_write_buffers_free(struct acm *acm) | |||
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 | /* Little helper: write buffers allocate */ | 861 | /* Little helper: write buffers allocate */ |
853 | static int acm_write_buffers_alloc(struct acm *acm) | 862 | static int acm_write_buffers_alloc(struct acm *acm) |
854 | { | 863 | { |
@@ -1171,8 +1180,7 @@ alloc_fail8: | |||
1171 | for (i = 0; i < ACM_NW; i++) | 1180 | for (i = 0; i < ACM_NW; i++) |
1172 | usb_free_urb(acm->wb[i].urb); | 1181 | usb_free_urb(acm->wb[i].urb); |
1173 | alloc_fail7: | 1182 | alloc_fail7: |
1174 | for (i = 0; i < num_rx_buf; i++) | 1183 | acm_read_buffers_free(acm); |
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++) | 1184 | for (i = 0; i < num_rx_buf; i++) |
1177 | usb_free_urb(acm->ru[i].urb); | 1185 | usb_free_urb(acm->ru[i].urb); |
1178 | usb_free_urb(acm->ctrlurb); | 1186 | usb_free_urb(acm->ctrlurb); |
@@ -1209,15 +1217,9 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1209 | { | 1217 | { |
1210 | struct acm *acm = usb_get_intfdata(intf); | 1218 | struct acm *acm = usb_get_intfdata(intf); |
1211 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1219 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1212 | int i; | ||
1213 | |||
1214 | if (!acm || !acm->dev) { | ||
1215 | dbg("disconnect on nonexisting interface"); | ||
1216 | return; | ||
1217 | } | ||
1218 | 1220 | ||
1219 | mutex_lock(&open_mutex); | 1221 | mutex_lock(&open_mutex); |
1220 | if (!usb_get_intfdata(intf)) { | 1222 | if (!acm || !acm->dev) { |
1221 | mutex_unlock(&open_mutex); | 1223 | mutex_unlock(&open_mutex); |
1222 | return; | 1224 | return; |
1223 | } | 1225 | } |
@@ -1236,10 +1238,10 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1236 | 1238 | ||
1237 | acm_write_buffers_free(acm); | 1239 | acm_write_buffers_free(acm); |
1238 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1240 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
1239 | for (i = 0; i < acm->rx_buflimit; i++) | 1241 | acm_read_buffers_free(acm); |
1240 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | ||
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 | if (!acm->used) { | 1246 | if (!acm->used) { |
1245 | acm_tty_unregister(acm); | 1247 | acm_tty_unregister(acm); |