Skip to content

Commit 7d26a78

Browse files
Frank Schäfergregkh
authored andcommitted
USB: pl2303: distinguish between original and cloned HX chips
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 61fa8d6 ("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. [1] http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&pcid=41 Signed-off-by: Frank Schäfer <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent dfe2902 commit 7d26a78

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed

drivers/usb/serial/pl2303.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ enum pl2303_type {
139139
HX_TA, /* HX(A) / X(A) / TA version */ /* TODO: improve */
140140
HXD_EA_RA_SA, /* HXD / EA / RA / SA version */ /* TODO: improve */
141141
TB, /* TB version */
142+
HX_CLONE, /* Cheap and less functional clone of the HX chip */
142143
};
143144
/*
144145
* NOTE: don't know the difference between type 0 and type 1,
@@ -206,8 +207,23 @@ static int pl2303_startup(struct usb_serial *serial)
206207
* the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
207208
*/
208209
if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
209-
type = HX_TA;
210-
type_str = "X/HX/TA";
210+
/* Check if the device is a clone */
211+
pl2303_vendor_read(0x9494, 0, serial, buf);
212+
/*
213+
* NOTE: Not sure if this read is really needed.
214+
* The HX returns 0x00, the clone 0x02, but the Windows
215+
* driver seems to ignore the value and continues.
216+
*/
217+
pl2303_vendor_write(0x0606, 0xaa, serial);
218+
pl2303_vendor_read(0x8686, 0, serial, buf);
219+
if (buf[0] != 0xaa) {
220+
type = HX_CLONE;
221+
type_str = "X/HX clone (limited functionality)";
222+
} else {
223+
type = HX_TA;
224+
type_str = "X/HX/TA";
225+
}
226+
pl2303_vendor_write(0x0606, 0x00, serial);
211227
} else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
212228
== 0x400) {
213229
type = HXD_EA_RA_SA;
@@ -305,8 +321,9 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
305321
{
306322
/*
307323
* NOTE: Only the values defined in baud_sup are supported !
308-
* => if unsupported values are set, the PL2303 seems to
309-
* use 9600 baud (at least my PL2303X always does)
324+
* => if unsupported values are set, the PL2303 uses 9600 baud instead
325+
* => HX clones just don't work at unsupported baud rates < 115200 baud,
326+
* for baud rates > 115200 they run at 115200 baud
310327
*/
311328
const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
312329
4800, 7200, 9600, 14400, 19200, 28800, 38400,
@@ -316,14 +333,14 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
316333
* NOTE: With the exception of type_0/1 devices, the following
317334
* additional baud rates are supported (tested with HX rev. 3A only):
318335
* 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
319-
* 403200, 806400. (*: not HX)
336+
* 403200, 806400. (*: not HX and HX clones)
320337
*
321338
* Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
322-
* type_0+1: 1228800; RA: 921600; SA: 115200
339+
* type_0+1: 1228800; RA: 921600; HX clones, SA: 115200
323340
*
324341
* As long as we are not using this encoding method for anything else
325-
* than the type_0+1 and HX chips, there is no point in complicating
326-
* the code to support them.
342+
* than the type_0+1, HX and HX clone chips, there is no point in
343+
* complicating the code to support them.
327344
*/
328345
int i;
329346

@@ -347,6 +364,8 @@ static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
347364
baud = min_t(int, baud, 6000000);
348365
else if (type == type_0 || type == type_1)
349366
baud = min_t(int, baud, 1228800);
367+
else if (type == HX_CLONE)
368+
baud = min_t(int, baud, 115200);
350369
/* Direct (standard) baud rate encoding method */
351370
put_unaligned_le32(baud, buf);
352371

@@ -359,7 +378,8 @@ static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
359378
/*
360379
* Divisor based baud rate encoding method
361380
*
362-
* NOTE: it's not clear if the type_0/1 chips support this method
381+
* NOTE: HX clones do NOT support this method.
382+
* It's not clear if the type_0/1 chips support it.
363383
*
364384
* divisor = 12MHz * 32 / baudrate = 2^A * B
365385
*
@@ -452,15 +472,15 @@ static void pl2303_encode_baudrate(struct tty_struct *tty,
452472
* 1) Direct method: encodes the baud rate value directly
453473
* => supported by all chip types
454474
* 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
455-
* => supported by HX chips (and likely not by type_0/1 chips)
475+
* => not supported by HX clones (and likely type_0/1 chips)
456476
*
457477
* NOTE: Although the divisor based baud rate encoding method is much
458478
* more flexible, some of the standard baud rate values can not be
459479
* realized exactly. But the difference is very small (max. 0.2%) and
460480
* the device likely uses the same baud rate generator for both methods
461481
* so that there is likley no difference.
462482
*/
463-
if (type == type_0 || type == type_1)
483+
if (type == type_0 || type == type_1 || type == HX_CLONE)
464484
baud = pl2303_baudrate_encode_direct(baud, type, buf);
465485
else
466486
baud = pl2303_baudrate_encode_divisor(baud, type, buf);
@@ -813,6 +833,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
813833
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
814834
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
815835
0, NULL, 0, 100);
836+
/* NOTE: HX clones don't support sending breaks, -EPIPE is returned */
816837
if (result)
817838
dev_err(&port->dev, "error sending break = %d\n", result);
818839
}

0 commit comments

Comments
 (0)