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 <[email protected]>
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html