Skip to content

ZeroCD WiFi dongles cannot be brought up at all: ship usb_modeswitch (but not usb_modeswitch_data) #189

Description

@mcfbytes

Prompted by a user report of a 0bda:c811 (RTL8811CU) dongle not working. That
particular case turned out to be fine on current stock — driver, firmware and USB ID all
check out — but chasing it surfaced a whole class of dongle this image cannot bring up at
all, and the reason is not a missing driver.

The gap

Many cheap WiFi dongles ship in ZeroCD mode: on first plug-in they enumerate as a USB
mass-storage device presenting a virtual CD-ROM full of Windows drivers, and only
re-enumerate as a WiFi NIC once the host sends a specific command. Until that happens they
never present the USB ID their driver is waiting for, so no amount of driver coverage helps.

For the Realtek case the switch is trivial — from usb_modeswitch.d/0bda:1a2b:

# D-Link DWA-171 Wifi Dongle
TargetVendor=0x2001
TargetProduct=0x331d
StandardEject=1

StandardEject=1 is a SCSI START STOP UNIT over the bulk endpoint. The device detaches
and returns as 2001:331d, which is in rtw8821cu.c's device table, so
rtw88_8821cu binds and the dongle works. Eject the fake CD; the device reboots into its
real identity.

Why the kernel will not do this for us

It half does, and the half it does makes userspace mandatory —
drivers/usb/storage/unusual_devs.h:1516:

/*
 * Reported by Zenm Chen <zenmchen@gmail.com>
 * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch
 * the device into Wi-Fi mode.
 */
UNUSUAL_DEV( 0x0bda, 0x1a2b, 0x0000, 0xffff,
        "Realtek", "DISK",
        USB_SC_DEVICE, USB_PR_DEVICE, NULL,
        US_FL_IGNORE_DEVICE ),

Mainline deliberately refuses to claim the device so that usb_modeswitch can reach
it, and says so in the comment. Two things follow:

  1. There is no kernel-only fix coming. Upstream has explicitly delegated this to userspace.
  2. eject cannot substitute. US_FL_IGNORE_DEVICE means no /dev/sr0 is created, so
    the eject applet we already ship (busybox, symlinked at /bin/eject and
    /usr/bin/eject) has nothing to act on. On this image such a dongle enumerates and then
    nothing at all happens.

Neither we nor stock ship usb_modeswitch — confirmed against stock's addon.tar at
9d9ff03a (Release 20260912), which has no modeswitch member.

This is a blind spot in docs/wifi-parity.md §12, structurally. That audit's method
was "enumerate every chip family under drivers/net/wireless/ with a USB bus file" — it
asked which chips have drivers, never whether the dongle ever reaches its driver's USB
ID
. A ZeroCD device fails the second test while passing the first, so the audit could not
have seen it.

Proposal: ship usb_modeswitch, not usb_modeswitch_data

Buildroot has both, and the split matters:

Package Contents Cost
BR2_PACKAGE_USB_MODESWITCH (2.6.2) the binary + dispatcher small; deps are libusb and jimtcl, both already in the image (libusb-1.0.so.0, libjim.so.0.83)
BR2_PACKAGE_USB_MODESWITCH_DATA (20251207) 513 device configs + a 44 KB udev rules file 2.1 MB, of which ~509 configs are 3G/4G modems, printers and WAN sticks

Take the first, skip the second, and vendor the handful of configs that matter into the
board overlay — the same pattern already used for 60-jms583-phantom.rules and
70-persistent-net.rules.

Skipping the data package is not only about the 2.1 MB. Its rules file opens with:

KERNEL=="ttyUSB*", ATTRS{bNumConfigurations}=="*", PROGRAM="usb_modeswitch --symlink-name %p ...

which forks usb_modeswitch on every ttyUSB* add event. This is a board where USB
serial is a first-class feature (uartmode, MIDI), so that is a real per-hotplug cost paid
for modems nobody will ever plug into a MiSTer. (The same file also carries a malformed
token: SUBSYSTEM!="usb", ACTION!="add",, GOTO=..., double comma included.)

What this actually buys

Every ZeroCD entry in the data package under a WiFi vendor ID, cross-checked against
whether we build a driver for the post-switch ID:

ZeroCD ID switches to driver in our image
0bda:1a2b 2001:331d (RTL8811CU/8821CU) rtw88_8821cuCONFIG_RTW88_8821CU=m
0bda:a192 0bda:f192 (RTL8192FU) rtl8xxxuCONFIG_RTL8XXXU=m
0e8d:2870 0e8d:7612 (MT7612U) mt76x2uCONFIG_MT76x2U=m
148f:2878 148f:7601 (MT7601U) mt7601uCONFIG_MT7601U=m

Four configs, four drivers already built and installed. Everything else in the 513 is out
of scope. The first row is the common AC600/AC1300 dongle sold under a dozen brand names,
which is why this is worth doing at all.

Work items

  • select BR2_PACKAGE_USB_MODESWITCH in package/mister-userspace/Config.in (§5.12
    USB/input), deliberately without _DATA; docs/buildroot-config.md and
    docs/package-manifest.md entries.
  • Vendor the four configs into board/mister/de10nano/rootfs-overlay/etc/usb_modeswitch.d/
    and a narrow exact-VID:PID rules file into .../etc/udev/rules.d/.
  • Confirm the wiring once built. The data package normally supplies both the rules
    and the packed DB at /usr/share/usb_modeswitch/, with /etc/usb_modeswitch.d/ as
    the override directory; verify the dispatcher's actual lookup order and the exact
    RUN+= invocation rather than assuming it from the Makefile
    (RULESDIR=/lib/udev/rules.d, PREFIX=/usr).
  • Measure the installed size of the binary + dispatcher (unmeasured here).
  • Hardware test — nothing in this issue has been tested on a real ZeroCD dongle;
    none was available. This should not land on source inspection alone, which is the
    same caveat wifi-parity.md §8 records against 8852cu.ko.
  • Fold into docs/wifi-parity.md as a new section, and note in §12 that its method
    does not cover enumeration state.

Scope note

configs/mister_de25nano_defconfig has no BR2_ROOTFS_OVERLAY, so an overlay-delivered
rule reaches the DE10 only. Given the DE25's current scope is a bare developer OS that is
probably fine, but it is a reason to consider whether these files belong in a shared
location rather than the DE10 overlay.

Caveats

  • Divergence from stock, which ships nothing here. Same class as ADR 0016: strictly
    more hardware works, nothing regresses.
  • Risk is low — our rules would be exact VID:PID matches, so there is no path to
    mis-firing an eject at a real USB drive.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions