Asus Zenbook Duo (2024 / UX8406MA) & NixOS

I’ ve created a simple experimental patch which make use of a generic input subsystem tablet switch support already impemented in asus_wmi modules and which is being used by quirks for Asus Transformer series (T100, T101HA, T200TA). With this patch enabled input events EV_SW/SW_TABLET_MODE are generated each tiime the keyboard is (det)attached. No KEY_WLAN is generated as 0x5e WMI code is consumed in the process of generating SW_TABLET_MODE event. What are your thougs about this concept?

diff -up orig/asus-nb-wmi.c new/asus-nb-wmi.c
--- orig/asus-nb-wmi.c	2024-10-08 10:18:04.000000000 +0200
+++ new/asus-nb-wmi.c	2024-10-08 10:15:52.141120621 +0200
@@ -146,7 +146,11 @@ static struct quirk_entry quirk_asus_ign
 };
 
 static struct quirk_entry quirk_asus_zenbook_duo_kbd = {
-	.ignore_key_wlan = true,
+	/* ignore_key_wlan = true, */
+	.tablet_switch_mode = asus_wmi_kbd_dock_devid,
+	.tablet_switch_devid = 0x00050051,
+	.tablet_switch_event_code = 0x5e,
+	.tablet_switch_not_inverted = true,
 };
 
 static int dmi_matched(const struct dmi_system_id *dmi)
diff -up orig/asus-wmi.c new/asus-wmi.c
--- orig/asus-wmi.c	2024-10-08 10:18:04.000000000 +0200
+++ new/asus-wmi.c	2024-10-08 10:10:56.471851626 +0200
@@ -609,8 +609,10 @@ static int asus_wmi_input_init(struct as
 	case asus_wmi_no_tablet_switch:
 		break;
 	case asus_wmi_kbd_dock_devid:
-		asus->tablet_switch_inverted = true;
-		asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE);
+		pr_info("asus_wmi_kbd_dock_devid: %x %x\n", asus->driver->quirks->tablet_switch_devid, asus->driver->quirks->tablet_switch_event_code);
+		/* asus->tablet_switch_inverted = true; */
+		asus->tablet_switch_inverted = !asus->driver->quirks->tablet_switch_not_inverted;
+		asus_wmi_tablet_sw_init(asus, asus->driver->quirks->tablet_switch_devid ? asus->driver->quirks->tablet_switch_devid : ASUS_WMI_DEVID_KBD_DOCK, asus->driver->quirks->tablet_switch_event_code ? asus->driver->quirks->tablet_switch_event_code : NOTIFY_KBD_DOCK_CHANGE);
 		break;
 	case asus_wmi_lid_flip_devid:
 		asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP);
diff -up orig/asus-wmi.h new/asus-wmi.h
--- orig/asus-wmi.h	2024-10-08 10:18:04.000000000 +0200
+++ new/asus-wmi.h	2024-10-08 10:10:06.854522495 +0200
@@ -42,6 +42,8 @@ struct quirk_entry {
 	bool filter_i8042_e1_extended_codes;
 	bool ignore_key_wlan;
 	enum asus_wmi_tablet_switch_mode tablet_switch_mode;
+	int tablet_switch_devid, tablet_switch_event_code;
+	bool tablet_switch_not_inverted;
 	int wapf;
 	/*
 	 * For machines with AMD graphic chips, it will send out WMI event

Cool! Makes sense to me - though whether this should actually be considered “tablet mode” may be up for debate. Personally, I don’t really use Linux on this without the keyboard - just Windows for note taking - so I’d be disabling any tablet mode UI changes in my desktop preferences.

A real 2-in-1 with an external keyboard would also go in to tablet mode when its internal keyboard is removed, though, so you could argue that this behaviour is consistent.

As for the actual implementation here, I wonder if the WMI values for the transformer series devices should also be put in quirks. If more devices with different values are made, the defaults will quickly stop making sense.

(Also, forgive me if I’m wrong, as I’m not that experienced in kernel-level C - but aren’t the extra struct values now undefined for the transformer series? The ternary expressions assume these to be zero, but might that not just be due to the compiler configuration?)

@hacker1024

quirks and default WMI values: I tried to make the patch as self contained as possible by minimizing the amount of changes in existing code. You are right it would be nice to have those values in quirk itself.

quirk struct values: all static structs without explicit initializers are guaranteed to be initialzed to zero (as per C specification).

1 Like

Hi all, writing again to highlight an issue I am having using VSCode under wayland with the latest version of GNOME. Scaling is at 200%, fractional scaling is disabled, still code launches with blurry UI. I tried all electron flags, I actually think the app is running with wayland but for some reason still displaying blurry. I also tried both the open source and the Microsoft version. It’s really annoying because it is the program I use the most and it feels like I have a 720p screen. Does anyone have the same problem and found a solution?

@ultramarine
Try adding

environment.sessionVariables.NIXOS_OZONE_WL = “1”;

to your configuration, as suggested on the NixOS wiki Wayland page.

I have a problem with the microphone, namely that it only records silence.

The Microphones recognized by the system are:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: sofhdadsp [sof-hda-dsp], device 0: HDA Analog () []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: sofhdadsp [sof-hda-dsp], device 6: DMIC Raw (
)
Subdevices: 1/1
Subdevice #0: subdevice #0

Potentially relevant parts of my configuration.nix:

services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
jack.enable = true;
wireplumber.enable = true;
};

If anyone solved a similar problem or might point me in the correct direction, it would be really helpful as I’m quite new to nixos.

On Gnome 47, night light does not function properly on Zenbook Duo since both monitors have the same id. I posted an issue on gnome’s gitlab mutter. I currently have a workaround using this patch:

diff --git a/src/backends/meta-color-device.c b/src/backends/meta-color-device.c
index 49f70dcf2..317a1e1e7 100644
--- a/src/backends/meta-color-device.c
+++ b/src/backends/meta-color-device.c
@@ -105,10 +105,12 @@ generate_cd_device_id (MetaMonitor *monitor)
   const char *vendor;
   const char *product;
   const char *serial;
+  const char *connector;
 
   vendor = meta_monitor_get_vendor (monitor);
   product = meta_monitor_get_product (monitor);
   serial = meta_monitor_get_serial (monitor);
+  connector = meta_monitor_get_connector (monitor);
 
   device_id = g_string_new ("xrandr");
 
@@ -135,6 +137,8 @@ generate_cd_device_id (MetaMonitor *monitor)
   if (serial)
     g_string_append_printf (device_id, "-%s", serial);
 
+  g_string_append_printf (device_id, "-%s", connector);
+
 out:
   return g_string_free (device_id, FALSE);
 }
diff --git a/src/backends/meta-color-manager.c b/src/backends/meta-color-manager.c
index 7a583789b..c28315afd 100644
--- a/src/backends/meta-color-manager.c
+++ b/src/backends/meta-color-manager.c
@@ -142,11 +142,13 @@ generate_monitor_id (MetaMonitor *monitor)
   const char *vendor;
   const char *product;
   const char *serial;
+  const char *connector;
   GString *id;
 
   vendor = meta_monitor_get_vendor (monitor);
   product = meta_monitor_get_product (monitor);
   serial = meta_monitor_get_serial (monitor);
+  connector = meta_monitor_get_connector (monitor);
   if (!vendor && !product && !serial)
     return g_strdup (meta_monitor_get_connector (monitor));
 
@@ -158,6 +160,8 @@ generate_monitor_id (MetaMonitor *monitor)
     g_string_append_printf (id, "%sp:%s", id->len > 0 ? ";" : "", product);
   if (serial)
     g_string_append_printf (id, "%sp:%s", id->len > 0 ? ";" : "", serial);
+  if (connector)
+    g_string_append_printf (id, "%sc:%s", id->len > 0 ? ";" : "", connector);
 
   return g_string_free (id, FALSE);
 }

Hello, I recently got a zenbook duo and have spent the last week setting it up, i’m still trying to get some things working and configured. Probably my biggest two are this:

  1. sometimes when the keyboard connects over bluetooth, it’ll connect in a mode where scrolling is disabled. I am looking for some way to fix this
  2. Palm rejection on the trackpad does not work the same way in bluetooth mode as direct connect.

Has anybody managed to make progress on either of these issues

2nd one seems to be similar to my issues. I discovered libinput has a different event number when for the trackpad when this happens (4 vs 24)

Not exactly the best solution, but you can use a USB cable to connect the keyboard instead, which should behave more like docked mode.

1 Like

That does work, very well, although it does have the hilarious limitation of activating the watcher script that disables the 2nd display, however, that is solvable

Side question, Did you ever manage to figure out the keyboard initialization step?

It looks like ASUS have just released a keyboard firmware update, available through the MyASUS app.
If anyone could grab a copy of this, I’d really appreciate it! It might be useful for reverse engineering.

It looks like the update may be downloaded in advance in C:\ProgramData\ASUS\ASUS System Control Interface\AsusSoftwareManager.

I was unable to find it using a packet capture tool: MyASUS must use another tool to check for updates, so even when clearing its app data, I could not trigger an update check (the check button actually does nothing lol). I figured I’d capture the update as it downloaded, but there was no traffic throughout the whole process, which is why I assume it was downloaded in advance.