> Date: Fri, 6 Feb 2026 23:10:38 +0100
> From: Alexandr Nedvedicky <[email protected]>
Hi Sasha,
Sorry, this dropped off my list of e-mails to reply to.
> Hello Mark,
>
> On Fri, Feb 06, 2026 at 02:32:20PM +0100, Mark Kettenis wrote:
> >
> > Can you try this diff?
>
> diff does not work. I had to opt for simple hack:
>
> --------8<---------------8<-----------------8<--------
> @@ -858,9 +906,9 @@ uchcom_param(void *arg, int portno, struct termios *t)
> if (usbd_is_dying(sc->sc_udev))
> return 0;
>
> + log(LOG_ERR, "%s (%d)\n", __func__, t->c_ospeed);
> if (t->c_ospeed <= 0 ||
> - (t->c_ospeed > 921600 && sc->sc_type != UCHCOM_TYPE_CH343) ||
> - (t->c_ospeed > 6000000 && sc->sc_type == UCHCOM_TYPE_CH343))
> + (t->c_ospeed > 6000000))
> return EINVAL;
>
> ret = uchcom_set_line_control(sc, t->c_cflag, &val);
> --------8<---------------8<-----------------8<--------
>
> with diff/hack above combined with your change things do work
> for me. My device reports as CH341:
> 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
>
> so by default the speed is limited to 921600. Your diff shows direction
> where we should be looking to. I will keep play around with it, however
> this whole new world for me, so my progress will be slow.
Ah, thanks for pointing that out. My diff didn't adjust that early
check to reject certain rates. Here is an updated diff that removes
that check.
> Meanwhile I have yet another question:
>
> If I understand things right I need to keep microSD card inserted
> to keep machine booting. as the card provides OpenBSD friendly
> u-boot, is my understanding correct? or is there a way to
> install system such microSD card won't be needed?
Your understanding is correct. Personally I like the having the
"firmware" on a microSD cards since it makes risk-free updates easy.
Just take a new microSD card, write the new firmware to it and if it
doesn't work, swap the old microSD card back in.
It is possible to put the "firmware" in SPI flash on boards that have
it. I haven't looked into that in detail since most of my boards
don't have SPI flash. And it can be hard to recover if you flash a
non-working firmware.
> currently OpenBSD boot loader prefers to boot system from
> microSD (sd0), is there a way to change it so it will boot
> from internal disk (sd1)? I always have to manually choose
> the boot path at boot prompt.
What I typically do is:
1. Erase the microSD card:
# dd if=/dev/zero of=/dev/sdXc bs=1m count=32
2. Write U-Boot to the microSD card:
# dd if=u-boot-rockchip.bin of=/dev/sdXc seek=64
Then it will load U-Boot from the microSD card, but look for the
OpenBSD bootloader on any of the other storage media supported by
U-Boot.
Cheers,
Mark
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 2 Mar 2026 10:54:43 -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;
@@ -858,9 +903,7 @@ uchcom_param(void *arg, int portno, stru
if (usbd_is_dying(sc->sc_udev))
return 0;
- if (t->c_ospeed <= 0 ||
- (t->c_ospeed > 921600 && sc->sc_type != UCHCOM_TYPE_CH343) ||
- (t->c_ospeed > 6000000 && sc->sc_type == UCHCOM_TYPE_CH343))
+ if (t->c_ospeed < 0)
return EINVAL;
ret = uchcom_set_line_control(sc, t->c_cflag, &val);