From 96a83c95c3da5ba55ea2cf6ce87de10fc03417a9 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Fri, 10 Sep 2021 14:11:27 +0200 Subject: USB: serial: clean up core error labels Clean up the core error labels by consistently naming them after what they do rather than after from where they are jumped to. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/usb-serial.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 090a78c948f2..d71f08da2dfd 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,17 +225,17 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) serial = port->serial; if (!try_module_get(serial->type->driver.owner)) - goto error_module_get; + goto err_put_serial; retval = usb_autopm_get_interface(serial->interface); if (retval) - goto error_get_interface; + goto err_put_module; init_termios = (driver->termios[idx] == NULL); retval = tty_standard_install(driver, tty); if (retval) - goto error_init_termios; + goto err_put_autopm; mutex_unlock(&serial->disc_mutex); @@ -247,11 +247,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) return retval; - error_init_termios: +err_put_autopm: usb_autopm_put_interface(serial->interface); - error_get_interface: +err_put_module: module_put(serial->type->driver.owner); - error_module_get: +err_put_serial: usb_serial_put(serial); mutex_unlock(&serial->disc_mutex); return retval; @@ -1328,7 +1328,7 @@ static int __init usb_serial_init(void) result = bus_register(&usb_serial_bus_type); if (result) { pr_err("%s - registering bus driver failed\n", __func__); - goto exit_bus; + goto err_put_driver; } usb_serial_tty_driver->driver_name = "usbserial"; @@ -1346,25 +1346,23 @@ static int __init usb_serial_init(void) result = tty_register_driver(usb_serial_tty_driver); if (result) { pr_err("%s - tty_register_driver failed\n", __func__); - goto exit_reg_driver; + goto err_unregister_bus; } /* register the generic driver, if we should */ result = usb_serial_generic_register(); if (result < 0) { pr_err("%s - registering generic driver failed\n", __func__); - goto exit_generic; + goto err_unregister_driver; } return result; -exit_generic: +err_unregister_driver: tty_unregister_driver(usb_serial_tty_driver); - -exit_reg_driver: +err_unregister_bus: bus_unregister(&usb_serial_bus_type); - -exit_bus: +err_put_driver: pr_err("%s - returning with error %d\n", __func__, result); tty_driver_kref_put(usb_serial_tty_driver); return result; @@ -1509,13 +1507,13 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[] rc = usb_register(udriver); if (rc) - goto failed_usb_register; + goto err_free_driver; for (sd = serial_drivers; *sd; ++sd) { (*sd)->usb_driver = udriver; rc = usb_serial_register(*sd); if (rc) - goto failed; + goto err_deregister_drivers; } /* Now set udriver's id_table and look for matches */ @@ -1523,11 +1521,11 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[] rc = driver_attach(&udriver->drvwrap.driver); return 0; - failed: +err_deregister_drivers: while (sd-- > serial_drivers) usb_serial_deregister(*sd); usb_deregister(udriver); -failed_usb_register: +err_free_driver: kfree(udriver); return rc; } -- cgit v1.2.3 From 6400b974910407cd299dc08578a6c1792b4c922a Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Fri, 10 Sep 2021 14:11:28 +0200 Subject: USB: serial: allow hung up ports to be suspended User space can keep a tty open indefinitely and that should not prevent a hung up port and its USB device from being runtime suspended. Fix this by incrementing the PM usage counter when the port it activated and decrementing the counter when the port is shutdown rather than when the tty is installed and the last reference is dropped, respectively. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/usb-serial.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d71f08da2dfd..24101bd7fcad 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -208,8 +208,8 @@ void usb_serial_put(struct usb_serial *serial) * * This is the first place a new tty gets used. Hence this is where we * acquire references to the usb_serial structure and the driver module, - * where we store a pointer to the port, and where we do an autoresume. - * All these actions are reversed in serial_cleanup(). + * where we store a pointer to the port. All these actions are reversed + * in serial_cleanup(). */ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) { @@ -227,15 +227,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) if (!try_module_get(serial->type->driver.owner)) goto err_put_serial; - retval = usb_autopm_get_interface(serial->interface); - if (retval) - goto err_put_module; - init_termios = (driver->termios[idx] == NULL); retval = tty_standard_install(driver, tty); if (retval) - goto err_put_autopm; + goto err_put_module; mutex_unlock(&serial->disc_mutex); @@ -247,8 +243,6 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) return retval; -err_put_autopm: - usb_autopm_put_interface(serial->interface); err_put_module: module_put(serial->type->driver.owner); err_put_serial: @@ -265,10 +259,19 @@ static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty) int retval; mutex_lock(&serial->disc_mutex); - if (serial->disconnected) + if (serial->disconnected) { retval = -ENODEV; - else - retval = port->serial->type->open(tty, port); + goto out_unlock; + } + + retval = usb_autopm_get_interface(serial->interface); + if (retval) + goto out_unlock; + + retval = port->serial->type->open(tty, port); + if (retval) + usb_autopm_put_interface(serial->interface); +out_unlock: mutex_unlock(&serial->disc_mutex); if (retval < 0) @@ -304,6 +307,8 @@ static void serial_port_shutdown(struct tty_port *tport) if (drv->close) drv->close(port); + + usb_autopm_put_interface(port->serial->interface); } static void serial_hangup(struct tty_struct *tty) @@ -352,8 +357,6 @@ static void serial_cleanup(struct tty_struct *tty) serial = port->serial; owner = serial->type->driver.owner; - usb_autopm_put_interface(serial->interface); - usb_serial_put(serial); module_put(owner); } -- cgit v1.2.3 From 0d027eea8988a9d9ec2ca4df150b37d82e9e6623 Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Mon, 2 Aug 2021 02:01:19 +0530 Subject: USB: serial: f81232: use usb_control_msg_recv() and usb_control_msg_send() The new wrapper functions usb_control_msg_send/recv accept stack variables for USB message buffers and eliminate the need of manually allocating temporary DMA buffers. The read wrapper also treats short reads as errors. Hence use the wrappers instead of using usb_control_msg() directly. Note that the conversion of f81534a_ctrl_set_register() adds an extra an extra allocation and memcpy for every retry. Since this function is called rarely and retries are hopefully rare, the overhead should be acceptable. Also note that short reads are now logged as -EREMOTEIO instead of indicating the amount of data read. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20210801203122.3515-4-himadrispandya@gmail.com [ johan: amend commit message ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/f81232.c | 96 ++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 62 deletions(-) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index a7a7af8d05bf..3ad1f515fb68 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -139,67 +139,46 @@ static int calc_baud_divisor(speed_t baudrate, speed_t clockrate) static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) { int status; - u8 *tmp; struct usb_device *dev = port->serial->dev; - tmp = kmalloc(sizeof(*val), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - status = usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), - F81232_REGISTER_REQUEST, - F81232_GET_REGISTER, - reg, - 0, - tmp, - sizeof(*val), - USB_CTRL_GET_TIMEOUT); - if (status != sizeof(*val)) { + status = usb_control_msg_recv(dev, + 0, + F81232_REGISTER_REQUEST, + F81232_GET_REGISTER, + reg, + 0, + val, + sizeof(*val), + USB_CTRL_GET_TIMEOUT, + GFP_KERNEL); + if (status) { dev_err(&port->dev, "%s failed status: %d\n", __func__, status); - - if (status < 0) - status = usb_translate_errors(status); - else - status = -EIO; - } else { - status = 0; - *val = *tmp; + status = usb_translate_errors(status); } - kfree(tmp); return status; } static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val) { int status; - u8 *tmp; struct usb_device *dev = port->serial->dev; - tmp = kmalloc(sizeof(val), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - *tmp = val; - - status = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - F81232_REGISTER_REQUEST, - F81232_SET_REGISTER, - reg, - 0, - tmp, - sizeof(val), - USB_CTRL_SET_TIMEOUT); - if (status < 0) { + status = usb_control_msg_send(dev, + 0, + F81232_REGISTER_REQUEST, + F81232_SET_REGISTER, + reg, + 0, + &val, + sizeof(val), + USB_CTRL_SET_TIMEOUT, + GFP_KERNEL); + if (status) { dev_err(&port->dev, "%s failed status: %d\n", __func__, status); status = usb_translate_errors(status); - } else { - status = 0; } - kfree(tmp); return status; } @@ -857,28 +836,22 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, struct usb_device *dev = interface_to_usbdev(intf); int retry = F81534A_ACCESS_REG_RETRY; int status; - u8 *tmp; - - tmp = kmemdup(val, size, GFP_KERNEL); - if (!tmp) - return -ENOMEM; while (retry--) { - status = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - F81232_REGISTER_REQUEST, - F81232_SET_REGISTER, - reg, - 0, - tmp, - size, - USB_CTRL_SET_TIMEOUT); - if (status < 0) { + status = usb_control_msg_send(dev, + 0, + F81232_REGISTER_REQUEST, + F81232_SET_REGISTER, + reg, + 0, + val, + size, + USB_CTRL_SET_TIMEOUT, + GFP_KERNEL); + if (status) { status = usb_translate_errors(status); if (status == -EIO) continue; - } else { - status = 0; } break; @@ -889,7 +862,6 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, reg, status); } - kfree(tmp); return status; } -- cgit v1.2.3 From a738859264981ae50986471ccd9c3bb096463c4f Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Mon, 2 Aug 2021 02:01:20 +0530 Subject: USB: serial: ftdi_sio: use usb_control_msg_recv() usb_control_msg_recv() nicely wraps usb_control_msg() and removes the compulsion of using DMA buffers for USB messages. It also includes proper error check for possible short read. So use the wrapper where appropriate and remove DMA buffers from the callers. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20210801203122.3515-5-himadrispandya@gmail.com [ johan: amend commit message ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/ftdi_sio.c | 53 ++++++++++++------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 99d19828dae6..4edebd14ef29 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1437,27 +1437,15 @@ static int _read_latency_timer(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_device *udev = port->serial->dev; - unsigned char *buf; + u8 buf; int rv; - buf = kmalloc(1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - rv = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - FTDI_SIO_GET_LATENCY_TIMER_REQUEST, - FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, - buf, 1, WDR_TIMEOUT); - if (rv < 1) { - if (rv >= 0) - rv = -EIO; - } else { - rv = buf[0]; - } - - kfree(buf); + rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST, + FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, + priv->interface, &buf, 1, WDR_TIMEOUT, + GFP_KERNEL); + if (rv == 0) + rv = buf; return rv; } @@ -1852,32 +1840,21 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; - unsigned char *buf; + u8 buf; int result; result = usb_autopm_get_interface(serial->interface); if (result) return result; - buf = kmalloc(1, GFP_KERNEL); - if (!buf) { - usb_autopm_put_interface(serial->interface); - return -ENOMEM; - } - - result = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - FTDI_SIO_READ_PINS_REQUEST, - FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, - priv->interface, buf, 1, WDR_TIMEOUT); - if (result < 1) { - if (result >= 0) - result = -EIO; - } else { - result = buf[0]; - } + result = usb_control_msg_recv(serial->dev, 0, + FTDI_SIO_READ_PINS_REQUEST, + FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, + priv->interface, &buf, 1, WDR_TIMEOUT, + GFP_KERNEL); + if (result == 0) + result = buf; - kfree(buf); usb_autopm_put_interface(serial->interface); return result; -- cgit v1.2.3 From c9129371cb3d4847ce20a6bcb9708b14eeee665b Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Mon, 2 Aug 2021 02:01:21 +0530 Subject: USB: serial: keyspan_pda: use usb_control_msg_recv() Use the wrapper function usb_control_msg_recv() that accepts stack variables and remove dma buffers from callers of usb_control_msg(). Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20210801203122.3515-6-himadrispandya@gmail.com [ johan: simplify write-room error handling further ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/keyspan_pda.c | 67 +++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 39b0f5f344c2..3e7628becdcd 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -77,36 +77,27 @@ static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv) { struct usb_serial_port *port = priv->port; struct usb_serial *serial = port->serial; - u8 *room; + u8 room; int rc; - room = kmalloc(1, GFP_KERNEL); - if (!room) - return -ENOMEM; - - rc = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value: 0 means "remaining room" */ - 0, /* index */ - room, - 1, - 2000); - if (rc != 1) { - if (rc >= 0) - rc = -EIO; + rc = usb_control_msg_recv(serial->dev, + 0, + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN, + 0, /* value: 0 means "remaining room" */ + 0, /* index */ + &room, + 1, + 2000, + GFP_KERNEL); + if (rc) { dev_dbg(&port->dev, "roomquery failed: %d\n", rc); - goto out_free; + return rc; } - dev_dbg(&port->dev, "roomquery says %d\n", *room); - rc = *room; -out_free: - kfree(room); + dev_dbg(&port->dev, "roomquery says %d\n", room); - return rc; + return room; } static void keyspan_pda_request_unthrottle(struct work_struct *work) @@ -381,22 +372,20 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial, unsigned char *value) { int rc; - u8 *data; - - data = kmalloc(1, GFP_KERNEL); - if (!data) - return -ENOMEM; - - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 3, /* get pins */ - USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN, - 0, 0, data, 1, 2000); - if (rc == 1) - *value = *data; - else if (rc >= 0) - rc = -EIO; + u8 data; + + rc = usb_control_msg_recv(serial->dev, 0, + 3, /* get pins */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN, + 0, + 0, + &data, + 1, + 2000, + GFP_KERNEL); + if (rc == 0) + *value = data; - kfree(data); return rc; } -- cgit v1.2.3 From 71b20b34afc2e709f3bbce516fbfdd9f042b607a Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Mon, 2 Aug 2021 02:01:22 +0530 Subject: USB: serial: kl5kusb105: use usb_control_msg_recv() and usb_control_msg_send() The wrappers usb_control_msg_send/recv eliminate the need of manually allocating DMA buffers for USB messages. They also treat short reads as an error. Hence use the wrappers and remove DMA allocations. Note that short reads are now logged as -EREMOTEIO instead of the amount of data read. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20210801203122.3515-7-himadrispandya@gmail.com [ johan: amend commit message ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/kl5kusb105.c | 79 ++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 45 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index f1e9628a9907..72d3920c9c48 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,16 +124,18 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port, { int rc; - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_SET_DATA, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, /* value */ - 0, /* index */ - settings, - sizeof(struct klsi_105_port_settings), - KLSI_TIMEOUT); - if (rc < 0) + rc = usb_control_msg_send(port->serial->dev, + 0, + KL5KUSB105A_SIO_SET_DATA, + USB_TYPE_VENDOR | USB_DIR_OUT | + USB_RECIP_INTERFACE, + 0, /* value */ + 0, /* index */ + settings, + sizeof(struct klsi_105_port_settings), + KLSI_TIMEOUT, + GFP_KERNEL); + if (rc) dev_err(&port->dev, "Change port settings failed (error = %d)\n", rc); @@ -167,28 +169,21 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, unsigned long *line_state_p) { int rc; - u8 *status_buf; + u8 status_buf[KLSI_STATUSBUF_LEN]; __u16 status; - status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); - if (!status_buf) - return -ENOMEM; - status_buf[0] = 0xff; status_buf[1] = 0xff; - rc = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_POLL, - USB_TYPE_VENDOR | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - status_buf, KLSI_STATUSBUF_LEN, - 10000 - ); - if (rc != KLSI_STATUSBUF_LEN) { + rc = usb_control_msg_recv(port->serial->dev, 0, + KL5KUSB105A_SIO_POLL, + USB_TYPE_VENDOR | USB_DIR_IN, + 0, /* value */ + 0, /* index */ + status_buf, KLSI_STATUSBUF_LEN, + 10000, + GFP_KERNEL); + if (rc) { dev_err(&port->dev, "reading line status failed: %d\n", rc); - if (rc >= 0) - rc = -EIO; } else { status = get_unaligned_le16(status_buf); @@ -198,7 +193,6 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, *line_state_p = klsi_105_status2linestate(status); } - kfree(status_buf); return rc; } @@ -245,7 +239,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) int retval = 0; int rc; unsigned long line_state; - struct klsi_105_port_settings *cfg; + struct klsi_105_port_settings cfg; unsigned long flags; /* Do a defined restart: @@ -255,27 +249,22 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) * Then read the modem line control and store values in * priv->line_state. */ - cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) - return -ENOMEM; - cfg->pktlen = 5; - cfg->baudrate = kl5kusb105a_sio_b9600; - cfg->databits = kl5kusb105a_dtb_8; - cfg->unknown1 = 0; - cfg->unknown2 = 1; - klsi_105_chg_port_settings(port, cfg); + cfg.pktlen = 5; + cfg.baudrate = kl5kusb105a_sio_b9600; + cfg.databits = kl5kusb105a_dtb_8; + cfg.unknown1 = 0; + cfg.unknown2 = 1; + klsi_105_chg_port_settings(port, &cfg); spin_lock_irqsave(&priv->lock, flags); - priv->cfg.pktlen = cfg->pktlen; - priv->cfg.baudrate = cfg->baudrate; - priv->cfg.databits = cfg->databits; - priv->cfg.unknown1 = cfg->unknown1; - priv->cfg.unknown2 = cfg->unknown2; + priv->cfg.pktlen = cfg.pktlen; + priv->cfg.baudrate = cfg.baudrate; + priv->cfg.databits = cfg.databits; + priv->cfg.unknown1 = cfg.unknown1; + priv->cfg.unknown2 = cfg.unknown2; spin_unlock_irqrestore(&priv->lock, flags); - kfree(cfg); - /* READ_ON and urb submission */ rc = usb_serial_generic_open(tty, port); if (rc) -- cgit v1.2.3 From a692d0e6066c9377699b88fc0555d719519e6fb0 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Tue, 21 Sep 2021 15:30:07 +0200 Subject: USB: serial: kl5kusb105: clean up line-status handling Clean up the line-status handling by dropping redundant initialisations and returning early on errors. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/kl5kusb105.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 72d3920c9c48..7681671ddb79 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -172,8 +172,6 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, u8 status_buf[KLSI_STATUSBUF_LEN]; __u16 status; - status_buf[0] = 0xff; - status_buf[1] = 0xff; rc = usb_control_msg_recv(port->serial->dev, 0, KL5KUSB105A_SIO_POLL, USB_TYPE_VENDOR | USB_DIR_IN, @@ -184,16 +182,17 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, GFP_KERNEL); if (rc) { dev_err(&port->dev, "reading line status failed: %d\n", rc); - } else { - status = get_unaligned_le16(status_buf); + return rc; + } - dev_dbg(&port->dev, "read status %02x %02x\n", - status_buf[0], status_buf[1]); + status = get_unaligned_le16(status_buf); - *line_state_p = klsi_105_status2linestate(status); - } + dev_dbg(&port->dev, "read status %02x %02x\n", + status_buf[0], status_buf[1]); - return rc; + *line_state_p = klsi_105_status2linestate(status); + + return 0; } -- cgit v1.2.3 From 2e0b78dad3b69df12baa925c4e42489deaaf4054 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Tue, 21 Sep 2021 15:30:08 +0200 Subject: USB: serial: kl5kusb105: simplify line-status handling Now that the driver is using usb_control_msg_recv(), the line status handling can be simplified further by reading directly into the status variable and doing the endian conversion in place. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/kl5kusb105.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 7681671ddb79..99dffbdd3142 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -163,21 +163,18 @@ static unsigned long klsi_105_status2linestate(const __u16 status) * Read line control via vendor command and return result through * *line_state_p */ -/* It seems that the status buffer has always only 2 bytes length */ -#define KLSI_STATUSBUF_LEN 2 static int klsi_105_get_line_state(struct usb_serial_port *port, unsigned long *line_state_p) { + u16 status; int rc; - u8 status_buf[KLSI_STATUSBUF_LEN]; - __u16 status; rc = usb_control_msg_recv(port->serial->dev, 0, KL5KUSB105A_SIO_POLL, USB_TYPE_VENDOR | USB_DIR_IN, 0, /* value */ 0, /* index */ - status_buf, KLSI_STATUSBUF_LEN, + &status, sizeof(status), 10000, GFP_KERNEL); if (rc) { @@ -185,10 +182,9 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, return rc; } - status = get_unaligned_le16(status_buf); + le16_to_cpus(&status); - dev_dbg(&port->dev, "read status %02x %02x\n", - status_buf[0], status_buf[1]); + dev_dbg(&port->dev, "read status %04x\n", status); *line_state_p = klsi_105_status2linestate(status); -- cgit v1.2.3 From c8345c0500de4411762db5941058e34979879128 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Tue, 21 Sep 2021 15:30:09 +0200 Subject: USB: serial: kl5kusb105: drop line-status helper Drop the line-status conversion helper and do the conversion in place instead. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/kl5kusb105.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 99dffbdd3142..edcc57bd9b5e 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -147,24 +147,12 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port, return rc; } -/* translate a 16-bit status value from the device to linux's TIO bits */ -static unsigned long klsi_105_status2linestate(const __u16 status) -{ - unsigned long res = 0; - - res = ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0) - | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0) - ; - - return res; -} - /* * Read line control via vendor command and return result through - * *line_state_p + * the state pointer. */ static int klsi_105_get_line_state(struct usb_serial_port *port, - unsigned long *line_state_p) + unsigned long *state) { u16 status; int rc; @@ -186,7 +174,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, dev_dbg(&port->dev, "read status %04x\n", status); - *line_state_p = klsi_105_status2linestate(status); + *state = ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0) | + ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0); return 0; } -- cgit v1.2.3 From 74f266455062c158f343bc3aa35ef84b3eb7adf1 Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Fri, 1 Oct 2021 08:57:19 +0200 Subject: USB: serial: ch314: use usb_control_msg_recv() usb_control_msg_recv() is a new wrapper function for usb_control_msg() that has error checks for short reads. This function also accepts data buffer on stack. Hence use this function to simplify error handling for short reads. Short reads will now get reported as -EREMOTEIO with no indication of how short the transfer was. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20211001065720.21330-2-himadrispandya@gmail.com [ johan: fix quirk-detection breakage, style changes ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/ch341.c | 85 ++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 59 deletions(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 2db917eab799..29f4b87a9e74 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -131,17 +131,11 @@ static int ch341_control_in(struct usb_device *dev, dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__, request, value, index, bufsize); - r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - value, index, buf, bufsize, DEFAULT_TIMEOUT); - if (r < (int)bufsize) { - if (r >= 0) { - dev_err(&dev->dev, - "short control message received (%d < %u)\n", - r, bufsize); - r = -EIO; - } - + r = usb_control_msg_recv(dev, 0, request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT, + GFP_KERNEL); + if (r) { dev_err(&dev->dev, "failed to receive control message: %d\n", r); return r; @@ -287,24 +281,19 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control) static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) { const unsigned int size = 2; - char *buffer; + u8 buffer[2]; int r; unsigned long flags; - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size); - if (r < 0) - goto out; + if (r) + return r; spin_lock_irqsave(&priv->lock, flags); priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT; spin_unlock_irqrestore(&priv->lock, flags); -out: kfree(buffer); - return r; + return 0; } /* -------------------------------------------------------------------------- */ @@ -312,31 +301,28 @@ out: kfree(buffer); static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) { const unsigned int size = 2; - char *buffer; + u8 buffer[2]; int r; - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - /* expect two bytes 0x27 0x00 */ r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size); - if (r < 0) - goto out; + if (r) + return r; dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]); r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0); if (r < 0) - goto out; + return r; r = ch341_set_baudrate_lcr(dev, priv, priv->baud_rate, priv->lcr); if (r < 0) - goto out; + return r; r = ch341_set_handshake(dev, priv->mcr); + if (r < 0) + return r; -out: kfree(buffer); - return r; + return 0; } static int ch341_detect_quirks(struct usb_serial_port *port) @@ -345,40 +331,27 @@ static int ch341_detect_quirks(struct usb_serial_port *port) struct usb_device *udev = port->serial->dev; const unsigned int size = 2; unsigned long quirks = 0; - char *buffer; + u8 buffer[2]; int r; - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - /* * A subset of CH34x devices does not support all features. The * prescaler is limited and there is no support for sending a RS232 * break condition. A read failure when trying to set up the latter is * used to detect these devices. */ - r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), CH341_REQ_READ_REG, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - CH341_REG_BREAK, 0, buffer, size, DEFAULT_TIMEOUT); + r = usb_control_msg_recv(udev, 0, CH341_REQ_READ_REG, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + CH341_REG_BREAK, 0, &buffer, size, + DEFAULT_TIMEOUT, GFP_KERNEL); if (r == -EPIPE) { dev_info(&port->dev, "break control not supported, using simulated break\n"); quirks = CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; r = 0; - goto out; - } - - if (r != size) { - if (r >= 0) - r = -EIO; + } else if (r) { dev_err(&port->dev, "failed to read break control: %d\n", r); - goto out; } - r = 0; -out: - kfree(buffer); - if (quirks) { dev_dbg(&port->dev, "enabling quirk flags: 0x%02lx\n", quirks); priv->quirks |= quirks; @@ -647,23 +620,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) struct ch341_private *priv = usb_get_serial_port_data(port); int r; uint16_t reg_contents; - uint8_t *break_reg; + uint8_t break_reg[2]; if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK) { ch341_simulate_break(tty, break_state); return; } - break_reg = kmalloc(2, GFP_KERNEL); - if (!break_reg) - return; - r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG, ch341_break_reg, 0, break_reg, 2); - if (r < 0) { + if (r) { dev_err(&port->dev, "%s - USB control read error (%d)\n", __func__, r); - goto out; + return; } dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n", __func__, break_reg[0], break_reg[1]); @@ -684,8 +653,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) if (r < 0) dev_err(&port->dev, "%s - USB control write error (%d)\n", __func__, r); -out: - kfree(break_reg); } static int ch341_tiocmset(struct tty_struct *tty, -- cgit v1.2.3 From f5cfbecb0a162319464c9408420282d22ed69721 Mon Sep 17 00:00:00 2001 From: Himadri Pandya <himadrispandya@gmail.com> Date: Fri, 1 Oct 2021 08:57:20 +0200 Subject: USB: serial: cp210x: use usb_control_msg_recv() and usb_control_msg_send() The new wrapper functions for usb_control_msg() can accept data from stack and treat short reads as errors. Hence use the wrappers functions. Please note that because of this change, cp210x_read_reg_block() will no longer log the length of short reads. Signed-off-by: Himadri Pandya <himadrispandya@gmail.com> Link: https://lore.kernel.org/r/20211001065720.21330-3-himadrispandya@gmail.com [ johan: style changes ] Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/cp210x.c | 109 +++++++++++++------------------------------- 1 file changed, 31 insertions(+), 78 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 66a6ac50a4cd..920b97665375 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -629,30 +629,20 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req, { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - void *dmabuf; int result; - dmabuf = kmalloc(bufsize, GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - req, REQTYPE_INTERFACE_TO_HOST, 0, - port_priv->bInterfaceNumber, dmabuf, bufsize, - USB_CTRL_GET_TIMEOUT); - if (result == bufsize) { - memcpy(buf, dmabuf, bufsize); - result = 0; - } else { + result = usb_control_msg_recv(serial->dev, 0, req, + REQTYPE_INTERFACE_TO_HOST, 0, + port_priv->bInterfaceNumber, buf, bufsize, + USB_CTRL_SET_TIMEOUT, GFP_KERNEL); + if (result) { dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n", req, bufsize, result); - if (result >= 0) - result = -EIO; + return result; } - kfree(dmabuf); - - return result; + return 0; } /* @@ -670,31 +660,19 @@ static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val) static int cp210x_read_vendor_block(struct usb_serial *serial, u8 type, u16 val, void *buf, int bufsize) { - void *dmabuf; int result; - dmabuf = kmalloc(bufsize, GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - CP210X_VENDOR_SPECIFIC, type, val, - cp210x_interface_num(serial), dmabuf, bufsize, - USB_CTRL_GET_TIMEOUT); - if (result == bufsize) { - memcpy(buf, dmabuf, bufsize); - result = 0; - } else { + result = usb_control_msg_recv(serial->dev, 0, CP210X_VENDOR_SPECIFIC, + type, val, cp210x_interface_num(serial), buf, bufsize, + USB_CTRL_GET_TIMEOUT, GFP_KERNEL); + if (result) { dev_err(&serial->interface->dev, "failed to get vendor val 0x%04x size %d: %d\n", val, bufsize, result); - if (result >= 0) - result = -EIO; + return result; } - kfree(dmabuf); - - return result; + return 0; } /* @@ -728,21 +706,13 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req, { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - void *dmabuf; int result; - dmabuf = kmemdup(buf, bufsize, GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - req, REQTYPE_HOST_TO_INTERFACE, 0, - port_priv->bInterfaceNumber, dmabuf, bufsize, - USB_CTRL_SET_TIMEOUT); - - kfree(dmabuf); - - if (result < 0) { + result = usb_control_msg_send(serial->dev, 0, req, + REQTYPE_HOST_TO_INTERFACE, 0, + port_priv->bInterfaceNumber, buf, bufsize, + USB_CTRL_SET_TIMEOUT, GFP_KERNEL); + if (result) { dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n", req, bufsize, result); return result; @@ -771,21 +741,12 @@ static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val) static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type, u16 val, void *buf, int bufsize) { - void *dmabuf; int result; - dmabuf = kmemdup(buf, bufsize, GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - CP210X_VENDOR_SPECIFIC, type, val, - cp210x_interface_num(serial), dmabuf, bufsize, - USB_CTRL_SET_TIMEOUT); - - kfree(dmabuf); - - if (result < 0) { + result = usb_control_msg_send(serial->dev, 0, CP210X_VENDOR_SPECIFIC, + type, val, cp210x_interface_num(serial), buf, bufsize, + USB_CTRL_SET_TIMEOUT, GFP_KERNEL); + if (result) { dev_err(&serial->interface->dev, "failed to set vendor val 0x%04x size %d: %d\n", val, bufsize, result); @@ -950,29 +911,21 @@ static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port, { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - struct cp210x_comm_status *sts; + struct cp210x_comm_status sts; int result; - sts = kmalloc(sizeof(*sts), GFP_KERNEL); - if (!sts) - return -ENOMEM; - - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - CP210X_GET_COMM_STATUS, REQTYPE_INTERFACE_TO_HOST, - 0, port_priv->bInterfaceNumber, sts, sizeof(*sts), - USB_CTRL_GET_TIMEOUT); - if (result == sizeof(*sts)) { - *count = le32_to_cpu(sts->ulAmountInOutQueue); - result = 0; - } else { + result = usb_control_msg_recv(serial->dev, 0, CP210X_GET_COMM_STATUS, + REQTYPE_INTERFACE_TO_HOST, 0, + port_priv->bInterfaceNumber, &sts, sizeof(sts), + USB_CTRL_GET_TIMEOUT, GFP_KERNEL); + if (result) { dev_err(&port->dev, "failed to get comm status: %d\n", result); - if (result >= 0) - result = -EIO; + return result; } - kfree(sts); + *count = le32_to_cpu(sts.ulAmountInOutQueue); - return result; + return 0; } static bool cp210x_tx_empty(struct usb_serial_port *port) -- cgit v1.2.3 From 910c996335c37552ee30fcb837375b808bb4f33b Mon Sep 17 00:00:00 2001 From: Wang Hai <wanghai38@huawei.com> Date: Fri, 15 Oct 2021 16:55:43 +0800 Subject: USB: serial: keyspan: fix memleak on probe errors I got memory leak as follows when doing fault injection test: unreferenced object 0xffff888258228440 (size 64): comm "kworker/7:2", pid 2005, jiffies 4294989509 (age 824.540s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<ffffffff8167939c>] slab_post_alloc_hook+0x9c/0x490 [<ffffffff8167f627>] kmem_cache_alloc_trace+0x1f7/0x470 [<ffffffffa02ac0e4>] keyspan_port_probe+0xa4/0x5d0 [keyspan] [<ffffffffa0294c07>] usb_serial_device_probe+0x97/0x1d0 [usbserial] [<ffffffff82b50ca7>] really_probe+0x167/0x460 [<ffffffff82b51099>] __driver_probe_device+0xf9/0x180 [<ffffffff82b51173>] driver_probe_device+0x53/0x130 [<ffffffff82b516f5>] __device_attach_driver+0x105/0x130 [<ffffffff82b4cfe9>] bus_for_each_drv+0x129/0x190 [<ffffffff82b50a69>] __device_attach+0x1c9/0x270 [<ffffffff82b518d0>] device_initial_probe+0x20/0x30 [<ffffffff82b4f062>] bus_probe_device+0x142/0x160 [<ffffffff82b4a4e9>] device_add+0x829/0x1300 [<ffffffffa0295fda>] usb_serial_probe.cold+0xc9b/0x14ac [usbserial] [<ffffffffa02266aa>] usb_probe_interface+0x1aa/0x3c0 [usbcore] [<ffffffff82b50ca7>] really_probe+0x167/0x460 If keyspan_port_probe() fails to allocate memory for an out_buffer[i] or in_buffer[i], the previously allocated memory for out_buffer or in_buffer needs to be freed on the error handling path, otherwise a memory leak will result. Fixes: bad41a5bf177 ("USB: keyspan: fix port DMA-buffer allocations") Reported-by: Hulk Robot <hulkci@huawei.com> Signed-off-by: Wang Hai <wanghai38@huawei.com> Link: https://lore.kernel.org/r/20211015085543.1203011-1-wanghai38@huawei.com Cc: stable@vger.kernel.org # 3.12 Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/usb/serial/keyspan.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 87b89c99d517..1cfcd805f286 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -2890,22 +2890,22 @@ static int keyspan_port_probe(struct usb_serial_port *port) for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) { p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL); if (!p_priv->in_buffer[i]) - goto err_in_buffer; + goto err_free_in_buffer; } for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) { p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL); if (!p_priv->out_buffer[i]) - goto err_out_buffer; + goto err_free_out_buffer; } p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL); if (!p_priv->inack_buffer) - goto err_inack_buffer; + goto err_free_out_buffer; p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL); if (!p_priv->outcont_buffer) - goto err_outcont_buffer; + goto err_free_inack_buffer; p_priv->device_details = d_details; @@ -2951,15 +2951,14 @@ static int keyspan_port_probe(struct usb_serial_port *port) return 0; -err_outcont_buffer: +err_free_inack_buffer: kfree(p_priv->inack_buffer); -err_inack_buffer: +err_free_out_buffer: for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) kfree(p_priv->out_buffer[i]); -err_out_buffer: +err_free_in_buffer: for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) kfree(p_priv->in_buffer[i]); -err_in_buffer: kfree(p_priv); return -ENOMEM; -- cgit v1.2.3