diff options
Diffstat (limited to 'drivers/usb/serial/pl2303.c')
-rw-r--r-- | drivers/usb/serial/pl2303.c | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index d93f5d584557..22579d0d8ab8 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -24,13 +24,14 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "pl2303.h" #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), @@ -118,6 +119,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, + { USB_DEVICE(MACROSILICON_VENDOR_ID, MACROSILICON_MS3020_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -456,6 +458,8 @@ static int pl2303_detect_type(struct usb_serial *serial) case 0x605: case 0x700: /* GR */ case 0x705: + case 0x905: /* GT-2AB */ + case 0x1005: /* GC-Q20 */ return TYPE_HXN; } break; @@ -466,6 +470,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; @@ -488,6 +511,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) { @@ -724,9 +750,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); @@ -1063,9 +1098,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 @@ -1234,7 +1273,6 @@ static void pl2303_process_read_urb(struct urb *urb) static struct usb_serial_driver pl2303_device = { .driver = { - .owner = THIS_MODULE, .name = "pl2303", }, .id_table = id_table, |