1
0
mirror of https://github.com/mik3y/usb-serial-for-android synced 2025-06-07 16:06:10 +00:00

support PL2303GC/GB/GT/GL/GE/GS

see https://lore.kernel.org/linux-usb/20190213123000.4656-1-charlesyeh522@gmail.com/
This commit is contained in:
kai-morich 2021-05-13 16:16:42 +02:00
parent 2f23bdfb6d
commit c82cd284ae
5 changed files with 101 additions and 28 deletions

View File

@ -12,8 +12,14 @@
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 --> <usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 --> <usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
<!-- 0x067B / 0x2303: Prolific PL2303 --> <!-- 0x067B / 0x23?3: Prolific PL2303x -->
<usb-device vendor-id="1659" product-id="8963" /> <usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->
<!-- 0x1a86 / 0x?523: Qinheng CH34x --> <!-- 0x1a86 / 0x?523: Qinheng CH34x -->
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A --> <usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->

View File

@ -323,6 +323,7 @@ public class DeviceTest {
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/ 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/
}; };
usb.open(); usb.open();
Assume.assumeFalse("only for non PL2303G*", ProlificWrapper.isDeviceTypeHxn(usb.serialPort)); // HXN does not use divisor
int minBaudRate = ProlificWrapper.isDeviceTypeT(usb.serialPort) ? 6 : 46; int minBaudRate = ProlificWrapper.isDeviceTypeT(usb.serialPort) ? 6 : 46;
try { try {
@ -1675,7 +1676,7 @@ public class DeviceTest {
@Test @Test
/* test not done by RFC2217 server. Instead output control lines are connected to /* test not done by RFC2217 server. Instead output control lines are connected to
input control lines with a binary decoder 74LS138, 74LS139, 74HC... or ... input control lines with a binary decoder 74LS42, 74LS138, 74LS139, 74HC... or ...
in in
A0 = RTS A0 = RTS
A1 = DTR A1 = DTR

View File

@ -5,4 +5,9 @@ public class ProlificWrapper {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort; ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_T; return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_T;
} }
public static boolean isDeviceTypeHxn(UsbSerialPort serialPort) {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_HXN;
}
} }

View File

@ -35,7 +35,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800, 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000
}; };
protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX} protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX, DEVICE_TYPE_HXN}
private final UsbDevice mDevice; private final UsbDevice mDevice;
private final UsbSerialPort mPort; private final UsbSerialPort mPort;
@ -62,34 +62,50 @@ public class ProlificSerialDriver implements UsbSerialDriver {
private static final int USB_RECIP_INTERFACE = 0x01; private static final int USB_RECIP_INTERFACE = 0x01;
private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01; private static final int VENDOR_READ_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01; private static final int VENDOR_WRITE_REQUEST = 0x01;
private static final int VENDOR_READ_HXN_REQUEST = 0x81;
private static final int VENDOR_WRITE_HXN_REQUEST = 0x80;
private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR; private static final int VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR; private static final int VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; private static final int CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int WRITE_ENDPOINT = 0x02; private static final int WRITE_ENDPOINT = 0x02;
private static final int READ_ENDPOINT = 0x83; private static final int READ_ENDPOINT = 0x83;
private static final int INTERRUPT_ENDPOINT = 0x81; private static final int INTERRUPT_ENDPOINT = 0x81;
private static final int FLUSH_RX_REQUEST = 0x08; // RX @ Prolific device = write @ usb-serial-for-android library private static final int RESET_HXN_REQUEST = 0x07;
private static final int FLUSH_RX_REQUEST = 0x08;
private static final int FLUSH_TX_REQUEST = 0x09; private static final int FLUSH_TX_REQUEST = 0x09;
private static final int SET_LINE_REQUEST = 0x20; // same as CDC SET_LINE_CODING private static final int SET_LINE_REQUEST = 0x20; // same as CDC SET_LINE_CODING
private static final int SET_CONTROL_REQUEST = 0x22; // same as CDC SET_CONTROL_LINE_STATE private static final int SET_CONTROL_REQUEST = 0x22; // same as CDC SET_CONTROL_LINE_STATE
private static final int SEND_BREAK_REQUEST = 0x23; // same as CDC SEND_BREAK private static final int SEND_BREAK_REQUEST = 0x23; // same as CDC SEND_BREAK
private static final int GET_CONTROL_HXN_REQUEST = 0x80;
private static final int GET_CONTROL_REQUEST = 0x87; private static final int GET_CONTROL_REQUEST = 0x87;
private static final int STATUS_NOTIFICATION = 0xa1; // similar to CDC SERIAL_STATE but different length private static final int STATUS_NOTIFICATION = 0xa1; // similar to CDC SERIAL_STATE but different length
/* RESET_HXN_REQUEST */
private static final int RESET_HXN_RX_PIPE = 1;
private static final int RESET_HXN_TX_PIPE = 2;
/* SET_CONTROL_REQUEST */
private static final int CONTROL_DTR = 0x01; private static final int CONTROL_DTR = 0x01;
private static final int CONTROL_RTS = 0x02; private static final int CONTROL_RTS = 0x02;
/* GET_CONTROL_REQUEST */
private static final int GET_CONTROL_FLAG_CD = 0x02; private static final int GET_CONTROL_FLAG_CD = 0x02;
private static final int GET_CONTROL_FLAG_DSR = 0x04; private static final int GET_CONTROL_FLAG_DSR = 0x04;
private static final int GET_CONTROL_FLAG_RI = 0x01; private static final int GET_CONTROL_FLAG_RI = 0x01;
private static final int GET_CONTROL_FLAG_CTS = 0x08; private static final int GET_CONTROL_FLAG_CTS = 0x08;
/* GET_CONTROL_HXN_REQUEST */
private static final int GET_CONTROL_HXN_FLAG_CD = 0x40;
private static final int GET_CONTROL_HXN_FLAG_DSR = 0x20;
private static final int GET_CONTROL_HXN_FLAG_RI = 0x80;
private static final int GET_CONTROL_HXN_FLAG_CTS = 0x08;
/* interrupt endpoint read */
private static final int STATUS_FLAG_CD = 0x01; private static final int STATUS_FLAG_CD = 0x01;
private static final int STATUS_FLAG_DSR = 0x02; private static final int STATUS_FLAG_DSR = 0x02;
private static final int STATUS_FLAG_RI = 0x08; private static final int STATUS_FLAG_RI = 0x08;
@ -137,11 +153,13 @@ public class ProlificSerialDriver implements UsbSerialDriver {
} }
private byte[] vendorIn(int value, int index, int length) throws IOException { private byte[] vendorIn(int value, int index, int length) throws IOException {
return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE, PROLIFIC_VENDOR_READ_REQUEST, value, index, length); int request = (mDeviceType == DeviceType.DEVICE_TYPE_HXN) ? VENDOR_READ_HXN_REQUEST : VENDOR_READ_REQUEST;
return inControlTransfer(VENDOR_IN_REQTYPE, request, value, index, length);
} }
private void vendorOut(int value, int index, byte[] data) throws IOException { private void vendorOut(int value, int index, byte[] data) throws IOException {
outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE, PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data); int request = (mDeviceType == DeviceType.DEVICE_TYPE_HXN) ? VENDOR_WRITE_HXN_REQUEST : VENDOR_WRITE_REQUEST;
outControlTransfer(VENDOR_OUT_REQTYPE, request, value, index, data);
} }
private void resetDevice() throws IOException { private void resetDevice() throws IOException {
@ -149,10 +167,21 @@ public class ProlificSerialDriver implements UsbSerialDriver {
} }
private void ctrlOut(int request, int value, int index, byte[] data) throws IOException { private void ctrlOut(int request, int value, int index, byte[] data) throws IOException {
outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index, data); outControlTransfer(CTRL_OUT_REQTYPE, request, value, index, data);
}
private boolean testHxStatus() {
try {
inControlTransfer(VENDOR_IN_REQTYPE, VENDOR_READ_REQUEST, 0x8080, 0, 1);
return true;
} catch(IOException ignored) {
return false;
}
} }
private void doBlackMagic() throws IOException { private void doBlackMagic() throws IOException {
if (mDeviceType == DeviceType.DEVICE_TYPE_HXN)
return;
vendorIn(0x8484, 0, 1); vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 0, null); vendorOut(0x0404, 0, null);
vendorIn(0x8484, 0, 1); vendorIn(0x8484, 0, 1);
@ -199,12 +228,20 @@ public class ProlificSerialDriver implements UsbSerialDriver {
if ((mReadStatusThread == null) && (mReadStatusException == null)) { if ((mReadStatusThread == null) && (mReadStatusException == null)) {
synchronized (mReadStatusThreadLock) { synchronized (mReadStatusThreadLock) {
if (mReadStatusThread == null) { if (mReadStatusThread == null) {
byte[] data = vendorIn(GET_CONTROL_REQUEST, 0, 1);
mStatus = 0; mStatus = 0;
if((data[0] & GET_CONTROL_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS; if(mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
if((data[0] & GET_CONTROL_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR; byte[] data = vendorIn(GET_CONTROL_HXN_REQUEST, 0, 1);
if((data[0] & GET_CONTROL_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD; if ((data[0] & GET_CONTROL_HXN_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS;
if((data[0] & GET_CONTROL_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI; if ((data[0] & GET_CONTROL_HXN_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR;
if ((data[0] & GET_CONTROL_HXN_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD;
if ((data[0] & GET_CONTROL_HXN_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI;
} else {
byte[] data = vendorIn(GET_CONTROL_REQUEST, 0, 1);
if ((data[0] & GET_CONTROL_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS;
if ((data[0] & GET_CONTROL_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR;
if ((data[0] & GET_CONTROL_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD;
if ((data[0] & GET_CONTROL_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI;
}
//Log.d(TAG, "start control line status thread " + mStatus); //Log.d(TAG, "start control line status thread " + mStatus);
mReadStatusThread = new Thread(this::readStatusThreadFunction); mReadStatusThread = new Thread(this::readStatusThreadFunction);
mReadStatusThread.setDaemon(true); mReadStatusThread.setDaemon(true);
@ -266,12 +303,14 @@ public class ProlificSerialDriver implements UsbSerialDriver {
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
} else if(deviceVersion == 0x500) { } else if(deviceVersion == 0x500) {
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
} else if(usbVersion == 0x200 && !testHxStatus()) {
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
} else { } else {
mDeviceType = DeviceType.DEVICE_TYPE_HX; mDeviceType = DeviceType.DEVICE_TYPE_HX;
} }
setControlLines(mControlLinesValue);
resetDevice(); resetDevice();
doBlackMagic(); doBlackMagic();
setControlLines(mControlLinesValue);
} }
@Override @Override
@ -304,6 +343,9 @@ public class ProlificSerialDriver implements UsbSerialDriver {
if (baudRate <= 0) { if (baudRate <= 0) {
throw new IllegalArgumentException("Invalid baud rate: " + baudRate); throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
} }
if (mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
return baudRate;
}
for(int br : standardBaudRates) { for(int br : standardBaudRates) {
if (br == baudRate) { if (br == baudRate) {
return baudRate; return baudRate;
@ -501,11 +543,16 @@ public class ProlificSerialDriver implements UsbSerialDriver {
@Override @Override
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
if (purgeWriteBuffers) { if (mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
int index = 0;
if(purgeWriteBuffers) index |= RESET_HXN_RX_PIPE;
if(purgeReadBuffers) index |= RESET_HXN_TX_PIPE;
if(index != 0)
vendorOut(RESET_HXN_REQUEST, index, null);
} else {
if (purgeWriteBuffers)
vendorOut(FLUSH_RX_REQUEST, 0, null); vendorOut(FLUSH_RX_REQUEST, 0, null);
} if (purgeReadBuffers)
if (purgeReadBuffers) {
vendorOut(FLUSH_TX_REQUEST, 0, null); vendorOut(FLUSH_TX_REQUEST, 0, null);
} }
} }
@ -519,7 +566,15 @@ public class ProlificSerialDriver implements UsbSerialDriver {
public static Map<Integer, int[]> getSupportedDevices() { public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>(); final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
supportedDevices.put(UsbId.VENDOR_PROLIFIC, supportedDevices.put(UsbId.VENDOR_PROLIFIC,
new int[] { UsbId.PROLIFIC_PL2303, }); new int[] {
UsbId.PROLIFIC_PL2303,
UsbId.PROLIFIC_PL2303GC,
UsbId.PROLIFIC_PL2303GB,
UsbId.PROLIFIC_PL2303GT,
UsbId.PROLIFIC_PL2303GL,
UsbId.PROLIFIC_PL2303GE,
UsbId.PROLIFIC_PL2303GS,
});
return supportedDevices; return supportedDevices;
} }
} }

View File

@ -50,7 +50,13 @@ public final class UsbId {
public static final int SILABS_CP2108 = 0xea71; public static final int SILABS_CP2108 = 0xea71;
public static final int VENDOR_PROLIFIC = 0x067b; public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303; public static final int PROLIFIC_PL2303 = 0x2303; // device type 01, T, HX
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
public static final int PROLIFIC_PL2303GT = 0x23cd; // "
public static final int PROLIFIC_PL2303GL = 0x23e3; // "
public static final int PROLIFIC_PL2303GE = 0x23e3; // "
public static final int PROLIFIC_PL2303GS = 0x23f3; // "
public static final int VENDOR_QINHENG = 0x1a86; public static final int VENDOR_QINHENG = 0x1a86;
public static final int QINHENG_CH340 = 0x7523; public static final int QINHENG_CH340 = 0x7523;