Files
jcd3198-t6-driver/README.md
Jacob Nelson 5dbbb34096 Initial commit: JCD3198 second HDMI driver setup for Fedora
Enables the MCT T6 USB Station (0711:5601) chip on the J5 Create JCD3198
dock, which drives the 4K30 HDMI port with no native Linux kernel driver.

Stack: EVDI 1.14.16 (kernel module + libevdi) → t6evdi userspace daemon
(mobilepixels-linux-driver, patched for EVDI 1.14 API) → MCT T6 over USB.

Includes DKMS registration for evdi.ko (auto-rebuilds on kernel updates)
and a Mutter D-Bus layout script that restores monitor positions by serial
number after each daemon restart, working around the incrementing DVI-I-N
connector name assigned by EVDI on every reconnect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 18:36:35 -05:00

6.6 KiB

J5 Create JCD3198 — Second HDMI (4K30) Driver on Linux

Problem

The JCD3198 dock has two HDMI outputs:

Port Chip Linux support
4K60 HDMI DP alt mode via USB-C Native — works out of the box
4K30 HDMI MCT T6 USB Station (0711:5601) Requires userspace driver

The T6 chip has no mainline Linux kernel driver. It presents as USB class ff-00-00 (vendor-specific) with no driver bound. A userspace daemon bridges it through the EVDI virtual display framework.

System

Item Value
Machine LG Gram 17Z90Q (jake@gram)
OS Fedora 43, GNOME Wayland
Left monitor LG FHD — vendor GSM, serial 0x01010101 (via T6 / EVDI)
Right monitor Acer SA270 — vendor ACR, serial 0x13102591 (via DP alt mode, stable)

Architecture

GNOME Wayland compositor
        │
        ▼
evdi.ko — virtual DRM device (card0, connector DVI-I-N)
        │  libevdi.so
        ▼
t6evdi — reads frames from EVDI, encodes JPEG, sends over USB bulk transfer
        │  libusb-1.0
        ▼
MCT T6 chip (USB 0711:5601) → 4K30 HDMI port

Installed Files

Repo path Installed to Purpose
bin/fix-monitor-layout /usr/local/bin/fix-monitor-layout Python script — applies monitor layout via Mutter D-Bus
bin/t6evdi-apply-layout /usr/local/bin/t6evdi-apply-layout Shell wrapper — called by systemd after t6evdi starts
systemd/t6evdi.service /etc/systemd/system/t6evdi.service Systemd service — starts daemon, auto-restarts on crash
systemd/evdi.conf /etc/modules-load.d/evdi.conf Loads evdi.ko at boot

The t6evdi binary itself lives at /usr/local/bin/t6evdi (built from source, not in this repo).

First-Time Build

1. Dependencies

sudo dnf install -y libusb1-devel turbojpeg-devel libdrm-devel git \
    bison elfutils-libelf-devel flex openssl-devel python3-dbus

# kernel-devel must match the running kernel exactly.
# If not available via dnf, fetch from Koji:
KVER=$(uname -r)
VER=$(echo $KVER | cut -d- -f1)
REL=$(echo $KVER | cut -d- -f2)
sudo rpm -i "https://kojipkgs.fedoraproject.org/packages/kernel/$VER/$REL/x86_64/kernel-devel-$KVER.rpm"

2. Build EVDI (kernel module + library)

EVDI 1.14.16 supports kernels through 6.20. The top-level Makefile passes -Werror=sign-compare which trips on Fedora kernel headers — patch it before building.

git clone --depth=1 https://github.com/DisplayLink/evdi.git
cd evdi

In Makefile, replace the module: recipe with:

module:
	CFLAGS="-isystem./include -isystem./include/uapi -Wextra -Wall -Wno-sign-compare -Wno-error $(CFLAGS)" $(MAKE) -C module $(MFLAGS)

Then build and install:

make module && make library
sudo make install          # installs evdi.ko + libevdi.so
sudo cp library/evdi_lib.h /usr/include/
sudo ldconfig
sudo modprobe evdi
echo "evdi" | sudo tee /etc/modules-load.d/evdi.conf

3. Register EVDI with DKMS

DKMS rebuilds evdi.ko automatically after each kernel update (AUTOINSTALL=yes).

sudo cp -r module /usr/src/evdi-1.14.16
sudo cp module/dkms.conf /usr/src/evdi-1.14.16/
sudo dkms add evdi/1.14.16
sudo dkms build evdi/1.14.16
sudo dkms install evdi/1.14.16

4. Build the T6 userspace daemon

Source: https://github.com/rfxDarth/mobilepixels-linux-driver
Supports 0711:5601 alongside the MobilePixels devices it was written for.

One API fix required — evdi_connect was renamed evdi_connect2 in EVDI 1.14+:

git clone --depth=1 https://github.com/rfxDarth/mobilepixels-linux-driver.git
cd mobilepixels-linux-driver/evdi_t6_1
# Edit main.c ~line 1117:
#   evdi_connect(..., 0, 0)  →  evdi_connect2(..., 0, 0)
make
sudo cp T6evdi /usr/local/bin/t6evdi

5. Install service and layout scripts

sudo cp bin/fix-monitor-layout bin/t6evdi-apply-layout /usr/local/bin/
sudo chmod +x /usr/local/bin/fix-monitor-layout /usr/local/bin/t6evdi-apply-layout
sudo cp systemd/t6evdi.service /etc/systemd/system/
sudo cp systemd/evdi.conf /etc/modules-load.d/
sudo systemctl daemon-reload
sudo systemctl enable --now t6evdi.service

After a Kernel Update

DKMS rebuilds evdi.ko automatically — nothing to do. If it fails:

sudo dkms build evdi/1.14.16 -k $(uname -r)
sudo dkms install evdi/1.14.16 -k $(uname -r)
# If kernel-devel isn't in repos, fetch it from Koji (see step 1)

How the Monitor Layout Fix Works

Problem: The DRM connector name for the EVDI display (DVI-I-N) increments every time t6evdi restarts. GNOME's monitors.xml matches saved layouts by connector name, so every restart lands the LG monitor on the wrong side.

Solution: fix-monitor-layout calls the Mutter DisplayConfig D-Bus API directly, matching monitors by serial number rather than connector name. It calls ApplyMonitorsConfig with method=2 (persistent), which also rewrites monitors.xml correctly for the current connector.

t6evdi-apply-layout is the shell wrapper called by systemd. It sleeps 6 seconds to give GNOME time to enumerate the new display, then runs fix-monitor-layout as jake via runuser with the correct session bus address.

Run the fix manually (without restarting the daemon):

DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /usr/local/bin/fix-monitor-layout

Troubleshooting

Second monitor black after restart:

sudo systemctl restart t6evdi.service
# Layout fix fires automatically ~6 seconds later

Monitors on wrong sides (layout fix didn't run):

DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /usr/local/bin/fix-monitor-layout

Check daemon health:

systemctl status t6evdi
journalctl -u t6evdi -n 30
sudo dmesg | grep evdi | tail -10

Healthy log output looks like:

monitor state =1
EDID_ret= 128
edid edid_size = 256
set mode finish
mct_dpms_handler: dpms_mode = 0

EDID_CheckSum error loop: No monitor connected to the 4K30 HDMI port. Daemon retries indefinitely — plug in the monitor and it will proceed.

DKMS status:

dkms status evdi

Known Limitations

  • Refresh rate capped at 75Hz at 1080p (T6 chip / USB bandwidth constraint)
  • UID 1000 is hardcoded in t6evdi-apply-layout — update if jake's UID changes
  • The 6-second sleep in t6evdi-apply-layout is a heuristic; increase it if GNOME is slow to enumerate the display under load
  • Layout fix only runs on service start, not on login. If the display is already connected but mis-positioned at login, run fix-monitor-layout manually
  • The t6evdi codebase is immature — do not use make install from the mobilepixels repo