> Date: Fri, 06 Feb 2026 13:11:00 +0100
> From: Mark Kettenis <[email protected]>
>
> > Date: Fri, 6 Feb 2026 12:57:36 +0100
> > From: Alexandr Nedvedicky <[email protected]>
> >
> > Hello,
> >
> > On Fri, Feb 06, 2026 at 12:20:20PM +0100, Mark Kettenis wrote:
> > </snip>
> > >
> > > What device are you using to connect to the serial port? OpenBSD does
> >
> > taking better look at drawing here [1] my device is actually
> > NanoPC-T6LTS
> > on the right hand side there is USB-C(Debug-UART) label. So this what
> > I'm using for console. I connect using USB A-to-C. According to dmesg
> > the device reports itself as:
> >
> > uchcom0 at uhub4 port 1 configuration 1 interface 0 "QinHeng Electronics
> > USB Serial" rev 1.10/2.64 addr 4
> > uchcom0: CH341
> > ucom0 at uchcom0: usb0.2.00001.0
> >
> > Trying to increasing the speed I'm seeing this error:
> >
> > lifty# cu -l usb0.2.00001.0 -s 1500000
> > cu: tcsetattr: Invalid argument
> >
> > I'm using USB A-to-C cable (~20cm long) plugged to USB-A port
> > directly in my T-14. Not sure if it is cable or driver. I will
> > try to dig more details later today. May be will try my luck
> > with USB C-to-C
>
> Definitely the driver. I'll have a look.
Can you try this diff?
Index: dev/usb/uchcom.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uchcom.c,v
diff -u -p -r1.40 uchcom.c
--- dev/usb/uchcom.c 18 Nov 2025 00:33:16 -0000 1.40
+++ dev/usb/uchcom.c 6 Feb 2026 13:30:29 -0000
@@ -83,10 +83,6 @@ int uchcomdebug = 0;
#define UCHCOM_VER_20 0x20
-#define UCHCOM_BASE_UNKNOWN 0
-#define UCHCOM_BPS_MOD_BASE 20000000
-#define UCHCOM_BPS_MOD_BASE_OFS 1100
-
#define UCHCOM_BPS_PRE_IMM 0x80 /* CH341: immediate RX forwarding */
#define UCHCOM_DTR_MASK 0x20
@@ -152,6 +148,21 @@ struct uchcom_endpoints {
int ep_intr_size;
};
+struct uchcom_divider
+{
+ uint8_t dv_prescaler;
+ uint8_t dv_div;
+};
+
+/* 0,1,2,3,7 are prescale factors for given 4x 12000000 clock formula */
+static const uint32_t rates4x[8] = {
+ [0] = 4 * 12000000 / 1024,
+ [1] = 4 * 12000000 / 128,
+ [2] = 4 * 12000000 / 16,
+ [3] = 4 * 12000000 / 2,
+ [7] = 4 * 12000000,
+};
+
void uchcom_get_status(void *, int, u_char *, u_char *);
void uchcom_set(void *, int, int, int);
int uchcom_param(void *, int, struct termios *);
@@ -634,52 +645,86 @@ uchcom_set_break_ch343(struct uchcom_sof
return 0;
}
-void
-uchcom_calc_baudrate(struct uchcom_softc *sc, uint32_t rate, uint8_t *divisor,
- uint8_t *factor)
+int
+uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)
{
- uint32_t clk = 12000000;
+/*
+ * combined with rates4x[] defined above, this routine generates,
+ * 1200: prescale = 1/0x1, divisor = 178/0xb2
+ * 2400: prescale = 1/0x1, divisor = 217/0xd9
+ * 4800: prescale = 2/0x2, divisor = 100/0x64
+ * 9600: prescale = 2/0x2, divisor = 178/0xb2
+ * 19200: prescale = 2/0x2, divisor = 217/0xd9
+ * 38400: prescale = 3/0x3, divisor = 100/0x64
+ * 57600: prescale = 2/0x2, divisor = 243/0xf3
+ * 115200: prescale = 3/0x3, divisor = 204/0xcc
+ * 921600: prescale = 7/0x7, divisor = 243/0xf3
+ * 500000: prescale = 3/0x3, divisor = 244/0xf4
+ * 1000000: prescale = 3/0x3, divisor = 250/0xfa
+ * 1500000: prescale = 3/0x3, divisor = 252/0xfc
+ * 2000000: prescale = 3/0x3, divisor = 253/0xfd
+ * 2500000: unsupported
+ * 3000000: prescale = 3/0x3, divisor = 254/0xfe
+ */
+ size_t i;
+ uint32_t best, div, pre;
+ const uint32_t rate4x = rate * 4U;
- if (rate == 921600 || rate == 4000000)
- *divisor = 7;
- else if (rate > 23529) {
- clk /= 2;
- *divisor = 3;
- } else if (rate > 2941) {
- clk /= 16;
- *divisor = 2;
- } else if (rate > 367) {
- clk /= 128;
- *divisor = 1;
- } else {
- clk = 11719;
- *divisor = 0;
+ if (rate == 0 || rate > 3000000)
+ return -1;
+
+ pre = nitems(rates4x);
+ best = UINT32_MAX;
+
+ for (i = 0; i < nitems(rates4x); i++) {
+ uint32_t score, try;
+ try = rates4x[i] * 2 / rate4x;
+ try = (try / 2) + (try & 1);
+ if (try < 2)
+ continue;
+ if (try > 255)
+ try = 255;
+ score = abs((int)rate4x - rates4x[i] / try);
+ if (score < best) {
+ best = score;
+ pre = i;
+ div = try;
+ }
}
- if (rate == 921600 && sc->sc_type != UCHCOM_TYPE_CH343)
- *factor = 243;
- else
- *factor = 256 - clk / rate;
+ if (pre >= nitems(rates4x))
+ return -1;
+ if ((rates4x[pre] / div / 4) < (rate * 99 / 100))
+ return -1;
+ if ((rates4x[pre] / div / 4) > (rate * 101 / 100))
+ return -1;
+
+ dp->dv_prescaler = pre;
+ dp->dv_div = 256 - div;
+
+ return 0;
}
int
uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate, uint16_t val)
{
usbd_status err;
+ struct uchcom_divider dv;
uint16_t idx;
- uint8_t factor, div;
- uchcom_calc_baudrate(sc, rate, &div, &factor);
+ if (uchcom_calc_divider_settings(&dv, rate))
+ return EINVAL;
if (sc->sc_type != UCHCOM_TYPE_CH343) {
- if ((err = uchcom_write_reg(sc,
- UCHCOM_REG_BPS_PRE, div | 0x80,
- UCHCOM_REG_BPS_DIV, factor)) ||
- (err = uchcom_write_reg(sc, UCHCOM_REG_LCR, val >> 8,
+ if ((err = uchcom_write_reg(sc, UCHCOM_REG_BPS_PRE,
+ dv.dv_prescaler | UCHCOM_BPS_PRE_IMM,
+ UCHCOM_REG_BPS_DIV, dv.dv_div)))
+ goto failed;
+ if ((err = uchcom_write_reg(sc, UCHCOM_REG_LCR, val >> 8,
UCHCOM_REG_LCR2, 0)))
goto failed;
} else {
- idx = (factor << 8) | div;
+ idx = (dv.dv_div << 8) | dv.dv_prescaler;
if ((err = uchcom_generic_control_out(sc,
UCHCOM_REQ_SET_BAUDRATE, val, idx)))
goto failed;