Contribute
Register

[Guide] Creating a Custom SSDT for USBInjectAll.kext

RehabMan

Moderator
Joined
May 2, 2012
Messages
180,798
Motherboard
Intel DH67BL
CPU
i7-2600K
Graphics
HD 3000
Mac
  1. MacBook Air
Mobile Phone
  1. iOS
Overview

One of the serious issues most users will face with 10.11.x (and later, including 10.12.x) is the new USB stack in OS X/macOS. It has a much heavier reliance on ACPI, and as a result is much more likely to expose bugs in your ACPI implementation of _PLD, and _UPC.

It is covered in detail in my guide: https://www.tonymacx86.com/threads/guide-10-11-usb-changes-and-solutions.173616/

You should be familiar with the write-up above before attempting a custom SSDT.

Many tend to over-simplify the problem, and, for example, believe they can simply apply the port-limit patch and install USBInjectAll.kext and be done with it. In fact, the port limit patch is known to cause problems (it causes access outside a fixed array bounds). Somewhat alarming is the fact that Multibeast includes the port limit patch without mention of its problems. Also, for each update, a new port limit patch may need to be created (as I write this, no working patch exists for 10.14.1, for example).

The fact: Using the port limit patch is not good solution for anything. For reliable USB (assuming your ACPI implementation of _PLD and _UPC is broken... and you don't want to fix it), you must implement a custom SSDT for USBInjectAll.kext that configures your ports on XHC such that the port limit patch is not needed, and each UsbConnnector value is correct for each port.

Note: It is also possible to build a port injector codeless kext. That method is not covered in this guide.

This guide is written such that there is no dependency on any port limit patch.

Not only does a custom SSDT allow you to avoid the port limit patch, but disabling USB ports that are not used can have some power saving properties, and can avoid bugs with sleep, restart, or shutdown.

This guide will show how this is done.

The process consists of the following steps:
- preparation for port discovery
- port discovery
- creating custom SSDT for USBInjectAll.kext
- testing/verification

The MaciASL used by this guide is available here: https://bitbucket.org/RehabMan/os-x-maciasl-patchmatic/downloads/
Make sure you have ACPI 6.2a selected in MaciASL->Preferences->iASL.


Preparation for port discovery

In order to create a custom SSDT that contains the correct data for a given computer's USB arrangement, we must first discover all the ports that need to be enabled. Once we know which ports are used, we can eliminate the unused ports.

In order to discover the ports, we need to at some point inject all possible ports, then test them. Due to the 15 port limit injection of the ports and testing may have to be done in groups (of 15 or less).

Requirements:
- EHC1->EH01 and EHC2->EH02 rename (in config.plist), if applicable (your chipset may not have EHCI, or it may be disabled)
- XHCI controller must be named XHC or XHCI (for most PCs it is default XHC)
- install USBInjectAll.kext (install to the system volume)
- if you plan to use it, install FakePCIID.kext + FakePCIID_XHCIMux.kext. FakePCIID_XHCIMux only applicable if you have enabled EHCI controller(s).
- if you have an existing SSDT for USBInjectAll, use -uia_ignore_rmcf
- XHCI injector kext, if required (XHCI-unsupported.kext)

The EHCx renames and port limit patches are available in config_patches.plist (https://github.com/RehabMan/OS-X-USB-Inject-All/raw/master/config_patches.plist) in the USBInjectAll.kext repository. Use copy/paste from a plist editor to get them into your own config.plist.

The EHCx renames look like this in Xcode:
Screen Shot 2017-01-02 at 2.10.01 PM.png


The -uia_ignore_rmcf is added to config.plist/Boot/Arguments:
Screen Shot 2017-01-02 at 2.12.18 PM.png


After preparing for port discovery, you should check in ioreg that all expected (depending on exclusions) ports are injected for your chipset on both EHCI and XHCI controllers.

For the NUC7i7KYK, we cannot inject all the ports at one time, so we inject at first only the HSxx ports, then next the SSxx and USRx ports. This partial injection is covered in detail in the following section.

Injection of just HSxx:
uia_exclude_ss exclude=USR1,USR2 injection.png


Injection of just HS03,SSxx,USRx:
uia_exclude_hs uia_include=HS03 injection.png


This is what full looks like on my Lenovo u430 using FakePCIID_XHCIMux.kext. Full injection is possible with the u430 as its xHCI controller has less than 15 ports possible.

Note they are the same as the ports provided by USBInjectAll.kext.

XHC:
Screen Shot 2017-01-02 at 2.49.02 PM.png


EH01:
Screen Shot 2017-01-02 at 2.50.08 PM.png


Once you have all ports being injected, you can proceed to the next step where you will determine which ports are actually needed.


Port discovery

In order to discover which ports need to be in the SSDT, we will use IORegistryExplorer:

- run IORegistryExplorer
- test each port with both USB2 and USB3 devices

Since IORegistryExplorer tracks changes to IOKit objects (existing objects black, new objects in green, disconnected objects in red), we can use the data to determine which ports are actually used.

IORegistryExplorer.app can be downloaded from the attachment at this thread: http://www.tonymacx86.com/audio/58368-guide-how-make-copy-ioreg.html

After you download and extract IORegistryExplorer.app, run it. And keep it running throughout the test.

Note: All data needed by this guide is in the IOService registry plane. DO NOT CHANGE the registry plane from IOService.

Test each port by inserting a both a USB2 device and a USB3 device (obviously, independently). If you look carefully while you insert and remove the devices you can see which ports are assigned to which physical port (you will see the changes in ioreg).

Note: If you have a USB3 hub it can make it easier to test each port. Since a USB3 hub connects to both the USB3 pins and the USB2 pins of a USB3 port (and can be used in a USB2-only port), and it requires no action to eject properly, you will find it much quicker to use a USB3 hub instead of a set of USB2/USB3 memory sticks. In the examples that follow, I'm using a USB3 hub to test ports.

DO NOT USE the 'Search' box in IORegistryExplorer.app! Just look at the correct section of the ioreg tree on the left pane (scroll as necessary to find the EH01/EH02/XHC as applicable to your hardware).

Note that to test each port properly, you may need to move any USB keyboard or mouse device to different ports so that you can test each port with both USB2 and USB3 (or USB3 hub).

For the NUC6i7KYK, testing must be done in groups as it is not possible to enable all ports at once. For this reason, we first test with just the HSxx ports enabled, then follow up testing of the SSxx and USRx ports.

On my NUC6i7KYK, we boot with kernel flag -uia_exclude_ss uia_exclude=USR1,USR2 to test only the HSxx ports.
This is what it looks like before testing any of the ports:
uia_exclude_ss exclude=USR1,USR2 before testing.png


You can see that only the HS03 port is being used. The HS03 port happens to be where my Dell U3011 USB hub is plugged in, which also happens to have my USB keyboard/mouse dongle. The HS09 is the internal bluetooth controller. Making a note of the ports needed for operable keyboard and mouse is important when you go to test the SSxx ports, since you will need to use uia_include to include the HSxx port that your keyboard and mouse are attached to.

After testing all ports:
uia_exclude_ss exclude=USR1,USR2 after testing.png


I usually monitor ioreg as I plug and unplug devices so I know where the ports are located physically.
As you can see, the following ports are used:
HS01: USB3 front left
HS02: USB3 front right
HS03: USB3 rear bottom
HS04: USB3 rear top
HS09: bluetooth

Next, we boot with -uia_exclude_hs uia_include=HS03 to test SSxx and USRx ports. Before testing, it looks like this:
uia_exclude_hs include=HS03 before testing.png


After testing all ports with a USB3 device:
uia_exclude_hs include=HS03 after testing.png


Results:
SS01: USB3 front left
SS02: USB3 front right
SS03: USB3 rear bottom
SS04: USB3 rear top

Note that the SSxx ports will have a corresponding HSxx port. The SSxx port (or SSPx) is used when you plug in a USB3 device. The HSxx port is used when you plug in a USB2 device. USB2 only ports will use only HSxx.

Composite results:
HS01/SS01: USB3 front left
HS02/SS02: USB3 front right
HS03/SS03: USB3 rear bottom
HS04/SS04: USB3 rear top
HS09: bluetooth

So, although the controller used on this Skylake computer has the potential for 26 ports (HS01-HS14, SS01-SS10, USR1, USR2), only 9 ports are connected. We can eliminate HS05-HS08, HS10-HS14, SS05-SS10, USR1, and USR2.

Let's take a look at the test results for my Lenovo u430 (using FakePCIID_XHCIMux.kext).

Before testing:
Screen Shot 2017-01-02 at 3.04.07 PM.png


Screen Shot 2017-01-02 at 2.59.49 PM.png


After testing all ports:
Screen Shot 2017-01-02 at 3.06.50 PM.png


Screen Shot 2017-01-02 at 3.07.28 PM.png


Ports used (EH01/HUB1/XHC):
PR11: internal hub
HP11: touchscreen
HP12/SSP1: USB3 left
HP14: USB2 far right
HP15: USB2 near right
HP15: camera
HP16: bluetooth

Or, if we remove FakePCIID_XHCIMux.kext:

Before testing:
Screen Shot 2017-01-02 at 3.17.40 PM.png


Screen Shot 2017-01-02 at 3.17.51 PM.png


After testing:
Screen Shot 2017-01-02 at 3.21.35 PM.png


Screen Shot 2017-01-02 at 3.23.05 PM.png


Ports used (only on XHC):
HS01: touchscreen
HS02/SSP1: USB3 left
HS02: USB2 far right
HS03: USB2 near right
HS05: camera
HS06: bluetooth

As you can see, FakePCIID_XHCIMux.kext has the effect of moving all HSxx ports to EHCI (to the internal hub on EH01.PR11).

After you have collected the data in IORegistryExplorer, and you are certain that is accurate, you are now prepared to create a custom SSDT based on the data you have obtained in ioreg.


Creating custom SSDT for USBInjectAll.kext

USBInjectAll.kext is coded in a data driven way. Nothing is hard-coded in the kext code itself. All data is contained in the Info.plist. When USBInjectAll.kext starts, matching on EH01/EH02/XHC, or the internal hubs connected to EH01/EH02 port 1, it consults the configuration data in Info.plist as related to the device it has attached to and injects the data it finds there. But an SSDT can be used to override the data in the Info.plist.

A template is provided in the USBInjectAll.kext github repo, SSDT-UIAC-ALL.dsl, which has overrides for all the data already in the USBInjectAll.kext Info.plist. You could compile SSDT-UIAC-ALL.dsl to SSDT-UIAC-ALL.aml (File Save As, format: ACPI Machine Language Binary in MaciASL) and place it in ACPI/patched, and although all the data in the Info.plist will be overridden by the SSDT, no net change would be observed, as the data in SSDT-UIAC-ALL.dsl is the same as the data already in the USBInjectAll.kext Info.plist.

In order to effect our changes, we must modify the SSDT-UIAC-ALL.dsl so it contains only the ports we need.

The steps are as follows:
- use SSDT-UIAC-ALL.dsl as a template (https://github.com/RehabMan/OS-X-USB-Inject-All/raw/master/SSDT-UIAC-ALL.dsl)
- remove configuration sections that don't apply to the target hardware
- remove ports from the various sections that are not needed
- change UsbConnector values to match physical hardware/ports

The first step is to eliminate configuration data from SSDT-UIAC-ALL.dsl that don't apply to the target hardware and USB configuration.

For example, if no ports are active on EH01/EH02 or the related USB hubs (on PR11/PR21), you can eliminate the configuration data for EH01/EH02/HUB1/HUB2. In the case of Skylake, it has no EHCI controllers, so EH01/EH02/HUB1/HUB2 configuration can be removed without much consideration. Same would be true if you're disabling EHCI either via BIOS or ACPI (covered later). And you can eliminate any XHC configuration that does not match your XHC device-id. Look in ioreg to find your XHC device-id.

For example, you can see that the NUC6i7KYK uses 0xa12f:
Screen Shot 2017-01-02 at 2.30.25 PM.png


So, for the NUC's XHC, it will match against the data for "8086_a12f" in the SSDT-UIAC-ALL.dsl. We can eliminate all other XHC configuration data.

For the NUC6i7KYK, we end up with this starter template:
Code:
// Initial trimmed SSDT-UIAC.dsl for NUC6i7KYK
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "8086_a12f", Package()
            {
                "port-count", Buffer() { 26, 0, 0, 0 },
                "ports", Package()
                {
                    "HS01", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HS02", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HS03", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HS04", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HS05", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 5, 0, 0, 0 },
                    },
                    "HS06", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 6, 0, 0, 0 },
                    },
                    "HS07", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 7, 0, 0, 0 },
                    },
                    "HS08", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 8, 0, 0, 0 },
                    },
                    "HS09", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 9, 0, 0, 0 },
                    },
                    "HS10", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 10, 0, 0, 0 },
                    },
                    "HS11", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 11, 0, 0, 0 },
                    },
                    "HS12", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 12, 0, 0, 0 },
                    },
                    "HS13", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 13, 0, 0, 0 },
                    },
                    "HS14", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 14, 0, 0, 0 },
                    },
                    "SS01", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 17, 0, 0, 0 },
                    },
                    "SS02", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 18, 0, 0, 0 },
                    },
                    "SS03", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 19, 0, 0, 0 },
                    },
                    "SS04", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 20, 0, 0, 0 },
                    },
                    "SS05", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 21, 0, 0, 0 },
                    },
                    "SS06", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 22, 0, 0, 0 },
                    },
                    "SS07", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 23, 0, 0, 0 },
                    },
                    "SS08", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 24, 0, 0, 0 },
                    },
                    "SS09", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 25, 0, 0, 0 },
                    },
                    "SS10", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 26, 0, 0, 0 },
                    },
                    "USR1", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 15, 0, 0, 0 },
                    },
                    "USR2", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 16, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

In the case of the NUC6i7KYK, it matches against a section in SSDT-UIAC-ALL.dsl that matches specifically against "8086_a12f". Some XHC devices will match against only part of the device-id. For example, the u430 device-id is 0x9c31. As there is no specific configuration for "8086_9c31", it will match against "8086_9xxx". Always use the template data that has the most specific match for your device-id. For example, if your device-id is 0x9cb1, you should use the template data for "8086_9cb1", not "8086_9xxx". Similarly, if your device id 0x9ded, use the template data 8086_9dxx, not 8086_9xxx.

After you trim the template down to include only the configuration sections you need, now it is time to further trim the data to eliminate unused ports. As you recall, the NUC6i7KYK uses only HS01-HS04, HS09, and SS01-SS04.

The resulting SSDT-UIAC.dsl for NUC6i7KYK with only the ports we need:
Code:
// Port trimmed SSDT-UIAC.dsl for NUC6i7KYK
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "8086_a12f", Package()
            {
                "port-count", Buffer() { 26, 0, 0, 0 },
                "ports", Package()
                {
                    "HS01", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HS02", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HS03", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HS04", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HS09", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 9, 0, 0, 0 },
                    },
                    "SS01", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 17, 0, 0, 0 },
                    },
                    "SS02", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 18, 0, 0, 0 },
                    },
                    "SS03", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 19, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

We can comment each port based on notes we took about each:
Code:
// Port trimmed with port comments SSDT-UIAC.dsl for NUC6i7KYK
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "8086_a12f", Package()
            {
                "port-count", Buffer() { 26, 0, 0, 0 },
                "ports", Package()
                {
                    "HS01", Package() // HS USB3 front left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HS02", Package() // HS USB3 front right
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HS03", Package() // HS USB3 rear bottom
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HS04", Package() // HS USB3 rear top
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HS09", Package() // bluetooth
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 9, 0, 0, 0 },
                    },
                    "SS01", Package() // SS USB3 front left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 17, 0, 0, 0 },
                    },
                    "SS02", Package() // SS USB3 front right
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 18, 0, 0, 0 },
                    },
                    "SS03", Package() // SS USB3 rear bottom
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 19, 0, 0, 0 },
                    },
                    "SS04", Package() // SS USB3 rear top
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 20, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

And we should change the UsbConnector values to match the type of port. The defaults are not always correct (USBInjectAll has no way to know what the correct value is).

Note: DO NOT CHANGE the port address assignments. All of the port addresses in SSDT-UIAC-ALL.dsl are correct. Changing them can only break things.

Common port connector types are USB2 = 0, USB3 = 3, internal = 255.

USB type C ports can be either 9 or 10, which depends on how the hardware deals with the two possible orientations of a USB type C device/cable.
If a USB-C uses the same SSxx in both orientations, then it has an internal switch (UsbConnector=9).
If a USB-C uses a different SSxx in each orientation, then it has no switch (UsbConnector=10).

HSxx ports that are connected to a USB3 port should be marked UsbConnector=3, not UsbConnector=0.

Note: Read the ACPI spec for more valid values (_UPC).

In the case of the NUC6i7KYK, only HS09 needs adjusting. Since the bluetooth controller is internal, it should be 255.

The final SSDT-UIAC.dsl is:
Code:
// Port trimmed with port comments and correct UsbConnector SSDT-UIAC.dsl for NUC6i7KYK
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "8086_a12f", Package()
            {
                "port-count", Buffer() { 26, 0, 0, 0 },
                "ports", Package()
                {
                    "HS01", Package() // HS USB3 front left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HS02", Package() // HS USB3 front right
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HS03", Package() // HS USB3 rear bottom
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HS04", Package() // HS USB3 rear top
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HS09", Package() // bluetooth
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 9, 0, 0, 0 },
                    },
                    "SS01", Package() // SS USB3 front left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 17, 0, 0, 0 },
                    },
                    "SS02", Package() // SS USB3 front right
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 18, 0, 0, 0 },
                    },
                    "SS03", Package() // SS USB3 rear bottom
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 19, 0, 0, 0 },
                    },
                    "SS04", Package() // SS USB3 rear top
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 20, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

Now we are ready to compile this file and place it in EFI/Clover/ACPI/patched. In MaciASL, you can compile as AML by using File -> Save As, format: ACPI Machine Language Binary. Save it to a location you know how to navigate to (desktop). Then mount your EFI partition and copy it to EFI/Clover/ACPI/patched. I suggest using SSDT-UIAC.aml for the name.

Note: If you're using config.plist/ACPI/SortedOrder, you must insure that the new SSDT is listed in SortedOrder. If SortedOrder is specified, Clover will load only those SSDTs listed in SortedOrder.

After you have copied the SSDT to ACPI/patched, you are ready to test. If it does not work (ports missing, port discovery done incorrectly, wrong template used, etc), you can always use -uia_ignore_rmcf to disable the override code in SSDT, and then check your work.

As you can see from the image below from the NUCi7KYK, we now have just the ports that we need injected and are well under the 15-port limit:
Screen Shot 2017-01-02 at 7.02.47 PM.png


Lenovo u430 example with EH01 and HUB1

Since Skylake doesn't have an EHCI controller, we only needed to customize for XHC. The Lenovo u430 uses an 8-series chipset, therefore it has an EHCI controller. Although it can be disabled (which I actually do for my u430 in real use), this walk through will keep it enabled as a way of demonstrating EHCI and the related hub configuration.

Just as we did with the Skylake NUC6, we start by removing all configuration sections not needed from SSDT-UIAC-ALL for the Lenovo u430 based on the data we collected with FakePCIID_XHCIMux.kext. The XHC controller is 0x9c31, so we need only "8086_9xxx" for the XHC configuration, and we need EH01 and HUB1 for the ports on the EHCI controller and related hub.

The resulting trimmed SSDT is:
Code:
// Initial trim SSDT-UIAC.dsl for u430
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")

        Name(RMCF, Package()
        {
            "HUB1", Package()
            {
                "port-count", Buffer() { 8, 0, 0, 0 },
                "ports", Package()
                {
                    "HP11", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HP12", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HP13", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HP14", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HP15", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 5, 0, 0, 0 },
                    },
                    "HP16", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 6, 0, 0, 0 },
                    },
                    "HP17", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 7, 0, 0, 0 },
                    },
                    "HP18", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 8, 0, 0, 0 },
                    },
                },
            },
            "EH01", Package()
            {
                "port-count", Buffer() { 8, 0, 0, 0 },
                "ports", Package()
                {
                    "PR11", Package()
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "PR12", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "PR13", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "PR14", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "PR15", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 5, 0, 0, 0 },
                    },
                    "PR16", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 6, 0, 0, 0 },
                    },
                    "PR17", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 7, 0, 0, 0 },
                    },
                    "PR18", Package()
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 8, 0, 0, 0 },
                    },
                },
            },
            "8086_9xxx", Package()
            {
                "port-count", Buffer() { 13, 0, 0, 0 },
                "ports", Package()
                {
                    "HS01", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HS02", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HS03", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HS04", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HS05", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 5, 0, 0, 0 },
                    },
                    "HS06", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 6, 0, 0, 0 },
                    },
                    "HS07", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 7, 0, 0, 0 },
                    },
                    "HS08", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 8, 0, 0, 0 },
                    },
                    "HS09", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 9, 0, 0, 0 },
                    },
                    "SSP1", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 10, 0, 0, 0 },
                    },
                    "SSP2", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 11, 0, 0, 0 },
                    },
                    "SSP3", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 12, 0, 0, 0 },
                    },
                    "SSP4", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 13, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

If we installed that SSDT unmodified at this point, because all possible ports are included, we would have same result as without it.

Also note it is good practice for the XHC configuration to change to the actual device id, in this case "8086_9c31". In this case, either will work "8086_9xxx" or "8086_9c31", but using a specific configuration identifier helps identify the specific XHC device this SSDT was made for.

Note: You can also use "XHC".

So, after removing ports that are not used, and changing the XHC configuration identifier to "8086_9c31":
Code:
// Port trimmed SSDT-UIAC.dsl for u430
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "HUB1", Package()
            {
                "port-count", Buffer() { 8, 0, 0, 0 },
                "ports", Package()
                {
                    "HP11", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                    "HP12", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 2, 0, 0, 0 },
                    },
                    "HP13", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 3, 0, 0, 0 },
                    },
                    "HP14", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 4, 0, 0, 0 },
                    },
                    "HP15", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 5, 0, 0, 0 },
                    },
                    "HP16", Package()
                    {
                        //"UsbConnector", 0,
                        "portType", 0,
                        "port", Buffer() { 6, 0, 0, 0 },
                    },
                },
            },
            "EH01", Package()
            {
                "port-count", Buffer() { 8, 0, 0, 0 },
                "ports", Package()
                {
                    "PR11", Package()
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 1, 0, 0, 0 },
                    },
                },
            },
            "8086_9c31", Package()
            {
                "port-count", Buffer() { 13, 0, 0, 0 },
                "ports", Package()
                {
                    "SSP1", Package()
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 10, 0, 0, 0 },
                    },
                },
            },
        })
    }
}
//EOF

In this case, there is no need to modify any of the UsbConnector values, since they are already set correctly. The USB Hub driver in macOS/OS X does not use UsbConnector and we don't really understand the purpose of portType. You can experiment with different values if you need to. Refer to the hub driver Info.plist in IOUSBHostFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/Info.plist for ideas.

Note: If anyone has a Sierra or El Capitan ioreg from a MacPro6,1, MacBookPro8,1, MacBookPro6,1, iMac13,x, or MacBookPro8,3 along with information about the physical hub ports where portType=2 or portType=0 is used, please share.

After we install this SSDT, remove -uia_ignore_rmcf, we can verify in ioreg and test that all ports work.

Here we have images of the ports injected on EH01, HUB1, and XHC:
Screen Shot 2017-01-02 at 2.43.14 PM.png


Screen Shot 2017-01-02 at 2.45.42 PM.png


Note that for my Lenovo u430, I decided to disable the EHCI controller and have everything on XHC. FakePCIID_XHCIMux.kext is not installed.

The resulting SSDT is as follows (in this SSDT, I used "XHC" instead of "8086_9xxx" or "8086_9c31" just to show it is possible):
Code:
// With EHCI disabled, SSDT-UIAC.dsl for u430
DefinitionBlock ("", "SSDT", 2, "hack", "UIAC", 0)
{
    Device(UIAC)
    {
        Name(_HID, "UIA00000")
        Name(RMCF, Package()
        {
            "XHC", Package()
            {
                //"port-count", Buffer() { 0x0d, 0, 0, 0},
                "ports", Package()
                {
                    "HS01", Package() // touchscreen
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 0x01, 0, 0, 0 },
                    },
                    "HS02", Package() // HS USB3 left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 0x02, 0, 0, 0 },
                    },
                    "HS03", Package() // USB2 far right
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 0x03, 0, 0, 0 },
                    },
                    "HS04", Package() // USB2 near right
                    {
                        "UsbConnector", 0,
                        "port", Buffer() { 0x04, 0, 0, 0 },
                    },
                    "HS05", Package() // camera
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 0x05, 0, 0, 0 },
                    },
                    "HS06", Package() // bluetooth
                    {
                        "UsbConnector", 255,
                        "port", Buffer() { 0x06, 0, 0, 0 },
                    },
                    "SSP1", Package() // SS USB3 left
                    {
                        "UsbConnector", 3,
                        "port", Buffer() { 0x0a, 0, 0, 0 },
                    },
                },
            },
        })
    }

//
// Disabling EHCI #1
//
    External(_SB.PCI0, DeviceObj)
    External(_SB.PCI0.LPCB, DeviceObj)
    External(_SB.PCI0.EH01, DeviceObj)
    Scope(_SB.PCI0)
    {
        // registers needed for disabling EHC#1
        Scope(EH01)
        {
            OperationRegion(PSTS, PCI_Config, 0x54, 2)
            Field(PSTS, WordAcc, NoLock, Preserve)
            {
                PSTE, 2  // bits 2:0 are power state
            }
        }
        Scope(LPCB)
        {
            OperationRegion(RMLP, PCI_Config, 0xF0, 4)
            Field(RMLP, DWordAcc, NoLock, Preserve)
            {
                RCB1, 32, // Root Complex Base Address
            }
            // address is in bits 31:14
            OperationRegion(FDM1, SystemMemory, Add(And(RCB1,Not(Subtract(ShiftLeft(1,14),1))),0x3418), 4)
            Field(FDM1, DWordAcc, NoLock, Preserve)
            {
                ,15,    // skip first 15 bits
                FDE1,1, // should be bit 15 (0-based) (FD EHCI#1)
            }
        }
        Device(RMD1)
        {
            //Name(_ADR, 0)
            Name(_HID, "RMD10000")
            Method(_INI)
            {
                // disable EHCI#1
                // put EHCI#1 in D3hot (sleep mode)
                Store(3, ^^EH01.PSTE)
                // disable EHCI#1 PCI space
                Store(1, ^^LPCB.FDE1)
            }
        }
    }
}
//EOF

Don't expect to understand the code under "Disabling EHCI #1" unless you have had a good read of the ACPI specification and the Intel 8-series chipset datasheet.

Here is the result with everything on XHC (no EH01 to be found in ioreg):
Screen Shot 2017-01-02 at 3.33.02 PM.png



Problem Reporting

If you have a problem, please describe the problem clearly, make sure your profile accurately describes your hardware and provide all the data as requested in the FAQ.

Read FAQ, "Problem Reporting". Attach all requested files/output.
https://www.tonymacx86.com/threads/faq-read-first-laptop-frequent-questions.164990/
Use the gen_debug.sh tool mentioned in the FAQ, that way it is less likely you'll omit something.

Compress all files as ZIP. Do not use external links. Attach all files using site attachments only.
 
Last edited:
Good job! Thx~
 
nice thread.i used "FakePCIID_XHCIMux.kext" and all my usb ports are working fine. i will try tomorrow for custom ssdt. btw, since all my usb ports are working on the given kext. what happen to my system if i didn't create a custom ssdt?and fakepciid_xhcimux.kext will remain in my system.
 
nice thread.i used "FakePCIID_XHCIMux.kext" and all my usb ports are working fine. i will try tomorrow for custom ssdt. btw, since all my usb ports are working on the given kext. what happen to my system if i didn't create a custom ssdt?and fakepciid_xhcimux.kext will remain in my system.

The need for a custom SSDT is covered in post #1.
 
Disable EHCI controller not working!
I copied the last code stretch of this guide into my working costum SSDT UIAC and rebooted only to find that EH01 + AppleHub were still there and ALSO the HS08 and HS09 ports of my XHC still show up in Ioreg even though they are not there in my SSDT edit... what am I doing wrong?
 

Attachments

Disable EHCI controller not working!
I copied the last code stretch of this guide into my working costum SSDT UIAC and rebooted only to find that EH01 + AppleHub were still there and ALSO the HS08 and HS09 ports of my XHC still show up in Ioreg even though they are not there in my SSDT edit... what am I doing wrong?

Read post #1 carefully regarding SortedOrder.
 
Thank you for your great guide! I made a custom SSDT and removed the port limit patch, so now only the ports I selected show up correctly in IOreg.
However, on my board (z170x-ud3) there is also a red USB 3.1 (and a USB type C which I can't test). The red USB 3.1 shows up in IOreg under RP01@1C. I didn't include it the SSDT but it still shows up. It seems to work ok but I doubt it is properly configured... Should I do anything about it?
IOreg attached as reference.
 

Attachments

Thank you for your great guide! I made a custom SSDT and removed the port limit patch, so now only the ports I selected show up correctly in IOreg.
However, on my board (z170x-ud3) there is also a red USB 3.1 (and a USB type C which I can't test). The red USB 3.1 shows up in IOreg under RP01@1C. I didn't include it the SSDT but it still shows up. It seems to work ok but I doubt it is properly configured... Should I do anything about it?
IOreg attached as reference.

If it is working, nothing to do.
 
Overview

Preparation for port discovery

In order to create a custom SSDT that contains the correct data for a given computer's USB arrangement, we must first discover all the ports that need to be enabled. Once we know which ports are used, we can eliminate the unused ports.

In order to discover the ports, we need to be certain all ports are enabled.

Requirements:
- EHC1->EH01 and EHC2->EH02 rename (in config.plist)
- XHCI controller must be named XHC (for most PCs it is default)
- port limit patch (in config.plist)
- install USBInjectAll.kext (install to the system volume)
- if you plan to use it, install FakePCIID.kext + FakePCIID_XHCIMux.kext
- if you have an existing SSDT for USBInjectAll, use -uia_ignore_rmcf

The EHCx renames and port limit patches are available in config_patches.plist in the USBInjectAll.kext repository. Use copy/paste from a plist editor to get them into your own config.plist.

Hello RehabMan, thank you for this huge guide!! A lot of work!

I installed a fresh copy of MacOs Sierra at my MSI Z77MA-G45. Everything works except USB and my Bluetooth dongle. And so I have to do this steps of your guide. But I´m a newbe. I don´t understand in which config.plist I have to rename EHC1, EHC2 and XHCI. How do I the port limit patch? And could I simple install USBInjectAll.kext with kexthelper for example?

:( Sorry for this newbe questions..
 
Hello RehabMan, thank you for this huge guide!! A lot of work!

I installed a fresh copy of MacOs Sierra at my MSI Z77MA-G45. Everything works except USB and my Bluetooth dongle. And so I have to do this steps of your guide. But I´m a newbe. I don´t understand in which config.plist I have to rename EHC1, EHC2 and XHCI. How do I the port limit patch? And could I simple install USBInjectAll.kext with kexthelper for example?

:( Sorry for this newbe questions..

Use a plist editor (Xcode or PlistEdit Pro) to edit your config.plist on your EFI partition at EFI/Clover/config.plist.
I don't use kext installers (I use Terminal instead), but one you should try is Kext Wizard. You could also use KextBeast from this site (be careful, it will install all kexts you might have sitting on your desktop).
 
Back
Top