Lenovo ThinkPad X1 Carbon (Gen 2)

出自 ArchWiki

本条目或章节不符合笔记本电脑页面指南

原因: 需要添加辅助功能和功能键章节。(在Talk:Lenovo ThinkPad X1 Carbon (Gen 2)中讨论)
硬件 PCI/USB ID 工作?
GPU 8086:0a16
音频 8086:9c20
Wi-Fi 8086:08b2
以太网 8086:155a
WWAN 1199:a001
GPS 未测试
蓝牙 8087:07dc
摄像头 04ca:7036
指纹识别器 138a:0017
触控板
触摸屏

几乎所有功能开箱即用。大多数硬件基于 Intel Lynx Point 参考设计。

电源管理

内核模块 thinkpad_acpi 拾取大多数传感器。当前不支持内核模块 tp_smapi。PCIe ASPM 当前无法工作。

Udev 不会在电池电量减少 1% 时发出通知,但会在 80%、20%、5%、4% 和 0% 时发出通知。要利用这一点,请参阅(低电量时挂起 Laptop#Hibernate on low battery level

从挂起唤醒

从挂起唤醒在早期版本的 bios 中可能存在错误,请参阅:[1]

这可以通过将 bios 刷新到 >=1.13 版本来解决。在此处查找联想的 bios 版本:[2]

有关如何制作可引导 BIOS 密钥驱动器的指南,请参见此处:[3]

以及联想在此处提供的一些相当旧的帮助:[4]

如果功能键在挂起后无法唤醒,请确保您的内核版本 >=3.15。

如果您构建自己的内核,请确保启用 TPM(可信平台模块)驱动程序或在 BIOS 中禁用安全芯片。

键盘

在内核 3.14 及更低版本中,键盘顶部的自适应面板锁定为功能模式。

从内核 3.15 开始,主页模式也可用,允许访问屏幕亮度和其它控件。

如果您希望重新映射按键以恢复到合理的键盘布局,您可以使用 xmodmap 或其它 输入重映射工具

打字时自动打开键盘背光

键盘背光开箱即用,软键盘上有一个按钮可以在关闭、低亮度和高亮度之间切换。使用持续检查键盘输入的 C 程序,可以仅在特定时间激活背光。

本条目或章节已过时。

程序源代码如下

kbdbacklight.c
/* Original Author: Howard Chu <hyc@symas.com> 2013-01-15
 *
 * compile as "gcc -O2 -o kbdbacklight kbdbacklight.c" and run it in the background, or arrange to have it run at bootup.
 *
 * adapted by gabtub@gmail.com 2017-01-22
 * using https://gist.github.com/hadess/6847281
 * based on http://askubuntu.com/questions/383501/enable-the-keyboard-backlights-on-supported-lenovo-e-g-carbon-x1-with-command
 * original code found at  http://forum.notebookreview.com/threads/asus-keyboard-backlight-controller.703985/
 * sigterm catching done as shown in https://airtower.wordpress.com/2010/06/16/catch-sigterm-exit-gracefully/
 *
 * fixed by sva 2022-10-08
 * refactored the whole code out of boredom. keyboard should now be detected automatically using libudev.h 2023-06-25
 * uses /sys/class/leds/, s.t. ec_sys is not necessary
 *
 * monitor keyboard activity and toggle keyboard backlight
 */
#include <stdio.h> // fprintf(), snprintf(), stderr
#include <unistd.h> // write(), close(), read()
#include <string.h> // strlen(), strncpy()
#include <fcntl.h> // open(), O_RDONLY, O_WRONLY
#include <limits.h> // PATH_MAX
#include <poll.h> // poll()

#include <linux/input.h> // struct input_event, EV_KEY
#include <libudev.h> // udev stuff

#define IDLE_MSEC 1000
#define BRGHT_OFF 0
#define BRGHT_MED 128
#define BRGHT_HI 255

static volatile int running = 1;

static int find_keyboard(char* devnode, size_t size) {
  struct udev* udev = udev_new();
  if (!udev) {
    fprintf(stderr, "Failed to create udev context\n");
    return -1;
  }

  struct udev_enumerate* enumerate = udev_enumerate_new(udev);
  if (!enumerate) {
    fprintf(stderr, "Failed to create udev enumerate\n");
    udev_unref(udev);
    return -1;
  }

  udev_enumerate_add_match_subsystem(enumerate, "input");
  udev_enumerate_add_match_property(enumerate, "ID_INPUT_KEYBOARD", "1");
  udev_enumerate_scan_devices(enumerate);

  struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
  struct udev_list_entry* entry;
  int found = 0;

  udev_list_entry_foreach(entry, devices) {
    const char* path = udev_list_entry_get_name(entry);
    struct udev_device* dev = udev_device_new_from_syspath(udev, path);
    if (!dev) {
      fprintf(stderr, "Failed to create udev device\n");
      continue;
    }

    const char* devnode_path = udev_device_get_devnode(dev);
    if (devnode_path) {
      if (strlen(devnode_path) < size) {
        strncpy(devnode, devnode_path, size);
        found = 1;
        break;
      } else {
        fprintf(stderr, "Device node path is too long\n");
      }
    }

    udev_device_unref(dev);
  }

  udev_enumerate_unref(enumerate);
  udev_unref(udev);

  return found ? 0 : -1;
}

static int set_backlight(int brightness) {
  char buf[16];
  snprintf(buf, sizeof(buf), "%d", brightness);
  int fd = open("/sys/class/leds/tpacpi::kbd_backlight/brightness", O_WRONLY);
  if (fd < 0) {
    fprintf(stderr, "Failed to open keyboard backlight file\n");
    return -1;
  }
  if (write(fd, buf, strlen(buf)) != strlen(buf)) {
    fprintf(stderr, "Failed to set keyboard backlight\n");
    close(fd);
    return -1;
  }
  close(fd);
  return 0;
}

static void handle_input(int fd, int* brightness) {
  struct input_event ev;
  int rc = read(fd, &ev, sizeof(ev));
  if (rc > 0) {
    if (ev.type == EV_KEY && ev.value == 1) {
      set_backlight(BRGHT_HI);
      *brightness = BRGHT_HI;
    }
  }
}

static void handle_timeout(int fd, int* brightness) {
  set_backlight(BRGHT_OFF);
  *brightness = BRGHT_OFF;
}

static void handle_poll(int fd, int* brightness) {
  struct pollfd pfd;
  pfd.fd = fd;
  pfd.events = POLLIN;
  int timeout = IDLE_MSEC;
  while (running) {
    int rc = poll(&pfd, 1, timeout);
    if (rc > 0) {
      handle_input(fd, brightness);
      timeout = IDLE_MSEC;
    } else if (rc == 0) {
      handle_timeout(fd, brightness);
      timeout = -1;
    }
  }
}

int main(int argc, char** argv) {
  char devnode[PATH_MAX];
  if (find_keyboard(devnode, sizeof(devnode)) < 0) {
    fprintf(stderr, "Failed to find keyboard device\n");
    return 1;
  }

  int fd = open(devnode, O_RDONLY);
  if (fd < 0) {
    fprintf(stderr, "Failed to open keyboard device\n");
    return 1;
  }

  int brightness = BRGHT_OFF;
  set_backlight(brightness);
  handle_poll(fd, &brightness);
  close(fd);
  return 0;
}

此文件可以使用以下命令编译

$ gcc -O2 -o kbdbacklight kbdbacklight.c -ludev

并且必须以 root 身份执行。

可以通过创建 systemd 服务来自动启动它,如下所示

  • 创建一个文件夹 /usr/local/customscripts/kbdbacklight/
  • 将编译后的 c 程序保存到 /usr/local/customscripts/kbdbacklight/kbdbacklight
  • 在同一文件夹中创建以下 bash 脚本
/usr/local/customscripts/kbdbacklight/kbdbacklight.sh
#!/bin/bash
# must be executed as root
./kbdbacklight &
RETVAL=$?
PID=$!
[ $RETVAL -eq 0 ] && echo $PID > /usr/local/customscripts/kbdbacklight/pid
  • 创建以下 systemd 服务并将其放置在 /etc/systemd/system/kbdbacklight.service 中
/etc/systemd/system/kbdbacklight.service
[Unit]
Description=starts a daemon monitoring keyboard usage. will turn on keyboard backlight until no key is pressed for a TIMEOUT period
Requires=
After=

[Service]
Type=forking
User=root
WorkingDirectory=/usr/local/customscripts/kbdbacklight/
ExecStart=/usr/local/customscripts/kbdbacklight/kbdbacklight.sh &
PIDFile=/usr/local/customscripts/kbdbacklight/pid

[Install]
WantedBy=multi-user.target
注意: 通过调整 C 程序中的常量 IDLE_MSEC(并重新编译),指定再次关闭背光的超时时间量。

触控板

本条目或章节的事实准确性存疑。

原因: 当同时安装 xf86-input-synapticsxf86-input-libinput 时,指点杆(红色小点)默认使用 libinput,因此它不与触控板(默认情况下由 synaptics 驱动)协作,结果您无法使用中键 + 指点杆滚动。仅保留 xf86-input-libinput 可以使一切正常工作。(在Talk:Lenovo ThinkPad X1 Carbon (Gen 2)中讨论)

要启用触控板支持,您需要安装 xf86-input-synaptics

点击时锁定

触控板在点击时锁定存在重大问题。这是由于触控板在有缺陷的 PS/2 模式下运行。

一种替代方法是完全放弃触控板并使用指点杆。确保未安装 xf86-input-synaptics - 触控板仍会注册鼠标左键单击。使用 xbindkeys Xbindkeysxdotool,可以将右键单击映射到其它事件。例如

~/.xbindkeysrc
# Emit a right click on Alt + trackpad click
"xdotool click 3"
  Mod1 + b:1 + Release

调整触控板行为

默认情况下,触控板的行为可能与您的期望相反,特别是如果您来自 OS X 风格的触控板。以下设置可以显著帮助

/etc/X11/xorg.conf.d/99-x1carbon.conf
# Copy this to /etc/X11/xorg.conf.d/99-x1carbon.conf
 Section "InputClass"
     Identifier "X1 carbon stuff"
     MatchIsTouchpad "on"
     MatchDevicePath "/dev/input/event*"
     Driver "synaptics"

     # Enable two finger scrolling vertically, disable horizontally
     Option "VertTwoFingerScroll" "1"
     Option "HorizTwoFingerScroll" "0"

     # No scrolling along the edge
     Option "VertEdgeScroll" "0"
     Option "HorizEdgeScroll" "0"

     Option "LockedDrags" "0"
     Option "FingerPress" "1"

     # Turn off the blasted corners as buttons
     Option "RTCornerButton" "0"
     Option "RBCornerButton" "0"
     Option "LTCornerButton" "0"
     Option "LBCornerButton" "0"

     # Ignore "taps" and listen for "clicks"
     Option "TapButton1" "0"
     Option "TapButton2" "0"
     Option "TapButton3" "0"
     Option "ClickFinger1" "1" # Left click one finger
     Option "ClickFinger2" "3" # Right click two fingers
     Option "ClickFinger3" "0" # Three finger click disabled

     Option "TapAndDragGesture" "0"

     # No circular scrolling
     Option "CircularScrolling" "0"
 EndSection

如果您使用 gnome-shell,您可能需要告知设置应用不要覆盖我们的更改

$ gsettings set org.gnome.settings-daemon.plugins.mouse active false

从睡眠唤醒后触控板无法工作

参见 Touchpad Synaptics#从休眠/挂起恢复后触控板无法工作

音频

您可能需要在其 内核模块参数 中添加默认声卡选项

/etc/modprobe.d/alsa-base.conf
options snd_hda_intel index=1

ALSA 前置放大器

在运行 Linux 的笔记本电脑上,一个常见的问题是声音即使调到最大也不够大。这可以通过添加 ALSA 前置放大器来解决。

安装 alsa-utils

将 /etc/asound.conf 中的配置更改为以下内容(您可能必须调整卡号)

# Set your DEFAULT device to the softvol plug-in
# NOT to a hardware card device
#
# The "!" means completely override the previous default
# Not just changing/adding to it.
pcm.!default {
  type plug
  slave.pcm "softvol"
}

# Configure softvol
pcm.softvol {
  type softvol

  # Send softvol's output to dmix
  slave {
    pcm "dmix"
    # If you wanted to you could send the output to a card directly
    # But in most cases it's better to send it to dmix and let
    # dmix handle where to send it. You can add a whole extra section
    # to configure dmix and where it sends output, but I'm
    # not covering that here.

    ## Use Card 0 Device 0 instead of dmix
    # pcm "hw:0,0"
    ## Use Card 2 Device 0 instead of dmix
    # pcm "hw:2,0"
  }

  # Add a control slider in your mixer interfaces
  # i.e. KMix and alsamixer
  control {
    name "Pre-Amp"
    card 0 #<CardNumberYouWantControlToShowOn> i.e. card 0 or card 2
  }

  # Minimum dB when slider is at 0%
  min_dB -5.0

  # Maximum DB when slider is at 100%
  max_dB 40.0

  # How many levels the slider should go through
  # i.e. how granular do you want your control to be
  resolution 12
}

摘自 此处

警告: 如果您将音量调得太高,可能会永久损坏您的扬声器!

处理器

参见 微码 了解如何更新到处理器的微码。

BIOS 更新

要从 Linux 安装 BIOS 更新,请从此处下载可引导 iso

由于没有光驱,因此可以使用此方法(德语)。

网络

有线

右侧有一个用于以太网的小端口。需要一个适配器。如果适配器丢失,订购的零件编号为 04X6435。

无线

开箱即用。模块 iwlwifi 应该由 udev 自动加载。

$ lspci
Network controller: Intel Corporation Wireless 7260 (rev 83)

显示

触摸屏

开箱即用,支持单点触控。硬件是多点触控,但当前稳定的驱动程序仅支持鼠标左键单击模拟。似乎可以使用 Touchegg

HiDPI

由于显示器具有如此高的像素密度,您可能会遇到问题。请参阅此处:HiDPI

参见