joshuagrisham / samsung-galaxybook-extras

Samsung Galaxybook Linux platform driver and accompanying utilities.
98 stars 13 forks source link

Samsung Galaxybook Extras ⚠️(WIP)⚠️

Samsung Galaxybook Linux platform driver and accompanying utilities.

Current status: ⚠️ WIP and dare I say definitely not yet even alpha! ⚠️ (use at your own risk!)

The intent is to somewhat replicate in Linux what Samsung has done in Windows with what I think the following components are doing:

Platform Driver

This is a new and (currently) completely out-of-tree kernel platform driver intended to mimic what the Samsung System Event Controller Windows system device driver seems to be doing (namely, communicate with the SCAI ACPI device in order to control these extra features). Once more features have been added and it has been tested then my intention was to try and submit the driver to be added to the kernel.

cd over to the driver/ folder and follow the README there for compiling and installing the module.

The following features are currently implemented:

The following features might be possible to implement but require additional debugging and development:

Module Parameters

The platform driver supports the following module parameters:

In general the intention of these parameters is to allow for enabling or disabling of various features provided by the driver, especially in cases where a particular feature does not appear to work with your device. The availability of the various "settings" flags (battery_saver, start_on_lid_open, etc) will always be enabled and cannot be disabled at this time.

Note: Please raise an issue if you find that you need to disable a certain feature in order to avoid a problem that it causes with your device!

General observations

One general observation that I have made is that there are in fact quite a lot of bugs in Samsung's firmware for these devices, for example:

And then that I have seen a bit of "flakiness" from the device when these kind of issues happen. One of the most noticeable is that the keyboard backlight starts to turn off by itself when such problems occur; this needs to be investigated further. One tip that I have found is that booting into Windows and starting/restarting the Samsung services seem to help "reset" some of this behavior (a clue that I still don't quite have some things 100% right!).

It would be great if we could actually get some help from Samsung regarding this!

Hotkeys

Samsung have decided to use the main keyboard device to also send most of the hotkey events. If the driver wishes to capture and act on these hotkeys, then we will have to do something like using a i8402 filter to "catch" the key events.

I have also found that some of the hotkey events have conflicts so it is a bit of a tricky territory. As such, this "feature" is in very early stages!

Keyboard backlight hotkey (Fn+F9)

The keyboard backlight hotkey will cycle through all available backlight brightnesses in a round-robin manner, starting again at 0 when the maximum is reached (i.e. 0, 1, 2, 3, 0, 1, ...).

The action will be triggered on keyup of the hotkey as the event reported by keydown seems to be the same event for battery charging progress (and thus things get a little crazy when you start charging!).

The hotkey should also trigger the hardware changed event for the LED, which in GNOME automatically displays a nice OSD popup with the correct baclight level displayed.

Performance mode hotkey (Fn+F11)

The performance mode hotkey will also cycle through all available platform profiles in a round-robin manner (low-power, quiet, balanced, performance, low-power, quiet, ...).

There is currently no OSD popup but the event can be captured from the "Samsung Galaxybook extra buttons" input device if desired.

Keyboard backlight

A new LED class called samsung-galaxybook::kbd_backlight is created which can be controlled via sysfs at /sys/class/leds/samsung-galaxybook::kbd_backlight/brightness (values 0 to 3) or by many of the standard utilities such as brightnessctl, light, etc.

It also seems to be picked up automatically in GNOME 45.x in the panel, where you can click the arrow beside Keyboard and adjust the slider:

GNOME Panel Keyboard Backlight

Note that the setting "automatically turn off the keyboard backlight after X seconds" in Windows is actually controlled by Samsung's application service and not by the device driver itself; if such a feature is desired then it would need to be a similar software-based solution (e.g. added to the "extras" or something).

Battery saver

To turn on or off the "Battery saver" mode (battery will stop charging at 80%), there is a new device attribute created at /sys/devices/platform/samsung-galaxybook/battery_saver which can be read from or written to. A value of 0 means "off" while a value of 1 means "on".

# read current value (0 for disabled, 1 for enabled)
cat /sys/devices/platform/samsung-galaxybook/battery_saver

# turn on (supports values such as: 1, on, true, yes, etc)
echo true | sudo tee /sys/devices/platform/samsung-galaxybook/battery_saver

# turn off (supports values such as: 0, off, false, no, etc)
echo 0 | sudo tee /sys/devices/platform/samsung-galaxybook/battery_saver

Note: I have noticed that if you are currently plugged in with the setting turned on and already sitting at 80%, then disable this setting (with the idea that you wish to charge to 100%), charging does not seem to start automatically. It may be necessary to disconnect and reconnect the charging cable in this case. The Windows driver seems to be doing some hocus pocus with the ACPI battery device that I have not quite sorted out yet; I am assuming this is how they made it work more seamlessly in Windows?

There is also an input event sent to the standard keyboard which is generated when battery saver is enabled and charging reaches 80%; I have also mapped this in so that notifications can be displayed (see below in the keyboard remapping section).

Start on lid open

To turn on or off the "Start on lid open" setting (the laptop will power on automatically when opening the lid), there is a new device attribute created at /sys/devices/platform/samsung-galaxybook/start_on_lid_open which can be read from or written to. A value of 0 means "off" while a value of 1 means "on".

# read current value (0 for disabled, 1 for enabled)
cat /sys/devices/platform/samsung-galaxybook/start_on_lid_open

# turn on (supports values such as: 1, on, true, yes, etc)
echo true | sudo tee /sys/devices/platform/samsung-galaxybook/start_on_lid_open

# turn off (supports values such as: 0, off, false, no, etc)
echo 0 | sudo tee /sys/devices/platform/samsung-galaxybook/start_on_lid_open

USB Charging mode

To turn on or off the "USB Charging" mode (allows USB ports to provide power even when the laptop is turned off), there is a new device attribute created at /sys/devices/platform/samsung-galaxybook/usb_charging which can be read from or written to. A value of 0 means "off" while a value of 1 means "on".

# read current value (0 for disabled, 1 for enabled)
cat /sys/devices/platform/samsung-galaxybook/usb_charging

# turn on (supports values such as: 1, on, true, yes, etc)
echo true | sudo tee /sys/devices/platform/samsung-galaxybook/usb_charging

# turn off (supports values such as: 0, off, false, no, etc)
echo 0 | sudo tee /sys/devices/platform/samsung-galaxybook/usb_charging

My own observations on how this feature appears to work (which has nothing to do with this driver itself, actually):

Fan speed

Samsung has implemented the ACPI method _FST for the fan device, but not the other optional methods in the ACPI specification which would cause the kernel to automatically add the fan_speed_rpm attribute. On top of this, it seems that there are some bugs in the firmware that throw an exception when you try to execute this ACPI method. This behavior is also seen in Windows (that an ACPI exception is thrown when the fan speed is attempted to be checked).

However, I believe I have succeeded in figuring out roughly the intention of how their _FST method is supposed to work:

  1. There is a data package FANT ("fan table"??) which seems to be some kind of list of possible RPM speeds that the fan can run at.
  2. There is a data field on the embedded controller called FANS ("fan speed"??) which seems to give the current "level" that the fan is operating at.

I have assumed that the values from FANT are integers which represent the actual RPM values (they seem reasonble, anyway), but can't be one hundred percent certain. It would be interesting to get confirmation from Samsung or if someone had a way to measure the actual speed of the fan!

The fan can either be completely off (0) or one of the levels represented by the speeds in FANT. This driver reads the values in from FANT instead of hard-coding the levels with the assumption that it could be different values and a different number of levels for different devices. For reference, the values I see with my Galaxy Book2 Pro are:

On top of this, in Samsung's _FST method it seems to be adding 0x0a (10) to each value before trying to report them, and that level 3 and 4 should have the same value, while level 5 should be the 4th value from FANT. However, real-life observation suggests that level 3 and 4 are in fact different, and that level 5 seems to be significantly louder than level 4. Due to this, this driver will just "guess" that levels 3 and 4 are actually as is listed in FANT, and that the last level is maybe 1000 RPM faster than level 4 (unless anyone can find something better than this!).

The fan speed can be monitored using hwmon sensors or by reading the fan_speed_rpm sysfs attribute.

# read current fan speed rpm from sysfs attribute
cat /sys/bus/acpi/devices/PNP0C0B\:00/fan_speed_rpm

# read current fan speed rpm from hwmon device
sensors

Performance mode

To modify the "performance mode", the driver implements the platform_profile interface. The following strings can be written to /sys/firmware/acpi/platform_profile to set the performance mode:

Examples:

# Get supported performance modes
cat /sys/firmware/acpi/platform_profile_choices

# set performance_mode to low-power
echo low-power | sudo tee /sys/firmware/acpi/platform_profile

# get current performance_mode
cat /sys/firmware/acpi/platform_profile

Note: To match the logic in the Windows driver, as well as avoid causing issues with other features, the driver currently will always set the performance mode to "Optimized" every time during its initialization (e.g. upon startup).

It should be possible to set your own desired startup performance mode or to save and restore the mode across reboots, you can eiter use a startup script or install TLP, power-profiles-daemon, or similar.

Limitations reading performance_mode

Unfortunately, I have still not been able to find any way to read the value of the "current" performance mode from the system.

At the same time, I have a suspicion that this might actually be controlled in Windows somehow at the software level. I did a small test where I set the value to "High performance" in Windows, booted to Linux, set the value to "Quiet" using this driver, noted a difference in the fan volume, then booted back into Windows where it was once again sitting at "High performance". My working assumption is that the Samsung software (namely, SamsungSystemSupportEngine.exe) is storing what latest "value" was chosen by the user in Windows, and then upon startup, is setting this value using their driver.

I suppose that we could do similar on the Linux side (and might need to, actually), either via something like sysfsutils or with whatever eventually comes in the "Samsung Galaxybook Extras".

In light of this, for now I have allowed reading of /sys/firmware/acpi/platform_profile (via cat, for example), but please remember that it will only echo back the value that was last set by the driver, which under normal circumstances will the one active in the hardware.

Does this performance_mode actually work?

This was a bit hard to test, but I tried to test by setting each different mode and then running a quick stress test using the following:

sudo stress-ng --cpu 0 --cpu-load 100 --metrics-brief --perf -t 20

Note that it does seem to take at least a few seconds before the setting really seems to kick in.

In the end what I found was that I could definitely tell a difference in the result when using the "silent" (0) mode, because the resulting number of completed operations in the stress test was significantly lower when using "silent" mode (almost half).

Subjectively, I do feel like I experienced that the fan volume was quite a bit lower in the "quiet" mode as compared to the other two, but I did not really notice any major difference in the number of completed operations from the stress test. Optimized and High Performance seemed almost the same to me. I did also notice that there might be some throttling happening when the cores reach near 100C, so maybe that is part of the problem why I could not tell a difference (not sure what is safe to adjust). This could also just be a flawed test mechanism, as well!

Galaxybook Extras

The "extras" I have added here will be intended to mimic some of the functionality that the windows Samsung Settings application and service provide for this device.

Currently I have just created a few simple shell scripts which provide the following functionality:

Once you have built, installed, and loaded the platform driver then you can also make use of these "extras". The various scripts and configuration files can be installed using the install-extras.sh script.

It could be possible to build some sort of service or more robust solution going forward, but this "quick and dirty" sort of works for now!

For notifications based on hotkey presses, I have just relied on notify-send which is also not ideal, but for a quick solution it does work for now.

Keyboard scancode remapping

The provided file 61-keyboard-samsung-galaxybook.hwdb will correct some keyboard mappings as follows:

Matching additional device keyboards

Currently, these keyboard mapping rules should apply to all Galaxy Book2 and Book3 series notebooks by matching on an "svn" starting with "Samsung" (case insensitve) plus a "pn" string of three digits followed by any one of the following suffixes:

This is quite a broad filter string but my hope is that the keyboard mappings should actually work for all of these models as from what I have seen, they all seem to have a similar keyboard layout.

In case you have issues where the mapping does not seem to be picked up on your device, then we might need to modify the filter string. You can get your own device's evdev dmi string like this:

sudo evemu-describe

Select the device for your "regular" keyboard (e.g. "/dev/input/event2: AT Translated Set 2 keyboard") and then you should see the full DMI string for your keyboard, like this:

# EVEMU 1.3
# Kernel: 6.5.0-13-generic
# DMI: dmi:bvnAmericanMegatrendsInternational,LLC.:bvrP11RGF.057.230404.ZQ:bd04/04/2023:br5.25:svnSAMSUNGELECTRONICSCO.,LTD.:pn950XED:pvrP11RGF:rvnSAMSUNGELECTRONICSCO.,LTD.:rnNP950XED-KA2SE:rvrSGLB208A0U-C01-G001-S0001+10.0.22000:cvnSAMSUNGELECTRONICSCO.,LTD.:ct10:cvrN/A:skuSCAI-ICPS-A5A5-ADLP-PRGF:
# Input device name: "AT Translated Set 2 keyboard"
# Input device ID: bus 0x11 vendor 0x01 product 0x01 version 0xab41
# ...
# Properties:
N: AT Translated Set 2 keyboard
I: 0011 0001 0001 ab41

The filter string in the hwdb file will need to modified so that it also matches your device. If you wish then you can create an issue here with the output of your evemu-describe and I can try to modify the file for you.

Otherwise, feel free to test yourself by modifying /etc/udev/hwdb.d/61-keyboard-samsung-galaxybook.hwdb and either restart or reload udev as follows:

sudo systemd-hwdb update
sudo udevadm trigger

Once we can put together a more definitive filter that supports more devices then I think it would make sense to ask for this keyboard mapping to get moved to systemd upstream. See: https://github.com/systemd/systemd/blob/main/hwdb.d/60-keyboard.hwdb