diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-11-15 17:45:04 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-11-15 17:45:04 +0100 |
commit | aa03bda68af74e2079ae5e064f61a3d3d0b0ffc4 (patch) | |
tree | 94c1e63629dfb98e9ca7f90ef672681f7b15342d /drivers/usb | |
parent | d6fa15bbcf9604e3c14816410550d2cf22b955e4 (diff) | |
parent | 8b524944f92ccad925b574f645e9c2709cf60d1e (diff) | |
download | lwn-aa03bda68af74e2079ae5e064f61a3d3d0b0ffc4.tar.gz lwn-aa03bda68af74e2079ae5e064f61a3d3d0b0ffc4.zip |
Merge tag 'usb-serial-6.13-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
USB-serial updates for 6.13-rc1
Here are the USB-serial updates for 6.13-rc1, including:
- improved support for quirky pl2303 hxd devices
- make sure ftdi_sio TIOCGSERIAL returns consistent data
Everything has been in linux-next with no reported issues.
* tag 'usb-serial-6.13-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
USB: serial: ftdi_sio: Fix atomicity violation in get_serial_info()
USB: serial: pl2303: account for deficits of clones
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/pl2303.c | 38 |
2 files changed, 39 insertions, 1 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c6f17d732b95..e07c5e3eb18c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1443,9 +1443,11 @@ static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); + mutex_lock(&priv->cfg_lock); ss->flags = priv->flags; ss->baud_base = priv->baud_base; ss->custom_divisor = priv->custom_divisor; + mutex_unlock(&priv->cfg_lock); } static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ad41363e3cea..010688dd9e49 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -31,6 +31,7 @@ #define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) #define PL2303_QUIRK_LEGACY BIT(1) #define PL2303_QUIRK_ENDPOINT_HACK BIT(2) +#define PL2303_QUIRK_NO_BREAK_GETLINE BIT(3) static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID), @@ -467,6 +468,25 @@ static int pl2303_detect_type(struct usb_serial *serial) return -ENODEV; } +static bool pl2303_is_hxd_clone(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + unsigned char *buf; + int ret; + + buf = kmalloc(7, GFP_KERNEL); + if (!buf) + return false; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + + kfree(buf); + + return ret == -EPIPE; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; @@ -489,6 +509,9 @@ static int pl2303_startup(struct usb_serial *serial) spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; + if (type == TYPE_HXD && pl2303_is_hxd_clone(serial)) + spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE; + usb_set_serial_data(serial, spriv); if (type != TYPE_HXN) { @@ -725,9 +748,18 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, static int pl2303_get_line_request(struct usb_serial_port *port, unsigned char buf[7]) { - struct usb_device *udev = port->serial->dev; + struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + struct usb_device *udev = serial->dev; int ret; + if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE) { + struct pl2303_private *priv = usb_get_serial_port_data(port); + + memcpy(buf, priv->line_settings, 7); + return 0; + } + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); @@ -1064,9 +1096,13 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) static int pl2303_set_break(struct usb_serial_port *port, bool enable) { struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); u16 state; int result; + if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE) + return -ENOTTY; + if (enable) state = BREAK_ON; else |