В статье приведён обзор общего подхода к разработке драйверов ввода
При разработке драйвера в первую очередь следует создать новый модуль ввода. Он описывается структурой input_module_t. Детали реализации можно изучить в README-файле в публичном репозитории, а также в опубликованных примерах реальных драйверов.
В зависимости от типа модуля ввода формат передаваемых в систему данных отличается. Модули устройств могут передавать любые данные, модули протоколов должны передавать данные в том формате, который ожидает ассоциированный модуль фильтра (см. input_module_t :: type):
struct packet_kbd
, описанная в <sys/devi.h>
. struct packet_rel
, описанная в <sys/devi.h>
. struct packet_abs
, описанная в <sys/devi.h>
. Все перечисленные структуры имеют поле timestamp, которое может быть проинициализировано с помощью clk_get().
Модули протокола и фильтра будут ожидать скан-коды, включая флаги нажатия/отжатия клавиши. При заполнении структуры struct packet_kbd
для передачи фильтру следует:
struct _keyboard_data
соответствующим скан-кодом, KEY_SCAN_VALID
. Фильтр клавиатуры считывает файл раскладки клавиатуры (.kbd
) и интерпретирует получаемые им скан-коды на основе содержимого этого файла. Эти файлы обычно размещаются по адресу /usr/photon/keyboard
. Их исходные описания .kdef
доступны в КР по адресу $KPDA_TARGET/usr/include/keyboard
и могут быть сгенерированы с помощью утилиты mkkbd.
При запуске драйвера модуль фильтра попытается подгрузить файлы раскладки согласно приоритетам:
/etc/system/trap/.KEYBOARD
. en_US_101.kbd
из директории $PHOTON/keyboard
. en_US_101.kbd
из директории /usr/photon/keyboard
.
Такие устройства требуют калибровки, поскольку координаты имеют аппаратно-обусловленное разрешение, которое никак не коррелирует с разрешением дисплея. Модули устройства и протокола получают сырые аппаратно-специфичные координаты, упаковывают их в struct packet_abs
и отправляют абсолютному фильтру.
Фильтр транслирует координаты из пространства устройства в координаты экрана (калибровка), выбирая его согласно приоритетам:
/etc/system/config/calib.<hostname>
. Данный файл может быть подготовлен только вручную, с помощью утилит calib и gf-calib.
Формат файла текстовый:
XLxYL:XHxYH:XRL XRH YRL YRH SWAP
где:
0
). 0
). 0
- нет, 1
- да). Обычно должно иметь значение 0
.
Модуль протокола получает сырые смещения координат устройства, должен запаковать их в формат struct packet_rel
и передает их модулю фильтра. Фильтр применяет алгоритм ускорения (мультиплицирование смещений), конвертирует сырые данные и передает их в систему.
Основная трудоемкость при разработке обычно сконцентрирована в реализации обработчиков, перечисленных в структуре input_module_t:
Основная последовательность callback-ов имеет вид: input_module_t :: init() → input_module_t :: parm() → input_module_t :: reset().
Для модулей устройств типовой набор следующий:
Для модулей протоколов основной callback - input_module_t :: input(), опционально также могут присутствовать input_module_t :: init(), input_module_t :: parm(), input_module_t :: devctrl().
В основном модули устройств и протоколов объединяют в один программный объект. Кроме заполнения callback-ов, инициализации и опроса оборудования и интерпретации протокола Вам будет необходимо:
DEVI_MODULE_TYPE_DEVICE
и DEVI_MODULE_TYPE_PROTO
. struct packet_*
.
Поскольку фреймворк библиотеки libinput является многопоточным, обращения к модулю могут быть многократными для различных шин событий. Примером является модуль kb, который может быть ассоциирован как с PS/2 клавиатурами, так и с PS/2 мышами:
devi-hirun kbd kb ps2 kb -2
При инициализации статическая структура input_module_t будет использована лишь для первой шины, второй экземпляр будет динамическим. Проблема может возникнуть при доступе к приватным данным драйвера, особенно реализованных в виде глобальных переменных. Их следует отдельно защищать примитивами синхронизации.
Callback-функции input_module_t :: init(), input_module_t :: reset() и input_module_t :: parm() в защите не нуждаются, этим занимается библиотека. Однако, они являются таковыми в момент инициализации, а не при ручном вызове этих callback-ов. Другие callback-и не являются безопасными в принципе.
Предыдущий раздел: Библиотека разработки драйверов ввода (libinput)