October 3

FreeBSD и тачпад

Рассказываю про одную технику решения проблем с тачпадами в этой замечательной ОС. Будет актуально только если вы #банулись настолько чтобы иметь это на ноутбуке.

Слева очередная версия Эльзы, созданная нейросетью, справа - виновник торжества.

Проблемы негров

Как вы наверное знаете коль уж читаете эту статью «у холмов есть глаз..» ээм это из другой оперы, «у периферийного оборудования есть драйвера» — специальные программы, реализующие низкоуровневую работу с устройством.

По крайней мере так учит Windows Drivers Kit.

В FreeBSD (так же как и в линуксах) нет концепции «драйвера», вместо нее есть определенная часть ядра, временами даже выгружаемая и отвечающая за работу с устройством или группой устройств одного класса.

Выгружаемая часть чаще всего называется «модулем ядра», но выгрузить можно далеко не все.

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

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

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

Лотерея, лохотрон и выбор устройства

Чтобы ядро ОС могло использовать конкретную часть логики (образно выражаясь — драйвер) для конкретного оборудования, существует сложный многоуровневый механизм определения типа оборудования, который начинается с двух числовых кодов: «device id» и «vendor id».

Vendor ID — код производителя устройства, DeviceID — код устройства.

По идее комбинация этих двух кодов дает уникальное и однозначное определение железки, но конечно же на практике все сильно сложнее:

Обратите внимание на subvendor и subdevice - еще два дополнительных идентификатора устройства

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

Появились дубли, поэтому примерно с начала 2000х полагаться только на DeviceID и VendorID стало фактически невозможно.

Помимо идентификаторов, разные устройства одного типа имеют еще и разные протоколы инициализации - пакеты данных, разного размера и с разными данными внутри.

Что в итоге приводит к необходимости в «логике перебора» — ядро натурально пытается подобрать подходящий драйвер, пуляя в железку разные пакеты инициализации и ожидая на какой она ответит:

Обратите внимание на цикл, выделенный в центре скриншота — вот так выглядит массив с данными, по которому идет итерация:

Обратите внимание на предупреждение о том что порядок записей крайне важен - также из-за дублей и сложной логики определения.

Видите дублирующиеся коды deviceId (0x08)?

Это означает, что устройства от трех разных производителей считают себя одной семьей отдают один и тот же deviceId.

А от четвертого производителя — нет:

Elantech - ренегаты до конца.

Но это еще не все.

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

В случае мыши, это например тот самый «Generic Mouse», которым бывает прикидывается тачпад или какая-нибудь особо навороченная модель.

Отсутствие или пробелы в реализации «vendor specific» протоколов плюс неверное определение устройства —  создают ту самую «проблему с поддержкой клиентского оборудования», от которой страдают все открытые ОС.

Для решения подобных проблем применяют самый настоящий reverse engineering, восстанавливают по крупицам работу протокола и на свет появляется функционал ядра с поддержкой нового оборудования.

Конечно же это п#здец какой сложный путь, доступный только очень опытным разработчикам. Но есть и другой вариант, сильно проще.

Нормальные герои всегда идут в обход

На одном из моих ноутбуков была давняя проблема с тачпадом — он успешно определялся, но «tap to click» (нажатия по поверхности тачпада) упорно не хотели работать, сколько бы я не крутил настройки.

Проблема была только в BSD, в Linux на этой же машине все работало как надо.

Однажды я обнаружил вот такое сообщение в багтрекере FreeBSD:

Хотя речь про абсолютно другую модель - смысл затеи не поменяется.

Суть описанного выше метода:

удаление кодов (deviceId) устройства из списка поддерживаемых на уровне исходников ядра, для того чтобы ОС использовала стандартный протокол инициализации и работы вместо «vendor specific».

Что я и проделал, внеся правки в файл:

/usr/src/sys/dev/atkbdc/psm.c

Вот так тачпад определялся до патча:

А так после патча:

После чего тачпад наконец заработал как надо и я получил работающий «tap to click».

Весь патч заключается в двух закомментированных строчках, отвечающих за инициализацию тачпада конкретной модели:

Разумеется ядро после этого необходимо пересобрать.

P.S.

Описанное в статье вполне актуально и применимо для всех BSD-систем, не только для одной FreeBSD.

Также замечу что подобным образом возможно исправить ситуацию далеко не только с тачпадом — видеокарты, аудио и множество других устройств имеют как свою специфику так и «базовый функционал», который можно попробовать включить аналогичным способом.