]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Oct 2012 23:13:26 +0000 (16:13 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Oct 2012 23:13:26 +0000 (16:13 -0700)
added patches:
usb-metro-usb-fix-io-after-disconnect.patch
usb-metro-usb-fix-port-data-memory-leak.patch
usb-mos7720-fix-port-data-memory-leak.patch
usb-mos7840-fix-port-device-leak-in-error-path.patch
usb-mos7840-fix-urb-leak-at-release.patch
usb-mos7840-remove-invalid-disconnect-handling.patch
usb-mos7840-remove-null-urb-submission.patch
usb-quatech2-fix-close-and-disconnect-urb-handling.patch
usb-quatech2-fix-io-after-disconnect.patch
usb-quatech2-fix-memory-leak-in-error-path.patch
usb-quatech2-fix-port-data-memory-leaks.patch
usb-serial-fix-memory-leak-in-sierra_release.patch
usb-sierra-fix-memory-leak-in-attach-error-path.patch
usb-sierra-fix-memory-leak-in-probe-error-path.patch
usb-sierra-fix-port-data-memory-leak.patch

16 files changed:
queue-3.6/series
queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch [new file with mode: 0644]
queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch [new file with mode: 0644]
queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch [new file with mode: 0644]
queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch [new file with mode: 0644]
queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch [new file with mode: 0644]
queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch [new file with mode: 0644]
queue-3.6/usb-mos7840-remove-null-urb-submission.patch [new file with mode: 0644]
queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch [new file with mode: 0644]
queue-3.6/usb-quatech2-fix-io-after-disconnect.patch [new file with mode: 0644]
queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch [new file with mode: 0644]
queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch [new file with mode: 0644]
queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch [new file with mode: 0644]
queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch [new file with mode: 0644]
queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch [new file with mode: 0644]
queue-3.6/usb-sierra-fix-port-data-memory-leak.patch [new file with mode: 0644]

index b2f3018ab35807fd4b4d97e833b7ad0d6d338d1d..b6746574c6e9c6335e871f1495852b3cb8b623ed 100644 (file)
@@ -53,3 +53,18 @@ usb-whiteheat-fix-memory-leak-in-error-path.patch
 usb-whiteheat-fix-port-data-memory-leak.patch
 usb-opticon-fix-dma-from-stack.patch
 usb-opticon-fix-memory-leak-in-error-path.patch
+usb-metro-usb-fix-port-data-memory-leak.patch
+usb-metro-usb-fix-io-after-disconnect.patch
+usb-mos7720-fix-port-data-memory-leak.patch
+usb-quatech2-fix-memory-leak-in-error-path.patch
+usb-quatech2-fix-port-data-memory-leaks.patch
+usb-quatech2-fix-close-and-disconnect-urb-handling.patch
+usb-quatech2-fix-io-after-disconnect.patch
+usb-serial-fix-memory-leak-in-sierra_release.patch
+usb-sierra-fix-memory-leak-in-attach-error-path.patch
+usb-sierra-fix-memory-leak-in-probe-error-path.patch
+usb-sierra-fix-port-data-memory-leak.patch
+usb-mos7840-fix-urb-leak-at-release.patch
+usb-mos7840-fix-port-device-leak-in-error-path.patch
+usb-mos7840-remove-null-urb-submission.patch
+usb-mos7840-remove-invalid-disconnect-handling.patch
diff --git a/queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch b/queue-3.6/usb-metro-usb-fix-io-after-disconnect.patch
new file mode 100644 (file)
index 0000000..9bbfdaf
--- /dev/null
@@ -0,0 +1,43 @@
+From 2ee44fbeac92c36e53779a57ee84cfee1affe418 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:00 +0200
+Subject: USB: metro-usb: fix io after disconnect
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 2ee44fbeac92c36e53779a57ee84cfee1affe418 upstream.
+
+Make sure no control urb is submitted during close after a disconnect by
+checking the disconnected flag.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/metro-usb.c |   13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/serial/metro-usb.c
++++ b/drivers/usb/serial/metro-usb.c
+@@ -188,16 +188,13 @@ static void metrousb_cleanup(struct usb_
+ {
+       dev_dbg(&port->dev, "%s\n", __func__);
+-      if (port->serial->dev) {
+-              /* Shutdown any interrupt in urbs. */
+-              if (port->interrupt_in_urb) {
+-                      usb_unlink_urb(port->interrupt_in_urb);
+-                      usb_kill_urb(port->interrupt_in_urb);
+-              }
++      usb_unlink_urb(port->interrupt_in_urb);
++      usb_kill_urb(port->interrupt_in_urb);
+-              /* Send deactivate cmd to device */
++      mutex_lock(&port->serial->disc_mutex);
++      if (!port->serial->disconnected)
+               metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
+-      }
++      mutex_unlock(&port->serial->disc_mutex);
+ }
+ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
diff --git a/queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch b/queue-3.6/usb-metro-usb-fix-port-data-memory-leak.patch
new file mode 100644 (file)
index 0000000..0a138b5
--- /dev/null
@@ -0,0 +1,103 @@
+From 50dde8686eec41bf3d7cbec7a6f76c073ab01903 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:28:59 +0200
+Subject: USB: metro-usb: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 50dde8686eec41bf3d7cbec7a6f76c073ab01903 upstream.
+
+Fix port-data memory leak by moving port data allocation and
+deallocation to port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Note that the call to metrousb_clean (close) in shutdown was redundant.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/metro-usb.c |   50 ++++++++++-------------------------------
+ 1 file changed, 13 insertions(+), 37 deletions(-)
+
+--- a/drivers/usb/serial/metro-usb.c
++++ b/drivers/usb/serial/metro-usb.c
+@@ -280,51 +280,27 @@ static int metrousb_set_modem_ctrl(struc
+       return retval;
+ }
+-static void metrousb_shutdown(struct usb_serial *serial)
++static int metrousb_port_probe(struct usb_serial_port *port)
+ {
+-      int i = 0;
++      struct metrousb_private *metro_priv;
+-      dev_dbg(&serial->dev->dev, "%s\n", __func__);
++      metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL);
++      if (!metro_priv)
++              return -ENOMEM;
+-      /* Stop reading and writing on all ports. */
+-      for (i = 0; i < serial->num_ports; ++i) {
+-              /* Close any open urbs. */
+-              metrousb_cleanup(serial->port[i]);
++      spin_lock_init(&metro_priv->lock);
+-              /* Free memory. */
+-              kfree(usb_get_serial_port_data(serial->port[i]));
+-              usb_set_serial_port_data(serial->port[i], NULL);
++      usb_set_serial_port_data(port, metro_priv);
+-              dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n",
+-                      __func__, serial->port[i]->number);
+-      }
++      return 0;
+ }
+-static int metrousb_startup(struct usb_serial *serial)
++static int metrousb_port_remove(struct usb_serial_port *port)
+ {
+       struct metrousb_private *metro_priv;
+-      struct usb_serial_port *port;
+-      int i = 0;
+-
+-      dev_dbg(&serial->dev->dev, "%s\n", __func__);
+-      /* Loop through the serial ports setting up the private structures.
+-       * Currently we only use one port. */
+-      for (i = 0; i < serial->num_ports; ++i) {
+-              port = serial->port[i];
+-
+-              /* Declare memory. */
+-              metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
+-              if (!metro_priv)
+-                      return -ENOMEM;
+-
+-              /* Initialize memory. */
+-              spin_lock_init(&metro_priv->lock);
+-              usb_set_serial_port_data(port, metro_priv);
+-
+-              dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
+-                      __func__, port->number);
+-      }
++      metro_priv = usb_get_serial_port_data(port);
++      kfree(metro_priv);
+       return 0;
+ }
+@@ -423,8 +399,8 @@ static struct usb_serial_driver metrousb
+       .close                  = metrousb_cleanup,
+       .read_int_callback      = metrousb_read_int_callback,
+       .write_int_callback     = metrousb_write_int_callback,
+-      .attach                 = metrousb_startup,
+-      .release                = metrousb_shutdown,
++      .port_probe             = metrousb_port_probe,
++      .port_remove            = metrousb_port_remove,
+       .throttle               = metrousb_throttle,
+       .unthrottle             = metrousb_unthrottle,
+       .tiocmget               = metrousb_tiocmget,
diff --git a/queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch b/queue-3.6/usb-mos7720-fix-port-data-memory-leak.patch
new file mode 100644 (file)
index 0000000..10c7274
--- /dev/null
@@ -0,0 +1,128 @@
+From 4230af572f95b3115bba1ee6fb95681f3851ab26 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:05 +0200
+Subject: USB: mos7720: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 4230af572f95b3115bba1ee6fb95681f3851ab26 upstream.
+
+Fix port-data memory leak by moving port data allocation and
+deallocation to port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Note that this patch also fixes a second port-data memory leak in the
+error path of attach, should parallel-port initialisation fail.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7720.c |   62 ++++++++++++++++++++++---------------------
+ 1 file changed, 32 insertions(+), 30 deletions(-)
+
+--- a/drivers/usb/serial/mos7720.c
++++ b/drivers/usb/serial/mos7720.c
+@@ -2023,9 +2023,7 @@ static int mos7720_ioctl(struct tty_stru
+ static int mos7720_startup(struct usb_serial *serial)
+ {
+-      struct moschip_port *mos7720_port;
+       struct usb_device *dev;
+-      int i;
+       char data;
+       u16 product;
+       int ret_val;
+@@ -2063,29 +2061,6 @@ static int mos7720_startup(struct usb_se
+               serial->port[1]->interrupt_in_buffer = NULL;
+       }
+-
+-      /* set up serial port private structures */
+-      for (i = 0; i < serial->num_ports; ++i) {
+-              mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
+-              if (mos7720_port == NULL) {
+-                      dev_err(&dev->dev, "%s - Out of memory\n", __func__);
+-                      return -ENOMEM;
+-              }
+-
+-              /* Initialize all port interrupt end point to port 0 int
+-               * endpoint.  Our device has only one interrupt endpoint
+-               * common to all ports */
+-              serial->port[i]->interrupt_in_endpointAddress =
+-                              serial->port[0]->interrupt_in_endpointAddress;
+-
+-              mos7720_port->port = serial->port[i];
+-              usb_set_serial_port_data(serial->port[i], mos7720_port);
+-
+-              dbg("port number is %d", serial->port[i]->number);
+-              dbg("serial number is %d", serial->minor);
+-      }
+-
+-
+       /* setting configuration feature to one */
+       usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                       (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ);
+@@ -2113,8 +2088,6 @@ static int mos7720_startup(struct usb_se
+ static void mos7720_release(struct usb_serial *serial)
+ {
+-      int i;
+-
+ #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+       /* close the parallel port */
+@@ -2153,9 +2126,36 @@ static void mos7720_release(struct usb_s
+               kref_put(&mos_parport->ref_count, destroy_mos_parport);
+       }
+ #endif
+-      /* free private structure allocated for serial port */
+-      for (i = 0; i < serial->num_ports; ++i)
+-              kfree(usb_get_serial_port_data(serial->port[i]));
++}
++
++static int mos7720_port_probe(struct usb_serial_port *port)
++{
++      struct moschip_port *mos7720_port;
++
++      mos7720_port = kzalloc(sizeof(*mos7720_port), GFP_KERNEL);
++      if (!mos7720_port)
++              return -ENOMEM;
++
++      /* Initialize all port interrupt end point to port 0 int endpoint.
++       * Our device has only one interrupt endpoint common to all ports.
++       */
++      port->interrupt_in_endpointAddress =
++              port->serial->port[0]->interrupt_in_endpointAddress;
++      mos7720_port->port = port;
++
++      usb_set_serial_port_data(port, mos7720_port);
++
++      return 0;
++}
++
++static int mos7720_port_remove(struct usb_serial_port *port)
++{
++      struct moschip_port *mos7720_port;
++
++      mos7720_port = usb_get_serial_port_data(port);
++      kfree(mos7720_port);
++
++      return 0;
+ }
+ static struct usb_serial_driver moschip7720_2port_driver = {
+@@ -2173,6 +2173,8 @@ static struct usb_serial_driver moschip7
+       .probe                  = mos77xx_probe,
+       .attach                 = mos7720_startup,
+       .release                = mos7720_release,
++      .port_probe             = mos7720_port_probe,
++      .port_remove            = mos7720_port_remove,
+       .ioctl                  = mos7720_ioctl,
+       .tiocmget               = mos7720_tiocmget,
+       .tiocmset               = mos7720_tiocmset,
diff --git a/queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch b/queue-3.6/usb-mos7840-fix-port-device-leak-in-error-path.patch
new file mode 100644 (file)
index 0000000..7211712
--- /dev/null
@@ -0,0 +1,30 @@
+From 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 13:35:10 +0200
+Subject: USB: mos7840: fix port-device leak in error path
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda upstream.
+
+The driver set the usb-serial port pointers to NULL on errors in attach,
+effectively preventing usb-serial core from decrementing the port ref
+counters and releasing the port devices and associated data.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -2684,7 +2684,6 @@ error:
+               kfree(mos7840_port->ctrl_buf);
+               usb_free_urb(mos7840_port->control_urb);
+               kfree(mos7840_port);
+-              serial->port[i] = NULL;
+       }
+       return status;
+ }
diff --git a/queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch b/queue-3.6/usb-mos7840-fix-urb-leak-at-release.patch
new file mode 100644 (file)
index 0000000..4c3c541
--- /dev/null
@@ -0,0 +1,28 @@
+From 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 13:35:09 +0200
+Subject: USB: mos7840: fix urb leak at release
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 upstream.
+
+Make sure control urb is freed at release.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -2754,6 +2754,7 @@ static void mos7840_release(struct usb_s
+                               del_timer_sync(&mos7840_port->led_timer1);
+                               del_timer_sync(&mos7840_port->led_timer2);
+                       }
++                      usb_free_urb(mos7840_port->control_urb);
+                       kfree(mos7840_port->ctrl_buf);
+                       kfree(mos7840_port->dr);
+                       kfree(mos7840_port);
diff --git a/queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch b/queue-3.6/usb-mos7840-remove-invalid-disconnect-handling.patch
new file mode 100644 (file)
index 0000000..1237d13
--- /dev/null
@@ -0,0 +1,58 @@
+From e681b66f2e19fadbe8a7e2a17900978cb6bc921f Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 18:56:33 +0200
+Subject: USB: mos7840: remove invalid disconnect handling
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e681b66f2e19fadbe8a7e2a17900978cb6bc921f upstream.
+
+Remove private zombie flag used to signal disconnect and to prevent
+control urb from being submitted from interrupt urb completion handler.
+
+The control urb will not be re-submitted as both the control urb and the
+interrupt urb is killed on disconnect.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c |   13 +------------
+ 1 file changed, 1 insertion(+), 12 deletions(-)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -222,7 +222,6 @@ struct moschip_port {
+       __u8 shadowMCR;         /* last MCR value received */
+       char open;
+       char open_ports;
+-      char zombie;
+       wait_queue_head_t wait_chase;   /* for handling sleeping while waiting for chase to finish */
+       wait_queue_head_t delta_msr_wait;       /* for handling sleeping while waiting for msr change to happen */
+       int delta_msr_cond;
+@@ -691,14 +690,7 @@ static void mos7840_interrupt_callback(s
+                                       wreg = MODEM_STATUS_REGISTER;
+                                       break;
+                               }
+-                              spin_lock(&mos7840_port->pool_lock);
+-                              if (!mos7840_port->zombie) {
+-                                      rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
+-                              } else {
+-                                      spin_unlock(&mos7840_port->pool_lock);
+-                                      return;
+-                              }
+-                              spin_unlock(&mos7840_port->pool_lock);
++                              rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
+                       }
+               }
+       }
+@@ -2700,9 +2692,6 @@ static void mos7840_disconnect(struct us
+               mos7840_port = mos7840_get_port_private(serial->port[i]);
+               dbg ("mos7840_port %d = %p", i, mos7840_port);
+               if (mos7840_port) {
+-                      spin_lock_irqsave(&mos7840_port->pool_lock, flags);
+-                      mos7840_port->zombie = 1;
+-                      spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
+                       usb_kill_urb(mos7840_port->control_urb);
+               }
+       }
diff --git a/queue-3.6/usb-mos7840-remove-null-urb-submission.patch b/queue-3.6/usb-mos7840-remove-null-urb-submission.patch
new file mode 100644 (file)
index 0000000..0f9feb8
--- /dev/null
@@ -0,0 +1,65 @@
+From 28c3ae9a8cf45f439c9a0779ebd0256e2ae72813 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 18:56:32 +0200
+Subject: USB: mos7840: remove NULL-urb submission
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 28c3ae9a8cf45f439c9a0779ebd0256e2ae72813 upstream.
+
+The private int_urb is never allocated so the submission from the
+control completion handler will always fail. Remove this odd piece of
+broken code.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/mos7840.c |   15 +--------------
+ 1 file changed, 1 insertion(+), 14 deletions(-)
+
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -218,7 +218,6 @@ struct moschip_port {
+       int port_num;           /*Actual port number in the device(1,2,etc) */
+       struct urb *write_urb;  /* write URB for this port */
+       struct urb *read_urb;   /* read URB for this port */
+-      struct urb *int_urb;
+       __u8 shadowLCR;         /* last LCR value received */
+       __u8 shadowMCR;         /* last MCR value received */
+       char open;
+@@ -493,7 +492,6 @@ static void mos7840_control_callback(str
+       unsigned char *data;
+       struct moschip_port *mos7840_port;
+       __u8 regval = 0x0;
+-      int result = 0;
+       int status = urb->status;
+       mos7840_port = urb->context;
+@@ -512,7 +510,7 @@ static void mos7840_control_callback(str
+       default:
+               dbg("%s - nonzero urb status received: %d", __func__,
+                   status);
+-              goto exit;
++              return;
+       }
+       dbg("%s urb buffer size is %d", __func__, urb->actual_length);
+@@ -525,17 +523,6 @@ static void mos7840_control_callback(str
+               mos7840_handle_new_msr(mos7840_port, regval);
+       else if (mos7840_port->MsrLsr == 1)
+               mos7840_handle_new_lsr(mos7840_port, regval);
+-
+-exit:
+-      spin_lock(&mos7840_port->pool_lock);
+-      if (!mos7840_port->zombie)
+-              result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC);
+-      spin_unlock(&mos7840_port->pool_lock);
+-      if (result) {
+-              dev_err(&urb->dev->dev,
+-                      "%s - Error %d submitting interrupt urb\n",
+-                      __func__, result);
+-      }
+ }
+ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
diff --git a/queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch b/queue-3.6/usb-quatech2-fix-close-and-disconnect-urb-handling.patch
new file mode 100644 (file)
index 0000000..64cddca
--- /dev/null
@@ -0,0 +1,42 @@
+From 8e512ab0b675da20e023439a5811e3f2554e6852 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:09 +0200
+Subject: USB: quatech2: fix close and disconnect urb handling
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 8e512ab0b675da20e023439a5811e3f2554e6852 upstream.
+
+Kill urbs unconditionally at close and disconnect.
+
+Note that URB status is not valid outside of completion handler.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/quatech2.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/quatech2.c
++++ b/drivers/usb/serial/quatech2.c
+@@ -425,8 +425,7 @@ static void qt2_close(struct usb_serial_
+       port_priv->is_open = false;
+       spin_lock_irqsave(&port_priv->urb_lock, flags);
+-      if (port_priv->write_urb->status == -EINPROGRESS)
+-              usb_kill_urb(port_priv->write_urb);
++      usb_kill_urb(port_priv->write_urb);
+       port_priv->urb_in_use = false;
+       spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+@@ -467,8 +466,7 @@ static void qt2_disconnect(struct usb_se
+ {
+       struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
+-      if (serial_priv->read_urb->status == -EINPROGRESS)
+-              usb_kill_urb(serial_priv->read_urb);
++      usb_kill_urb(serial_priv->read_urb);
+ }
+ static int get_serial_info(struct usb_serial_port *port,
diff --git a/queue-3.6/usb-quatech2-fix-io-after-disconnect.patch b/queue-3.6/usb-quatech2-fix-io-after-disconnect.patch
new file mode 100644 (file)
index 0000000..3ca0a6f
--- /dev/null
@@ -0,0 +1,42 @@
+From 2f0295adf6438188c4cd0868f2b1976a2b034e1d Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:10 +0200
+Subject: USB: quatech2: fix io after disconnect
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 2f0295adf6438188c4cd0868f2b1976a2b034e1d upstream.
+
+Make sure no control urb is submitted during close after a disconnect by
+checking the disconnected flag.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/quatech2.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/usb/serial/quatech2.c
++++ b/drivers/usb/serial/quatech2.c
+@@ -429,6 +429,12 @@ static void qt2_close(struct usb_serial_
+       port_priv->urb_in_use = false;
+       spin_unlock_irqrestore(&port_priv->urb_lock, flags);
++      mutex_lock(&port->serial->disc_mutex);
++      if (port->serial->disconnected) {
++              mutex_unlock(&port->serial->disc_mutex);
++              return;
++      }
++
+       /* flush the port transmit buffer */
+       i = usb_control_msg(serial->dev,
+                           usb_rcvctrlpipe(serial->dev, 0),
+@@ -460,6 +466,7 @@ static void qt2_close(struct usb_serial_
+               dev_err(&port->dev, "%s - close port failed %i\n",
+                       __func__, i);
++      mutex_unlock(&port->serial->disc_mutex);
+ }
+ static void qt2_disconnect(struct usb_serial *serial)
diff --git a/queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch b/queue-3.6/usb-quatech2-fix-memory-leak-in-error-path.patch
new file mode 100644 (file)
index 0000000..1e7be27
--- /dev/null
@@ -0,0 +1,29 @@
+From b8a0055050b6294826171641b182c09f78f4cc63 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:07 +0200
+Subject: USB: quatech2: fix memory leak in error path
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit b8a0055050b6294826171641b182c09f78f4cc63 upstream.
+
+Fix memory leak in attach error path where the read urb was never freed.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Cc: Bill Pemberton <wfp5p@virginia.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/quatech2.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/quatech2.c
++++ b/drivers/usb/serial/quatech2.c
+@@ -825,6 +825,7 @@ static int qt2_setup_urbs(struct usb_ser
+       if (status != 0) {
+               dev_err(&serial->dev->dev,
+                       "%s - submit read urb failed %i\n", __func__, status);
++              usb_free_urb(serial_priv->read_urb);
+               return status;
+       }
diff --git a/queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch b/queue-3.6/usb-quatech2-fix-port-data-memory-leaks.patch
new file mode 100644 (file)
index 0000000..ada716e
--- /dev/null
@@ -0,0 +1,230 @@
+From 40d04738491d7ac1aa708ba434ff3480ec9e1b96 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:08 +0200
+Subject: USB: quatech2: fix port-data memory leaks
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 40d04738491d7ac1aa708ba434ff3480ec9e1b96 upstream.
+
+Fix port-data memory leak by moving port data allocation and
+deallocation to port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Note that this also fixes memory leaks in the error path of attach where
+the write urbs were not freed on errors.
+
+Make sure all interface-data deallocation is done in release by moving
+the read urb deallocation from disconnect.
+
+Note that the write urb is killed during close so that the call in
+disconnect was superfluous.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Cc: Bill Pemberton <wfp5p@virginia.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/quatech2.c |  121 +++++++++++++++++-------------------------
+ 1 file changed, 51 insertions(+), 70 deletions(-)
+
+--- a/drivers/usb/serial/quatech2.c
++++ b/drivers/usb/serial/quatech2.c
+@@ -145,12 +145,12 @@ static void qt2_read_bulk_callback(struc
+ static void qt2_release(struct usb_serial *serial)
+ {
+-      int i;
++      struct qt2_serial_private *serial_priv;
+-      kfree(usb_get_serial_data(serial));
++      serial_priv = usb_get_serial_data(serial);
+-      for (i = 0; i < serial->num_ports; i++)
+-              kfree(usb_get_serial_port_data(serial->port[i]));
++      usb_free_urb(serial_priv->read_urb);
++      kfree(serial_priv);
+ }
+ static inline int calc_baud_divisor(int baudrate)
+@@ -466,21 +466,9 @@ static void qt2_close(struct usb_serial_
+ static void qt2_disconnect(struct usb_serial *serial)
+ {
+       struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
+-      struct qt2_port_private *port_priv;
+-      int i;
+       if (serial_priv->read_urb->status == -EINPROGRESS)
+               usb_kill_urb(serial_priv->read_urb);
+-
+-      usb_free_urb(serial_priv->read_urb);
+-
+-      for (i = 0; i < serial->num_ports; i++) {
+-              port_priv = usb_get_serial_port_data(serial->port[i]);
+-
+-              if (port_priv->write_urb->status == -EINPROGRESS)
+-                      usb_kill_urb(port_priv->write_urb);
+-              usb_free_urb(port_priv->write_urb);
+-      }
+ }
+ static int get_serial_info(struct usb_serial_port *port,
+@@ -775,11 +763,9 @@ static void qt2_read_bulk_callback(struc
+ static int qt2_setup_urbs(struct usb_serial *serial)
+ {
+-      struct usb_serial_port *port;
+       struct usb_serial_port *port0;
+       struct qt2_serial_private *serial_priv;
+-      struct qt2_port_private *port_priv;
+-      int pcount, status;
++      int status;
+       port0 = serial->port[0];
+@@ -797,30 +783,6 @@ static int qt2_setup_urbs(struct usb_ser
+                         sizeof(serial_priv->read_buffer),
+                         qt2_read_bulk_callback, serial);
+-      /* setup write_urb for each port */
+-      for (pcount = 0; pcount < serial->num_ports; pcount++) {
+-
+-              port = serial->port[pcount];
+-              port_priv = usb_get_serial_port_data(port);
+-
+-              port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+-              if (!port_priv->write_urb) {
+-                      dev_err(&serial->dev->dev,
+-                              "failed to alloc write_urb for port %i\n",
+-                              pcount);
+-                      return -ENOMEM;
+-              }
+-
+-              usb_fill_bulk_urb(port_priv->write_urb,
+-                                serial->dev,
+-                                usb_sndbulkpipe(serial->dev,
+-                                                port0->
+-                                                bulk_out_endpointAddress),
+-                                port_priv->write_buffer,
+-                                sizeof(port_priv->write_buffer),
+-                                qt2_write_bulk_callback, port);
+-      }
+-
+       status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
+       if (status != 0) {
+               dev_err(&serial->dev->dev,
+@@ -830,14 +792,12 @@ static int qt2_setup_urbs(struct usb_ser
+       }
+       return 0;
+-
+ }
+ static int qt2_attach(struct usb_serial *serial)
+ {
+       struct qt2_serial_private *serial_priv;
+-      struct qt2_port_private *port_priv;
+-      int status, pcount;
++      int status;
+       /* power on unit */
+       status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+@@ -857,26 +817,6 @@ static int qt2_attach(struct usb_serial
+       usb_set_serial_data(serial, serial_priv);
+-      for (pcount = 0; pcount < serial->num_ports; pcount++) {
+-              port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+-              if (!port_priv) {
+-                      dev_err(&serial->dev->dev,
+-                              "%s- kmalloc(%Zd) failed.\n", __func__,
+-                              sizeof(*port_priv));
+-                      pcount--;
+-                      status = -ENOMEM;
+-                      goto attach_failed;
+-              }
+-
+-              spin_lock_init(&port_priv->lock);
+-              spin_lock_init(&port_priv->urb_lock);
+-              init_waitqueue_head(&port_priv->delta_msr_wait);
+-
+-              port_priv->port = serial->port[pcount];
+-
+-              usb_set_serial_port_data(serial->port[pcount], port_priv);
+-      }
+-
+       status = qt2_setup_urbs(serial);
+       if (status != 0)
+               goto attach_failed;
+@@ -884,14 +824,53 @@ static int qt2_attach(struct usb_serial
+       return 0;
+ attach_failed:
+-      for (/* empty */; pcount >= 0; pcount--) {
+-              port_priv = usb_get_serial_port_data(serial->port[pcount]);
+-              kfree(port_priv);
+-      }
+       kfree(serial_priv);
+       return status;
+ }
++static int qt2_port_probe(struct usb_serial_port *port)
++{
++      struct usb_serial *serial = port->serial;
++      struct qt2_port_private *port_priv;
++      u8 bEndpointAddress;
++
++      port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
++      if (!port_priv)
++              return -ENOMEM;
++
++      spin_lock_init(&port_priv->lock);
++      spin_lock_init(&port_priv->urb_lock);
++      init_waitqueue_head(&port_priv->delta_msr_wait);
++      port_priv->port = port;
++
++      port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
++      if (!port_priv->write_urb) {
++              kfree(port_priv);
++              return -ENOMEM;
++      }
++      bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
++      usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
++                              usb_sndbulkpipe(serial->dev, bEndpointAddress),
++                              port_priv->write_buffer,
++                              sizeof(port_priv->write_buffer),
++                              qt2_write_bulk_callback, port);
++
++      usb_set_serial_port_data(port, port_priv);
++
++      return 0;
++}
++
++static int qt2_port_remove(struct usb_serial_port *port)
++{
++      struct qt2_port_private *port_priv;
++
++      port_priv = usb_get_serial_port_data(port);
++      usb_free_urb(port_priv->write_urb);
++      kfree(port_priv);
++
++      return 0;
++}
++
+ static int qt2_tiocmget(struct tty_struct *tty)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+@@ -1130,6 +1109,8 @@ static struct usb_serial_driver qt2_devi
+       .attach              = qt2_attach,
+       .release             = qt2_release,
+       .disconnect          = qt2_disconnect,
++      .port_probe          = qt2_port_probe,
++      .port_remove         = qt2_port_remove,
+       .dtr_rts             = qt2_dtr_rts,
+       .break_ctl           = qt2_break_ctl,
+       .tiocmget            = qt2_tiocmget,
diff --git a/queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch b/queue-3.6/usb-serial-fix-memory-leak-in-sierra_release.patch
new file mode 100644 (file)
index 0000000..034a4af
--- /dev/null
@@ -0,0 +1,30 @@
+From f7bc5051667b74c3861f79eed98c60d5c3b883f7 Mon Sep 17 00:00:00 2001
+From: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
+Date: Wed, 24 Oct 2012 10:23:09 -0400
+Subject: USB: serial: Fix memory leak in sierra_release()
+
+From: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>
+
+commit f7bc5051667b74c3861f79eed98c60d5c3b883f7 upstream.
+
+I found a memory leak in sierra_release() (well sierra_probe() I guess)
+that looses 8 bytes each time the driver releases a device.
+
+Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
+Acked-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/sierra.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -961,6 +961,7 @@ static void sierra_release(struct usb_se
+                       continue;
+               kfree(portdata);
+       }
++      kfree(serial->private);
+ }
+ #ifdef CONFIG_PM
diff --git a/queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch b/queue-3.6/usb-sierra-fix-memory-leak-in-attach-error-path.patch
new file mode 100644 (file)
index 0000000..e1e37f0
--- /dev/null
@@ -0,0 +1,43 @@
+From 7e41f9bcdd2e813ea2a3c40db291d87ea06b559f Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:17 +0200
+Subject: USB: sierra: fix memory leak in attach error path
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 7e41f9bcdd2e813ea2a3c40db291d87ea06b559f upstream.
+
+Make sure port private data is deallocated on errors in attach.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/sierra.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -907,7 +907,7 @@ static int sierra_startup(struct usb_ser
+                       dev_dbg(&port->dev, "%s: kmalloc for "
+                               "sierra_port_private (%d) failed!\n",
+                               __func__, i);
+-                      return -ENOMEM;
++                      goto err;
+               }
+               spin_lock_init(&portdata->lock);
+               init_usb_anchor(&portdata->active);
+@@ -944,6 +944,13 @@ static int sierra_startup(struct usb_ser
+       }
+       return 0;
++err:
++      for (--i; i >= 0; --i) {
++              portdata = usb_get_serial_port_data(serial->port[i]);
++              kfree(portdata);
++      }
++
++      return -ENOMEM;
+ }
+ static void sierra_release(struct usb_serial *serial)
diff --git a/queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch b/queue-3.6/usb-sierra-fix-memory-leak-in-probe-error-path.patch
new file mode 100644 (file)
index 0000000..15f6184
--- /dev/null
@@ -0,0 +1,70 @@
+From 084817d79399ab5ccab2f90a148b0369912a8369 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:18 +0200
+Subject: USB: sierra: fix memory leak in probe error path
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 084817d79399ab5ccab2f90a148b0369912a8369 upstream.
+
+Move interface data allocation to attach so that it is deallocated on
+errors in usb-serial probe.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/sierra.c |   16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -162,7 +162,6 @@ static int sierra_probe(struct usb_seria
+ {
+       int result = 0;
+       struct usb_device *udev;
+-      struct sierra_intf_private *data;
+       u8 ifnum;
+       udev = serial->dev;
+@@ -189,11 +188,6 @@ static int sierra_probe(struct usb_seria
+               return -ENODEV;
+       }
+-      data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL);
+-      if (!data)
+-              return -ENOMEM;
+-      spin_lock_init(&data->susp_lock);
+-
+       return result;
+ }
+@@ -887,11 +881,20 @@ static void sierra_dtr_rts(struct usb_se
+ static int sierra_startup(struct usb_serial *serial)
+ {
+       struct usb_serial_port *port;
++      struct sierra_intf_private *intfdata;
+       struct sierra_port_private *portdata;
+       struct sierra_iface_info *himemoryp = NULL;
+       int i;
+       u8 ifnum;
++      intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL);
++      if (!intfdata)
++              return -ENOMEM;
++
++      spin_lock_init(&intfdata->susp_lock);
++
++      usb_set_serial_data(serial, intfdata);
++
+       /* Set Device mode to D0 */
+       sierra_set_power_state(serial->dev, 0x0000);
+@@ -949,6 +952,7 @@ err:
+               portdata = usb_get_serial_port_data(serial->port[i]);
+               kfree(portdata);
+       }
++      kfree(intfdata);
+       return -ENOMEM;
+ }
diff --git a/queue-3.6/usb-sierra-fix-port-data-memory-leak.patch b/queue-3.6/usb-sierra-fix-port-data-memory-leak.patch
new file mode 100644 (file)
index 0000000..5d5f91d
--- /dev/null
@@ -0,0 +1,188 @@
+From f525c05babc7938cc1d4236550fd8a659fb05960 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 25 Oct 2012 10:29:19 +0200
+Subject: USB: sierra: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit f525c05babc7938cc1d4236550fd8a659fb05960 upstream.
+
+Fix port-data memory leak by moving port data allocation and
+deallocation to port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release as
+it is no longer accessible.
+
+Note also that urb-count for multi-port interfaces has not been changed
+even though the usb-serial port number is now determined from the port
+and interface minor numbers.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/sierra.c |  127 ++++++++++++++++++++------------------------
+ 1 file changed, 59 insertions(+), 68 deletions(-)
+
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -880,12 +880,7 @@ static void sierra_dtr_rts(struct usb_se
+ static int sierra_startup(struct usb_serial *serial)
+ {
+-      struct usb_serial_port *port;
+       struct sierra_intf_private *intfdata;
+-      struct sierra_port_private *portdata;
+-      struct sierra_iface_info *himemoryp = NULL;
+-      int i;
+-      u8 ifnum;
+       intfdata = kzalloc(sizeof(*intfdata), GFP_KERNEL);
+       if (!intfdata)
+@@ -902,77 +897,71 @@ static int sierra_startup(struct usb_ser
+       if (nmea)
+               sierra_vsc_set_nmea(serial->dev, 1);
+-      /* Now setup per port private data */
+-      for (i = 0; i < serial->num_ports; i++) {
+-              port = serial->port[i];
+-              portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+-              if (!portdata) {
+-                      dev_dbg(&port->dev, "%s: kmalloc for "
+-                              "sierra_port_private (%d) failed!\n",
+-                              __func__, i);
+-                      goto err;
+-              }
+-              spin_lock_init(&portdata->lock);
+-              init_usb_anchor(&portdata->active);
+-              init_usb_anchor(&portdata->delayed);
+-              ifnum = i;
+-              /* Assume low memory requirements */
+-              portdata->num_out_urbs = N_OUT_URB;
+-              portdata->num_in_urbs  = N_IN_URB;
+-
+-              /* Determine actual memory requirements */
+-              if (serial->num_ports == 1) {
+-                      /* Get interface number for composite device */
+-                      ifnum = sierra_calc_interface(serial);
+-                      himemoryp =
+-                          (struct sierra_iface_info *)&typeB_interface_list;
+-                      if (is_himemory(ifnum, himemoryp)) {
+-                              portdata->num_out_urbs = N_OUT_URB_HM;
+-                              portdata->num_in_urbs  = N_IN_URB_HM;
+-                      }
+-              }
+-              else {
+-                      himemoryp =
+-                          (struct sierra_iface_info *)&typeA_interface_list;
+-                      if (is_himemory(i, himemoryp)) {
+-                              portdata->num_out_urbs = N_OUT_URB_HM;
+-                              portdata->num_in_urbs  = N_IN_URB_HM;
+-                      }
+-              }
+-              dev_dbg(&serial->dev->dev,
+-                      "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
+-                      ifnum,portdata->num_in_urbs, portdata->num_out_urbs );
+-              /* Set the port private data pointer */
+-              usb_set_serial_port_data(port, portdata);
+-      }
+-
+       return 0;
+-err:
+-      for (--i; i >= 0; --i) {
+-              portdata = usb_get_serial_port_data(serial->port[i]);
+-              kfree(portdata);
+-      }
+-      kfree(intfdata);
+-
+-      return -ENOMEM;
+ }
+ static void sierra_release(struct usb_serial *serial)
+ {
+-      int i;
+-      struct usb_serial_port *port;
++      struct sierra_intf_private *intfdata;
++
++      intfdata = usb_get_serial_data(serial);
++      kfree(intfdata);
++}
++
++static int sierra_port_probe(struct usb_serial_port *port)
++{
++      struct usb_serial *serial = port->serial;
+       struct sierra_port_private *portdata;
++      const struct sierra_iface_info *himemoryp;
++      u8 ifnum;
+-      for (i = 0; i < serial->num_ports; ++i) {
+-              port = serial->port[i];
+-              if (!port)
+-                      continue;
+-              portdata = usb_get_serial_port_data(port);
+-              if (!portdata)
+-                      continue;
+-              kfree(portdata);
++      portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
++      if (!portdata)
++              return -ENOMEM;
++
++      spin_lock_init(&portdata->lock);
++      init_usb_anchor(&portdata->active);
++      init_usb_anchor(&portdata->delayed);
++
++      /* Assume low memory requirements */
++      portdata->num_out_urbs = N_OUT_URB;
++      portdata->num_in_urbs  = N_IN_URB;
++
++      /* Determine actual memory requirements */
++      if (serial->num_ports == 1) {
++              /* Get interface number for composite device */
++              ifnum = sierra_calc_interface(serial);
++              himemoryp = &typeB_interface_list;
++      } else {
++              /* This is really the usb-serial port number of the interface
++               * rather than the interface number.
++               */
++              ifnum = port->number - serial->minor;
++              himemoryp = &typeA_interface_list;
++      }
++
++      if (is_himemory(ifnum, himemoryp)) {
++              portdata->num_out_urbs = N_OUT_URB_HM;
++              portdata->num_in_urbs  = N_IN_URB_HM;
+       }
+-      kfree(serial->private);
++
++      dev_dbg(&port->dev,
++                      "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
++                      ifnum, portdata->num_in_urbs, portdata->num_out_urbs);
++
++      usb_set_serial_port_data(port, portdata);
++
++      return 0;
++}
++
++static int sierra_port_remove(struct usb_serial_port *port)
++{
++      struct sierra_port_private *portdata;
++
++      portdata = usb_get_serial_port_data(port);
++      kfree(portdata);
++
++      return 0;
+ }
+ #ifdef CONFIG_PM
+@@ -1076,6 +1065,8 @@ static struct usb_serial_driver sierra_d
+       .tiocmset          = sierra_tiocmset,
+       .attach            = sierra_startup,
+       .release           = sierra_release,
++      .port_probe        = sierra_port_probe,
++      .port_remove       = sierra_port_remove,
+       .suspend           = sierra_suspend,
+       .resume            = sierra_resume,
+       .read_int_callback = sierra_instat_callback,