FreeBSD Bugzilla – Attachment 190665 Details for
Bug 225932
uplcom Prolific PL2302 doesn't support high baud rates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
proposed patch for high baudrate support
uplcom_high_baudrate.patch (text/plain), 9.58 KB, created by
Gabor Simon
on 2018-02-15 19:53:21 UTC
(
hide
)
Description:
proposed patch for high baudrate support
Filename:
MIME Type:
Creator:
Gabor Simon
Created:
2018-02-15 19:53:21 UTC
Size:
9.58 KB
patch
obsolete
>--- uplcom.c.orig 2018-02-14 16:49:34.153088000 +0400 >+++ uplcom.c 2018-02-15 23:23:07.835149000 +0400 >@@ -132,11 +132,19 @@ > #define UPLCOM_SET_CRTSCTS 0x41 > #define UPLCOM_SET_CRTSCTS_PL2303X 0x61 > #define RSAQ_STATUS_CTS 0x80 >+#define RSAQ_STATUS_OVERRUN_ERROR 0x40 >+#define RSAQ_STATUS_PARITY_ERROR 0x20 >+#define RSAQ_STATUS_FRAME_ERROR 0x10 >+#define RSAQ_STATUS_RING 0x08 >+#define RSAQ_STATUS_BREAK_ERROR 0x04 > #define RSAQ_STATUS_DSR 0x02 > #define RSAQ_STATUS_DCD 0x01 > > #define TYPE_PL2303 0 > #define TYPE_PL2303HX 1 >+#define TYPE_PL2303HXD 2 >+ >+#define UPLCOM_STATE_INDEX 8 > > enum { > UPLCOM_BULK_DT_WR, >@@ -367,18 +375,49 @@ > > sc->sc_udev = uaa->device; > >- /* Determine the chip type. This algorithm is taken from Linux. */ > dd = usbd_get_device_descriptor(sc->sc_udev); >- if (dd->bDeviceClass == 0x02) >- sc->sc_chiptype = TYPE_PL2303; >- else if (dd->bMaxPacketSize == 0x40) >+ >+ switch (dd->bcdDevice[0]) { >+ case 3: > sc->sc_chiptype = TYPE_PL2303HX; >- else >- sc->sc_chiptype = TYPE_PL2303; >+ /* or TA, that is HX with external crystal */ >+ break; >+ case 4: >+ sc->sc_chiptype = TYPE_PL2303HXD; >+ /* or EA, that is HXD with ESD protection */ >+ /* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */ >+ break; >+ case 5: >+ sc->sc_chiptype = TYPE_PL2303HXD; >+ /* in fact it's TB, that is HXD with external crystal */ >+ break; >+ default: >+ /* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud, >+ only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */ >+ /* Determine the chip type. This algorithm is taken from Linux. */ >+ if (dd->bDeviceClass == 0x02) >+ sc->sc_chiptype = TYPE_PL2303; >+ else if (dd->bMaxPacketSize == 0x40) >+ sc->sc_chiptype = TYPE_PL2303HX; >+ else >+ sc->sc_chiptype = TYPE_PL2303; >+ break; >+ } > >- DPRINTF("chiptype: %s\n", >- (sc->sc_chiptype == TYPE_PL2303HX) ? >- "2303X" : "2303"); >+ switch (sc->sc_chiptype) { >+ case TYPE_PL2303: >+ DPRINTF("chiptype: 2303\n"); >+ break; >+ case TYPE_PL2303HX: >+ DPRINTF("chiptype: 2303HX/TA\n"); >+ break; >+ case TYPE_PL2303HXD: >+ DPRINTF("chiptype: 2303HXD/TB/RA/EA\n"); >+ break; >+ default: >+ DPRINTF("chiptype: unknown %d\n", sc->sc_chiptype); >+ break; >+ } > > /* > * USB-RSAQ1 has two interface >@@ -427,13 +466,14 @@ > goto detach; > } > >- if (sc->sc_chiptype != TYPE_PL2303HX) { >+ if (sc->sc_chiptype == TYPE_PL2303) { > /* HX variants seem to lock up after a clear stall request. */ > mtx_lock(&sc->sc_mtx); > usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]); > usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]); > mtx_unlock(&sc->sc_mtx); > } else { >+ /* reset upstream data pipes */ > if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE, > UPLCOM_SET_REQUEST, 8, 0, 0) || > uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE, >@@ -552,7 +592,7 @@ > || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0)) > return (EIO); > >- if (chiptype == TYPE_PL2303HX) >+ if (chiptype != TYPE_PL2303) > err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0); > else > err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0); >@@ -632,23 +672,52 @@ > &req, NULL, 0, 1000); > } > >+/* >+ * NOTE: These baud rates are officially supported, they can be written >+ * directly into dwDTERate register. >+ * >+ * Free baudrate setting is not supported by the base PL2303, and on >+ * other models it requires writing a divisor value to dwDTERate instead >+ * of the raw baudrate. The formula for divisor calculation is not published >+ * by the vendor, so it is speculative, though the official product homepage >+ * refers to the Linux module source as a reference implementation. >+ */ > static const uint32_t uplcom_rates[] = { >- 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, >- 19200, 28800, 38400, 57600, 115200, > /* >- * Higher speeds are probably possible. PL2303X supports up to >- * 6Mb and can set any rate >+ * Basic 'standard' speed rates, supported by all models >+ * NOTE: 900 and 56000 actually works as well >+ */ >+ 75, 150, 300, 600, 900, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, >+ 19200, 28800, 38400, 56000, 57600, 115200, >+ /* >+ * Advanced speed rates up to 6Mbs, supported by HX/TA and HXD/TB/EA/RA >+ * NOTE: regardless of the spec, 256000 does not work >+ */ >+ 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400, >+ 806400, 921600, 1228800, 2457600, 3000000, 6000000, >+ /* >+ * Advanced speed rates up to 12, supported by HXD/TB/EA/RA > */ >- 230400, 460800, 614400, 921600, 1228800 >+ 12000000 > }; > > #define N_UPLCOM_RATES nitems(uplcom_rates) > > static int >+uplcom_baud_supported(unsigned int speed) >+{ >+ int i; >+ for (i = 0; i < N_UPLCOM_RATES; i++) { >+ if (uplcom_rates[i] == speed) >+ return 1; >+ } >+ return 0; >+} >+ >+static int > uplcom_pre_param(struct ucom_softc *ucom, struct termios *t) > { > struct uplcom_softc *sc = ucom->sc_parent; >- uint8_t i; > > DPRINTF("\n"); > >@@ -656,26 +725,75 @@ > * Check requested baud rate. > * > * The PL2303 can only set specific baud rates, up to 1228800 baud. >- * The PL2303X can set any baud rate up to 6Mb. >+ * The PL2303HX can set any baud rate up to 6Mb. > * The PL2303HX rev. D can set any baud rate up to 12Mb. > * >- * XXX: We currently cannot identify the PL2303HX rev. D, so treat >- * it the same as the PL2303X. > */ >- if (sc->sc_chiptype != TYPE_PL2303HX) { >- for (i = 0; i < N_UPLCOM_RATES; i++) { >- if (uplcom_rates[i] == t->c_ospeed) >+ >+ /* accept raw divisor data, if someone wants to do the math in user domain */ >+ if (t->c_ospeed & 0x80000000) >+ return 0; >+ switch (sc->sc_chiptype) { >+ case TYPE_PL2303HXD: >+ if (t->c_ospeed <= 12000000) > return (0); >- } >- } else { >- if (t->c_ospeed <= 6000000) >- return (0); >+ break; >+ case TYPE_PL2303HX: >+ if (t->c_ospeed <= 6000000) >+ return (0); >+ break; >+ default: >+ if (uplcom_baud_supported(t->c_ospeed)) >+ return (0); >+ break; > } > > DPRINTF("uplcom_param: bad baud rate (%d)\n", t->c_ospeed); > return (EIO); > } > >+static unsigned int >+uplcom_encode_baud_rate_divisor(uint8_t *buf, unsigned int baud) >+{ >+ unsigned int baseline, mantissa, exponent; >+ >+ /* Determine the baud rate divisor. This algorithm is taken from Linux. */ >+ /* >+ * Apparently the formula is: >+ * baudrate = baseline / (mantissa * 4^exponent) >+ * where >+ * mantissa = buf[8:0] >+ * exponent = buf[11:9] >+ */ >+ if (baud == 0) >+ baud = 1; >+ baseline = 383385600; >+ mantissa = baseline / baud; >+ if (mantissa == 0) >+ mantissa = 1; >+ exponent = 0; >+ while (mantissa >= 512) { >+ if (exponent < 7) { >+ mantissa >>= 2; /* divide by 4 */ >+ exponent++; >+ } else { >+ /* Exponent is maxed. Trim mantissa and leave. This gives approx. 45.8 baud */ >+ mantissa = 511; >+ break; >+ } >+ } >+ >+ buf[3] = 0x80; >+ buf[2] = 0; >+ buf[1] = exponent << 1 | mantissa >> 8; >+ buf[0] = mantissa & 0xff; >+ >+ /* Calculate and return the exact baud rate. */ >+ baud = (baseline / mantissa) >> (exponent << 1); >+ DPRINTF("real baud rate will be %u\n", baud); >+ >+ return baud; >+} > static void > uplcom_cfg_param(struct ucom_softc *ucom, struct termios *t) > { >@@ -687,10 +805,24 @@ > > memset(&ls, 0, sizeof(ls)); > >- USETDW(ls.dwDTERate, t->c_ospeed); >+ /* >+ * NOTE: If unsupported baud rates are set directly, the PL2303* uses 9600 baud. >+ */ >+ if ((t->c_ospeed & 0x80000000) || uplcom_baud_supported(t->c_ospeed)) >+ USETDW(ls.dwDTERate, t->c_ospeed); >+ else >+ t->c_ospeed = uplcom_encode_baud_rate_divisor((uint8_t*)&ls.dwDTERate, t->c_ospeed); > > if (t->c_cflag & CSTOPB) { >- ls.bCharFormat = UCDC_STOP_BIT_2; >+ if ((t->c_cflag & CSIZE) == CS5) { >+ /* >+ * NOTE: Comply with "real" UARTs / RS232: >+ * use 1.5 instead of 2 stop bits with 5 data bits >+ */ >+ ls.bCharFormat = UCDC_STOP_BIT_1_5; >+ } else { >+ ls.bCharFormat = UCDC_STOP_BIT_2; >+ } > } else { > ls.bCharFormat = UCDC_STOP_BIT_1; > } >@@ -720,7 +852,7 @@ > break; > } > >- DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n", >+ DPRINTF("rate=0x%08x fmt=%d parity=%d bits=%d\n", > UGETDW(ls.dwDTERate), ls.bCharFormat, > ls.bParityType, ls.bDataBits); > >@@ -741,7 +873,7 @@ > req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > req.bRequest = UPLCOM_SET_REQUEST; > USETW(req.wValue, 0); >- if (sc->sc_chiptype == TYPE_PL2303HX) >+ if (sc->sc_chiptype != TYPE_PL2303) > USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X); > else > USETW(req.wIndex, UPLCOM_SET_CRTSCTS); >@@ -807,7 +939,6 @@ > > DPRINTF("\n"); > >- /* XXX Note: sc_lsr is always zero */ > *lsr = sc->sc_lsr; > *msr = sc->sc_msr; > } >@@ -832,18 +963,33 @@ > pc = usbd_xfer_get_frame(xfer, 0); > usbd_copy_out(pc, 0, buf, sizeof(buf)); > >- DPRINTF("status = 0x%02x\n", buf[8]); >+ DPRINTF("status = 0x%02x\n", buf[UPLCOM_STATE_INDEX]); > > sc->sc_lsr = 0; > sc->sc_msr = 0; > >- if (buf[8] & RSAQ_STATUS_CTS) { >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_CTS) { > sc->sc_msr |= SER_CTS; > } >- if (buf[8] & RSAQ_STATUS_DSR) { >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_OVERRUN_ERROR) { >+ sc->sc_lsr |= ULSR_OE; >+ } >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_PARITY_ERROR) { >+ sc->sc_lsr |= ULSR_PE; >+ } >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_FRAME_ERROR) { >+ sc->sc_lsr |= ULSR_FE; >+ } >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_RING) { >+ sc->sc_msr |= SER_RI; >+ } >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_BREAK_ERROR) { >+ sc->sc_lsr |= ULSR_BI; >+ } >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DSR) { > sc->sc_msr |= SER_DSR; > } >- if (buf[8] & RSAQ_STATUS_DCD) { >+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DCD) { > sc->sc_msr |= SER_DCD; > } > ucom_status_change(&sc->sc_ucom);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 225932
: 190665 |
190666
|
190667