Skip to content
Create a gist now

Instantly share code, notes, and snippets.

Hack to control the keyboard backlight level on a Thinkpad Lenovo X1 Carbon Touch
/* gcc -o tmp `pkg-config --libs --cflags glib-2.0` tmp.c
*
* # modprobe ec_sys
*
* # watch -n 0.1 hexdump -C /sys/kernel/debug/ec/ec0/io
*
* 00000000 a7 05 a0 e2 00 86 05 00 00 00 47 00 00 03 00 10 |..........G.....|
* 00000000 a7 05 a0 e2 00 86 05 00 00 00 47 00 00 43 00 10 |..........G..C..|
* 00000000 a7 05 a0 e2 00 86 05 00 00 00 47 00 00 83 00 10 |..........G.....|
*
* # ./tmp 0
* # ./tmp 1
* # ./tmp 2
*
*/
#include <glib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
char levels[] = {
0x03,
0x43,
0x83
};
static void
usage (char **argv)
{
g_print ("%s [level]\n", argv[0]);
g_print ("Where level is between 1 and 3\n");
}
int main (int argc, char **argv)
{
int fd;
int level;
if (argc < 2) {
usage (argv);
return 1;
}
level = atoi(argv[1]);
if (level < 0 || level > 3) {
usage (argv);
return 1;
}
fd = open ("/sys/kernel/debug/ec/ec0/io", O_RDWR);
if (fd < 0) {
g_print ("open: %s\n", g_strerror (errno));
return 1;
}
if (lseek (fd, 0xd, SEEK_CUR) < 0) {
g_print ("seek: %s\n", g_strerror (errno));
return 1;
}
if (write (fd, &levels[level], 1) < 0) {
g_print ("write: %s\n", g_strerror (errno));
return 1;
}
return 0;
}
@rashad612

Thank you for this great gist, as it solved our needed issue. I posted an answer based on this gist:

http://askubuntu.com/questions/383501/enable-the-keyboard-backlights-on-supported-lenovo-e-g-carbon-x1-with-command/

@pieces029

Any chance this will work for the 2014 none touch version?

@mberkowski

Thanks! Confirmed this works on a Fedora 20 system, compiled with:

$ gcc -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include thinklight.c -o ThinkLight -lglib-2.0
@rossigee
rossigee commented Nov 9, 2014

Dude, nice one. 1 coffee @changetip

@iwansyahp

is this code gonna work on Toshiba U945, or do I need change this code for getting my keyboard backling works?

@maltinho

I've the 3rd edition of the x1 carbon, running ubuntu on it with kernel 3.19.0-25-generic.
Seems to be that the path on this machine is different. There is no "/sys/kernel/debug/ec/ec0/io" on my system.

root@X1:~# ls /sys/kernel/debug/
acpi           fault_around_bytes  kvm-guest         regulator
bdi            frontswap           mce               sched_features
bluetooth      gpio                mei0              sleep_time
cleancache     hid                 pinctrl           suspend_stats
clk            ieee80211           pkg_temp_thermal  tracing
dma_buf        intel_powerclamp    pstate_snb        usb
dri            iosf_sb             pwm               virtio-ports
dynamic_debug  iwlwifi             ras               wakeup_sources
extfrag  

Any idea?

Thanks in advance!

@bruno066

I am experiencing the same issue as @maltinho, with the same laptop. By the way, even if I expect no difference, my thinkpad is not a touch one.

Hopping this will be solved, thanks in advance

@epi
epi commented Sep 28, 2015

Works on ThinkPad T430s with Ubuntu 14.04, thanks! It's really helpful since my Fn key stopped working.

@chriswareham

Here's a version that doesn't need libglib:

/* gcc -Wall -Werror -o backlight backlight.c
 *
 * # modprobe ec_sys
 *
 * # watch -n 0.1 hexdump -C /sys/kernel/debug/ec/ec0/io
 *
 * 00000000  a7 05 a0 e2 00 86 05 00  00 00 47 00 00 03 00 10  |..........G.....|
 * 00000000  a7 05 a0 e2 00 86 05 00  00 00 47 00 00 43 00 10  |..........G..C..|
 * 00000000  a7 05 a0 e2 00 86 05 00  00 00 47 00 00 83 00 10  |..........G.....|
 *
 * # ./backlight 0
 * # ./backlight 1
 * # ./backlight 2
 *
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static char levels[] = {
    0x03,
    0x43,
    0x83
};

static void
usage(char **argv)
{
    printf("%s [level]\n", argv[0]);
    printf("Where level is between 1 and 3\n");
}

int
main(int argc, char **argv)
{
    int fd;
    int level;

    if (argc < 2) {
        usage(argv);
        return 1;
    }

    level = atoi(argv[1]);

    if (level < 0 || level > 3) {
        usage(argv);
        return 1;
    }

    fd = open("/sys/kernel/debug/ec/ec0/io", O_RDWR);

    if (fd < 0) {
        printf("open: %s\n", strerror(errno));
        return 1;
    }

    if (lseek(fd, 0xd, SEEK_CUR) < 0) {
        printf("seek: %s\n", strerror(errno));
        return 1;
    }

    if (write(fd, &levels[level], 1) < 0) {
        printf("write: %s\n", strerror(errno));
        return 1;
    }

    return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.