summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/pl2303.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman2019-05-03 18:00:15 +0200
committerGreg Kroah-Hartman2019-05-03 18:00:15 +0200
commit6f6a407a591ebe3e4c6bd2329b29862b3980a3ca (patch)
treea3a5ba5402e5fa0740d6dad13f6d6fae0cc2b94f /drivers/usb/serial/pl2303.c
parentusb: usb251xb: Add US port lanes inversion property (diff)
parentUSB: serial: f81232: implement break control (diff)
downloadkernel-qcow2-linux-6f6a407a591ebe3e4c6bd2329b29862b3980a3ca.tar.gz
kernel-qcow2-linux-6f6a407a591ebe3e4c6bd2329b29862b3980a3ca.tar.xz
kernel-qcow2-linux-6f6a407a591ebe3e4c6bd2329b29862b3980a3ca.zip
Merge tag 'usb-serial-5.2-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes: USB-serial updates for 5.2-rc1 Here are the USB-serial updates for 5.2-rc1, including: - flow-control related fixes for pl2303 - fix for an initial-termios issue - fix for a couple of unthrottle() races - fix for f81232 interrupt-handling issues - improved f81232 overrun handling - support for higher f81232 line speeds - support for f81232 break control Included are also various clean ups. All but the last four commits have been in linux-next and with no reported issues. Signed-off-by: Johan Hovold <johan@kernel.org> * tag 'usb-serial-5.2-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: (22 commits) USB: serial: f81232: implement break control USB: serial: f81232: add high baud rate support USB: serial: f81232: clear overrun flag USB: serial: f81232: fix interrupt worker not stop USB: serial: io_edgeport: fix up switch fall-through comments USB: serial: drop unused iflag macro USB: serial: drop unnecessary goto USB: serial: clean up throttle handling USB: serial: fix unthrottle races USB: serial: spcp8x5: simplify init_termios USB: serial: oti6858: simplify init_termios USB: serial: iuu_phoenix: simplify init_termios USB: serial: iuu_phoenix: drop bogus initial cflag USB: serial: cypress_m8: clean up initial-termios handling USB: serial: cypress_m8: drop unused termios USB: serial: cypress_m8: drop unused driver data flag USB: serial: ark3116: drop redundant init_termios USB: serial: fix initial-termios handling USB: serial: digi_acceleport: clean up set_termios USB: serial: digi_acceleport: clean up modem-control handling ...
Diffstat (limited to 'drivers/usb/serial/pl2303.c')
-rw-r--r--drivers/usb/serial/pl2303.c58
1 files changed, 49 insertions, 9 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index bb3f9aa4a909..55122ac84518 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -145,6 +145,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
+#define PL2303_FLOWCTRL_MASK 0xf0
+
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type {
@@ -156,6 +158,7 @@ enum pl2303_type {
struct pl2303_type_data {
speed_t max_baud_rate;
unsigned long quirks;
+ unsigned int no_autoxonxoff:1;
};
struct pl2303_serial_private {
@@ -173,11 +176,12 @@ struct pl2303_private {
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
[TYPE_01] = {
- .max_baud_rate = 1228800,
- .quirks = PL2303_QUIRK_LEGACY,
+ .max_baud_rate = 1228800,
+ .quirks = PL2303_QUIRK_LEGACY,
+ .no_autoxonxoff = true,
},
[TYPE_HX] = {
- .max_baud_rate = 12000000,
+ .max_baud_rate = 12000000,
},
};
@@ -223,6 +227,29 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
return 0;
}
+static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
+{
+ int ret = 0;
+ u8 *buf;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = pl2303_vendor_read(serial, reg | 0x80, buf);
+ if (ret)
+ goto out_free;
+
+ *buf &= ~mask;
+ *buf |= val & mask;
+
+ ret = pl2303_vendor_write(serial, reg, *buf);
+out_free:
+ kfree(buf);
+
+ return ret;
+}
+
static int pl2303_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
@@ -552,6 +579,20 @@ static bool pl2303_termios_change(const struct ktermios *a, const struct ktermio
return tty_termios_hw_change(a, b) || ixon_change;
}
+static bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_type_data *type)
+{
+ if (!I_IXON(tty) || I_IXANY(tty))
+ return false;
+
+ if (START_CHAR(tty) != 0x11 || STOP_CHAR(tty) != 0x13)
+ return false;
+
+ if (type->no_autoxonxoff)
+ return false;
+
+ return true;
+}
+
static void pl2303_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -678,14 +719,13 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (C_CRTSCTS(tty)) {
if (spriv->quirks & PL2303_QUIRK_LEGACY)
- pl2303_vendor_write(serial, 0x0, 0x41);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
else
- pl2303_vendor_write(serial, 0x0, 0x61);
- } else if (I_IXON(tty) && !I_IXANY(tty) && START_CHAR(tty) == 0x11 &&
- STOP_CHAR(tty) == 0x13) {
- pl2303_vendor_write(serial, 0x0, 0xc0);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
+ } else if (pl2303_enable_xonxoff(tty, spriv->type)) {
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
} else {
- pl2303_vendor_write(serial, 0x0, 0x0);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
}
kfree(buf);