# 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 ```bash 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. ```bash git clone --depth=1 https://github.com/DisplayLink/evdi.git cd evdi ``` In `Makefile`, replace the `module:` recipe with: ```makefile module: CFLAGS="-isystem./include -isystem./include/uapi -Wextra -Wall -Wno-sign-compare -Wno-error $(CFLAGS)" $(MAKE) -C module $(MFLAGS) ``` Then build and install: ```bash 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`). ```bash 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+: ```bash 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 ```bash 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: ```bash 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): ```bash DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /usr/local/bin/fix-monitor-layout ``` ## Troubleshooting **Second monitor black after restart:** ```bash sudo systemctl restart t6evdi.service # Layout fix fires automatically ~6 seconds later ``` **Monitors on wrong sides (layout fix didn't run):** ```bash DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /usr/local/bin/fix-monitor-layout ``` **Check daemon health:** ```bash 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:** ```bash 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