Skip to content

Add ch340 support - #2

Merged
Boernsman merged 3 commits into
mainfrom
ch340-support
Sep 16, 2026
Merged

Boernsman merged 3 commits into
mainfrom
ch340-support

Conversation

@Boernsman

@Boernsman Boernsman commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Adds a ch340 driver for the WCH CH340B's 64-byte on-chip configuration area,
alongside the existing FTDI families.

What works

Detection, and it is proven on two chips. WCH gives the whole family one
identity — a CH340G and a CH340B both enumerate as 1a86:7523, with the same
bcdDevice and the same chip version byte — so nothing in the descriptor tells
them apart. The driver asks the chip instead: a part without the configuration
memory stalls vendor request 0x54, and that refusal is the test. A CH340G
(version 0x30) stalls it; the CH340B (version 0x31) accepts it. The error
message says plainly that the chip holds its identity in mask ROM and that no
tool can change it.

What does not

Writing has never been observed to land. The CH340B accepts every 0x54 write —
no stall, no error — and stores nothing. It was tried with no preamble, with the
three-command pre-read preamble, with the full six-command init, with a settling
delay, and with four different wIndex values; none of them changed a byte. The
signature byte was deliberately left invalid throughout, so the chip was never at
risk. The likely explanation is an unlock step missing from the public capture,
and settling it needs a USB capture of WCH's own CH34xSerCfg doing a write.

So the driver is built to fail loudly rather than quietly:

  • Every write is read back. If the area comes back exactly as it was, the tool
    says the chip is unharmed and needs no recovery, rather than sending the user
    after a backup they do not need.
  • An area that reads uniformly is called out at attach time, before any values
    are printed, so a table of vendor defaults is never mistaken for values read
    off the chip.
  • The write-protect byte (0x57 at offset 0x03) is a one-way door, so nothing
    writes it and an image carrying it is refused.
  • The signature is cleared first and written last, so an interrupted write leaves
    a chip that still enumerates.

The README and the driver description both mark it experimental, and the tables
say "writing unconfirmed".

Layout

Offsets come from WCH's "CH340 Datasheet (I)" version 3B, section 5.2. The
transport that reaches them — request 0x54, address in the high half of
wValue — is not documented by WCH and comes from USB captures of
CH34xSerCfg; the credits section says so.

Two things differ from the FTDI parts and shape the code:

  • No checksum. The signature byte plays the role of the correctness gate:
    0x58 means the chip reads the area, anything else means it runs on vendor
    defaults.
  • A factory part reads as all zeroes with the signature clear. Decoding that
    reports the datasheet defaults rather than 0000:0000 at 0 mA, and any encode
    stamps the signature — otherwise set serial_number=… would commit an identity
    picked up from bytes the chip was never reading.

erase clears the signature rather than wiping the area, so it is reversible.

Also

props now marks read-only properties as such, since the CH340B is the first
driver to have any (config_active, write_protected), and info prints them.

Tests

11 new cases pin the layout to the datasheet addresses: the inactive-area decode,
signature activation, identity/power offsets, the serial-number and product
descriptor encodings, the write-protect refusal and the round trip. No hardware
needed — Ch340Config is pure.

Lint

The lint job was already red on main before this branch, on a
readability-convert-member-functions-to-static finding in ftdi_codec.cpp.
The new driver added four more of the same, and converting the methods is the
wrong fix: Ch340Config deliberately mirrors the FTDI Codec as an object with
instance state, so making decode/encode/size static just moves the error to
every call site. The check is switched off in .clang-tidy instead, alongside
the others there that contradict a deliberate choice in this project. That also
clears the pre-existing failure on main.

Two genuine findings from the same run are fixed rather than silenced: the two
empty catch blocks in the driver are restructured so each handler returns or
throws, and two test locals are made const.

@Boernsman
Boernsman merged commit 8cc9796 into main Sep 16, 2026
5 checks passed
@Boernsman
Boernsman deleted the ch340-support branch September 16, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant