usb-host-xhci-new-system-added-for-compliance-mode-patch-on-sn65lvpe502cp.patch
usb-iuu_phoenix-fix-port-data-memory-leak.patch
usb-iuu_phoenix-fix-sysfs-attribute-creation.patch
+usb-ark3116-fix-null-pointer-dereference.patch
+usb-f81232-fix-port-data-memory-leak.patch
+usb-oti6858-fix-port-data-memory-leak.patch
+usb-belkin_sa-fix-port-data-memory-leak.patch
+usb-pl2303-fix-port-data-memory-leak.patch
+usb-ssu100-fix-port-data-memory-leak.patch
+usb-kobil_sct-fix-port-data-memory-leak.patch
+usb-cypress_m8-fix-port-data-memory-leak.patch
--- /dev/null
+From 7bdce71822f471433dd3014692e9096996c7b5f0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 15 Oct 2012 18:20:52 +0200
+Subject: USB: ark3116: fix NULL-pointer dereference
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 7bdce71822f471433dd3014692e9096996c7b5f0 upstream.
+
+Fix NULL-pointer dereference at release by replacing attach and release
+with port_probe and port_remove.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is NULL when release is called.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ark3116.c | 26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+--- a/drivers/usb/serial/ark3116.c
++++ b/drivers/usb/serial/ark3116.c
+@@ -126,9 +126,6 @@ static inline int calc_divisor(int bps)
+
+ static int ark3116_attach(struct usb_serial *serial)
+ {
+- struct usb_serial_port *port = serial->port[0];
+- struct ark3116_private *priv;
+-
+ /* make sure we have our end-points */
+ if ((serial->num_bulk_in == 0) ||
+ (serial->num_bulk_out == 0) ||
+@@ -143,8 +140,15 @@ static int ark3116_attach(struct usb_ser
+ return -EINVAL;
+ }
+
+- priv = kzalloc(sizeof(struct ark3116_private),
+- GFP_KERNEL);
++ return 0;
++}
++
++static int ark3116_port_probe(struct usb_serial_port *port)
++{
++ struct usb_serial *serial = port->serial;
++ struct ark3116_private *priv;
++
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+@@ -199,18 +203,15 @@ static int ark3116_attach(struct usb_ser
+ return 0;
+ }
+
+-static void ark3116_release(struct usb_serial *serial)
++static int ark3116_port_remove(struct usb_serial_port *port)
+ {
+- struct usb_serial_port *port = serial->port[0];
+ struct ark3116_private *priv = usb_get_serial_port_data(port);
+
+ /* device is closed, so URBs and DMA should be down */
+-
+- usb_set_serial_port_data(port, NULL);
+-
+ mutex_destroy(&priv->hw_lock);
+-
+ kfree(priv);
++
++ return 0;
+ }
+
+ static void ark3116_init_termios(struct tty_struct *tty)
+@@ -725,7 +726,8 @@ static struct usb_serial_driver ark3116_
+ .id_table = id_table,
+ .num_ports = 1,
+ .attach = ark3116_attach,
+- .release = ark3116_release,
++ .port_probe = ark3116_port_probe,
++ .port_remove = ark3116_port_remove,
+ .set_termios = ark3116_set_termios,
+ .init_termios = ark3116_init_termios,
+ .ioctl = ark3116_ioctl,
--- /dev/null
+From fa919751a2d26a88140fc5810124dd81644efe51 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 15 Oct 2012 18:20:53 +0200
+Subject: USB: belkin_sa: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit fa919751a2d26a88140fc5810124dd81644efe51 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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 write waitqueue was initialised but never used.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/belkin_sa.c | 31 +++++++++++++++----------------
+ 1 file changed, 15 insertions(+), 16 deletions(-)
+
+--- a/drivers/usb/serial/belkin_sa.c
++++ b/drivers/usb/serial/belkin_sa.c
+@@ -47,8 +47,8 @@ static bool debug;
+ #define DRIVER_DESC "USB Belkin Serial converter driver"
+
+ /* function prototypes for a Belkin USB Serial Adapter F5U103 */
+-static int belkin_sa_startup(struct usb_serial *serial);
+-static void belkin_sa_release(struct usb_serial *serial);
++static int belkin_sa_port_probe(struct usb_serial_port *port);
++static int belkin_sa_port_remove(struct usb_serial_port *port);
+ static int belkin_sa_open(struct tty_struct *tty,
+ struct usb_serial_port *port);
+ static void belkin_sa_close(struct usb_serial_port *port);
+@@ -90,8 +90,8 @@ static struct usb_serial_driver belkin_d
+ .break_ctl = belkin_sa_break_ctl,
+ .tiocmget = belkin_sa_tiocmget,
+ .tiocmset = belkin_sa_tiocmset,
+- .attach = belkin_sa_startup,
+- .release = belkin_sa_release,
++ .port_probe = belkin_sa_port_probe,
++ .port_remove = belkin_sa_port_remove,
+ };
+
+ static struct usb_serial_driver * const serial_drivers[] = {
+@@ -120,17 +120,15 @@ struct belkin_sa_private {
+ (c), BELKIN_SA_SET_REQUEST_TYPE, \
+ (v), 0, NULL, 0, WDR_TIMEOUT)
+
+-/* do some startup allocations not currently performed by usb_serial_probe() */
+-static int belkin_sa_startup(struct usb_serial *serial)
++static int belkin_sa_port_probe(struct usb_serial_port *port)
+ {
+- struct usb_device *dev = serial->dev;
++ struct usb_device *dev = port->serial->dev;
+ struct belkin_sa_private *priv;
+
+- /* allocate the private data structure */
+ priv = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL);
+ if (!priv)
+- return -1; /* error */
+- /* set initial values for control structures */
++ return -ENOMEM;
++
+ spin_lock_init(&priv->lock);
+ priv->control_state = 0;
+ priv->last_lsr = 0;
+@@ -142,18 +140,19 @@ static int belkin_sa_startup(struct usb_
+ le16_to_cpu(dev->descriptor.bcdDevice),
+ priv->bad_flow_control);
+
+- init_waitqueue_head(&serial->port[0]->write_wait);
+- usb_set_serial_port_data(serial->port[0], priv);
++ usb_set_serial_port_data(port, priv);
+
+ return 0;
+ }
+
+-static void belkin_sa_release(struct usb_serial *serial)
++static int belkin_sa_port_remove(struct usb_serial_port *port)
+ {
+- int i;
++ struct belkin_sa_private *priv;
+
+- for (i = 0; i < serial->num_ports; ++i)
+- kfree(usb_get_serial_port_data(serial->port[i]));
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static int belkin_sa_open(struct tty_struct *tty,
--- /dev/null
+From 5c1a0f418d8d985f3a62849bcac43fc5404cc592 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 13:34:55 +0200
+Subject: USB: cypress_m8: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 5c1a0f418d8d985f3a62849bcac43fc5404cc592 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/cypress_m8.c | 82 ++++++++++++++++++++--------------------
+ 1 file changed, 41 insertions(+), 41 deletions(-)
+
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -124,10 +124,10 @@ struct cypress_private {
+ };
+
+ /* function prototypes for the Cypress USB to serial device */
+-static int cypress_earthmate_startup(struct usb_serial *serial);
+-static int cypress_hidcom_startup(struct usb_serial *serial);
+-static int cypress_ca42v2_startup(struct usb_serial *serial);
+-static void cypress_release(struct usb_serial *serial);
++static int cypress_earthmate_port_probe(struct usb_serial_port *port);
++static int cypress_hidcom_port_probe(struct usb_serial_port *port);
++static int cypress_ca42v2_port_probe(struct usb_serial_port *port);
++static int cypress_port_remove(struct usb_serial_port *port);
+ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
+ static void cypress_close(struct usb_serial_port *port);
+ static void cypress_dtr_rts(struct usb_serial_port *port, int on);
+@@ -157,8 +157,8 @@ static struct usb_serial_driver cypress_
+ .description = "DeLorme Earthmate USB",
+ .id_table = id_table_earthmate,
+ .num_ports = 1,
+- .attach = cypress_earthmate_startup,
+- .release = cypress_release,
++ .port_probe = cypress_earthmate_port_probe,
++ .port_remove = cypress_port_remove,
+ .open = cypress_open,
+ .close = cypress_close,
+ .dtr_rts = cypress_dtr_rts,
+@@ -183,8 +183,8 @@ static struct usb_serial_driver cypress_
+ .description = "HID->COM RS232 Adapter",
+ .id_table = id_table_cyphidcomrs232,
+ .num_ports = 1,
+- .attach = cypress_hidcom_startup,
+- .release = cypress_release,
++ .port_probe = cypress_hidcom_port_probe,
++ .port_remove = cypress_port_remove,
+ .open = cypress_open,
+ .close = cypress_close,
+ .dtr_rts = cypress_dtr_rts,
+@@ -209,8 +209,8 @@ static struct usb_serial_driver cypress_
+ .description = "Nokia CA-42 V2 Adapter",
+ .id_table = id_table_nokiaca42v2,
+ .num_ports = 1,
+- .attach = cypress_ca42v2_startup,
+- .release = cypress_release,
++ .port_probe = cypress_ca42v2_port_probe,
++ .port_remove = cypress_port_remove,
+ .open = cypress_open,
+ .close = cypress_close,
+ .dtr_rts = cypress_dtr_rts,
+@@ -437,10 +437,10 @@ static void cypress_set_dead(struct usb_
+ *****************************************************************************/
+
+
+-static int generic_startup(struct usb_serial *serial)
++static int cypress_generic_port_probe(struct usb_serial_port *port)
+ {
++ struct usb_serial *serial = port->serial;
+ struct cypress_private *priv;
+- struct usb_serial_port *port = serial->port[0];
+
+ priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
+ if (!priv)
+@@ -489,15 +489,17 @@ static int generic_startup(struct usb_se
+ }
+
+
+-static int cypress_earthmate_startup(struct usb_serial *serial)
++static int cypress_earthmate_port_probe(struct usb_serial_port *port)
+ {
++ struct usb_serial *serial = port->serial;
+ struct cypress_private *priv;
+- struct usb_serial_port *port = serial->port[0];
++ int ret;
+
+- if (generic_startup(serial)) {
++ ret = cypress_generic_port_probe(port);
++ if (ret) {
+ dbg("%s - Failed setting up port %d", __func__,
+ port->number);
+- return 1;
++ return ret;
+ }
+
+ priv = usb_get_serial_port_data(port);
+@@ -517,54 +519,52 @@ static int cypress_earthmate_startup(str
+ }
+
+ return 0;
+-} /* cypress_earthmate_startup */
+-
++}
+
+-static int cypress_hidcom_startup(struct usb_serial *serial)
++static int cypress_hidcom_port_probe(struct usb_serial_port *port)
+ {
+ struct cypress_private *priv;
++ int ret;
+
+- if (generic_startup(serial)) {
+- dbg("%s - Failed setting up port %d", __func__,
+- serial->port[0]->number);
+- return 1;
++ ret = cypress_generic_port_probe(port);
++ if (ret) {
++ dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__);
++ return ret;
+ }
+
+- priv = usb_get_serial_port_data(serial->port[0]);
++ priv = usb_get_serial_port_data(port);
+ priv->chiptype = CT_CYPHIDCOM;
+
+ return 0;
+-} /* cypress_hidcom_startup */
+-
++}
+
+-static int cypress_ca42v2_startup(struct usb_serial *serial)
++static int cypress_ca42v2_port_probe(struct usb_serial_port *port)
+ {
+ struct cypress_private *priv;
++ int ret;
+
+- if (generic_startup(serial)) {
+- dbg("%s - Failed setting up port %d", __func__,
+- serial->port[0]->number);
+- return 1;
++ ret = cypress_generic_port_probe(port);
++ if (ret) {
++ dev_dbg(&port->dev, "%s - Failed setting up port\n", __func__);
++ return ret;
+ }
+
+- priv = usb_get_serial_port_data(serial->port[0]);
++ priv = usb_get_serial_port_data(port);
+ priv->chiptype = CT_CA42V2;
+
+ return 0;
+-} /* cypress_ca42v2_startup */
+-
++}
+
+-static void cypress_release(struct usb_serial *serial)
++static int cypress_port_remove(struct usb_serial_port *port)
+ {
+ struct cypress_private *priv;
+
+- /* all open ports are closed at this point */
+- priv = usb_get_serial_port_data(serial->port[0]);
++ priv = usb_get_serial_port_data(port);
+
+- if (priv) {
+- kfifo_free(&priv->write_fifo);
+- kfree(priv);
+- }
++ kfifo_free(&priv->write_fifo);
++ kfree(priv);
++
++ return 0;
+ }
+
+
--- /dev/null
+From 3124d1d71d3df59d40b913b5481df58099e811d1 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 13:34:56 +0200
+Subject: USB: f81232: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 3124d1d71d3df59d40b913b5481df58099e811d1 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/f81232.c | 43 +++++++++++++++++--------------------------
+ 1 file changed, 17 insertions(+), 26 deletions(-)
+
+--- a/drivers/usb/serial/f81232.c
++++ b/drivers/usb/serial/f81232.c
+@@ -319,39 +319,30 @@ static int f81232_ioctl(struct tty_struc
+ return -ENOIOCTLCMD;
+ }
+
+-static int f81232_startup(struct usb_serial *serial)
++static int f81232_port_probe(struct usb_serial_port *port)
+ {
+ struct f81232_private *priv;
+- int i;
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL);
+- if (!priv)
+- goto cleanup;
+- spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+- usb_set_serial_port_data(serial->port[i], priv);
+- }
+- return 0;
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ spin_lock_init(&priv->lock);
++ init_waitqueue_head(&priv->delta_msr_wait);
++
++ usb_set_serial_port_data(port, priv);
+
+-cleanup:
+- for (--i; i >= 0; --i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+- return -ENOMEM;
++ return 0;
+ }
+
+-static void f81232_release(struct usb_serial *serial)
++static int f81232_port_remove(struct usb_serial_port *port)
+ {
+- int i;
+ struct f81232_private *priv;
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- }
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static struct usb_serial_driver f81232_device = {
+@@ -374,8 +365,8 @@ static struct usb_serial_driver f81232_d
+ .tiocmset = f81232_tiocmset,
+ .process_read_urb = f81232_process_read_urb,
+ .read_int_callback = f81232_read_int_callback,
+- .attach = f81232_startup,
+- .release = f81232_release,
++ .port_probe = f81232_port_probe,
++ .port_remove = f81232_port_remove,
+ };
+
+ static struct usb_serial_driver * const serial_drivers[] = {
--- /dev/null
+From 95940a04bfe8a4d246f4ca17c6a3b00148bdead0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 13:35:02 +0200
+Subject: USB: kobil_sct: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 95940a04bfe8a4d246f4ca17c6a3b00148bdead0 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/kobil_sct.c | 23 +++++++++++++----------
+ 1 file changed, 13 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/serial/kobil_sct.c
++++ b/drivers/usb/serial/kobil_sct.c
+@@ -56,8 +56,8 @@ static bool debug;
+
+
+ /* Function prototypes */
+-static int kobil_startup(struct usb_serial *serial);
+-static void kobil_release(struct usb_serial *serial);
++static int kobil_port_probe(struct usb_serial_port *probe);
++static int kobil_port_remove(struct usb_serial_port *probe);
+ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
+ static void kobil_close(struct usb_serial_port *port);
+ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
+@@ -91,8 +91,8 @@ static struct usb_serial_driver kobil_de
+ .description = "KOBIL USB smart card terminal",
+ .id_table = id_table,
+ .num_ports = 1,
+- .attach = kobil_startup,
+- .release = kobil_release,
++ .port_probe = kobil_port_probe,
++ .port_remove = kobil_port_remove,
+ .ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
+ .init_termios = kobil_init_termios,
+@@ -119,9 +119,10 @@ struct kobil_private {
+ };
+
+
+-static int kobil_startup(struct usb_serial *serial)
++static int kobil_port_probe(struct usb_serial_port *port)
+ {
+ int i;
++ struct usb_serial *serial = port->serial;
+ struct kobil_private *priv;
+ struct usb_device *pdev;
+ struct usb_host_config *actconfig;
+@@ -152,7 +153,7 @@ static int kobil_startup(struct usb_seri
+ printk(KERN_DEBUG "KOBIL KAAN SIM detected\n");
+ break;
+ }
+- usb_set_serial_port_data(serial->port[0], priv);
++ usb_set_serial_port_data(port, priv);
+
+ /* search for the necessary endpoints */
+ pdev = serial->dev;
+@@ -180,12 +181,14 @@ static int kobil_startup(struct usb_seri
+ }
+
+
+-static void kobil_release(struct usb_serial *serial)
++static int kobil_port_remove(struct usb_serial_port *port)
+ {
+- int i;
++ struct kobil_private *priv;
+
+- for (i = 0; i < serial->num_ports; ++i)
+- kfree(usb_get_serial_port_data(serial->port[i]));
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static void kobil_init_termios(struct tty_struct *tty)
--- /dev/null
+From 289b076f89c2c3260e914dad18ae12f193ea86d5 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 16:31:32 +0200
+Subject: USB: oti6858: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 289b076f89c2c3260e914dad18ae12f193ea86d5 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/oti6858.c | 68 +++++++++++++++++--------------------------
+ 1 file changed, 28 insertions(+), 40 deletions(-)
+
+--- a/drivers/usb/serial/oti6858.c
++++ b/drivers/usb/serial/oti6858.c
+@@ -139,8 +139,8 @@ static int oti6858_chars_in_buffer(struc
+ static int oti6858_tiocmget(struct tty_struct *tty);
+ static int oti6858_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear);
+-static int oti6858_startup(struct usb_serial *serial);
+-static void oti6858_release(struct usb_serial *serial);
++static int oti6858_port_probe(struct usb_serial_port *port);
++static int oti6858_port_remove(struct usb_serial_port *port);
+
+ /* device info */
+ static struct usb_serial_driver oti6858_device = {
+@@ -163,8 +163,8 @@ static struct usb_serial_driver oti6858_
+ .write_bulk_callback = oti6858_write_bulk_callback,
+ .write_room = oti6858_write_room,
+ .chars_in_buffer = oti6858_chars_in_buffer,
+- .attach = oti6858_startup,
+- .release = oti6858_release,
++ .port_probe = oti6858_port_probe,
++ .port_remove = oti6858_port_remove,
+ };
+
+ static struct usb_serial_driver * const serial_drivers[] = {
+@@ -333,36 +333,33 @@ static void send_data(struct work_struct
+ usb_serial_port_softint(port);
+ }
+
+-static int oti6858_startup(struct usb_serial *serial)
++static int oti6858_port_probe(struct usb_serial_port *port)
+ {
+- struct usb_serial_port *port = serial->port[0];
+ struct oti6858_private *priv;
+- int i;
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
+- if (!priv)
+- break;
+-
+- spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->intr_wait);
+-/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */
+-/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */
+- priv->port = port;
+- INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line);
+- INIT_DELAYED_WORK(&priv->delayed_write_work, send_data);
+-
+- usb_set_serial_port_data(serial->port[i], priv);
+- }
+- if (i == serial->num_ports)
+- return 0;
+-
+- for (--i; i >= 0; --i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+- return -ENOMEM;
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ spin_lock_init(&priv->lock);
++ init_waitqueue_head(&priv->intr_wait);
++ priv->port = port;
++ INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line);
++ INIT_DELAYED_WORK(&priv->delayed_write_work, send_data);
++
++ usb_set_serial_port_data(port, priv);
++
++ return 0;
++}
++
++static int oti6858_port_remove(struct usb_serial_port *port)
++{
++ struct oti6858_private *priv;
++
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
+@@ -714,15 +711,6 @@ static int oti6858_ioctl(struct tty_stru
+ return -ENOIOCTLCMD;
+ }
+
+-
+-static void oti6858_release(struct usb_serial *serial)
+-{
+- int i;
+-
+- for (i = 0; i < serial->num_ports; ++i)
+- kfree(usb_get_serial_port_data(serial->port[i]));
+-}
+-
+ static void oti6858_read_int_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
--- /dev/null
+From 8bf769eb5f6efc33f95088850f33fcc05d28b508 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 15 Oct 2012 15:47:21 +0200
+Subject: USB: pl2303: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 8bf769eb5f6efc33f95088850f33fcc05d28b508 upstream.
+
+Fix port-data memory leak by allocating and freeing port data in
+port_probe/remove rather than in attach/release, and by introducing
+serial private data to store the device type which is interface rather
+than port specific.
+
+Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no
+driver is bound) the port private data is no longer freed at release.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/pl2303.c | 90 ++++++++++++++++++++++++++------------------
+ 1 file changed, 54 insertions(+), 36 deletions(-)
+
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -135,12 +135,15 @@ enum pl2303_type {
+ HX, /* HX version of the pl2303 chip */
+ };
+
++struct pl2303_serial_private {
++ enum pl2303_type type;
++};
++
+ struct pl2303_private {
+ spinlock_t lock;
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+- enum pl2303_type type;
+ };
+
+ static int pl2303_vendor_read(__u16 value, __u16 index,
+@@ -169,14 +172,19 @@ static int pl2303_vendor_write(__u16 val
+
+ static int pl2303_startup(struct usb_serial *serial)
+ {
+- struct pl2303_private *priv;
++ struct pl2303_serial_private *spriv;
+ enum pl2303_type type = type_0;
+ unsigned char *buf;
+- int i;
++
++ spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
++ if (!spriv)
++ return -ENOMEM;
+
+ buf = kmalloc(10, GFP_KERNEL);
+- if (buf == NULL)
++ if (!buf) {
++ kfree(spriv);
+ return -ENOMEM;
++ }
+
+ if (serial->dev->descriptor.bDeviceClass == 0x02)
+ type = type_0;
+@@ -188,15 +196,8 @@ static int pl2303_startup(struct usb_ser
+ type = type_1;
+ dev_dbg(&serial->interface->dev, "device type: %d\n", type);
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
+- if (!priv)
+- goto cleanup;
+- spin_lock_init(&priv->lock);
+- init_waitqueue_head(&priv->delta_msr_wait);
+- priv->type = type;
+- usb_set_serial_port_data(serial->port[i], priv);
+- }
++ spriv->type = type;
++ usb_set_serial_data(serial, spriv);
+
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_write(0x0404, 0, serial);
+@@ -215,15 +216,40 @@ static int pl2303_startup(struct usb_ser
+
+ kfree(buf);
+ return 0;
++}
+
+-cleanup:
+- kfree(buf);
+- for (--i; i >= 0; --i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+- return -ENOMEM;
++static void pl2303_release(struct usb_serial *serial)
++{
++ struct pl2303_serial_private *spriv;
++
++ spriv = usb_get_serial_data(serial);
++ kfree(spriv);
++}
++
++static int pl2303_port_probe(struct usb_serial_port *port)
++{
++ struct pl2303_private *priv;
++
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ spin_lock_init(&priv->lock);
++ init_waitqueue_head(&priv->delta_msr_wait);
++
++ usb_set_serial_port_data(port, priv);
++
++ return 0;
++}
++
++static int pl2303_port_remove(struct usb_serial_port *port)
++{
++ struct pl2303_private *priv;
++
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static int set_control_lines(struct usb_device *dev, u8 value)
+@@ -242,6 +268,7 @@ static void pl2303_set_termios(struct tt
+ struct usb_serial_port *port, struct ktermios *old_termios)
+ {
+ struct usb_serial *serial = port->serial;
++ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int cflag;
+@@ -325,7 +352,7 @@ static void pl2303_set_termios(struct tt
+ }
+ if (baud > 1228800) {
+ /* type_0, type_1 only support up to 1228800 baud */
+- if (priv->type != HX)
++ if (spriv->type != HX)
+ baud = 1228800;
+ else if (baud > 6000000)
+ baud = 6000000;
+@@ -428,7 +455,7 @@ static void pl2303_set_termios(struct tt
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+ if (cflag & CRTSCTS) {
+- if (priv->type == HX)
++ if (spriv->type == HX)
+ pl2303_vendor_write(0x0, 0x61, serial);
+ else
+ pl2303_vendor_write(0x0, 0x41, serial);
+@@ -470,10 +497,10 @@ static int pl2303_open(struct tty_struct
+ {
+ struct ktermios tmp_termios;
+ struct usb_serial *serial = port->serial;
+- struct pl2303_private *priv = usb_get_serial_port_data(port);
++ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
+ int result;
+
+- if (priv->type != HX) {
++ if (spriv->type != HX) {
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+ } else {
+@@ -657,17 +684,6 @@ static void pl2303_break_ctl(struct tty_
+ dev_err(&port->dev, "error sending break = %d\n", result);
+ }
+
+-static void pl2303_release(struct usb_serial *serial)
+-{
+- int i;
+- struct pl2303_private *priv;
+-
+- for (i = 0; i < serial->num_ports; ++i) {
+- priv = usb_get_serial_port_data(serial->port[i]);
+- kfree(priv);
+- }
+-}
+-
+ static void pl2303_update_line_status(struct usb_serial_port *port,
+ unsigned char *data,
+ unsigned int actual_length)
+@@ -829,6 +845,8 @@ static struct usb_serial_driver pl2303_d
+ .read_int_callback = pl2303_read_int_callback,
+ .attach = pl2303_startup,
+ .release = pl2303_release,
++ .port_probe = pl2303_port_probe,
++ .port_remove = pl2303_port_remove,
+ };
+
+ static struct usb_serial_driver * const serial_drivers[] = {
--- /dev/null
+From 638b9e15233c9570bce65301aa9877235316b9f0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 17 Oct 2012 16:31:34 +0200
+Subject: USB: ssu100: fix port-data memory leak
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 638b9e15233c9570bce65301aa9877235316b9f0 upstream.
+
+Fix port-data memory leak by replacing attach and release with
+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.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ssu100.c | 34 ++++++++++++++++++++--------------
+ 1 file changed, 20 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/serial/ssu100.c
++++ b/drivers/usb/serial/ssu100.c
+@@ -69,13 +69,6 @@ struct ssu100_port_private {
+ struct async_icount icount;
+ };
+
+-static void ssu100_release(struct usb_serial *serial)
+-{
+- struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
+-
+- kfree(priv);
+-}
+-
+ static inline int ssu100_control_msg(struct usb_device *dev,
+ u8 request, u16 data, u16 index)
+ {
+@@ -444,21 +437,33 @@ static int ssu100_ioctl(struct tty_struc
+
+ static int ssu100_attach(struct usb_serial *serial)
+ {
++ return ssu100_initdevice(serial->dev);
++}
++
++static int ssu100_port_probe(struct usb_serial_port *port)
++{
+ struct ssu100_port_private *priv;
+- struct usb_serial_port *port = *serial->port;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+- if (!priv) {
+- dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
+- sizeof(*priv));
++ if (!priv)
+ return -ENOMEM;
+- }
+
+ spin_lock_init(&priv->status_lock);
+ init_waitqueue_head(&priv->delta_msr_wait);
++
+ usb_set_serial_port_data(port, priv);
+
+- return ssu100_initdevice(serial->dev);
++ return 0;
++}
++
++static int ssu100_port_remove(struct usb_serial_port *port)
++{
++ struct ssu100_port_private *priv;
++
++ priv = usb_get_serial_port_data(port);
++ kfree(priv);
++
++ return 0;
+ }
+
+ static int ssu100_tiocmget(struct tty_struct *tty)
+@@ -649,7 +654,8 @@ static struct usb_serial_driver ssu100_d
+ .open = ssu100_open,
+ .close = ssu100_close,
+ .attach = ssu100_attach,
+- .release = ssu100_release,
++ .port_probe = ssu100_port_probe,
++ .port_remove = ssu100_port_remove,
+ .dtr_rts = ssu100_dtr_rts,
+ .process_read_urb = ssu100_process_read_urb,
+ .tiocmget = ssu100_tiocmget,