Wake a Legacy Hackintosh with Bluetooth: BCM2046 Patches and ACPI Fixes

Step-by-step guide to enable Bluetooth wake on legacy Hackintosh systems using BCM2046 modules. Covers USB port injection, ACPI GPE patches, IOBluetoothFamily kext fixes, and diagnostics.

When you rely on a Bluetooth keyboard or mouse to wake a legacy Hackintosh from sleep, the difference between a seamless resume and a forced power-cycle often comes down to a single byte in your IORegistry: the BluetoothControllerInfo or, more commonly, the hidden WakeOnBluetooth property inside the USB device node. On real Macs, the Broadcom BCM2046 and BCM20702 controllers are programmed to assert a wake signal on the internal USB port when a paired HID device sends a connection request. On a custom PC, that signal is often lost because the motherboard's USB root hub does not forward the remote wake event to the ACPI power state. This guide focuses on the second generation of Apple's Bluetooth modules—the BCM2046-based cards often found in iMacs and MacBooks from 2008 to 2011—and the specific plist and ACPI patches needed to make them wake a Hackintosh reliably.

Before touching any configuration, understand the scope: this is not about BCM94360CD or other modern combo cards that work out-of-the-box with native power management. We are dealing with the older USB Bluetooth dongles and internal modules that expose a vendor-specific HCI interface. These devices require a combination of a correct IOBluetoothFamily kext patch, a USB port injection that preserves the RemoteWake capability, and an ACPI method that actually enables the wake source. Skipping any one of these steps results in a machine that sleeps but never wakes to a Bluetooth event—or worse, wakes immediately after sleeping due to a misconfigured GPE.

Identifying Your Bluetooth Controller

Start by inspecting the IORegistry for your Bluetooth device. Open IORegistryExplorer and locate the node named IOBluetoothHCIController. Look for the device-id (e.g., 0x2046) and the vendor-id (should be 0x05ac for Apple). If your device shows a vendor ID of 0x0a5c (Broadcom) or 0x0b05 (ASUS), it is a third-party adapter that will not respond to Apple's wake commands without additional spoofing. For a genuine Apple BCM2046 module, you should also see a revision value of 0x0001 or 0x0002. Write down the full device path, as you will need it later for the ACPI patch.

If your controller is not recognized as an Apple device, the first step is to spoof its identity. This is done by adding a device property vendor-id and device-id to the USB port in your DSDT or via a SSDT hotpatch. The values should mirror a real Apple Bluetooth module: 0x05ac and 0x2046 respectively. This alone will not fix wake, but it is a prerequisite for the IOBluetoothFamily kext to load the correct personality.

The Role of USB Port Injection

Wake-on-Bluetooth is fundamentally a USB remote wake feature. The Bluetooth controller sits on an internal USB port (usually on the motherboard's root hub or a USB 2.0 header). For the wake to propagate, the port must have the RemoteWake capability enabled in the USB device's descriptor. On many legacy boards, this capability is not set by default because the BIOS does not expose it for internal devices. Use a tool like grep on the IORegistry dump to check for RemoteWake or USB Remote Wake under the port node. If it is missing, you must inject it via a USB port injector kext or via a custom SSDT that adds a _PRW method to the port.

For a clean solution, create a SSDT that renames the USB port device (e.g., XHC1 to XHC) and adds a _PRW method that returns Package (0x02) { 0x0D, 0x03 } — the GPE number and wake level. This is the same method used by real Macs to wake from S3 on Bluetooth activity. However, be cautious: adding _PRW to a port that also handles other devices can cause spurious wakes. Limit the injection to the port where the Bluetooth adapter is physically connected.

ACPI GPE and _PSW Patches

Even with _PRW in place, the ACPI GPE (General Purpose Event) that triggers the wake must be correctly defined. Many motherboards use GPE 0x0D for USB remote wake, but this is not universal. Check your DSDT for the _GPE block and look for a method that handles the USB wake event. If your board does not have one, you must add a custom _L0D or _E0D method that calls Notify (_SB.PCI0.XHC, 0x2) to signal a device wake. This is a delicate operation; a wrong GPE number can cause the system to wake immediately after sleep or not at all. Use a kernel log to see which GPE fires when you press a Bluetooth key during sleep. The log entry will show something like ACPI: GPE 0x0D triggered. Match your patch to that number.

Another important ACPI object is _PSW (Power Source for Wake). This method tells the firmware whether the device is allowed to wake the system. On real Macs, the Bluetooth controller's _PSW returns 1 when the system is running on AC power. On a Hackintosh, you may need to add a _PSW method to the Bluetooth device node that returns One unconditionally. Without it, the firmware may ignore the wake request even if the GPE is correct.

IOBluetoothFamily Kext Patches

The kext that handles Bluetooth on macOS, IOBluetoothFamily, contains a personality for each supported controller. For the BCM2046, the driver expects a specific set of HCI commands to enable wake. In some versions of macOS (notably 10.10 and 10.11), the driver checks a private key BluetoothWakeOnHost in the controller's registry entry. If this key is absent, the driver will not enable the wake feature. You can add this key via a device property injection in your bootloader's config (e.g., Clover's Devices/Properties or OpenCore's DeviceProperties). Set BluetoothWakeOnHost to true (or 0x01).

Additionally, the kext may require a patch to the IOBluetoothFamily binary to allow third-party controllers to use the wake feature. This is not a security bypass; it is a compatibility patch that changes a single conditional jump. The exact patch varies by macOS version. For example, in 10.10.5, the patch is often a find/replace of 0F 85 3C 00 00 00 to 90 90 90 90 90 90 in the IOBluetoothController class. Always verify the patch against the specific kext version you are using; a wrong patch can cause a kernel panic on boot. Make a backup of the original kext before applying any patch, and test in a virtual environment if possible.

Power Management and Sleep Settings

Even with all the above in place, the system may still not wake if the Bluetooth controller is put into a deep sleep state. On some legacy boards, the USB port power is cut during S3 sleep, which prevents the Bluetooth module from receiving power to generate a wake signal. Check your BIOS settings for USB Wake Support or Wake on USB and enable it. If the option is not available, you may need to disable USB selective suspend in macOS by setting the IOUSBHostDevice property idVendor to 0x05ac and idProduct to 0x2046 — this forces macOS to treat the port as an internal device and keep it powered.

Also, ensure that hibernatemode is set to 0 (sleep only, no safe sleep). Safe sleep writes memory to disk and can interfere with the wake sequence. Run sudo pmset -a hibernatemode 0 and sudo pmset -a womp 0 (disable wake on LAN) to reduce interference. Some users have found that disabling Wake on Demand in System Preferences also helps, as it can conflict with Bluetooth wake.

Testing and Diagnostics

After applying the patches, do not immediately assume success. Put the system to sleep and wait at least 30 seconds, then press a key on the Bluetooth keyboard. If nothing happens, wake the system with the power button and check the system log for clues. Use log show --last 1h | grep -i bluetooth to see if the controller received the wake command. Look for lines like IOBluetoothHCIController::wakeEvent or Bluetooth: Wake from sleep. If you see USB: device wake but no Bluetooth activity, the issue is likely in the GPE routing.

A common mistake is to test with a Bluetooth mouse that has a low-power sleep mode. Some mice require a physical click to wake, not just a movement. Use a keyboard for initial testing, as it sends a more predictable HID command. Also, ensure the keyboard is paired before sleeping; a device that is not paired will not send a wake signal.

Preserving Your Configuration

Once you have a working wake-on-Bluetooth setup, archive the entire configuration: the SSDT files, the kext patches, and the bootloader plist. Document the exact GPE number and the _PRW values, as they are specific to your motherboard. Future macOS updates may reset the kext patches, so keep a copy of the original kext and the patched version. If you ever rebuild the system, you can refer to your notes to avoid re-diagnosing the same issues. For a broader approach to archiving your build, consider the strategies discussed in our guide on SSDT Creation Guide for Legacy Hackintosh.

Remember that every motherboard has a different ACPI implementation. What works on a Gigabyte GA-EP45-UD3P may not work on an ASUS P5Q. The key is to understand the logic of wake events and adapt the patches to your specific hardware. Do not blindly copy another user's SSDT; instead, use the diagnostic steps above to craft your own.

Finally, always test with a backup of your current working configuration. A misapplied ACPI patch can prevent the system from booting, and you will need a way to revert. Keep a USB bootable recovery partition with your previous config. The time invested in a solid backup is minimal compared to the hours lost in troubleshooting a non-booting system.