[Перевод] USB-C хаб за 40 евро превратился в док-станцию для Switch 2 благодаря 540 байтам прошивки питания и 108 байтам для HDR
Я часто беру Nintendo Switch 2 в поездки и всякий раз сталкиваюсь с одной проблемой: официальная док-станция слишком громоздкая и на вид хрупкая, поэтому возить её с собой не хочется. А жаль: она использует DisplayPort Alt Mode через USB-C, и у меня уже есть хаб с поддержкой этого режима, который отлично работает со всеми остальными устройствами. Но Nintendo, как это нередко бывает, выбрала собственный путь: обычный хаб заменить док не может.
Недавно друг подарил мне сниффер USB-PD. Я решил разобраться, как именно ведёт себя консоль и почему она согласна работать только с официальной док-станцией.
Хаб
Я пользуюсь Cable Matters 7-in-1 с выходами для трёх мониторов — DP, HDMI и VGA — и поддержкой питания до 60 Вт. Разобрав хаб, я обнаружил внутри следующие компоненты:
-
VL103 — контроллер USB-PD;
-
VL817 — USB-хаб;
-
RTD2142 — MST-хаб DisplayPort, который здесь используется как конвертер DP→HDMI;
-
флеш-память XT25F16B с прошивками.


Switch заряжается через этот хаб, а значит, стандартный USB-PD ей понятен. Можно предположить, что фирменное «рукопожатие» дока Nintendo происходит поверх USB-PD с помощью сообщений, определяемых производителем, — vendor-defined messages.
Со штатной прошивкой процесс подключения Switch заходит на удивление далеко. Консоль согласовывает питание, переходит в DisplayPort Alt Mode и даже настраивает назначение контактов D, а хаб подтверждает каждый этап. Но затем всё останавливается: ни телевизионного режима, ни изображения. Одного DisplayPort Alt Mode недостаточно — прежде должно произойти что-то ещё.
Инструменты
Сниффер USB-PD. Я использовал WITRN K2: он подключается в разрыв кабеля USB-C и показывает PD-трафик. Приложение для него доступно только под Windows, поэтому я попросил Claude написать небольшую консольную утилиту для Linux. Она считывает HID-отчёты в отдельном потоке, декодирует их с помощью usbpdparser и сохраняет в JSONL для последующего воспроизведения.
Прошивка PD-контроллера. В VL103 установлен микроконтроллер 8051 с 32 КиБ прошивки. Плагин vli для fwupd уже умеет считывать и записывать её через хаб VL817 — не хватало лишь записи quirk с USB ID моего хаба. В конце образа находится CRC-16/USB, а свободного стёртого пространства для нового кода предостаточно.
sudo fwupdtool --plugins vli firmware-dump OUT.bin <device-id>
sudo fwupdtool --plugins vli --allow-reinstall --prepare --cleanup \
install-blob patched.bin <device-id>
Для реверс-инжиниринга я использовал процессорный модуль 8051 в Ghidra для дизассемблирования, ассемблер из SDCC для создания патчей и симулятор 8051 uCsim, чтобы проверять настоящую прошивку на записанных дампах трафика.
Хотя опыт программирования под 8051 у меня есть, в этом проекте я активно пользовался Claude и GPT. Они помогали с дизассемблированием, созданием патчей и анализом штатной прошивки хаба. Без их помощи завершить работу было бы гораздо сложнее.
Изучаем трафик официального дока
Подключаю сниффер, запускаю скрипт на ПК и наблюдаю за обменом USB-PD:
14:19:11.863 SOP Source_Capabilities Source/DFP id=0 [F 5.0V@3.0A, F 9.0V@3.0A, F 15.0V@2.8A]
14:19:11.868 SOP Request Sink/UFP id=0 [[3] F 15.0V@2.8A]
14:19:12.070 SOP Vendor_Defined Sink/DFP id=4 VDM PD SID(0xFF00) Discover Identity REQ
14:19:12.073 SOP Vendor_Defined Source/UFP id=5 VDM PD SID(0xFF00) Discover Identity ACK VDOs: 0x5460057E 0x00000000 0x20620000 0x65000031 0x00000000
14:19:12.080 SOP Vendor_Defined Source/UFP id=6 VDM PD SID(0xFF00) Discover SVIDs ACK SVIDs: DisplayPort(0xFF01), Nintendo(0x057E)
14:19:12.162 SOP Vendor_Defined Sink/DFP id=0 VDM Nintendo(0x057E) Enter Mode REQ mode #1
14:19:12.183 SOP Vendor_Defined Sink/DFP id=1 VDM DisplayPort(0xFF01) Enter Mode REQ mode #1
14:19:12.210 SOP Vendor_Defined Sink/DFP id=3 VDM DisplayPort(0xFF01) 17 REQ VDOs: 0x00000806
14:19:12.228 SOP Vendor_Defined Sink/DFP id=4 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x00000020
14:19:12.240 SOP Vendor_Defined Source/UFP id=5 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000020 0x00000000
14:19:12.249 SOP Vendor_Defined Sink/DFP id=5 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x00000001
14:19:12.260 SOP Vendor_Defined Source/UFP id=6 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000001 0x03010503
14:19:12.438 SOP Vendor_Defined Sink/DFP id=6 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x00000002
14:19:12.450 SOP Vendor_Defined Source/UFP id=7 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000002 0x0003006E
14:19:12.458 SOP Vendor_Defined Sink/DFP id=7 VDM/unstructured Nintendo(0x057E) 0x0001 VDOs: 0x00000006
14:19:12.471 SOP Vendor_Defined Source/UFP id=0 VDM/unstructured Nintendo(0x057E) 0x0041 VDOs: 0x00000006 0x330107DA 0x06016D68 0x330107DA 0x06016D68
Сразу можно заметить несколько особенностей:
-
Discover Identity. Док представляется устройством Nintendo с VID 057E, идентификатором продукта 2062 и типом «периферия».
-
Discover SVIDs. Наряду с DisplayPort (FF01) док объявляет собственный SVID Nintendo — 057E. Switch переходит в режим Nintendo раньше, чем в режим DisplayPort.
-
Сообщения Nintendo. После настройки DP консоль отправляет серию неструктурированных vendor-сообщений. Каждый запрос содержит 057E0001 и номер команды; в ответ док передаёт 057E0041, ту же команду и данные.
|
Команда |
Ответ дока |
Примечание |
|---|---|---|
|
20 |
00000000 |
также опрашивается периодически |
|
01 |
03010503 |
|
|
29, 44, 41, 49, 23, 131, 51 |
эхо |
|
|
02 |
0003006E |
вероятно, номер версии |
|
06 |
330107DA 06016D68 ×2 |
запись о версии, тег hm |
|
04 |
330107DA 06016D61 ×2 |
запись о версии, тег am |
Значение большей части этих данных мне неизвестно. Записи о версиях по формату совпадают с версиями прошивок Cypress/Infineon CCGx, а в другом проекте по модификации доков заметили, что ответ на команду 02 изменился после обновления официальной станции.
Учим хаб «рукопожатию»
Для начала я извлёк прошивку VL103 и попросил Claude декомпилировать и изучить её. Однако при попытке запустить Ghidra сработал классификатор безопасности, и работа остановилась. В итоге декомпиляцией занялся GPT.
Я добавил в прошивку VL103 обработчик: около 540 байт кода для 8051 разместил в стёртой области и встроил в штатный PD-стек. Он отвечает на сообщения Nintendo, передавая всё остальное оригинальному коду. Затем я вносил изменения по одному:
|
Версия |
Что изменил |
Результат |
|---|---|---|
|
v1/v2 |
добавил ответы на Discover/Enter Mode Nintendo и эхо-команды |
подтверждения на линии есть, DP настроен, изображения нет |
|
v3 |
предложил 15 В / 2,8 А, как у дока (штатный хаб: 2,53 А) |
изображения нет |
|
v4 |
указал vendor ID Nintendo вместо VIA |
изображения нет |
|
v5 |
передал полные идентификационные данные официального дока |
телевизионный режим заработал! |
|
v6 |
добавил ответ на 02 с версией дока |
теперь Switch застревает на 06 |
|
v7 |
добавил ответы на 06 и 04 с записями дока |
последовательность полностью совпадает, док подключается быстрее |
Интереснее всего различие между v4 и v5: одного vendor ID недостаточно, Switch проверяет и другие идентификационные данные. Версия v7 устранила паузу примерно в три секунды: с v5 консоль отправляла запрос 02, получала ответ «Not supported» и ждала, прежде чем продолжить.
Ответы с версиями скопированы с официального дока. Они не отражают реальные версии каких-либо компонентов хаба, а сами команды никак не реализованы. На любую нераспознанную команду по-прежнему отправляется штатный ответ «Not supported».
Проблема с блёклым HDR
Телевизионный режим заработал, но при включённом HDR цвета выглядели заметно бледнее. Официальный док с тем же монитором и в той же игре показывал нормальную картинку. Вот что удалось исключить:
-
Дисплей. Проблема воспроизводится и на мониторе, и на телевизоре; оба показывают значок HDR.
-
Диапазон RGB. С ограниченным диапазоном становится ещё хуже, а с полным изображение всё равно остаётся блёклым.
-
Хаб в целом. Мой ПК с Linux корректно выводит HDR через тот же хаб.
-
PD-контроллер. Трафик PD с включённым и выключенным HDR не отличается.
Изображение выглядело так, словно возникла путаница с цветовым пространством. Я предположил, что Switch передаёт цвет в BT.2020, а дисплею сообщают о BT.709, из-за чего тот сжимает цвета. PD-контроллер вообще не участвует в обработке DisplayPort: сигнал поступает напрямую в RTD2142. Значит, дальше нужно было изучить этот чип.
Внутри RTD2142
Прежде всего требовалось извлечь его прошивку. В flashrom есть программатор realtek_mst_i2c_spi, который взаимодействует с чипом по I²C поверх DP AUX через тот же кабель USB-C. Два считывания дали одинаковые образы размером 2 МиБ. Прошивка не подписана, поэтому изменённый образ можно просто записать обратно. Запасным вариантом была клипса SOIC-8.
flashrom -p realtek_mst_i2c_spi:bus=7,allow_brick=yes,reset_mcu=1 -r rtd2142.bin
Анализ. Внутри снова оказался 8051, на этот раз с восемью банками кода по 64 КиБ, переключаемыми через трамплины. Я доработал свой симулятор, чтобы он отслеживал эти переключения.
Большую помощь оказала база данных инструмента Realtek для родственного чипа RTD2172, найденная в публичном репозитории на GitHub. В ней содержались названия и описания аппаратных регистров, совпавшие с тем, как их использует эта прошивка.
На выходе HDMI цвет изображения описывается в AVI InfoFrame — небольшом пакете, передаваемом вместе с видео. Поля колориметрии в нём указывали на BT.709. Конвертер берёт BT.2020 из входящего потока DisplayPort только в том случае, если оно объявлено одним конкретным стандартным способом, а цветовую метку HDMI обновляет лишь при запуске выхода. Метаданные яркости HDR передаются отдельным пакетом, поэтому телевизор всё равно переходил в режим HDR.
Я изучил, как эту проблему решают производители других сторонних доков. Они выпускали обновления прошивки, которые «исправляют серый или тусклый HDR». В одном из них нашлась отладочная строка «switch2 color space patch»: обнаружив Switch 2 и поток, в котором BT.2020 не обозначен стандартным способом, прошивка берёт колориметрию из EDID дисплея. Похоже, с этой проблемой столкнулся не только я.
Исправляем HDR
Мой патч не распознаёт Switch, а анализирует сами метаданные HDR:
-
если метаданные HDR присутствуют и в них указана передаточная функция PQ или HLG, каждый AVI InfoFrame помечается как BT.2020, после чего его контрольная сумма пересчитывается;
-
InfoFrame пересобирается при каждом включении и выключении HDR;
-
всё остальное остаётся без изменений: те же пиксели и пакеты для SDR, никаких вмешательств в путь DP и процесс запуска.
Патч занимает 108 байт в одном банке: три небольших хука и немного кода в стёртой области заполнения. Перед записью я проверил оригинальную прошивку с патчем в симуляторе: все форматы пикселей, переключение HDR в обе стороны и полную цепочку от входа до выхода.
В результате HDR стал выглядеть правильно. Сами пиксели изначально были в порядке — ошибочной оказалась только метка.
Выход DisplayPort хаба использует другой путь, который я не модифицировал, поэтому HDR через порт DP по-прежнему выглядит блёклым. Я решил, что для меня это недостаточно важно, чтобы заниматься исправлением 🙂
А что с VRR?
Поскольку хаб теперь представляется официальным доком, Switch предлагает включить VRR. Но если это сделать, изображение через порт DP замирает, а частота на HDMI остаётся на уровне 60 Гц. Судя по прошивке, поддержки VRR в ней нет вовсе: она не сообщает источнику о возможности использовать переменные тайминги и не отправляет HDMI-пакет VRR.
Мне хотелось получить полноценный док, поэтому я всё же решил попробовать. В прошивке RTD2142 обнаружился отладочный интерфейс по адресу I²C 0x35 через тот же канал AUX: одна команда считывает любой регистр, другая записывает его. Это позволило наблюдать текущее состояние чипа и изменять регистры без перепрошивки.
Чтобы получить источник, действительно использующий VRR, я сделал второй патч, с которым хаб объявляет поддержку Adaptive-Sync, и передал Linux подменённый EDID. Драйвер amdgpu охотно включил VRR, но экран погас, как только частота кадров начала меняться. Главный цикл чипа переставал отвечать до тех пор, пока тайминги снова не становились стабильными. Чип не перезагружался, а отключение сторожевого таймера FIFO и прерываний не помогло. Моё лучшее предположение — проблема в цикле повторного захвата тактовой частоты, который никак не может стабилизироваться.
Чтобы всё заработало, пришлось бы переписать механизм захвата входного сигнала, надеяться, что генератор таймингов справится с переменной частотой кадров, и добавить HDMI-пакет VRR. На этом я остановился и вернулся к прошивке, исправляющей только HDR. При использовании хаба я просто отключаю VRR в настройках Switch.
Итог
Теперь хаб выполняет роль дорожного дока во всём, что для меня важно: работает телевизионный режим, HDR выводится по HDMI, а Switch при этом заряжается. USB-порты и Ethernet я как следует не проверял. VRR не поддерживается, поэтому в настройках консоли он у меня выключен. Всего для доработки хаба понадобилось около 540 байт в PD-контроллере и 108 байт в RTD2142.
Несмотря на то что хаб теперь представляется официальным доком Nintendo, с моим ПК и телефоном он по-прежнему работает в обычном режиме.
Отдельное спасибо VIA и Realtek за использование 8051: с этими микроконтроллерами взлом становится гораздо проще и доступнее 🙂
Обновление: код опубликован. Патчер доступен на GitHub: https://github.com/mkopec/switch2-hub-patcher. Пробуйте.
Vivo X300 Ultra получил OriginOS 7: камеру улучшили, а автономность увеличили
Данные 46 тысяч сотрудников TSMC продают за 3 биткоина
Атака за пределами GitHub: хакеры нацелились на 8000 репозиториев в поисках ключей OpenAI, Anthropic и облачных сервисов
Сбой Claude связали с аварией Microsoft 365: Anthropic восстановила работу сервиса ИИ
Масштабный сбой Microsoft лишил миллионы пользователей доступа к Outlook и парализовал железнодорожное сообщение в ряде стран
Qwen и локальные нейросети на Mac mini: зачем это нужно?
Как я ремонтировал роутер Starlink в Испании