В настройке USB на хакинтоше мне почудилось какое-то неуловимое сходство с настройкой музыкального инструмента. Потребовалось в процессе и после: программы IORegistryExplorer и maciASL, расширения USBInjectAll.kext и XHCI-200-series-injector.kext, редактор для plist (сойдет TextMate), устройства USB 2.0 и USB 3.0. На выходе получился файл SSDT-USB.aml.

IORegistry / XHC / USB

Для начала нужно положить USBInjectAll.kext и XHCI-200-series-injector.kext в папку /EFI/CLOVER/kexts/other. Первый нужен всем и скорее всего уже будет куда-либо установлен проверьте обычные места (/S/L/E /L/E). Второй необходим для материнских плат на чипсетах 200 серии, без него у меня не работал USB3. Далее нужно устранить ограничение на 15 портов, делается правкой /EFI/CLOVER/config.plist.

Ахтунг, никогда не редактируйте plist/xml и т.п. в приложениях типа TextEdit.

<key>KextsToPatch</key>
 <array>
 <dict>
 <key>Comment</key>
 <string>change 15 port limit to 26 in XHCI kext (200-series) 10.12</string>
 <key>Find</key>
 <data>
 g710////EA==
 </data>
 <key>Name</key>
 <string>AppleUSBXHCIPCI</string>
 <key>Replace</key>
 <data>
 g710////Gw==
 </data>
 </dict>
 ...

После перезагрузки у вас должны работать все имеющиеся USB порты. На этом можно было бы остановиться, но если делать по-уму, то дальше начинается забавная рутина. Суть — оставить только те порты, которые реально существуют на вашей машине и назначить им правильный тип.

Запускаем IORegistryExplorer и ищем HS01, находится он в ветке XHC. Смотрим список соседей. Я не удосужился сделать скриншот «до», но изначально там было 26 устройств типа HSxx SSxx и какие-то USRxx. Для каждого устройства есть набор параметров, из которых нас будет интересовать только port и UsbConnector.

Теперь развлекушка — нужно поочередно подключить к каждому USB 2.0 (черные) и USB 3.0 (обычно синие) разъему на корпусе и материнке USB 2.0 устройство, отследить изменения в IOReg и записать ID устройства, его порт и расположение. Типа такого: HS01 — <04 00 00 00> — Top MB USB3 port. Затем нужно подключить USB 3.0 устройство ко всем USB 3.0 портам и разъемам на материнской плате и сделать похожий список: SS03 — <13 00 00 00> — Internal USB3_1 header. В общем списке должно получиться USB2_count + USB3_count x 2 записей — для каждого USB3 порта будет одна HSxx запись и одна SSxx.

У меня получился такой список:

HS01 USB2 on Back bottom outer USB3 <01 00 00 00>
HS02 USB2 on Back bottom inner USB3 <02 00 00 00>
HS03 USB2 on Back top outer USB3 <03 00 00 00>
HS04 USB2 on Back top inner USB3 <04 00 00 00>
HS06 USB2 on Case top slot USB3 mobo header 1 <06 00 00 00>
HS08 USB2 on Case top slot USB3 mobo header 2 <08 00 00 00>
HS09 USB2 on Case bottom slot USB_1 mobo header <09 00 00 00>
HS11 USB2 on Case bottom slot USB_2 mobo header <0b 00 00 00>
HS13 USB2 on Back topmost inner USB2 <0d 00 00 00>
HS14 USB2 on Back topmost inner USB2 <0e 00 00 00>
SS01 USB3 on Back bottom outer USB3 <11 00 00 00>
SS02 USB3 on Back bottom inner USB3 <12 00 00 00>
SS03 USB3 on Back top outer USB3 <13 00 00 00>
SS04 USB3 on Back top inner USB3 <14 00 00 00>
SS06 USB3 on Case top slot USB3 mobo header 1 <16 00 00 00>
SS08 USB3 on Case top slot USB3 mobo header 2 <18 00 00 00>

В списке есть «дыры» — на внутренних коннекторах USB доступны по 2 порта, но у меня на корпус выведены только 1xUSB2 и 1xUSB3, то есть к оставшимся 4 разъемам я подключиться не могу. Можно их просто заполнить по порядку, но большого смысла нет, поскольку в конце рабочих портов все равно останется только 15.

С этой табличкой на руках запускаем maciASL, создаем новый dsl файл и заполняем нашими данными. Значение для UsbConnector такие: 0 для обычного USB2, 3 для USB3 type A, 10 для USB3 type C, 255 для внутреннего разъема для того самого Bluetooth. В итоге должно получиться что-то типа такого.

DefinitionBlock ("SSDT-USB.aml", "SSDT", 1, "sample", "USBFix", 0x00003000)
{
 // "USBInjectAllConfiguration" : override settings for USBInjectAll.kext
 Device(UIAC)
 {
 Name(_HID, "UIA00000")
 // "RehabManConFiguration"
 Name(RMCF, Package()
 {
 // XHC overrides for 100-series boards
 "8086_a2af", Package()
 {
 "port-count", Buffer() { 0x18, 0, 0, 0}, // Highest port number is SS** at 0xNN
 "ports", Package()
 { // TO COMPLETE THIS FILE, ADD ALL YOUR PORTS BELOW HERE, THEN SET port-count ABOVE
 "HS01", Package() // USB2 on Back bottom outer USB3 <01 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x01, 0, 0, 0 },
 },
 "HS02", Package() // USB2 on Back bottom inner USB3 <02 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x02, 0, 0, 0 },
 },
 "HS03", Package() // USB2 on Back top outer USB3 <03 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x03, 0, 0, 0 },
 },
 "HS04", Package() // USB2 on Back top inner USB3 <04 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x04, 0, 0, 0 },
 },
 "HS06", Package() // USB2 on Case top slot USB3 mobo header 1 <06 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x06, 0, 0, 0 },
 },
 "HS08", Package() // USB2 on Case top slot USB3 mobo header 2 <08 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x08, 0, 0, 0 },
 },
 "HS09", Package() // USB2 on Case bottom slot USB_1 mobo header <09 00 00 00> 
 {
 "UsbConnector", 0,
 "port", Buffer() { 0x09, 0, 0, 0 },
 },
 "HS11", Package() // Bluetooth on slot USB_2 mobo header <0b 00 00 00>
 {
 "UsbConnector", 255,
 "port", Buffer() { 0x0b, 0, 0, 0 },
 },
 "HS13", Package() // USB2 on Back topmost inner USB2 <0d 00 00 00>
 {
 "UsbConnector", 0,
 "port", Buffer() { 0x0d, 0, 0, 0 },
 },
 "HS14", Package() // USB2 on Back topmost outer USB2 <0e 00 00 00>
 {
 "UsbConnector", 0,
 "port", Buffer() { 0x0e, 0, 0, 0 },
 }, 
 "SS01", Package() // USB3 on Back bottom outer USB3 <11 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x11, 0, 0, 0 },
 },
 "SS02", Package() // USB3 on Back bottom inner USB3 <12 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x12, 0, 0, 0 },
 },
 "SS03", Package() // USB3 on Back top outer USB3 <13 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x13, 0, 0, 0 },
 },
 "SS04", Package() // USB3 on Back top inner USB3 <14 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x14, 0, 0, 0 },
 },
 "SS06", Package() // USB3 on Case top slot USB3 mobo header 1 <16 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x16, 0, 0, 0 },
 },
 "SS08", Package() // USB3 on Back bottom outer USB3 <11 00 00 00>
 {
 "UsbConnector", 3,
 "port", Buffer() { 0x18, 0, 0, 0 },
 },

},
 },
 })
 }
}

В port-count нужно вписать цифровое значение port самого последнего порта, у меня это SS08 и порт 0x18.

Полученный файл нужно сохранить в формате ACPI Machine Language Library (asl). Если по ходу компиляции никаких ошибок не будет, то полученный SSDT-USB.aml кладем в /EFI/CLOVER/ACPI/patched и перезагружаемся. Если все прошло нормально, то в XHC должны остаться только описанные порты, все они должны нормально работать.

Опционально — можно довести число портов до 15 и избавиться от патча в config.plist. Сделать это можно при помощи параметра загрузки uia_exclude в том же config.plist. У меня эта строчка выглядит так:

<key>Boot</key>
 <dict>
 <key>Arguments</key>
 <string>dart=0 nv_disable=1 uia_exclude=HS08;SS08</string>
 <key>Debug</key>
 ...

Я исключил порты HS08 и SS08, это внутренний разъем USB3_2, который я не использую — всего осталось 14 штук. В принципе, можно просто выкинуть пару портов из самого asl, наверно, поскольку еще 4 порта я вообще не вписал.

Размышления напоследок

  • Тип разъема мало на что-то влияет, по-моему. Разницы между 0 и 255 я не увидел — Bluetooth не заработал ни так, ни эдак, при этом обычная флэшка в обоих случаях работает.
  • У меня все синие порты вроде заявлены как USB 3.1 Gen 1 (он же новый 3.0), в системной информации показывает Speed: Up to 5 Gb/sec, но фактическую скорость померить нечем.
  • Зачем избавляться от патча, делающего доступными все порты? Чем чревато — непонятно.
  • USB 3.1 Gen 2 у меня нет, как и Type-C, так что двумя проблемами меньше.

Ссылки и респекты