Тонка настройка ACPI на прикладі Thinkpad X220

Лірика
За минулі пару місяців мені досить часто доводилося вступати в дискусії про всіляких портативних комп'ютерах: ламати списи в суперечках який виробник краще і чому, обговорювати сумісність з GNU/Linux і те, як у цій системі налаштувати ту чи іншу функцію і, періодично, мене таки просять поділитися конфіг. Під впливом цих обговорень і народилася ця стаття.

Більшу частину свого комп'ютерного стажу я користуюся лаптопами так званої «бізнес серії»: IBM ThinkPad 600, HP-Compaq nc2400, Lenovo ThinkPad X61T, Lenovo ThinkPad X220.



Були короткочасні перерви, коли доводилося перебиватися аби-чим, чи то пак комп'ютерами споживчого сегмента: Apple ibook G4 і Acer aspire 5112 і саме в ці моменти приходило розуміння того, як сильно не вистачає таких очевидних і звичних речей, як трекпоинт і док-станція.



Що це таке? Підставка для лаптопа з роз'ємом живлення і всілякими додатковими портами. В деякі моделі можна встановити додатковий жорсткий диск або акумулятор. Док-станція позбавляє від необхідності кожного разу підключати весь набір кабелів, приходячи на робоче місце і від'єднувати, йдучи.

Особливо зручна така конфігурація під управлінням GNU/Linux (в моєму випадку, Debian stable), де кількома сценаріями можна детально описати поведінку комп'ютера.

Опис сценарію роботи
На роботі я використовую конфігурацію із зовнішнім монітором і bluetooth клавіатурою Lenovo ThinkPad kt1255. Лаптоп практично ніколи не вимикається, замість цього використовується suspend to ram. Опишу сценарії обробників:

— Пробудження в доці з закритою кришкою: включити зовнішній монітор, активувати bluetooth і підключити клавіатуру, cpu performance
— Відкриття кришки в доці: погасити зовнішній монітор і перевести зображення на внутрішній
— Витяг з відкритою кришкою: додатково відключить клавіатуру і bt, cpu on-demand
— Витягу з закритою кришкою: залочить екран, перевести зображення на внутрішній екран відключивши зовнішній, вирубати клавіатуру і bt-модуль, cpu в on-demand, перейти у pm-suspend
— Закриття кришки не в доці: блокування екрану, pm-suspend

Безпосередньо налаштування
Якими-небудь DE я не користуюся, та й не бачу сенсу покладати на них функцію управління живленням. Тому, будемо налаштовувати засобами acpid.

Налаштування починаємо, як завжди, з установки потрібних програм:
#apt-get install acpid acpi-support cpufrequtils


Далі, дивимося які події у нас генера при відстиковки лаптопа:
#acpi_listen
ac_adapter ACPI0003:00 00000080 00000000
ibm/hotkey LEN0068:00 00000080 00006030
thermal_zone LNXTHERM:00 00000081 00000000
battery PNP0C0A:00 00000080 00000001
ibm/hotkey LEN0068:00 00000080 00004011


При стикуванні:
#acpi_listen
ibm/hotkey LEN0068:00 00000080 00004010
ac_adapter ACPI0003:00 00000080 00000001
ibm/hotkey LEN0068:00 00000080 00006030
thermal_zone LNXTHERM:00 00000081 00000000
battery PNP0C0A:00 00000080 00000001
button/lid LID close


Варто відзначити, що ThinkPad Mini Dock Series 3 не надає proc інтерфейсу.

Напишемо правила для подій:
#vim /etc/acpi/events/thinkpad-dock
event=ibm/hotkey LEN0068:00 00000080 00004010
action=/etc/acpi/thinkpad-dock.sh

#vim /etc/acpi/events/thinkpad-undock
event=ibm/hotkey LEN0068:00 00000080 00004011
action=/etc/acpi/thinkpad-undock.sh


Правило на закриття кришки йде в комплекті з пакетом acpi-support. Наведемо його до належного вигляду, вказавши шлях до скрипта-обробникові:
#vim /etc/acpi/events/lidbtn
event=button[ /]lid
action=/etc/acpi/lid.sh


А тепер перейдемо до найцікавішого: скриптам, що описує реакцію на події при описаних вище умовах.

#vim /etc/acpi/lid.sh

#!/bin/bash

#перевіряємо, чи підключений лаптоп до док-станції
grep -q on /etc/tp_dock_state;
if [ $? = 0 ] 
then
#якщо так, перевіряємо відкрита кришка
grep -q open /proc/acpi/button/lid/*/state
if [ $? = 0 ] 
then
#якщо так, включаємо вбудований монітор, гасимо зовнішній
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --auto'
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --off'
else
#якщо ні, включаємо зовнішній, гасимо вмонтований
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --auto'
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --off'
#включаємо bluetooth-модуль і запускаємо сервіс
echo enabled> /proc/acpi/ibm/bluetooth
/etc/init.d/bluetooth start
#підключаємо bluetooth клавіатуру. 
echo 'connect 90:7F:61:10:A3:BC'|bluetoothctl
#виставляємо перемикання розкладки з alt_gr, подгружаем кастомні биндинги
DISPLAY=:0.0 su user -c 'setxkbmap -option grp:toggle us,ru'
DISPLAY=:0.0 su user -c 'xmodmap ~/.xmodmaprc'
fi
else
#якщо не підключений
grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ] 
then
#відключаємо відключаємо клавіатуру, зупиняємо сервіс і відключаємо bt-модуль
echo 'disconnect 90:7F:61:10:A3:BC'|bluetoothctl
/etc/init.d/bluetooth stop
echo disabled> /proc/acpi/ibm/bluetooth
#викликаємо з правами користувача user блокувальник екрану
DISPLAY=:0.0 su user -c /home/user/bin/lock
#переводимо изоражение на вбудований екран
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --auto'
#відключаємо зовнішній
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --off'
#відправляємо лаптоп спати
pm-suspend
#при пробудженні перевіряємо, в доці чи thinkpad:
grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ] 
then
#якщо так, то, повідомляємо про це:
echo on >/etc/tp_dock_state
#включаємо зовнішній монітор і гасимо вбудований
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --auto'
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --off'
#включаємо bt-модуль, запускаємо сервіс, підключаємо bt-клавіатуру
echo enabled> /proc/acpi/ibm/bluetooth
/etc/init.d/bluetooth start
echo 'connect 90:7F:61:10:A3:BC'|bluetoothctl
#подгружаем розкладку і биндинги
DISPLAY=:0.0 su user -c 'setxkbmap -option grp:toggle us,ru'
DISPLAY=:0.0 su user -c 'xmodmap ~/.xmodmaprc &'
fi
else
#якщо ні, то просто включаємо вбудований екран
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --auto'
fi 


Поясню, на всяк випадок, що 90:7F:61:10:A3:BC — це адреса моєї клавіатури. Налаштовуються bluetooth пристрою досить просто:
#apt-get install bluez
#bluetoothctl
[NEW] Controller 40:2C:F4:BB:3C:FC nethack [default]
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent 
Default request agent successful
[bluetooth]# scan on
Discovery started
[CHG] Controller 40:2C:F4:BB:3C:FC nethack [default]
[NEW] Device 90:7F:61:10:A3:BC ThinkPad Compact Bluetooth Keyboard with TrackPoint
[bluetooth]# pair 90:7F:61:10:A3:BC
Attempting to pair with 90:7F:61:10:A3:BC
[CHG] Device 90:7F:61:10:A3:BC Connected: yes
[agent] PIN code: 12345 #вводимо з клавіатури PIN
[bluetooth]# connect 90:7F:61:10:A3:BC
Attempting to connect to 90:7F:61:10:A3:BC
Connection successful


Надалі, коли пристрої пов'язані, досить передати
#echo 'connect 90:7F:61:10:A3:BC'| bluetoothctl

Чим ми в скриптах і користуємося.

Опишемо обробник стикування:
#vim /etc/acpi/thinkpad-dock.sh
#!/bin/sh

#повідомляємо про стикуванні
echo on >/etc/tp_dock_state

#переводимо процесор в режим performance
cpufreq-set -c 0 -g performance
cpufreq-set -c 1 -g performance 
cpufreq-set -c 2 g performance
cpufreq-set -c 3 -g performance 

#підключаємо клавіатуру, на випадок, якщо ми кудись несли лаптоп
echo 'connect 90:7F:61:10:A3:BC'|bluetoothctl


І відстиковки:
#vim /etc/acpi/thinkpad-undock.sh

#!/bin/bash

#повідомляємо про відстиковки
echo off >/etc/tp_dock_state

#переводимо процесор в економічний режим
cpufreq-set -c 0 -g powersave
cpufreq-set -c 1 -g powersave 
cpufreq-set -c 2 g powersave
cpufreq-set -c 3 -g powersave 

#перевіряємо, закрита кришка:
grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ] 
then
#якщо так, то викликаємо локскрин
DISPLAY=:0.0 su user -c /home/user/bin/lock
#відключаємо bt-клавіатуру, зупиняємо сервіс, відключаємо модуль
echo 'disconnect 90:7F:61:10:A3:BC'|bluetoothctl
/etc/init.d/bluetooth stop
echo disabled> /proc/acpi/ibm/bluetooth
#переклюочаем зображення на вбудований екран
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --auto'
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --off'
#усипляємо лаптоп
pm-suspend
#після пробудження знову перевіряємо, закрита кришка
grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ] 
then 
#якщо так, то включаємо зовнішній монітор і вимикаємо внутрішній
DISPLAY=:0.0 su user -c 'xrandr --output HDMI3 --auto'
DISPLAY=:0.0 su user -c 'xrandr --output LVDS 1 --off'
#включаємо bt-модуль, запускаємо сервіс, підключіть клавіатуру
echo enabled> /proc/acpi/ibm/bluetooth
/etc/init.d/bluetooth start
echo 'connect 90:7F:61:10:A3:BC'|bluetoothctl
#повідомляємо про стикуванні
echo on >/etc/tp_dock_state
fi
fi


Підводні камені
Після оновлення debian 8, де в системі з'явився systemd, я зіткнувся з наступною проблемою: при закритті кришки, pm-suspend чомусь відпрацьовував два рази. Тобто виконувався скрипт lid.sh але паралельно з ним вироблялося дію pm-suspend без всяких скриптових обв'язок.

Головним підозрюваним, звичайно ж, став новий ініціалізаційний комбайн. І не даремно: після десяти хвилин гугления з'ясувалося, що, виявляється, systemd намагається, до купи, брати на себе і функцію з управління подіями acpi, але робить це поки не дуже добре: на даний момент не може обробляти події підключення адаптера живлення та батареї.

Переписувати скрипти під нові віяння моди бажання не виникло, тому було зроблено наступне:
#sed -i 's/HandleLidSwitch=yes/HandleLidSwitch=ignore/' /etc/systemd/logind.conf

Тим самим ми відучили systemd робити те, про що не просять і все стало на круги своя. В принципі, те ж саме варто зробити з HandleSuspendKey, HandleHibernateKey і HandlePowerKey, якщо є бажання обробляти натискання через acpid.

Висновок
Таким чином, отримуємо зручну конфігурацію, що не вимагає якихось зайвих рутинних маніпуляцій. Приходячи вранці на роботу, я дістаю лаптоп з рюкзака, вставляю його в док-станцію і натискаю кнопку живлення на цій самій док-станції, після чого працюю як зі стаціонарним комп'ютером. Йдучи, просто тисну кнопку відстиковки і прибираю комп'ютер в сумку.

Недолік у такого підходу рівно один: викликає сильне звикання.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.