Linux DRM/KMS driver for MacroSilicon USB-to-VGA/HDMI adapters.
Supported USB IDs:
534d:6021and alternate ID534d:0821(USB 2)345f:9132(USB 3 capable; may negotiate a USB 2 link)
This branch targets current DRM APIs. The 0.3.x series was built and exercised on
Fedora 44 with kernel 7.1.13-200.fc44.x86_64, including GNOME framebuffer imports.
GNOME 50 mode switching was verified at 800x600, 1024x768, 1280x720, and 1440x900.
Other kernels need their own build/runtime validation. For Linux 6.1, use the
kernel-6.1 branch instead.
Install a compiler, make, DKMS, and the development headers matching the running kernel. On Fedora:
sudo dnf install gcc make dkms "kernel-devel-$(uname -r)"
make -j"$(getconf _NPROCESSORS_ONLN)" W=1
sudo dkms install .
sudo install -m 644 99-ms912x.rules /etc/udev/rules.d/
sudo udevadm control --reload-rulesSave your work and reboot to activate the installed module and power-management rule. DKMS rebuilds the module for kernel updates when matching headers are available; newer kernel APIs may still require driver changes. Secure Boot systems must enroll the DKMS signing key before loading an out-of-tree module.
Verify the installed and loaded versions separately:
dkms status
modinfo -F version ms912x
cat /sys/module/ms912x/version
journalctl -k -b --no-pager | grep ms912xmake KVER=<kernel-release> builds for another installed kernel. For development,
sh insmod.sh builds and loads the local module without installing it persistently.
It refuses to unload a module held open by a compositor; never force an unload.
To roll back, keep the previous DKMS source/version, remove ms912x/0.3.2 with
sudo dkms remove ms912x/0.3.2 --all, reinstall the previous version with
sudo dkms install ms912x/<previous-version>, then reboot.
Version 0.3.2 adds extra_mode_1360x768=1, disabled by default. It offers the
standard 1360x768@60 timing even if absent from EDID, without replacing EDID or
duplicating an existing mode. This mode was visually verified on a Samsung
S20B350 with the tested 345f:9132 adapter. Its aspect ratio is within 0.4% of
16:9 and its 16-pixel-aligned width avoids the corruption seen at 1366x768.
After testing your monitor, install ms912x-widescreen.conf in /etc/modprobe.d/,
reload the driver or reboot, and select 1360x768 in Display Settings. Kernel/GNOME
may label the standard timing as 60.015 Hz. If the driver loads from an initramfs,
regenerate that image after changing the module configuration. To undo this,
remove the configuration and reload/reboot; no monitor firmware is changed.
The Samsung accepted the 1366x768 colour-bar probe but its normal desktop was scrambled; it rejected the 1920x1080 probe. Successful USB transfers alone do not prove a display mode works. Neither candidate is added by this option.
The adapter has no hardware cursor plane. GNOME should draw a software cursor, but mixed-GPU configurations may leave it invisible. The optional workaround below was verified with GNOME 50. It forces software cursors on all outputs in this user's session, not just the USB display:
mkdir -p ~/.config/environment.d
cp 90-ms912x-cursor.conf ~/.config/environment.d/Log out and back in (or reboot) to activate it. This is a compositor workaround,
not hardware-cursor support in the driver, and DKMS does not install it automatically.
To undo it, remove the installed file, run
systemctl --user unset-environment MUTTER_DEBUG_DISABLE_HW_CURSORS, and log out/in.
- One approximately 8 MiB vmalloc snapshot buffer holds the largest supported rectangle; a 16 KiB DMA-capable USB buffer and 8 KiB scanline buffer are reused. There are no scatter-gather tables or asynchronous frame workers.
- XRGB8888 is converted to limited-range BT.601 UYVY before USB transmission, so changes to the source framebuffer cannot mix pixels from different frames.
- Each dirty rectangle has one protocol header and one terminator, even when split into many 16 KiB USB fragments. Version 0.2.0 incorrectly treated transport chunks as separate display updates, contributing to visible strip artifacts.
- Dirty rectangles are aligned to 16-pixel hardware blocks. The final block is padded from the last visible pixel, without reading beyond the framebuffer row.
- Control messages, EDID reads, modesets, and uploads are serialized. DRM unplug guards prevent USB access after disconnect, and DRM manages buffer lifetimes.
- Modesets wait for firmware to report the requested width, height, and refresh rate rather than uploading pixels immediately after the control command.
- Short transfers and control failures are reported. Only a zero-byte endpoint stall is retried after clearing the halt; partially transmitted packets are not blindly replayed. An incomplete upload stops streaming and schedules one USB reset/re-modeset attempt. Recovery is limited to one attempt per failure streak to avoid endless resets. A successful full repaint re-arms recovery.
On Linux, with Python 3 and a C compiler (Fedora additionally needs libasan and
libubsan), run python3 tests/run.py. The tests compile the actual transfer code
with mocked kernel/USB APIs and AddressSanitizer/UndefinedBehaviorSanitizer. They
cover color conversion, framebuffer pitch, right-edge padding, clipping, maximum
dimensions, single-rectangle framing across fragments, snapshot isolation,
allocation failures, short writes, and stalls.
They do not replace physical display, suspend/resume, or USB-unplug testing.
re_notes/test-display.py is an opt-in PyUSB hardware diagnostic for colour bars,
mode readback, and continuous frame transfers. Stop the desktop and unload the
display module before using it; restore the module/session afterward. A stale
USB decoder may need a device reset before testing. The script never automatically
unbinds the display driver. Its experimental 1600x900 choices are probes, not
advertised driver modes. Firmware IDs are documented in the
upstream mode investigation.
- Only the resolutions and refresh rates in
ms912x_mode_listare supported; unsupported modes are rejected, not silently replaced with another resolution. - The tested
345f:9132unit ignored both documented 1600x900 mode IDs (0x6f00and0x7000) and retained its previous timing. A monitor advertising 1600x900 in EDID does not make that mode work in the adapter firmware. It is therefore deliberately not advertised by this driver. - Connector type is currently reported as HDMI, and connection status remains connected while the USB adapter is present because hardware status reads can flap during streaming. Monitor-side hotplug detection is not implemented.
- A 60 Hz display mode does not imply 60 full-frame USB uploads per second. USB 2 bandwidth and CPU color conversion limit refresh performance. Sending one rectangle fixes strip framing but does not provide hardware-vblank synchronization or guarantee tear-free video. Lower resolutions and small dirty regions are faster.
- Repeated
-110timeouts, especially USB descriptor-read errors, can indicate cable, power, or link problems. Checklsusb -t, try a direct USB 3 port and a suitable cable, and keep adapter autosuspend disabled using the supplied rule.
The protocol was reverse-engineered from Wireshark captures and device registers;
see re_notes/ for the original investigation.