diff options
Diffstat (limited to 'drivers/usb/serial/pl2303.c')
-rw-r--r-- | drivers/usb/serial/pl2303.c | 352 |
1 files changed, 248 insertions, 104 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index cb6bbed374f2..e7a84f0f5179 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -4,6 +4,11 @@ * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2003 IBM Corp. * + * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com> + * - fixes, improvements and documentation for the baud rate encoding methods + * Copyright (C) 2013 Reinhard Max <max@suse.de> + * - fixes and improvements for the divisor based baud rate encoding method + * * Original driver for 2.2.x by anonymous * * This program is free software; you can redistribute it and/or @@ -29,6 +34,7 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <asm/unaligned.h> #include "pl2303.h" /* @@ -128,10 +134,17 @@ MODULE_DEVICE_TABLE(usb, id_table); enum pl2303_type { - type_0, /* don't know the difference between type 0 and */ - type_1, /* type 1, until someone from prolific tells us... */ - HX, /* HX version of the pl2303 chip */ + type_0, /* H version ? */ + type_1, /* H version ? */ + HX_TA, /* HX(A) / X(A) / TA version */ /* TODO: improve */ + HXD_EA_RA_SA, /* HXD / EA / RA / SA version */ /* TODO: improve */ + TB, /* TB version */ }; +/* + * NOTE: don't know the difference between type 0 and type 1, + * until someone from Prolific tells us... + * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants + */ struct pl2303_serial_private { enum pl2303_type type; @@ -171,6 +184,7 @@ static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; enum pl2303_type type = type_0; + char *type_str = "unknown (treating as type_0)"; unsigned char *buf; spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); @@ -183,15 +197,38 @@ static int pl2303_startup(struct usb_serial *serial) return -ENOMEM; } - if (serial->dev->descriptor.bDeviceClass == 0x02) + if (serial->dev->descriptor.bDeviceClass == 0x02) { type = type_0; - else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) - type = HX; - else if (serial->dev->descriptor.bDeviceClass == 0x00) - type = type_1; - else if (serial->dev->descriptor.bDeviceClass == 0xFF) + type_str = "type_0"; + } else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) { + /* + * NOTE: The bcdDevice version is the only difference between + * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB + */ + if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) { + type = HX_TA; + type_str = "X/HX/TA"; + } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) + == 0x400) { + type = HXD_EA_RA_SA; + type_str = "HXD/EA/RA/SA"; + } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) + == 0x500) { + type = TB; + type_str = "TB"; + } else { + dev_info(&serial->interface->dev, + "unknown/unsupported device type\n"); + kfree(spriv); + kfree(buf); + return -ENODEV; + } + } else if (serial->dev->descriptor.bDeviceClass == 0x00 + || serial->dev->descriptor.bDeviceClass == 0xFF) { type = type_1; - dev_dbg(&serial->interface->dev, "device type: %d\n", type); + type_str = "type_1"; + } + dev_dbg(&serial->interface->dev, "device type: %s\n", type_str); spriv->type = type; usb_set_serial_data(serial, spriv); @@ -206,10 +243,10 @@ static int pl2303_startup(struct usb_serial *serial) pl2303_vendor_read(0x8383, 0, serial, buf); pl2303_vendor_write(0, 1, serial); pl2303_vendor_write(1, 0, serial); - if (type == HX) - pl2303_vendor_write(2, 0x44, serial); - else + if (type == type_0 || type == type_1) pl2303_vendor_write(2, 0x24, serial); + else + pl2303_vendor_write(2, 0x44, serial); kfree(buf); return 0; @@ -235,6 +272,8 @@ static int pl2303_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } @@ -261,6 +300,175 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) return retval; } +static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, + u8 buf[4]) +{ + /* + * NOTE: Only the values defined in baud_sup are supported ! + * => if unsupported values are set, the PL2303 seems to + * use 9600 baud (at least my PL2303X always does) + */ + const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, + 57600, 115200, 230400, 460800, 614400, 921600, + 1228800, 2457600, 3000000, 6000000, 12000000 }; + /* + * NOTE: With the exception of type_0/1 devices, the following + * additional baud rates are supported (tested with HX rev. 3A only): + * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800, + * 403200, 806400. (*: not HX) + * + * Maximum values: HXD, TB: 12000000; HX, TA: 6000000; + * type_0+1: 1228800; RA: 921600; SA: 115200 + * + * As long as we are not using this encoding method for anything else + * than the type_0+1 and HX chips, there is no point in complicating + * the code to support them. + */ + int i; + + /* Set baudrate to nearest supported value */ + for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { + if (baud_sup[i] > baud) + break; + } + if (i == ARRAY_SIZE(baud_sup)) + baud = baud_sup[i - 1]; + else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) + baud = baud_sup[i - 1]; + else + baud = baud_sup[i]; + /* Respect the chip type specific baud rate limits */ + /* + * FIXME: as long as we don't know how to distinguish between the + * HXD, EA, RA, and SA chip variants, allow the max. value of 12M. + */ + if (type == HX_TA) + baud = min_t(int, baud, 6000000); + else if (type == type_0 || type == type_1) + baud = min_t(int, baud, 1228800); + /* Direct (standard) baud rate encoding method */ + put_unaligned_le32(baud, buf); + + return baud; +} + +static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type, + u8 buf[4]) +{ + /* + * Divisor based baud rate encoding method + * + * NOTE: it's not clear if the type_0/1 chips support this method + * + * divisor = 12MHz * 32 / baudrate = 2^A * B + * + * with + * + * A = buf[1] & 0x0e + * B = buf[0] + (buf[1] & 0x01) << 8 + * + * Special cases: + * => 8 < B < 16: device seems to work not properly + * => B <= 8: device uses the max. value B = 512 instead + */ + unsigned int A, B; + + /* + * NOTE: The Windows driver allows maximum baud rates of 110% of the + * specified maximium value. + * Quick tests with early (2004) HX (rev. A) chips suggest, that even + * higher baud rates (up to the maximum of 24M baud !) are working fine, + * but that should really be tested carefully in "real life" scenarios + * before removing the upper limit completely. + * Baud rates smaller than the specified 75 baud are definitely working + * fine. + */ + if (type == type_0 || type == type_1) + baud = min_t(int, baud, 1228800 * 1.1); + else if (type == HX_TA) + baud = min_t(int, baud, 6000000 * 1.1); + else if (type == HXD_EA_RA_SA) + /* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */ + /* + * FIXME: as long as we don't know how to distinguish between + * these chip variants, allow the max. of these values + */ + baud = min_t(int, baud, 12000000 * 1.1); + else if (type == TB) + baud = min_t(int, baud, 12000000 * 1.1); + /* Determine factors A and B */ + A = 0; + B = 12000000 * 32 / baud; /* 12MHz */ + B <<= 1; /* Add one bit for rounding */ + while (B > (512 << 1) && A <= 14) { + A += 2; + B >>= 2; + } + if (A > 14) { /* max. divisor = min. baudrate reached */ + A = 14; + B = 512; + /* => ~45.78 baud */ + } else { + B = (B + 1) >> 1; /* Round the last bit */ + } + /* Handle special cases */ + if (B == 512) + B = 0; /* also: 1 to 8 */ + else if (B < 16) + /* + * NOTE: With the current algorithm this happens + * only for A=0 and means that the min. divisor + * (respectively: the max. baudrate) is reached. + */ + B = 16; /* => 24 MBaud */ + /* Encode the baud rate */ + buf[3] = 0x80; /* Select divisor encoding method */ + buf[2] = 0; + buf[1] = (A & 0x0e); /* A */ + buf[1] |= ((B & 0x100) >> 8); /* MSB of B */ + buf[0] = B & 0xff; /* 8 LSBs of B */ + /* Calculate the actual/resulting baud rate */ + if (B <= 8) + B = 512; + baud = 12000000 * 32 / ((1 << A) * B); + + return baud; +} + +static void pl2303_encode_baudrate(struct tty_struct *tty, + struct usb_serial_port *port, + enum pl2303_type type, + u8 buf[4]) +{ + int baud; + + baud = tty_get_baud_rate(tty); + dev_dbg(&port->dev, "baud requested = %d\n", baud); + if (!baud) + return; + /* + * There are two methods for setting/encoding the baud rate + * 1) Direct method: encodes the baud rate value directly + * => supported by all chip types + * 2) Divisor based method: encodes a divisor to a base value (12MHz*32) + * => supported by HX chips (and likely not by type_0/1 chips) + * + * NOTE: Although the divisor based baud rate encoding method is much + * more flexible, some of the standard baud rate values can not be + * realized exactly. But the difference is very small (max. 0.2%) and + * the device likely uses the same baud rate generator for both methods + * so that there is likley no difference. + */ + if (type == type_0 || type == type_1) + baud = pl2303_baudrate_encode_direct(baud, type, buf); + else + baud = pl2303_baudrate_encode_divisor(baud, type, buf); + /* Save resulting baud rate */ + tty_encode_baud_rate(tty, baud, baud); + dev_dbg(&port->dev, "baud set = %d\n", baud); +} + static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -268,27 +476,18 @@ static void pl2303_set_termios(struct tty_struct *tty, struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag; unsigned char *buf; - int baud; int i; u8 control; - const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, - 57600, 115200, 230400, 460800, 500000, 614400, - 921600, 1228800, 2457600, 3000000, 6000000 }; - int baud_floor, baud_ceil; - int k; - - /* The PL2303 is reported to lose bytes if you change - serial settings even to the same values as before. Thus - we actually need to filter in this specific case */ + /* + * The PL2303 is reported to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + */ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; - cflag = tty->termios.c_cflag; - buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); @@ -303,8 +502,8 @@ static void pl2303_set_termios(struct tty_struct *tty, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); - if (cflag & CSIZE) { - switch (cflag & CSIZE) { + if (C_CSIZE(tty)) { + switch (C_CSIZE(tty)) { case CS5: buf[6] = 5; break; @@ -317,73 +516,22 @@ static void pl2303_set_termios(struct tty_struct *tty, default: case CS8: buf[6] = 8; - break; } dev_dbg(&port->dev, "data bits = %d\n", buf[6]); } - /* For reference buf[0]:buf[3] baud rate value */ - /* NOTE: Only the values defined in baud_sup are supported ! - * => if unsupported values are set, the PL2303 seems to use - * 9600 baud (at least my PL2303X always does) - */ - baud = tty_get_baud_rate(tty); - dev_dbg(&port->dev, "baud requested = %d\n", baud); - if (baud) { - /* Set baudrate to nearest supported value */ - for (k=0; k<ARRAY_SIZE(baud_sup); k++) { - if (baud_sup[k] / baud) { - baud_ceil = baud_sup[k]; - if (k==0) { - baud = baud_ceil; - } else { - baud_floor = baud_sup[k-1]; - if ((baud_ceil % baud) - > (baud % baud_floor)) - baud = baud_floor; - else - baud = baud_ceil; - } - break; - } - } - if (baud > 1228800) { - /* type_0, type_1 only support up to 1228800 baud */ - if (spriv->type != HX) - baud = 1228800; - else if (baud > 6000000) - baud = 6000000; - } - dev_dbg(&port->dev, "baud set = %d\n", baud); - if (baud <= 115200) { - buf[0] = baud & 0xff; - buf[1] = (baud >> 8) & 0xff; - buf[2] = (baud >> 16) & 0xff; - buf[3] = (baud >> 24) & 0xff; - } else { - /* apparently the formula for higher speeds is: - * baudrate = 12M * 32 / (2^buf[1]) / buf[0] - */ - unsigned tmp = 12*1000*1000*32 / baud; - buf[3] = 0x80; - buf[2] = 0; - buf[1] = (tmp >= 256); - while (tmp >= 256) { - tmp >>= 2; - buf[1] <<= 1; - } - buf[0] = tmp; - } - } + /* For reference: buf[0]:buf[3] baud rate value */ + pl2303_encode_baudrate(tty, port, spriv->type, buf); /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - if (cflag & CSTOPB) { - /* NOTE: Comply with "real" UARTs / RS232: + if (C_CSTOPB(tty)) { + /* + * NOTE: Comply with "real" UARTs / RS232: * use 1.5 instead of 2 stop bits with 5 data bits */ - if ((cflag & CSIZE) == CS5) { + if (C_CSIZE(tty) == CS5) { buf[4] = 1; dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { @@ -395,14 +543,14 @@ static void pl2303_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "stop bits = 1\n"); } - if (cflag & PARENB) { + if (C_PARENB(tty)) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ - if (cflag & PARODD) { - if (cflag & CMSPAR) { + if (C_PARODD(tty)) { + if (tty->termios.c_cflag & CMSPAR) { buf[5] = 3; dev_dbg(&port->dev, "parity = mark\n"); } else { @@ -410,7 +558,7 @@ static void pl2303_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "parity = odd\n"); } } else { - if (cflag & CMSPAR) { + if (tty->termios.c_cflag & CMSPAR) { buf[5] = 4; dev_dbg(&port->dev, "parity = space\n"); } else { @@ -431,7 +579,7 @@ static void pl2303_set_termios(struct tty_struct *tty, /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; - if ((cflag & CBAUD) == B0) + if (C_BAUD(tty) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); @@ -443,26 +591,21 @@ static void pl2303_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&priv->lock, flags); } - buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - + memset(buf, 0, 7); i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); - if (cflag & CRTSCTS) { - if (spriv->type == HX) - pl2303_vendor_write(0x0, 0x61, serial); - else + if (C_CRTSCTS(tty)) { + if (spriv->type == type_0 || spriv->type == type_1) pl2303_vendor_write(0x0, 0x41, serial); + else + pl2303_vendor_write(0x0, 0x61, serial); } else { pl2303_vendor_write(0x0, 0x0, serial); } - /* Save resulting baud rate */ - if (baud) - tty_encode_baud_rate(tty, baud, baud); - kfree(buf); } @@ -495,7 +638,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) struct pl2303_serial_private *spriv = usb_get_serial_data(serial); int result; - if (spriv->type != HX) { + if (spriv->type == type_0 || spriv->type == type_1) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); } else { @@ -521,7 +664,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } - port->port.drain_delay = 256; return 0; } @@ -789,8 +931,10 @@ static void pl2303_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); + if (tty_flag != TTY_NORMAL) + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, + tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); |