Commit d3d53894 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'usb-serial-4.0-rc3' of...

Merge tag 'usb-serial-4.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-linus

Johan writes:

USB-serial fixes for v4.0-rc3

Here are a few fixes for reported problems including a usb-debug device
buffer overflow, potential use-after-free on failed probe, and a couple
of issues with the USB console.

Some new device IDs are also added.
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parents b20b1618 c7d373c3
...@@ -38,56 +38,51 @@ static int usb_serial_device_match(struct device *dev, ...@@ -38,56 +38,51 @@ static int usb_serial_device_match(struct device *dev,
return 0; return 0;
} }
static ssize_t port_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
return sprintf(buf, "%d\n", port->port_number);
}
static DEVICE_ATTR_RO(port_number);
static int usb_serial_device_probe(struct device *dev) static int usb_serial_device_probe(struct device *dev)
{ {
struct usb_serial_driver *driver; struct usb_serial_driver *driver;
struct usb_serial_port *port; struct usb_serial_port *port;
struct device *tty_dev;
int retval = 0; int retval = 0;
int minor; int minor;
port = to_usb_serial_port(dev); port = to_usb_serial_port(dev);
if (!port) { if (!port)
retval = -ENODEV; return -ENODEV;
goto exit;
}
/* make sure suspend/resume doesn't race against port_probe */ /* make sure suspend/resume doesn't race against port_probe */
retval = usb_autopm_get_interface(port->serial->interface); retval = usb_autopm_get_interface(port->serial->interface);
if (retval) if (retval)
goto exit; return retval;
driver = port->serial->type; driver = port->serial->type;
if (driver->port_probe) { if (driver->port_probe) {
retval = driver->port_probe(port); retval = driver->port_probe(port);
if (retval) if (retval)
goto exit_with_autopm; goto err_autopm_put;
} }
retval = device_create_file(dev, &dev_attr_port_number); minor = port->minor;
if (retval) { tty_dev = tty_register_device(usb_serial_tty_driver, minor, dev);
if (driver->port_remove) if (IS_ERR(tty_dev)) {
retval = driver->port_remove(port); retval = PTR_ERR(tty_dev);
goto exit_with_autopm; goto err_port_remove;
} }
minor = port->minor; usb_autopm_put_interface(port->serial->interface);
tty_register_device(usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev, dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d\n", "%s converter now attached to ttyUSB%d\n",
driver->description, minor); driver->description, minor);
exit_with_autopm: return 0;
err_port_remove:
if (driver->port_remove)
driver->port_remove(port);
err_autopm_put:
usb_autopm_put_interface(port->serial->interface); usb_autopm_put_interface(port->serial->interface);
exit:
return retval; return retval;
} }
...@@ -114,8 +109,6 @@ static int usb_serial_device_remove(struct device *dev) ...@@ -114,8 +109,6 @@ static int usb_serial_device_remove(struct device *dev)
minor = port->minor; minor = port->minor;
tty_unregister_device(usb_serial_tty_driver, minor); tty_unregister_device(usb_serial_tty_driver, minor);
device_remove_file(&port->dev, &dev_attr_port_number);
driver = port->serial->type; driver = port->serial->type;
if (driver->port_remove) if (driver->port_remove)
retval = driver->port_remove(port); retval = driver->port_remove(port);
......
...@@ -84,6 +84,10 @@ struct ch341_private { ...@@ -84,6 +84,10 @@ struct ch341_private {
u8 line_status; /* active status of modem control inputs */ u8 line_status; /* active status of modem control inputs */
}; };
static void ch341_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios);
static int ch341_control_out(struct usb_device *dev, u8 request, static int ch341_control_out(struct usb_device *dev, u8 request,
u16 value, u16 index) u16 value, u16 index)
{ {
...@@ -309,19 +313,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -309,19 +313,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ch341_private *priv = usb_get_serial_port_data(port); struct ch341_private *priv = usb_get_serial_port_data(port);
int r; int r;
priv->baud_rate = DEFAULT_BAUD_RATE;
r = ch341_configure(serial->dev, priv); r = ch341_configure(serial->dev, priv);
if (r) if (r)
goto out; goto out;
r = ch341_set_handshake(serial->dev, priv->line_control); if (tty)
if (r) ch341_set_termios(tty, port, NULL);
goto out;
r = ch341_set_baudrate(serial->dev, priv);
if (r)
goto out;
dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__); dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/console.h> #include <linux/console.h>
...@@ -144,6 +145,7 @@ static int usb_console_setup(struct console *co, char *options) ...@@ -144,6 +145,7 @@ static int usb_console_setup(struct console *co, char *options)
init_ldsem(&tty->ldisc_sem); init_ldsem(&tty->ldisc_sem);
INIT_LIST_HEAD(&tty->tty_files); INIT_LIST_HEAD(&tty->tty_files);
kref_get(&tty->driver->kref); kref_get(&tty->driver->kref);
__module_get(tty->driver->owner);
tty->ops = &usb_console_fake_tty_ops; tty->ops = &usb_console_fake_tty_ops;
if (tty_init_termios(tty)) { if (tty_init_termios(tty)) {
retval = -ENOMEM; retval = -ENOMEM;
......
...@@ -147,6 +147,8 @@ static const struct usb_device_id id_table[] = { ...@@ -147,6 +147,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
{ USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
{ USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
{ USB_DEVICE(0x16C0, 0x09B0) }, /* Lunatico Seletek */
{ USB_DEVICE(0x16C0, 0x09B1) }, /* Lunatico Seletek */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
{ USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
......
...@@ -799,6 +799,8 @@ static const struct usb_device_id id_table_combined[] = { ...@@ -799,6 +799,8 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
{ USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID),
...@@ -978,6 +980,23 @@ static const struct usb_device_id id_table_combined[] = { ...@@ -978,6 +980,23 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
/* GE Healthcare devices */ /* GE Healthcare devices */
{ USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) }, { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
/* Active Research (Actisense) devices */
{ USB_DEVICE(FTDI_VID, ACTISENSE_NDC_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_USG_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_NGT_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_NGW_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_D9AC_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_D9AD_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_D9AE_PID) },
{ USB_DEVICE(FTDI_VID, ACTISENSE_D9AF_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEAGAUGE_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASWITCH_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_NMEA2000_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ETHERNET_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_WIFI_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#define FTDI_LUMEL_PD12_PID 0x6002 #define FTDI_LUMEL_PD12_PID 0x6002
/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
#define CYBER_CORTEX_AV_PID 0x8698
/* /*
* Marvell OpenRD Base, Client * Marvell OpenRD Base, Client
* http://www.open-rd.org * http://www.open-rd.org
...@@ -1438,3 +1441,23 @@ ...@@ -1438,3 +1441,23 @@
*/ */
#define GE_HEALTHCARE_VID 0x1901 #define GE_HEALTHCARE_VID 0x1901
#define GE_HEALTHCARE_NEMO_TRACKER_PID 0x0015 #define GE_HEALTHCARE_NEMO_TRACKER_PID 0x0015
/*
* Active Research (Actisense) devices
*/
#define ACTISENSE_NDC_PID 0xD9A8 /* NDC USB Serial Adapter */
#define ACTISENSE_USG_PID 0xD9A9 /* USG USB Serial Adapter */
#define ACTISENSE_NGT_PID 0xD9AA /* NGT NMEA2000 Interface */
#define ACTISENSE_NGW_PID 0xD9AB /* NGW NMEA2000 Gateway */
#define ACTISENSE_D9AC_PID 0xD9AC /* Actisense Reserved */
#define ACTISENSE_D9AD_PID 0xD9AD /* Actisense Reserved */
#define ACTISENSE_D9AE_PID 0xD9AE /* Actisense Reserved */
#define ACTISENSE_D9AF_PID 0xD9AF /* Actisense Reserved */
#define CHETCO_SEAGAUGE_PID 0xA548 /* SeaGauge USB Adapter */
#define CHETCO_SEASWITCH_PID 0xA549 /* SeaSwitch USB Adapter */
#define CHETCO_SEASMART_NMEA2000_PID 0xA54A /* SeaSmart NMEA2000 Gateway */
#define CHETCO_SEASMART_ETHERNET_PID 0xA54B /* SeaSmart Ethernet Gateway */
#define CHETCO_SEASMART_WIFI_PID 0xA5AC /* SeaSmart Wifi Gateway */
#define CHETCO_SEASMART_DISPLAY_PID 0xA5AD /* SeaSmart NMEA2000 Display */
#define CHETCO_SEASMART_LITE_PID 0xA5AE /* SeaSmart Lite USB Adapter */
#define CHETCO_SEASMART_ANALOG_PID 0xA5AF /* SeaSmart Analog Adapter */
...@@ -1284,7 +1284,8 @@ static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -1284,7 +1284,8 @@ static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
} }
/* Initial port termios */ /* Initial port termios */
mxuport_set_termios(tty, port, NULL); if (tty)
mxuport_set_termios(tty, port, NULL);
/* /*
* TODO: use RQ_VENDOR_GET_MSR, once we know what it * TODO: use RQ_VENDOR_GET_MSR, once we know what it
......
...@@ -132,6 +132,7 @@ MODULE_DEVICE_TABLE(usb, id_table); ...@@ -132,6 +132,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define UART_OVERRUN_ERROR 0x40 #define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80 #define UART_CTS 0x80
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type { enum pl2303_type {
TYPE_01, /* Type 0 and 1 (difference unknown) */ TYPE_01, /* Type 0 and 1 (difference unknown) */
...@@ -615,6 +616,7 @@ static void pl2303_close(struct usb_serial_port *port) ...@@ -615,6 +616,7 @@ static void pl2303_close(struct usb_serial_port *port)
{ {
usb_serial_generic_close(port); usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
pl2303_set_break(port, false);
} }
static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
...@@ -741,17 +743,16 @@ static int pl2303_ioctl(struct tty_struct *tty, ...@@ -741,17 +743,16 @@ static int pl2303_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
static void pl2303_break_ctl(struct tty_struct *tty, int break_state) static void pl2303_set_break(struct usb_serial_port *port, bool enable)
{ {
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
u16 state; u16 state;
int result; int result;
if (break_state == 0) if (enable)
state = BREAK_OFF;
else
state = BREAK_ON; state = BREAK_ON;
else
state = BREAK_OFF;
dev_dbg(&port->dev, "%s - turning break %s\n", __func__, dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
state == BREAK_OFF ? "off" : "on"); state == BREAK_OFF ? "off" : "on");
...@@ -763,6 +764,13 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) ...@@ -763,6 +764,13 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
dev_err(&port->dev, "error sending break = %d\n", result); dev_err(&port->dev, "error sending break = %d\n", result);
} }
static void pl2303_break_ctl(struct tty_struct *tty, int state)
{
struct usb_serial_port *port = tty->driver_data;
pl2303_set_break(port, state);
}
static void pl2303_update_line_status(struct usb_serial_port *port, static void pl2303_update_line_status(struct usb_serial_port *port,
unsigned char *data, unsigned char *data,
unsigned int actual_length) unsigned int actual_length)
......
...@@ -687,6 +687,21 @@ static void serial_port_dtr_rts(struct tty_port *port, int on) ...@@ -687,6 +687,21 @@ static void serial_port_dtr_rts(struct tty_port *port, int on)
drv->dtr_rts(p, on); drv->dtr_rts(p, on);
} }
static ssize_t port_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
return sprintf(buf, "%u\n", port->port_number);
}
static DEVICE_ATTR_RO(port_number);
static struct attribute *usb_serial_port_attrs[] = {
&dev_attr_port_number.attr,
NULL
};
ATTRIBUTE_GROUPS(usb_serial_port);
static const struct tty_port_operations serial_port_ops = { static const struct tty_port_operations serial_port_ops = {
.carrier_raised = serial_port_carrier_raised, .carrier_raised = serial_port_carrier_raised,
.dtr_rts = serial_port_dtr_rts, .dtr_rts = serial_port_dtr_rts,
...@@ -902,6 +917,7 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -902,6 +917,7 @@ static int usb_serial_probe(struct usb_interface *interface,
port->dev.driver = NULL; port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type; port->dev.bus = &usb_serial_bus_type;
port->dev.release = &usb_serial_port_release; port->dev.release = &usb_serial_port_release;
port->dev.groups = usb_serial_port_groups;
device_initialize(&port->dev); device_initialize(&port->dev);
} }
...@@ -940,8 +956,9 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -940,8 +956,9 @@ static int usb_serial_probe(struct usb_interface *interface,
port = serial->port[i]; port = serial->port[i];
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
goto probe_error; goto probe_error;
buffer_size = max_t(int, serial->type->bulk_out_size, buffer_size = serial->type->bulk_out_size;
usb_endpoint_maxp(endpoint)); if (!buffer_size)
buffer_size = usb_endpoint_maxp(endpoint);
port->bulk_out_size = buffer_size; port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress; port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
......
...@@ -190,8 +190,7 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data) ...@@ -190,8 +190,7 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
* @num_ports: the number of different ports this device will have. * @num_ports: the number of different ports this device will have.
* @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer * @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
* (0 = end-point size) * (0 = end-point size)
* @bulk_out_size: minimum number of bytes to allocate for bulk-out buffer * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
* (0 = end-point size)
* @calc_num_ports: pointer to a function to determine how many ports this * @calc_num_ports: pointer to a function to determine how many ports this
* device has dynamically. It will be called after the probe() * device has dynamically. It will be called after the probe()
* callback is called, but before attach() * callback is called, but before attach()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment