Skip to content

Instantly share code, notes, and snippets.

@jbuncle
Last active September 23, 2021 12:20
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save jbuncle/7dacde983b3c33b3b816b10e2fd2308a to your computer and use it in GitHub Desktop.
Save jbuncle/7dacde983b3c33b3b816b10e2fd2308a to your computer and use it in GitHub Desktop.
Compile and install Linux Kernel with patch for Lenovo Legion 5 15ARH05 Touchpad
#! /bin/bash
#
# Lenovo Legion 5 Patch Utility
#
# This script aims to simplify the application of various patches required for Lenovo Legion 5 15ARH05.
# For convenience you can run this script with `bash <(curl https://gist.githubusercontent.com/jbuncle/7dacde983b3c33b3b816b10e2fd2308a/raw/build-patched-kernel.sh)`
#
# References:
# - Original bug and related patch: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1887190
# - Touchpad patch file: https://www.spinics.net/lists/linux-input/msg69458.html
# - Tutorial for building the linux kernel: https://www.freecodecamp.org/news/building-and-installing-the-latest-linux-kernel-from-source-6d8df5345980/, then adapted based on https://wiki.ubuntu.com/KernelTeam/GitKernelBuild
#
set -e
KERNEL_VERSION_511='5.11-rc6'
PROC=`getconf _NPROCESSORS_ONLN`
install_build_deps() {
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex bison libelf-dev dwarves
}
prompt_kernel_version() {
while true; do
echo ""
echo "=============================================================="
echo ""
echo "What version of the kernel do you want to use, '5.8', '5.9' or '${KERNEL_VERSION_511}?'"
echo "5.8 and 5.9 are stable and will be patched with the required changes to allow the touchpad to work."
echo "5.11 is currently a release candidate and therefore not fully stable, however it will not need patching as it contains the necessary changes already."
echo ""
echo "Enter '5.8', '5.9' or '${KERNEL_VERSION_511}':"
read -p "" BUILD_MODE
case $BUILD_MODE in
"5.9" )
KERNEL_VERSION='5.9'
break
;;
"5.8" )
KERNEL_VERSION='5.8'
break;
;;
"${KERNEL_VERSION_511}" )
KERNEL_VERSION=${KERNEL_VERSION_511}
break;
;;
* )
echo "Please enter either 5.11-rc6, 5.9, 5.8."
;;
esac
done
}
#
# Generate Kernel configuration based on current systems existing config.
#
generate_config() {
# Copy in old config
cp /boot/config-`uname -r` .config
echo ""
echo "About to run 'make oldconfig', do you want to accept all new kernel options automatically or do you want to be prompted for each one? [y/n]"
echo " y - (Default) Accept all new options"
echo " n - Prompt for each option"
read -p "" ACCEPT_NEW_CONFIG
case $ACCEPT_NEW_CONFIG in
[Nn]* )
make oldconfig
;;
* )
yes '' | make oldconfig
;;
esac
# Allow adjustments to kernel config
make -j ${PROC} menuconfig
}
#
# Check if we have an existing download of the kernel in the current directory
#
has_kernel() {
if [ "${1}" = "${KERNEL_VERSION_511}" ] ; then
test -f linux-${1}.tar.gz
else
test -f linux-${1}.tar.xz
fi
}
#
# Download kernel into current directory
#
download_kernel() {
echo "Downloading kernel"
if [ "${1}" = "${KERNEL_VERSION_511}" ] ; then
wget https://git.kernel.org/torvalds/t/linux-${1}.tar.gz
else
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${1}.tar.xz
fi
}
#
# Extract kernel
#
extract_kernel() {
echo "Extracting kernel"
if [ "${1}" = "${KERNEL_VERSION_511}" ] ; then
tar xf linux-${1}.tar.gz
else
tar xf linux-${1}.tar.xz
fi
}
#
# Apply touchpad kernel patch
#
apply_patch() {
# Apply a suggested patch for Lenovo Legion 5 touchpad
echo "Downloading patch"
wget https://gist.githubusercontent.com/jbuncle/7dacde983b3c33b3b816b10e2fd2308a/raw/touchpad-kernel-workaround.patch
echo "Applying patch"
# TODO: Use downloaded script
patch -p1 -i touchpad-kernel-workaround.patch
}
#
# Fetches kernel using given version, extracts and enters the source directory.
#
get_kernel_source() {
echo "Using version ${1}"
cd /tmp/
test -d kernel-build-${1} || mkdir kernel-build-${1}
cd kernel-build-${1}
# Check for existing download
if [ ! -d linux-${1} ] ; then
# Fetch kernel source
has_kernel ${1} || download_kernel ${1}
# Extract kernel
extract_kernel ${1}
cd linux-${1}
if [ "${1}" != "${KERNEL_VERSION_511}" ] ; then
apply_patch
else
echo "Not applying patches (using version '${KERNEL_VERSION_511}' which should already contain required updates )"
fi
else
echo "Using existing downloaded source"
cd linux-${1}
fi
}
build_and_install_kernel() {
LOCALVERSION=-touchpad-patch
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
prompt_kernel_version
VERSION=${KERNEL_VERSION}
get_kernel_source ${VERSION}
generate_config
# Build kernel deb packages
echo "Running 'make clean'"
make -j ${PROC} clean
echo "Creating linux kernel deb packages with 'make deb-pkg'"
sudo make -j ${PROC} CONFIG_HID=y CONFIG_I2C_HID=y deb-pkg LOCALVERSION=${LOCALVERSION}
cd ..
# Locate the freshly built deb packages
LINUX_IMG_DEB=$(ls linux-image-*_amd64.deb | grep -v "\-dbg_" | head -n 1)
LINUX_IMG_HEADERS=$(ls linux-headers-*_amd64.deb | head -n 1)
# Install the new kernel with deb package manager
sudo dpkg -i ${LINUX_IMG_DEB}
sudo dpkg -i ${LINUX_IMG_HEADERS}
echo ""
echo "=========="
echo "Now update '/etc/default/grub', setting GRUB_CMDLINE_LINUX_DEFAULT to contain 'i2c_hid.polling_mode=1' e.g.:"
echo ' GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i2c_hid.polling_mode=1"'
echo "(Don't forget to run 'sudo update-grub')"
echo 'Then reboot and select the new kernel'
echo "=========="
echo ""
# TODO: Prompt update and prompt reboot
}
build_and_install_module() {
KERNEL_PATH=$(modinfo --filename i2c-hid)
BUILD_SPACE=/tmp/build/i2c-hid
MODULE_DOWNLOAD=https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1887190/+attachment/5422562/+files/i2c-hid_standalone.zip
MODULE_EXP_CHECKSUM=30cec04d640cbfe0f0f3bc8e68478ebf
# Check module is active
lsmod | grep i2c_hid || (echo "Module i2c_hid doesn't seem to be enabled"; exit)
# Download patched module source
if [ ! -d ${BUILD_SPACE} ] ; then
cd /tmp
rm -rf i2c-hid_standalone i2c-hid_standalone.zip
mkdir -p $(dirname ${BUILD_SPACE})
echo "Downloading module source code"
wget https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1887190/+attachment/5422562/+files/i2c-hid_standalone.zip
DOWNLOAD_MD5=$(md5sum i2c-hid_standalone.zip | awk '{ print $1 }')
if [ "${DOWNLOAD_MD5}" != "${MODULE_EXP_CHECKSUM}" ] ; then
echo "Checksum '${DOWNLOAD_MD5}' failed to match '${MODULE_EXP_CHECKSUM}'"
fi
unzip -d ${BUILD_SPACE} i2c-hid_standalone.zip
rm i2c-hid_standalone.zip
fi
cd ${BUILD_SPACE}/i2c-hid_standalone
echo "Building module"
make -j ${PROC}
# Backup old, but don't overwrite
test -f "${KERNEL_PATH}.old" || (echo "Backing up existing module to ${KERNEL_PATH}.old" ; sudo cp "${KERNEL_PATH}" "${KERNEL_PATH}.old")
# Replace module
echo "Replacing module with patched version"
sudo cp ${BUILD_SPACE}/i2c-hid_standalone/i2c-hid.ko ${KERNEL_PATH}
# Remove existing module if enabled
echo "Removing module"
sudo rmmod i2c-hid || true
# Insert module into the kernel Temporarilty set with polling_mode
echo "Re-enabling with polling_mode=1 (temporary)"
sudo insmod ${KERNEL_PATH} polling_mode=1
echo ""
echo "=========="
# For some reason, when I did it this way, I had to use "i2c_hid" instead of "i2c-hid"
echo "To activate the patch permanently update '/etc/default/grub', setting GRUB_CMDLINE_LINUX_DEFAULT to contain 'i2c_hid.polling_mode=1' e.g.:"
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i2c_hid.polling_mode=1"'
echo "(Don't forget to run 'sudo update-grub')"
echo "=========="
echo ""
}
brightness_fix() {
LINE='Option \"RegistryDwords\" \"EnableBrightnessControl=1\"'
FILE='/usr/share/X11/xorg.conf.d/10-nvidia.conf'
AFTER='Option \"AllowEmptyInitialConfiguration\"'
echo "Applying brightness fix"
echo "Checking nvidia config"
(grep -q "${LINE}" ${FILE} && echo "Nvidia config already updated") || sudo sed -i "s/${AFTER}/${AFTER}\n ${LINE}/" "${FILE}"
echo "Checking Grub option"
(grep -q "video.use_native_backlight=1" /etc/default/grub && echo "Grub already updated") || (\
echo "Inserting option\n"; \
sudo sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash video.use_native_backlight=1/" /etc/default/grub && \
echo "Updating grub\n" && \
sudo update-grub && \
echo "You will need to reboot\n" \
)
echo "Done"
}
help() {
echo " m - (Riskier but faster) Build the i2c-hid module alone and insert it into you current kernel (this could break your kernel - ideally make sure you have other kernels available)."
echo " This may not work if kernel module signature verification is enabled"
echo " k - (Safer but slower) Compile and install the whole kernel (alongside your existing kernel) with a patched i2c-hid module"
echo " b - Apply screen brightness fix (issue where screen brightness cannot be adjusted)"
echo ""
echo "Note, to build the latest kernel (${KERNEL_VERSION_511}) you will need to choose 'k'"
echo ""
}
do_prompt() {
echo ""
echo "This utility script is intended for use with Ubuntu 20 on Lenovo Legion 5"
echo ""
echo "What do you want to do?"
echo "Build patched module [m], build patched kernel [k], apply brightness fix [b], more info [h]:"
read -p "" BUILD_MODE
case $BUILD_MODE in
[mM]* )
install_build_deps
build_and_install_module
;;
[kK]* )
install_build_deps
build_and_install_kernel
;;
[bB]* )
brightness_fix
;;
[hH]* | "-h" | * )
help
do_prompt
;;
esac
}
do_prompt
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index dbd04492825d..0bb8075424b6 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -36,6 +36,8 @@
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/acpi.h>
+#include <linux/kthread.h>
+#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
@@ -60,6 +62,24 @@
#define I2C_HID_PWR_ON 0x00
#define I2C_HID_PWR_SLEEP 0x01
+/* polling mode */
+#define I2C_POLLING_DISABLED 0
+#define I2C_POLLING_GPIO_PIN 1
+#define POLLING_INTERVAL 10
+
+static u8 polling_mode;
+module_param(polling_mode, byte, 0444);
+MODULE_PARM_DESC(polling_mode, "How to poll - 0 disabled; 1 based on GPIO pin's status");
+
+static unsigned int polling_interval_active_us = 4000;
+module_param(polling_interval_active_us, uint, 0644);
+MODULE_PARM_DESC(polling_interval_active_us,
+ "Poll every {polling_interval_active_us} us when the touchpad is active. Default to 4000 us");
+
+static unsigned int polling_interval_idle_ms = 10;
+module_param(polling_interval_idle_ms, uint, 0644);
+MODULE_PARM_DESC(polling_interval_ms,
+ "Poll every {polling_interval_idle_ms} ms when the touchpad is idle. Default to 10 ms");
/* debug option */
static bool debug;
module_param(debug, bool, 0444);
@@ -158,6 +178,8 @@ struct i2c_hid {
struct i2c_hid_platform_data pdata;
+ struct task_struct *polling_thread;
+
bool irq_wake_enabled;
struct mutex reset_lock;
};
@@ -772,7 +794,9 @@ static int i2c_hid_start(struct hid_device *hid)
i2c_hid_free_buffers(ihid);
ret = i2c_hid_alloc_buffers(ihid, bufsize);
- enable_irq(client->irq);
+
+ if (polling_mode == I2C_POLLING_DISABLED)
+ enable_irq(client->irq);
if (ret)
return ret;
@@ -814,6 +838,86 @@ struct hid_ll_driver i2c_hid_ll_driver = {
};
EXPORT_SYMBOL_GPL(i2c_hid_ll_driver);
+static int get_gpio_pin_state(struct irq_desc *irq_desc)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(&irq_desc->irq_data);
+
+ return gc->get(gc, irq_desc->irq_data.hwirq);
+}
+
+static bool interrupt_line_active(struct i2c_client *client)
+{
+ unsigned long trigger_type = irq_get_trigger_type(client->irq);
+ struct irq_desc *irq_desc = irq_to_desc(client->irq);
+
+ /*
+ * According to Windows Precsiontion Touchpad's specs
+ * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-precision-touchpad-device-bus-connectivity,
+ * GPIO Interrupt Assertion Leve could be either ActiveLow or
+ * ActiveHigh.
+ */
+ if (trigger_type & IRQF_TRIGGER_LOW)
+ return !get_gpio_pin_state(irq_desc);
+
+ return get_gpio_pin_state(irq_desc);
+}
+
+static int i2c_hid_polling_thread(void *i2c_hid)
+{
+ struct i2c_hid *ihid = i2c_hid;
+ struct i2c_client *client = ihid->client;
+ unsigned int polling_interval_idle;
+
+ while (1) {
+ /*
+ * re-calculate polling_interval_idle
+ * so the module parameters polling_interval_idle_ms can be
+ * changed dynamically through sysfs as polling_interval_active_us
+ */
+ polling_interval_idle = polling_interval_idle_ms * 1000;
+ if (test_bit(I2C_HID_READ_PENDING, &ihid->flags))
+ usleep_range(50000, 100000);
+
+ if (kthread_should_stop())
+ break;
+
+ while (interrupt_line_active(client)) {
+ i2c_hid_get_input(ihid);
+ usleep_range(polling_interval_active_us,
+ polling_interval_active_us + 100);
+ }
+
+ usleep_range(polling_interval_idle,
+ polling_interval_idle + 1000);
+ }
+
+ do_exit(0);
+ return 0;
+}
+
+static int i2c_hid_init_polling(struct i2c_hid *ihid)
+{
+ struct i2c_client *client = ihid->client;
+
+ if (!irq_get_trigger_type(client->irq)) {
+ dev_warn(&client->dev,
+ "Failed to get GPIO Interrupt Assertion Level, could not enable polling mode for %s",
+ client->name);
+ return -1;
+ }
+
+ ihid->polling_thread = kthread_create(i2c_hid_polling_thread, ihid,
+ "I2C HID polling thread");
+
+ if (ihid->polling_thread) {
+ pr_info("I2C HID polling thread");
+ wake_up_process(ihid->polling_thread);
+ return 0;
+ }
+
+ return -1;
+}
+
static int i2c_hid_init_irq(struct i2c_client *client)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
@@ -997,6 +1101,15 @@ static void i2c_hid_fwnode_probe(struct i2c_client *client,
pdata->post_power_delay_ms = val;
}
+static void free_irq_or_stop_polling(struct i2c_client *client,
+ struct i2c_hid *ihid)
+{
+ if (polling_mode != I2C_POLLING_DISABLED)
+ kthread_stop(ihid->polling_thread);
+ else
+ free_irq(client->irq, ihid);
+}
+
static int i2c_hid_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
@@ -1090,7 +1203,11 @@ static int i2c_hid_probe(struct i2c_client *client,
if (ret < 0)
goto err_regulator;
- ret = i2c_hid_init_irq(client);
+ if (polling_mode != I2C_POLLING_DISABLED)
+ ret = i2c_hid_init_polling(ihid);
+ else
+ ret = i2c_hid_init_irq(client);
+
if (ret < 0)
goto err_regulator;
@@ -1129,7 +1246,7 @@ static int i2c_hid_probe(struct i2c_client *client,
hid_destroy_device(hid);
err_irq:
- free_irq(client->irq, ihid);
+ free_irq_or_stop_polling(client, ihid);
err_regulator:
regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies),
@@ -1146,7 +1263,7 @@ static int i2c_hid_remove(struct i2c_client *client)
hid = ihid->hid;
hid_destroy_device(hid);
- free_irq(client->irq, ihid);
+ free_irq_or_stop_polling(client, ihid);
if (ihid->bufsize)
i2c_hid_free_buffers(ihid);
@@ -1162,7 +1279,7 @@ static void i2c_hid_shutdown(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client);
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
- free_irq(client->irq, ihid);
+ free_irq_or_stop_polling(client, ihid);
}
#ifdef CONFIG_PM_SLEEP
@@ -1183,15 +1300,16 @@ static int i2c_hid_suspend(struct device *dev)
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
- disable_irq(client->irq);
-
- if (device_may_wakeup(&client->dev)) {
- wake_status = enable_irq_wake(client->irq);
- if (!wake_status)
- ihid->irq_wake_enabled = true;
- else
- hid_warn(hid, "Failed to enable irq wake: %d\n",
- wake_status);
+ if (polling_mode == I2C_POLLING_DISABLED) {
+ disable_irq(client->irq);
+ if (device_may_wakeup(&client->dev)) {
+ wake_status = enable_irq_wake(client->irq);
+ if (!wake_status)
+ ihid->irq_wake_enabled = true;
+ else
+ hid_warn(hid, "Failed to enable irq wake: %d\n",
+ wake_status);
+ }
} else {
regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies),
ihid->pdata.supplies);
@@ -1208,7 +1326,7 @@ static int i2c_hid_resume(struct device *dev)
struct hid_device *hid = ihid->hid;
int wake_status;
- if (!device_may_wakeup(&client->dev)) {
+ if (!device_may_wakeup(&client->dev) || polling_mode != I2C_POLLING_DISABLED) {
ret = regulator_bulk_enable(ARRAY_SIZE(ihid->pdata.supplies),
ihid->pdata.supplies);
if (ret)
@@ -1225,7 +1343,8 @@ static int i2c_hid_resume(struct device *dev)
wake_status);
}
- enable_irq(client->irq);
+ if (polling_mode == I2C_POLLING_DISABLED)
+ enable_irq(client->irq);
/* Instead of resetting device, simply powers the device on. This
* solves "incomplete reports" on Raydium devices 2386:3118 and
@heppix
Copy link

heppix commented Oct 13, 2020

Hey,
Nice script. Good job. I have 2 advices from my noob experience. For building you can use make -j nproc to use all cores instead of 4. It should speed up process a little bit. Second advice, I would recommend to make deb packages for ubuntu build and then install it from them.
For this, you could use make -j getconf _NPROCESSORS_ONLN deb-pkg LOCALVERSION=-custom command.
For more info, check https://wiki.ubuntu.com/KernelTeam/GitKernelBuild

@edit
Editor parse my comment since I used ``` sign. Keep in mind there is ` in commands.

@jbuncle
Copy link
Author

jbuncle commented Oct 13, 2020

Hey,
Nice script. Good job. I have 2 advices from my noob experience. For building you can use make -j nproc to use all cores instead of 4. It should speed up process a little bit. Second advice, I would recommend to make deb packages for ubuntu build and then install it from them.
For this, you could use make -j getconf _NPROCESSORS_ONLN deb-pkg LOCALVERSION=-custom command.
For more info, check https://wiki.ubuntu.com/KernelTeam/GitKernelBuild

@edit
Editor parse my comment since I used ``` sign. Keep in mind there is ` in commands.

Thanks for the tips! I've made those changes so it now builds the kernel deb packages then installs them (using more processes). Hopefully this way it will be easy to cleanup when a fix is available in Ubuntu.

@jbuncle
Copy link
Author

jbuncle commented Oct 18, 2020

Updated to give the option to build the i2c_hid module standalone, as per the continued discussion in https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1887190

@sadmansakib00
Copy link

Is the any fix for the brightness control of Lenovo Legion 5 in Ubuntu? I'm using Ubuntu 20.04 and can't seem to find any solution for it.

@adiadi2
Copy link

adiadi2 commented Feb 1, 2021

@ChasedByDeath for me this is working on discrete graphic with stock kernel 5.8.0-41-generic and nvidia 460 default driver

Brightness in Ubuntu 20.04 / 20.10 linux

1- Install the nvidia propietary driver

sudo nano /usr/share/X11/xorg.conf.d/10-nvidia.conf

Add entry:

Option "RegistryDwords" "EnableBrightnessControl=1"

Example of the section:

Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration"
Option "RegistryDwords" "EnableBrightnessControl=1"
ModulePath "/usr/lib/nvidia/xorg"
ModulePath "/usr/lib/xorg/modules"
EndSection

sudo nano /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video.use_native_backlight=1"

sudo update-grub2

sudo reboot

Hope this helps.

@sadmansakib00
Copy link

Hey. Thanks for the reply.
I followed your instructions and it didn't work apparently.
I appreciate taking your time to reply me though.

@adiadi2
Copy link

adiadi2 commented Feb 3, 2021

@ChasedByDeath I forgot to mention that it probably don't work in switchable graphic mode, try to select discrete graphic mode in bios/uefi settings or use X.Org.X server-nouveau driver for switchable graphic mode at least it works for me that way.

@jbuncle
Copy link
Author

jbuncle commented Feb 5, 2021

Not sure what this brightness issue is, mine is fine with a pretty plain install.

I've updated the script to give the option to install the current latest 5.11 release, which has the anticipated updates. Obviously you don't need the script if you know how to install a kernel from source. This might help with any other issues that could also be fixed in the release.

I'm currently running with that kernel version and it seems fine.

@adiadi2
Copy link

adiadi2 commented Feb 5, 2021

@jbuncle I don't know what vrrsion your laptop is, mine is 15arh05H with ryzen5 4600H, gtx 1660ti mobile and with plain kernel 5.8 generic brightness ctrl (fn+f4 f5) doesn't work with nvidia driver (it does with the fix from above).
Does nvidia driver work with 5.11, I've tried 5.11 rc5 before your how to for i2c standalone but couldn't get it to work with nvidia driver, just with nouveau driver, and if it does can you please post steps for installation (driver version, where to get it from, how to install it...)
I'm new to linux and this how tos - scripts worth a lot for me to analyze it and figire out what every line does.
thanks

@jbuncle
Copy link
Author

jbuncle commented Feb 6, 2021

@adiadi2 I see, I was expecting the issue to be that the Fn combo didn't work at all and didn't notice it not actually changing the brightness.

I've added the fix you described as an extra option to the script for convenience (which works for me).

So for me everything appears to work fine (touchpad and brightness) - Ubuntu 20.10, Linux kernel 5.11-rc6 (with grub i2c_hid.polling_mode=1), nvidia-driver-460, and the brightness config described applied.

In terms of what the script does, for the Linux Kernel 5.11 it downloads the source, decompresses it, compiles it (using configuration copied from the current running kernel), packs it into a deb packages, then installs the required deb packages for you. (For the other kernels it patches them before compiling to add the necessary fixes for the touchpad). Probably the closest tutorial is this one: https://wiki.ubuntu.com/KernelTeam/GitKernelBuild, but rather than getting the source from git it downloads the relevant zip.

@adiadi2
Copy link

adiadi2 commented Feb 9, 2021

@jbuncle thanks for explaining, do you say that you still have to add "i2c_hid.polling_mode=1" to grub with 5.11?

@jbuncle
Copy link
Author

jbuncle commented Feb 12, 2021

@adiadi2 I've tried Grub without "i2c_hid.polling_mode=1" and touchpad seems to work fine

@jaaneo
Copy link

jaaneo commented Feb 24, 2021

Will it work for arch linux and Lenovo Legion 5 15ARH05?

@antony-jr
Copy link

antony-jr commented May 5, 2021

@adiadi2 I see, I was expecting the issue to be that the Fn combo didn't work at all and didn't notice it not actually changing the brightness.

This is a bug and only openSUSE folks have fixed it(I mean backported it, kernel v5.12 should fix it with amdgpu.backlight=0 kernel param). Please see the below git repo for more info.

There is a workaround without patching the kernel, Please see https://github.com/antony-jr/lenovo-legion5-15arh05-scripts

@rubber-soul
Copy link

I‘m new to linux but from reading your .sh file, I suppose one has to have at least version 5.8 of kernel? I'm currently using Ubuntu 18.04 with 5.4.0-74 generic so I got to first install 5.8 or 5.9?

@rubber-soul
Copy link

@adiadi2 I see, I was expecting the issue to be that the Fn combo didn't work at all and didn't notice it not actually changing the brightness.

This is a bug and only openSUSE folks have fixed it(I mean backported it, kernel v5.12 should fix it with amdgpu.backlight=0 kernel param). Please see the below git repo for more info.

There is a workaround without patching the kernel, Please see https://github.com/antony-jr/lenovo-legion5-15arh05-scripts

Does the touchpad workaround in your repo require that kernel version must be 5.12.x?

@antony-jr
Copy link

@adiadi2 I see, I was expecting the issue to be that the Fn combo didn't work at all and didn't notice it not actually changing the brightness.

This is a bug and only openSUSE folks have fixed it(I mean backported it, kernel v5.12 should fix it with amdgpu.backlight=0 kernel param). Please see the below git repo for more info.
There is a workaround without patching the kernel, Please see https://github.com/antony-jr/lenovo-legion5-15arh05-scripts

Does the touchpad workaround in your repo require that kernel version must be 5.12.x?

No workaround is required in 5.12.x(Touchpad works without any workaround in this version) but for linux kernel below 5.12.x you need the workaround.

@yashpatel1392
Copy link

I have recently purchased Lenovo Legion 5i Pro, I am trying to run Ubuntu 18.04, but the touchpad doesnt work at all. I tried all the fixes online, can you please try to explain me how to get it working or how to use your fix to get is working?

@antony-jr
Copy link

I have recently purchased Lenovo Legion 5i Pro, I am trying to run Ubuntu 18.04, but the touchpad doesnt work at all. I tried all the fixes online, can you please try to explain me how to get it working or how to use your fix to get is working?

@yashpatel1392 Nope. Ubuntu 18.04 is not supported. You need at least linux kernel 5.11. Better try some rolling distro like Manjaro Linux. You can try this but I highly recommend you to use linux kernel 5.12 or above for legion laptops.

su # Make yourself root user.
cd /sys/class/gpio/
echo 386 > export
cd gpio386
echo out > direction
# Your touchpad should start working

@yashpatel1392
Copy link

I have recently purchased Lenovo Legion 5i Pro, I am trying to run Ubuntu 18.04, but the touchpad doesnt work at all. I tried all the fixes online, can you please try to explain me how to get it working or how to use your fix to get is working?

@yashpatel1392 Nope. Ubuntu 18.04 is not supported. You need at least linux kernel 5.11. Better try some rolling distro like Manjaro Linux. You can try this but I highly recommend you to use linux kernel 5.12 or above for legion laptops.

su # Make yourself root user.
cd /sys/class/gpio/
echo 386 > export
cd gpio386
echo out > direction
# Your touchpad should start working

Thanks for the response. I have updated my kernel to be 5.12. So, should your solution work?

@antony-jr
Copy link

antony-jr commented Sep 23, 2021

I have recently purchased Lenovo Legion 5i Pro, I am trying to run Ubuntu 18.04, but the touchpad doesnt work at all. I tried all the fixes online, can you please try to explain me how to get it working or how to use your fix to get is working?

@yashpatel1392 Nope. Ubuntu 18.04 is not supported. You need at least linux kernel 5.11. Better try some rolling distro like Manjaro Linux. You can try this but I highly recommend you to use linux kernel 5.12 or above for legion laptops.

su # Make yourself root user.
cd /sys/class/gpio/
echo 386 > export
cd gpio386
echo out > direction
# Your touchpad should start working

Thanks for the response. I have updated my kernel to be 5.12. So, should your solution work?

@yashpatel1392 With linux kernel 5.12 you DO NOT NEED ANY workaround at all. Maybe you just disabled your touchpad with F10?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment