Am 14.09.2013 12:13, schrieb Frank Schäfer: > According to Prolific, several (unauthorized) cheap and less functional > clones of the PL2303HX chip are in circulation. [1] > I've had the chance to test such a cloned device and it turned out that > it doesn't support any baud rates above 115200 baud (original: 6 Mbaud) > It also doesn't support the divisior based baud rate encoding method, > so no continuous baud rate adjustment is possible. > Nevertheless, these devices have been working (unintentionally) with > the driver up to commit 61fa8d694b ("pl2303: also use the divisor based > baud rate encoding method for baud rates < 115200 with HX chips"), and > this commit broke support for them. > Fortunately, it is pretty simple to distinguish between the original > and the cloned HX chips, so I've added a check and an extra chip type > to keep the clones working. > The same check is used by the latest Prolific Windows driver, so it > should be solid. > > Signed-off-by: Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx> Changes since v1: - always restore address 0x0606/0x8686 after the clone test - update another code comment Greg, IMHO this patch must be regarded as a regression fix for 3.12. Wether we should try to support cloned chips or not is of course discussable. Regards, Frank > --- > drivers/usb/serial/pl2303.c | 43 ++++++++++++++++++++++++++++++++----------- > 1 Datei geändert, 32 Zeilen hinzugefügt(+), 11 Zeilen entfernt(-) > > diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c > index e7a84f0..bedf8e4 100644 > --- a/drivers/usb/serial/pl2303.c > +++ b/drivers/usb/serial/pl2303.c > @@ -139,6 +139,7 @@ enum pl2303_type { > HX_TA, /* HX(A) / X(A) / TA version */ /* TODO: improve */ > HXD_EA_RA_SA, /* HXD / EA / RA / SA version */ /* TODO: improve */ > TB, /* TB version */ > + HX_CLONE, /* Cheap and less functional clone of the HX chip */ > }; > /* > * NOTE: don't know the difference between type 0 and type 1, > @@ -206,8 +207,23 @@ static int pl2303_startup(struct usb_serial *serial) > * 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"; > + /* Check if the device is a clone */ > + pl2303_vendor_read(0x9494, 0, serial, buf); > + /* > + * NOTE: Not sure if this read is really needed. > + * The HX returns 0x00, the clone 0x02, but the Windows > + * driver seems to ignore the value and continues. > + */ > + pl2303_vendor_write(0x0606, 0xaa, serial); > + pl2303_vendor_read(0x8686, 0, serial, buf); > + if (buf[0] != 0xaa) { > + type = HX_CLONE; > + type_str = "X/HX clone (limited functionality)"; > + } else { > + type = HX_TA; > + type_str = "X/HX/TA"; > + } > + pl2303_vendor_write(0x0606, 0x00, serial); > } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) > == 0x400) { > type = HXD_EA_RA_SA; > @@ -305,8 +321,9 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, > { > /* > * 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) > + * => if unsupported values are set, the PL2303 uses 9600 baud instead > + * => HX clones just don't work at unsupported baud rates < 115200 baud, > + * for baud rates > 115200 they run at 115200 baud > */ > const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, > 4800, 7200, 9600, 14400, 19200, 28800, 38400, > @@ -316,14 +333,14 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, > * 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) > + * 403200, 806400. (*: not HX and HX clones) > * > * Maximum values: HXD, TB: 12000000; HX, TA: 6000000; > - * type_0+1: 1228800; RA: 921600; SA: 115200 > + * type_0+1: 1228800; RA: 921600; HX clones, 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. > + * than the type_0+1, HX and HX clone chips, there is no point in > + * complicating the code to support them. > */ > int i; > > @@ -347,6 +364,8 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, > baud = min_t(int, baud, 6000000); > else if (type == type_0 || type == type_1) > baud = min_t(int, baud, 1228800); > + else if (type == HX_CLONE) > + baud = min_t(int, baud, 115200); > /* Direct (standard) baud rate encoding method */ > put_unaligned_le32(baud, buf); > > @@ -359,7 +378,8 @@ static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type, > /* > * Divisor based baud rate encoding method > * > - * NOTE: it's not clear if the type_0/1 chips support this method > + * NOTE: HX clones do NOT support this method. > + * It's not clear if the type_0/1 chips support it. > * > * divisor = 12MHz * 32 / baudrate = 2^A * B > * > @@ -452,7 +472,7 @@ static void pl2303_encode_baudrate(struct tty_struct *tty, > * 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) > + * => not supported by HX clones (and likely 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 > @@ -460,7 +480,7 @@ static void pl2303_encode_baudrate(struct tty_struct *tty, > * 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) > + if (type == type_0 || type == type_1 || type == HX_CLONE) > baud = pl2303_baudrate_encode_direct(baud, type, buf); > else > baud = pl2303_baudrate_encode_divisor(baud, type, buf); > @@ -813,6 +833,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) > result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), > BREAK_REQUEST, BREAK_REQUEST_TYPE, state, > 0, NULL, 0, 100); > + /* NOTE: HX clones don't support sending breaks, -EPIPE is returned */ > if (result) > dev_err(&port->dev, "error sending break = %d\n", result); > } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html