Хабрахабр

ACPI: Добавление устройств без перекомпиляции ядра

Как выясняется, далеко немногие знают о существовании режима оверлеев в ACPICA и их поддержки в ОС Linux. Я хочу восполнить этот пробел на примере добавления ведомых устройств I2C в систему без перекомпиляции.

Начальные условия

Допустим, при запуске

i2cdetect -y -r 0

у нас выдаётся такая картина:

Вывод i2cdetect

0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- 53 -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

где по адресу 0x53 обнаруживается акселерометер ADXL345, а по адресу 0x57 — микросхема EEPROM памяти 24c128. Описания этих устройств отсутствуют в ACPI, а именно в таблице DSDT.

Добавляем акселерометер ADXL345

Всё, что нам необходимо знать здесь — это адрес, по которому отзывается устройство, его ID, поддерживаемые драйвером, частота шины, на которой он должен работать. Обратите внимание, что частота I2C шины со стороны драйвера часто устанавливается в ту минимальную, которая поддерживается всеми ведомыми устройствами на данной шине!

Так вот, мы используем новый, который доступен через подсистему IIO. Ах, да, было время, когда подсистемы IIO не существовало, а драйвер ADXL345 уже был.

Итого,

  • Адрес: 0x53
  • Частота шины: 400кГц
  • Ссылка на ведущее (контроллер) устройство: \_SB.PCI0.I2C1
  • Идентификатор: adi,adxl345

Следует обратить внимание, что мы используем здесь специальный идентификатор, который предназначен для систем с OF. В качестве прослойки в ACPI был добавлен специальный идентификатор PRP0001, который и обеспечивает совместимость с драйверами, написанными ранее для OF.

Переводим полученную информацию на язык ASL:

ASL код для акселерометра ADXL345

DefinitionBlock ("adxl345.aml", "SSDT", 5, "", "ADXL345", 1)
) Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "compatible", "adi,adxl345" }, } }) } }
}

Добавляем EEPROM 24c128

Так же, как и в предыдущем случае получаем необходимую информацию про устройство и его драйвер:

  • Адрес: 0x57
  • Частота шины: 400кГц
  • Ссылка на ведущее (контроллер) устройство: \_SB.PCI0.I2C1
  • Идентификатор: INT3499
  • Объём: 1024
  • Размер страницы: 32

ASL код для EEPROM 24c128

DefinitionBlock ("at24.aml", "SSDT", 5, "", "AT24", 1)
{ External (_SB_.PCI0.I2C1, DeviceObj) Scope (\_SB.PCI0.I2C1) { Device (EEP0) { Name (_HID, "INT3499") Name (_DDN, "Atmel AT24 compatible EEPROM") Name (_CRS, ResourceTemplate () { I2cSerialBusV2 ( 0x0057, // I2C Slave Address ControllerInitiated, 400000, // Bus speed AddressingMode7Bit, "\\_SB.PCI0.I2C1", // Link to ACPI I2C host controller 0 ) }) Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () { "size", 1024 }, Package () { "pagesize", 32 }, } }) } }
}

Заметьте разницу с предыдущим вариантом. Здесь используется напрямую ACPI ID, который выделен в пространстве, контроллируемом Intel, спасибо платформе Intel Galileo. Второе отличие, мы передаём дополнительные параметры устройства в виде строк ключ-значение.

Возможные варианты инициализации

Что теперь с этим всем делать? Алгоритм прост. Во-первых, необходимо откомпилировать полученные файлы в ASL байт-код. Достигается с помощью вызова команды

iasl adxl345.asl

и по аналогии для EEPROM. Во-вторых, выбрать способ инициализации новоиспечённой таблицы. Их собственно три: 1) присоединение к initramfs, 2) загрузка на рабочей системе через ConfigFS, 3) загрузка таблицы из переменной EFI. Рассмотрим первые два из них ниже.

Присоединение к initramfs

Ничего с самим архивом initramfs мы делать не будем, однако рекомендуется сохранить оригинал где-нибудь в сторонке.


# Добавляем ACPI таблицы в некомпрессированный cpio архив.
# Они обязаны находится в подкаталоге /kernel/firmware/acpi внутри архива.
# Некомпрессированные архивы должны идти первыми в цепочке.
mkdir -p kernel/firmware/acpi
cp adxl345.aml kernel/firmware/acpi
cp at24.aml kernel/firmware/acpi # Создаём архив и цепочкой к нему присоединяем оригинальный initramfs:
find kernel | cpio -H newc --create > /boot/instrumented_initramfs-vX.Y
cat /boot/initramfs-vX.Y >> /boot/instrumented_initramfs-vX.Y

После этой процедуры старый архив можно заменить новым и перезагрузить компьютер.
Должно появиться в выводе dmesg что-то типа:

[ 0.000000] ACPI: Table Upgrade: install [SSDT- - ADXL345]
[ 0.000000] ACPI: SSDT 0x000000003F4FF5C4 0000A6 (v05 ADXL345 00000001 INTL 20170303)

Учтите, что ядро поддерживает только цепочку до 64 таких архивов.

Загрузка через ConfigFS

Такая возможность доступна, когда ядро собрано с опцией CONFIG_ACPI_CONFIGFS и ConfigFS примонтирована. Если предположить, что она примонтирована в подкаталог /sys/kernel/config, то нижеследующий пример показывает как загрузить таблицу.


cd /sys/kernel/config/acpi/table
mkdir adxl345
cat ~/adxl354.aml > adxl345/aml

Заключение

Хотя язык ASL требует больше скобочек, чем аналоги, тем не менее он предоставляет не меньшие возможности для описания устройств. Так, существует некоторое количество примеров в проекте meta-acpi, где в частности можно найти описания светодиодов и кнопок, подключенных к GPIO линиям, микросхем памяти, и даже описание модуля Adafruit 2.8" — TFT дисплея с сенсорным экраном!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть