суббота, 11 марта 2017 г.

Как активировать тачпад в Recovery на MTK или патчим ядро Android.

Как вы заметили я редко пишу узкоспециализированные технические посты, в основном контент расчитан на более широкую аудиторию, но сегодня я не удержался. Предыстория очень простая. Во время сборки кастомного Recovery для одного из аппаратов на чипе от Mediatek я столкнулся с проблемой - тачпад в Recovery не работал, а любые упоминания о mtk-tpd напрочь отсутствовали в /sys/class/input. Надо сказать что mtk-tpd это как раз и есть тот самый MTK Android Linux Touch Panel Device Driver, который отвечает за работу тачпада. Напомню, что в нормальной ситуации, когда тачпад в recovery работает, сделав что-то вроде grep . /sys/class/input/input*/name в консоли мы должны увидеть примерно следующее:


/sys/class/input/input0/name:ACCDET
/sys/class/input/input1/name:mtk-kpd
/sys/class/input/input2/name:hwmdata
/sys/class/input/input3/name:m_alsps_input
/sys/class/input/input4/name:m_acc_input
/sys/class/input/input5/name:m_gyro_input
/sys/class/input/input6/name:mtk-tpd
/sys/class/input/input7/name:mtk-tpd-kpd

Однако в моей ситуации mtk-tpd отсутствовал. Зная что на одном из форумов есть человек, который уже занимался патчами ядра ARM64 для Mediatek, я обратился к нему с вопросом, а каким образом (честно говоря я рассчитывал на ответ в двух словах, такая-то функция, такая-то проверка) он заставил работать тачпад в recovery и что конкретно он патчил в ядре. Правда здесь я почему-то наткнулся на стену глухого непонимания и какой-то секретности. Ну "секрет" так секрет, настаивать, чтобы кто-то что-то рассказал, если человек сам не хочет бессмысленно. Поэтому я решил провести некий анализ, который занял от минут 30-40 ... теперь голые факты. В MTK существует несколько режимов загрузки, который описаны в заголовочных файлах ядра (mt_boot_common.h), вот они:

/* boot type definitions */
enum boot_mode_t {
 NORMAL_BOOT = 0,
 META_BOOT = 1,
 RECOVERY_BOOT = 2,
 SW_REBOOT = 3,
 FACTORY_BOOT = 4,
 ADVMETA_BOOT = 5,
 ATE_FACTORY_BOOT = 6,
 ALARM_BOOT = 7,
#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)
 KERNEL_POWER_OFF_CHARGING_BOOT = 8,
 LOW_POWER_OFF_CHARGING_BOOT = 9,
#endif
 DONGLE_BOOT = 10,
 UNKNOWN_BOOT
};

В драйвере дисплея в процедуре инициализации тача есть проверка:

static s32 tpd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
 int err = 0;
 int count = 0;

 GTP_INFO("tpd_i2c_probe start.");
 if (RECOVERY_BOOT == get_boot_mode())
  return 0;
 probe_thread = kthread_run(tpd_registration, client, "tpd_probe");
 if (IS_ERR(probe_thread)) {
  err = PTR_ERR(probe_thread);
  GTP_INFO(TPD_DEVICE " failed to create probe thread: %d\n", err);
  return err;
 }

 do {
  msleep(20);
  count++;
  if (check_flag)
   break;
 } while (count < 50);
 GTP_INFO("tpd_i2c_probe done.count = %d, flag = %d", count, check_flag);
 return 0;
}

Как видно при вызове tpd_i2c_probe проверяется, если boot mode у нас равен RECOVERY_BOOT, то драйвер у нас не инициализируется ;) Т.е. со стороны MTK так и задумано что в recovery тач пользователю не нужен. Но ведь TWRP фактически использует только тач, скажете вы и будете правы. Но девайсы на платформе MTK никогда ведь не идут с TWRP в комплекте, а стоковому recovery тач естественно не нужен. Поэтому сейчас я вам расскажу как найти соответствующую проверку в бинарнике ядра, ну а непосредственно патч будет "домашним заданием" ) Должна же остаться какая-то "изюминка" ... Так вот. Для начала узнаем адрес tpd_i2c_probe, для этого от имени root выполняем:

sh -c "echo 0 > /proc/sys/kernel/kptr_restrict"
cat /proc/kallsyms | grep tpd_i2c_probe

В результате получаем нужный нам адрес 0xffffffc000760494. Далее загружаем в любом дизассемблер распакованное ядро (архитектура моего CPU - ARM64, поэтому offset нужной нам функции как видите 64-битный) с адреса 0xFFFFFFC000080000 (для 32-bit ядер - 0xC0008000) и переходим по найденному адресу:


На скриншоте выше наглядно видно и исходники и дизассемблированный код. На поиск нужной функции, как вы можете убедиться, и места проверки в ядре у нас ушло не более 5 минут. Теперь нам достаточно убрать условный переход по адресу 0xFFFFFFC0007604D0, заменив его NOP'ами или любой другой "пустой операцией" и собрать boot с модифицированным ядром назад. После чего при загрузке в recovery тачпад будет успешно инициализироваться.

Успехов вам!

p.s. Да, забыл сказать ... в данном примере мы разбирали инициализацию MediaTek gt91xx touch panel driver. Естественно, что в вашем устройстве может быть другой драйвер тача.

5 комментариев :

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

    ОтветитьУдалить
  2. Добрый день! А возможно ли инвертировать оси тачскрина или акселерометра, не имея исходников ядра?

    ОтветитьУдалить
  3. Здравствуйте. Классная статья, все понятно как делать, но работаю из-под Windows и не могу подобрать дизассемблер под arm64, подскажите, пожалуйста, инструмент. У меня надежда, что bokken откроет, но его с сервера не скачать, internal error.

    ОтветитьУдалить
  4. Какие проги нужны? чтоб выполнить по мануалу

    ОтветитьУдалить