Лирика


За прошедшие пару месяцев мне довольно часто приходилось вступать в дискуссии о всевозможных портативных компьютерах: ломать копья в спорах какой производитель лучше и почему, обсуждать совместимость с 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 LVDS1 --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 LVDS1 --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 LVDS1 --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 LVDS1 --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 LVDS1 --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 agent request 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 LVDS1 --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 LVDS1 --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.

Заключение


Таким образом, получаем удобную конфигурацию, не требующую каких-то лишних рутинных манипуляций. Приходя утром на работу, я достаю лаптоп из рюкзака, вставляю его в док-станцию и нажимаю кнопку питания на этой самой док-станции, после чего работаю как со стационарным компьютером. Уходя, просто жму кнопку отстыковки и убираю компьютер в рюкзак.

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

Комментарии (24)


  1. evg_krsk
    07.12.2015 10:40

    Всё не дочитал ещё, но выглядит вкусно. С systemd уже и сам натолкнулся. Только наверное лучше не править /etc/systemd/logind.conf, а создавать снипет в /etc/systemd/logind.conf.d/


    1. evg_krsk
      07.12.2015 19:22
      +1

      А, нет, вру, systemd отлично отрабатывает события ACPI (ну, у меня), достаточно было ему сказать HandleLidSwitch=suspend, HandleLidSwitchDocked=suspend, чтобы снова начал засыпать при закрытии крышки ноута (в апстриме это починили для более другого случая, мне не подошло новое поведение). acpid лежит на случай непредвиденного возврата к sysv :-)


      1. d7s2di
        07.12.2015 21:35

        Проблема в том, что просто сделать suspend недостаточно, тут совершенно разные действия в зависимости от того, находится ли лаптоп в доке, подключен ли адаптер и тому подобное. А чтобы все это заработало, нужно писать юниты.

        Нужно ли это? Мне покамест не нужно. Не люблю менять решения, которые работают хорошо на что-то более модное.


        1. kstep
          08.12.2015 09:34

          Ну у меня всё просто:

          1) в /etc/systemd/logind.conf.d лежит файлик no-lid-sleep.conf

          no-lid-sleep.conf
          [Login] HandleLidSwitch=ignore


          1. kstep
            08.12.2015 09:42

            Парсер убил переносы строк в спойлерах. Надеюсь, понятно, где там нужно разбить на строчки?


            1. d7s2di
              08.12.2015 10:15

              Да, с этим все понятно. В общем, похоже, что рано или поздно systemd заменит собой очень многие демоны. Уж не знаю, хорошо это или плохо.


  1. d7s2di
    07.12.2015 10:49
    +2

    >не править /etc/systemd/logind.conf, а создавать снипет в /etc/systemd/logind.conf.d/

    Тут интересно, как оно расставит приоритеты. Проще поправить logind.conf, я считаю. Вообще, с переходом на это самое, лишнее засыпание было не единственной проблемой: до кучи автомонтирование на скриптах udev отвалилось по причине нововведения с килянием процессов по таймауту…

    Надо бы назад на sysv откатиться, благо в дебиане есть такая возможность.


    1. evg_krsk
      07.12.2015 12:49
      +1

      Нормально оно расставляет приоритеты. Сначала грузит файл, потом сниппеты (насколько помню, их в лексикологическом порядке). В итоге и обновляется systemd штатно и конфиг не слетает.

      У меня наоборот, засыпание нормально работало и в sysv и в systemd, но потом «сломали» дефолт в logind.conf, пришлось настроить. В systemd есть родное монтирование юнитами и/или настройкой в /e/fstab. Сам не пробовал (использую aufos ещё с sysv), но говорят что работает. Попробуйте.

      Я наоборот последние пару лет плавно перевожусь на systemd. Не без шероховатостей конечно, но прогресс впечатляет :-)


      1. d7s2di
        07.12.2015 12:52

        Меня в systemd пугает концепция «все в одном». Как-то неюниксвейно. Ну и проблемы с переходом: перспектива переписывать под systemd конфиги тоже не разу не радуют.


        1. grossws
          07.12.2015 12:58
          +1

          Это «всё в одном» состоит из более чем 80 бинарников.
          Ну и поддерживает старые rc и init-скрипты для совместимости. Естественно, вопрос поддержки этого перехода в конкретном дистрибутиве ложится на плечи мейнтейнеров, которые могут положить болт и рассказывать, как им всё сломали.


          1. d7s2di
            07.12.2015 13:06

            >состоит из более чем 80 бинарников.

            По-моему, это многовато для системы инициализации. Хотя, у нас тут вместо системы инициализации, получается эдакая маленькая операционная система. На ум приходит шутка про OS GNU/Emacs, в которой есть все, но нет нормального текстового редактора.


            1. grossws
              07.12.2015 13:11

              Оно и не позиционируется, как init. init — только один из кусков systemd.

              systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system. systemd provides aggressive parallelization capabilities, uses socket and D-Bus activation for starting services, offers on-demand starting of daemons, keeps track of processes using Linux control groups, supports snapshotting and restoring of the system state, maintains mount and automount points and implements an elaborate transactional dependency-based service control logic. systemd supports SysV and LSB init scripts and works as a replacement for sysvinit. Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution.


          1. evg_krsk
            07.12.2015 14:16
            +1

            … а могут, как я, наоборот, собирать новые пакеты только с юнитами, ибо их можно написать и отладить в разумное время, в отличии от :-)


            1. grossws
              07.12.2015 15:28

              Я локальные пакеты так и собираю. Но, если вы мейнтейнер дистрибутива ещё активно использующего sysv, то это не очень гуманно по отношению к пользователям =)


              1. evg_krsk
                07.12.2015 15:54

                Ну, как админу приходится серверный софт собирать с sysv-портянками (хорошо хоть в последнее время крайне редко). Для пользователей — по запросу в багтрекере (никто пока не жаловался :-)).


        1. kstep
          07.12.2015 14:21

          Почему же, конфиги в системд прекрасно разбиваются по логическим частям, можно перекрывать общесистемные настройки юнитов на уровне пользователя и т.п.

          Например, если не нравится настройки запуска сервиса по умолчанию, можно создать каталог /etc/systemd/system/имясервиса.service.d/local.conf и прописать их в этом файле, эти настройки перекроют общесистемные, и при обновлении пакетов не затронутся.


        1. khim
          08.12.2015 04:32
          +2

          Меня в systemd пугает концепция «все в одном». Как-то неюниксвейно.
          Вот эта критика касательно systemd меня всегда убивает.

          Как может концепция используемая в 100% UNIX'ов быть «неюниксвейной»?

          Все, абсолютно все «настоящие» UNIX'ы (то есть системы ведущие родословную кодобазы от творения Кернигана и Ритчи) собирают «базовую систему» (состоящую из десятков, а то и сотен, программ) из одного дерева, которое может быть обновлено только и исключительно синхронно (login из System 6 в System 5 не вставить и наоборот).

          systemd — это как раз во-многом «возврат к истокам».


  1. ragesteel
    07.12.2015 12:56
    +1

    Вот вы говорите что вам нужен trackpoint, а судя по MACу у вас bluetooth клавиатура от Chicony, у них моделей с TrackPoint'ом нет. Или вам указательное устройство больше не нужно?


    1. d7s2di
      07.12.2015 13:03
      +5

      Клавиатура у меня не от chiconi (: Вот она, собственно:




      1. kstep
        07.12.2015 14:24
        +1

        О, класс. Хочу такую! Где взяли? Или просто выдрали из старого Thinkpad и доработали напильником? У меня лично уже лет 5 блютусная Logitech diNovo Edge, пока устраивает, но рано или поздно аккумулятор сядет, надо будет искать замену…


        1. d7s2di
          07.12.2015 14:30

          Заказывал на ali, когда деревья были большие, а бакс стоил 30 рублей. Сейчас стоит жутких 6-7 тысяч деревянных.


          1. sashkin
            07.12.2015 15:18

            У меня такая же, но USB. Заказывал на Амазоне. Очень долго выбирал из десятков других. У Вас, кстати, все клавиши работают ОК? У меня вертикальный ряд возле Enter неприятно поскрипывает при нажатии. С остальными такое не наблюдается. Ну и трекпоинт весьма туговат, что отбивает желание его использовать: месяца 1,5-2 на нём сидел, но так и не привык, а ведь когда брал, то очень надеялся на работу в духе «руки постоянно на клавиатуре». С укороченной клавой мышь показала себя всё же более удобной.


            1. d7s2di
              07.12.2015 15:23

              Да вроде все работают нормально. Верхним рядом (функциональными) я не пользуюсь, но сейчас специально потыкал: скрипа нет. Ускорение трекпоинта можно настороить через xset m. Хотя, по ощущениям, чувствительность примерно как на x220. А вот на 31P9490 трекпоинт тугой, да.

              Впрочем, задача трекпоинта — быстро передвинуть графический курсор, когда руки лежат на клавиатуре. А мышью я не пользуюсь. Совсем (:


      1. Arceny
        07.12.2015 19:14

        У меня была проводная и с классической раскладкой, к сожалению блютус таких не было.
        Новую thinkpad'овскую клавиатуру не признаю :-С