Применение embedded controller для управления устройствами

Применение embedded controller для управления устройствами

Решился на написание еще одного опуса. Слышу возмущения — опять написал ерунду, чтобы показать себя..... но я уже не в том возрасте, чтобы писать для этой цели ….. как говорится жизнь на закате и писать только ради этогого …. это несеръезно да и не перед кем мне уже заискывать....
Как то уже упоминал, что программирование не моя стихия, не мое это …. а нравился мне всегда реверсинг, но сейчас уже не до него..... а покапаться в чем то похожем хочется ….. поэтому и родилась эта статья — покапать то покапался, но подумал, что может пригодится и другим...

embedded controller - дословный перевод - встроенный контроллер, предназначен для управления отдельными устройствами компьютера, наверное, точнее будет сказать для обработки отдельных ACPI-событий.
Embedded Controller имеет свой BIOS, который может хранится или в отдельном чипе или входить в состав системного BIOS.
В настоящее время увеличивается как количество разных типов компьютеров, так и количество операционных систем (ОС). Чисто теоретически, да и практически, просто не возможно добиться полной совместимости (в части управления устройствами/ACPI-событиями) всех существующих компьютеров и всех существующих ОС . Вот здесь то и возрастает роль embedded controller при управлении различными проблемными устройствами. И вполне возможно, что количество устройств/ACPI-событий, способных осуществлять свои функции управления посредством embedded controller будет со временем увеличиваться. В настоящее время этот перечень не велик и зависит от разработчиков — в разных типах ноутбуков этот перечень отличается. В основном это вентилятор (имеется практически во всех ноутбуках), в других ноутбуках включена функция управления подсветкой монитора и клавиатуры, включение/выключение некоторых устройств, например, Bluetooth и др.
Подробное описание всех возможных функций управления embedded controller Intel приведено в документе Embedded Controller Usage in Low Power Embedded Designs
Цель данной статьи чисто ознакомительная - ознакомить пользователей Archlinux с возможносью управления определенных устройств компьютера через регистры embedded controller, все будет показно на примере вентилятора (как уже упоминал, возможность управления вентилятором имеется практически во всех типах ноутбуков).
В инете эту тему можно нагуглить, но в основном узконаправлено и все публикации посвящены большей частью скрипту acer_ec.pl , и как я понял идет переписывание одной статьи, но в разных вариациях. Основопологающие принципы практически отсутствуют, имеются отдельные скупые заметки и то на иностранных языках. Одним словом общей картины нет ......... а потому и решил все свести в одно место. Просто в свое время пришлось очень долго все лопатить, да и доходить до некоторых вещей самому.....а пользователю, не имеющему опыта работы с байтами, с разными системами исчисления, слабо знающему другие языки копаться во всем этом будет довольно затруднительно.

Но пора и приступать к экспериментам.....
Условно подход к управлению через embedded controller можно разбить на три способа — названия, конечно, не подходящие, но ничего подходящего не придумал.
1. Ручной (полностью под контролем пользователя - как говорится, все в твоих руках)
2. Полуавтоматический (практически совпадает с 1-ым способом, но для облегчения записи в регистры используется программа).
3. Автоматический (самый простой, даже не нужно загружать модуль, все за тебя продумали)

1. Ручной способ управления.
Управление осуществляется через модуль ec_sys , встроенный в ядро — этот модуль позволяет осуществлять операции чтения/записи в памяти (в регистры) embedded controller. Модуль в общем то предназначен для отладки - CONFIG_ACPI_EC_DEBUGFS=m , но и для наших целей он тоже хорошо подходит.
- загружаем модуль - # modprobe ec_sys
- проверяем - $ lsmod | grep ec_sys
ec_sys 16384 0
После загрузки модуля должна появиться директория /sys/kernel/debug/ec
# ls /sys/kernel/debug/ec
ec0
# ls /sys/kernel/debug/ec/ec0
gpe  io  use_global_lock
Но если просто загрузить модуль, без параметров, то в дальнейшем не возможно будет провести операции записи значений в регистры. За это отвечает параметр write_support, который по умолчанию равен 0
$ modinfo ec_sys -p
write_support:Dangerous, reboot and removal of battery may be needed. (bool)
Для того чтобы можно было выполнять операции записи необходимо загрузить модуль с данным параметром, равным 1
Для начала, если модуль был загружен, выгружаем его, а потом загружаем по новой, с нужным параметром
# modprobe -r ec_sys
# modprobe ec_sys write_support=1
Но обращаю внимание на запись в строке parm Dangerous.... вот что пишут на этот счет …..
..... ec_sys module that provides a useful debugfs interface to allow one to read + write to the EC memory. Write support is enabled with the ec_sys module parameter 'write_support' but it is generally discouraged as one may be poking data into memory may break things in an unpredictable manner, hence by default write support is disabled.
Но это просто предупреждение ….. просто нужно быть внимательным … но если и ошибетесь, то особо страшного ничего не произойдет.
Если все выполнили правильно, то можно посмотреть таблицу значений данных, записанных в регистрах embedded controller. Эти значения хранятся в бинарном файле /sys/kernel/debug/ec/ec0/io, посмотреть эти значения удобнее следующим способом
# od -Ax -t x1 /sys/kernel/debug/ec/ec0/io
000000 d4 83 59 01 18 08 20 43 00 2c 31 9f 03 ff ff 00
000010 00 3a 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
000020 ff ff 00 00 00 00 14 01 00 00 00 00 00 00 4a 4a
000030 00 00 14 00 00 23 2c 00 00 00 00 00 00 00 00 00
000040 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00
000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
000080 00 00 04 01 01 01 00 14 0f 01 00 ff ff 01 00 00
000090 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 c8 00 00
0000b0 00 96 00 00 00 64 10 00 00 64 41 00 41 00 ff e0
0000c0 2e ff 00 00 ff ff ff aa aa ff ff 3f 28 00 00 00
0000d0 00 00 00 00 00 6b ff ff 02 ff ff ff ff ff ff ff
0000e0 74 0b ff 07 00 b4 00 01 01 00 04 00 ff ff ff 00
0000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000100
Значения данных в регистрах записаны в 16-ричном виде и изменяются в пределах 00 - ff (или 0 - 255 в 10-ричном исчислении). При этом чем меньше значение записанное в регистре, тем больше физическая величина реального значения контролируемого параметра (выразился непонятно, но дальше это будет понятно на примере).
Обозначение регистров — в 16-ричном виде удобно определять прямо по таблице строка - столбец, …. в 10-ричной системе по порядковому номеру элемента в таблице (16 элементов в строке)......но при записи удобнее использовать номера регистров в 10-ричной системе, так как применяется команда dd.
Строки и столбцы нумеруются, согласно таблице, 0, 1, 2, 3 ... d, e, f
Пример. Регистры для моего вентилятора (у Вас будут другие). Как они определяются, опишу позже.
2E (46) — read
2F (47) — write

В них записаны, как видно из таблицы, значения 4a (74 в 10-ричной системе исчисления). Попробуем увеличить мощность вентилятора, а точнее запишем в регистр 2F (47) значение 3a (58).
Запись в регистры осуществляется следующей командой (пояснять не буду, вроде и так все понятно)
# echo -n -e "\x3a" | sudo dd of="/sys/kernel/debug/ec/ec0/io" bs=1 seek=47 count=1 conv=notrunc 2> /dev/null
Ждем 2-3с, слышим, что звук увеличился и проверяем значение
# od -Ax -t x1 -j 47 -N 1 /sys/kernel/debug/ec/ec0/io
00002f 3a
Возвращаем обратно, т.е. устанавливаем значение 4a
# echo -n -e "\x4a" | sudo dd of="/sys/kernel/debug/ec/ec0/io" bs=1 seek=47 count=1 conv=notrunc 2> /dev/null
Слышим, что звук притих и проверяем
# od -Ax -t x1 -j 47 -N 1 /sys/kernel/debug/ec/ec0/io
00002f 4a
Все работает и, как видим, ничего не попортили ….
Можно, в принципе, производить запись и такой командой
# printf '\x3a' | sudo dd of="/sys/kernel/debug/ec/ec0/io" bs=1 seek=47 count=1 conv=notrunc 2> /dev/null

2. Полуавтоматический способ управления.
Основное отличие от 1 способа - использование готовой программы для упрощения операций чтения/записи значений регистров embedded controller . Программа работает только при наличии директории /sys/kernel/debug/ec …... т.е. загрузка модуля ec_sys с параметром write_support=1 обязательна.
Пробуем …....
1. Загружаем модуль ec_sys
# modprobe ec_sys write_support=1
2. Скачиваем исходник программы ec_access.c
wget ftp://ftp.suse.com/pub/people/trenn/sources/ec/ec_access.c
3. Компилируем
$ gcc ~/ec_access.c -o ~/ec_access
4. Читаем таблицу значений регистров
# ~/ec_access -r
     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F
00:  52  0b  7d  01  18  08  20  43  00  2c  31  9f  03  ff  ff  00
10:  00  3c  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
20:  ff  ff  00  00  00  00  14  01  00  00  00  00  00  00  4a  4a
30:  00  00  14  00  00  23  2c  00  00  00  00  00  00  00  00  00
40:  00  00  00  10  00  00  00  00  00  00  00  00  00  00  00  00
50:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
60:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
70:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
80:  00  00  04  01  01  01  00  14  0f  01  00  ff  ff  01  00  00
90:  00  01  00  00  00  00  00  00  00  00  00  00  00  00  00  00
A0:  00  00  00  00  00  00  00  00  00  00  00  00  00  c8  00  00
B0:  00  96  00  00  00  64  10  00  00  64  41  00  41  00  ff  e0
C0:  2e  ff  00  00  ff  ff  ff  aa  aa  ff  ff  3f  28  00  00  00
D0:  00  00  00  00  00  6b  ff  ff  02  ff  ff  ff  ff  ff  ff  ff
E0:  74  0b  ff  07  00  b4  00  00  01  00  04  00  ff  ff  ff  00
F0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
Как видим очень удобная таблица и видим в регистре 2F знакомое значение 4a. Кстати значение регистра по этой таблице вычислять удобнее.
5. Попробуем изменить значение 4a на 3a , как это проделали в способе 1, и заметим, что это проще и все делается в 16-ричном исчислении
# ~/ec_access -w 2F -v 3a
Проверяем
# od -Ax -t x1 -j 47 -N 1 /sys/kernel/debug/ec/ec0/io
00002f 3a
6. Возвращаем обратно и проверяем
# ~/ec_access -w 2F -v 4a
# od -Ax -t x1 -j 47 -N 1 /sys/kernel/debug/ec/ec0/io
00002f 4a
Описания опций программы нет, но их, при желании, можно подсмотреть в исходниках.

3. Автоматический способ управления.
При использовании этого способа нам не нужно знать, что существует какой то модуль ec_sys т.е. не нужно заботиться ни о загрузке этого модуля ни о том, что у него имеется параметр write_support .
А поэтому раз у меня этот модуль загружен, то я его выгружу
# modprobe -r ec_sys
И проверим - $ lsmod | grep ec_sys ….. пусто
Этот способ строится на скрипте acer_ec.pl , который специально разработали для ноутбука Acer. Насколько я понял в этом ноутбуке, используя embedded controller, можно управлять не только мощностью вентилятора, но, как пишут, и подсветкой монитора и др. К сожалению данный тип ноутбука мне при работе ни разу не попадал и сказать об этом ничего не могу. Но этот скрипт я применял и на других ноутбуках ….. этот скрипт не привязан конкретно к ноутбуку Acer ….
Кстати, в инете по использованию embedded controller с применением этого скрипта, очень много информации — приводить не буду, кому интересно — найдет сам.
Пробуем.....
1. Скачиваем скрипт. Откуда я его скачал, уже не помню, но нашел на GitHub , сверил с имеющимся — и разницы не нашел.
2. Читаем таблицу
# perl acer_ec.pl regs
Полный вывод не привожу — таблица похожа на таблицу способа 2, но значения регистров приведены в 10-ричном исчислении.
Привожу часть таблицы, в которой находятся регистры вентилятора
….............. 0E ….... 0F
10 …......... 255 …..255
20 …......... 75 …....74
Замечу, что 75 — 0x4b , 740x4a
3. Пробуем изменить значение 4a на 3a , как это проделывали раньше
# sudo perl acer_ec.pl := 0x2F 0x3a
REG[0x2f] == 0x4a
REG[0x2f] := 0x3a
REG[0x2f] == 0x4a
Проверяем
# perl acer_ec.pl regs
….............. 0E ….... 0F
10 …......... 255 …..255
20 …......... 58 …....58
(580x3a)
4. Возвращаем все на место и проверяем
# perl acer_ec.pl := 0x2F 0x4a
REG[0x2f] == 0x3a
REG[0x2f] := 0x4a
REG[0x2f] == 0x3a
# perl acer_ec.pl regs
….............. 0E ….... 0F
10 …......... 255 …..255
20 …......... 75 …....74

Ну вот отработали все 3 способа, все работоспособны, а вот какой использовать — каждый решает сам...... безусловно, 3 способ самый простой.

4. Ну и самое последнее — как же определить нужный регистр.
Здесь конкретных рекомендаций нет, все зависит от ситуации и нужна смекалка.
Конечно, если параметр в Linux не управляется, то нужно заниматься определением регистра в Windows. Рекомендую для этих целей неплохую программу RW-Everything.
В этой программе много всяких приблуд, но выбираем EC (embedded controller), появится таблица регистров и их значений, аналогичная показанным выше. В этой таблице непрерывно меняются значения. Например, чтобы определить регистры, ответственные за события вентилятора, любой прогой, умеющей управлять мощностью вентилятора, например, NBFC - NoteBook FanControl, увеличиваем/уменьшаем эту мощность и смотрим в каких регистрах происходит изменение (изменения будут происходит и в других регистрах, но все зависит от ваших действий и наблюдательности). Ну и, конечно, неплохо подстраховаться. Рекомендую зайти на сайт и скачать FanControlConfig для своего ноутбука — этот конфиг является составной частью замечательной проги NBFC - NoteBook FanControl (имеется и для Windows и для Linux), а главное в этом конфиге указаны нужные регистры — например, для моего ноутбуках - привожу выдержки из этого конфига
<FanControlConfig>
<UniqueId>HP ProBook 4530s</UniqueId>
<NotebookModel>HP ProBook 4530s</NotebookModel>
<ReadRegister>46</ReadRegister>
<WriteRegister>47</WriteRegister>
И как видим, это регистры 46 и 47, что в 16-ричном исчислении соответствует 2E и 2F.
Хочу отметить также, что в инете ходят готовые скрипты для управления вентилятором на основе embedded controller - управлять как известно, а потому далее необходимо только привязаться к температуре (реперные точки можно выбрать самому или взять из того же FanControlConfig для нужного ноутбука). Ссылки на скрипты не даю, найти их в инете не сложно.

В части подсветки монитора, если у кого входит в управление embedded controller, можно определить регистры и из Linux. Для чего
- загружаем модуль
# modprobe ec_sys
- запускаем команду
# watch od -Ax -t x1 /sys/kernel/debug/ec/ec0/io
и получаем динамическую, непрерывно меняющуюся таблицу значений регистров. Подсветку можно менять в Linux практически всегда, через xrandr …. и смотрим в каком регистре меняются цифирки ….
Вообщем нужен подход и определить регистр можно всегда.

На этом заканчиваю …... и так написал много лишнего ….
основательно пишешь, продолжай в том же духе. vasek - в твоих блогах узнаю много интересного и полезного...
vasek
опять написал ерунду, чтобы показать себя...
Вот если бы все писали вот такую ерунду, насколько жить было бы легче! А статья действительно полезная. Таких статей — тех, которые по существу, всегда мало.
root@vpupkin# cat /dev/ass > /dev/head
 
Зарегистрироваться или войдите чтобы оставить сообщение.