aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2008-06-25 08:17:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-21 18:16:37 -0400
commit830f4021a8d5ce97c6bed267132e5e90fb166192 (patch)
treea07956625a505ebfd808f39ce8cb698db3dc358d /drivers/usb/class
parent62ad296b6ca78bd123864c138814c0a597873693 (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>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r--drivers/usb/class/cdc-acm.c28
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 */
842static void acm_write_buffers_free(struct acm *acm) 842static 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
852static 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 */
853static int acm_write_buffers_alloc(struct acm *acm) 862static 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);
1173alloc_fail7: 1182alloc_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);