summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-11-15 17:45:04 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-11-15 17:45:04 +0100
commitaa03bda68af74e2079ae5e064f61a3d3d0b0ffc4 (patch)
tree94c1e63629dfb98e9ca7f90ef672681f7b15342d /drivers/usb
parentd6fa15bbcf9604e3c14816410550d2cf22b955e4 (diff)
parent8b524944f92ccad925b574f645e9c2709cf60d1e (diff)
downloadlwn-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.c2
-rw-r--r--drivers/usb/serial/pl2303.c38
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