├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── BrcmBluetoothInjector.kext
└── Contents
│ └── Info.plist
├── BrcmBluetoothInjectorLegacy.kext
└── Contents
│ └── Info.plist
├── BrcmNonPatchRAM-Info.plist
├── BrcmNonPatchRAM2-Info.plist
├── BrcmPatchRAM.xcodeproj
└── project.pbxproj
├── BrcmPatchRAM
├── BlueToolFixup-Info.plist
├── BlueToolFixup.cpp
├── BrcmFirmwareData-Info.plist
├── BrcmFirmwareRepo-Info.plist
├── BrcmFirmwareStore.cpp
├── BrcmFirmwareStore.h
├── BrcmPatchRAM-Info.plist
├── BrcmPatchRAM.cpp
├── BrcmPatchRAM.h
├── BrcmPatchRAM2-Info.plist
├── BrcmPatchRAM3-Info.plist
├── BrcmPatchRAM3.cpp
├── Common.h
├── FirmwareData.cpp
├── FirmwareData.h
├── USBDeviceShim.cpp
├── USBDeviceShim.h
├── USBHostDeviceShim.cpp
├── hci.h
└── package.tool
├── Changelog.md
├── LICENSE
├── README-Mac.md
├── README.md
├── README_CN.md
├── extra_firmwares
├── 0a5c_22be
│ ├── BrcmFirmwareInjector2_0a5c_22be.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_22be.kext
│ │ └── Contents
│ │ └── Info.plist
└── 0a5c_6412
│ ├── BCM4350C5_003.006.007.0222.4689_v8785.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6412.kext
│ └── Contents
│ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6412.kext
│ └── Contents
│ └── Info.plist
├── firmware.rb
├── firmware_update.tool
├── firmwares
├── 0489_e032
│ ├── BCM20702A1_001.002.014.1443.1485_v5581.zhx
│ ├── BrcmFirmwareInjector2_0489_e032.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e032.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e042
│ ├── BCM20702A1_001.002.014.1443.1484_v5580.zhx
│ ├── BrcmFirmwareInjector2_0489_e042.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e042.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e046
│ ├── BCM20702A1_001.002.014.1443.1465_v5561.zhx
│ ├── BrcmFirmwareInjector2_0489_e046.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e046.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e047
│ ├── BCM20702A1_001.002.014.1055.1061_v5157.zhx
│ ├── BrcmFirmwareInjector2_0489_e047.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e047.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e04f
│ ├── BCM20702A1_001.002.014.1443.1486_v5582.zhx
│ ├── BrcmFirmwareInjector2_0489_e04f.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e04f.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e052
│ ├── BCM20702A1_001.002.014.1502.1758_v5854.zhx
│ ├── BrcmFirmwareInjector2_0489_e052.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e052.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e055
│ ├── BCM43142A0_001.001.011.0311.0331_v4427.zhx
│ ├── BrcmFirmwareInjector2_0489_e055.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e055.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e059
│ ├── BCM20702A1_001.002.014.1443.1466_v5562.zhx
│ ├── BrcmFirmwareInjector2_0489_e059.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e059.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e062
│ ├── BCM43142A0_001.001.011.0277.0280_v4376.zhx
│ ├── BrcmFirmwareInjector2_0489_e062.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e062.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e079
│ ├── BCM4335C0_003.001.009.0066.0115_v4211.zhx
│ ├── BrcmFirmwareInjector2_0489_e079.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e079.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e07a
│ ├── BCM20702A1_001.002.014.1483.1651_v5747.zhx
│ ├── BrcmFirmwareInjector2_0489_e07a.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e07a.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e087
│ ├── BCM20702A1_001.002.014.1443.1532_v5628.zhx
│ ├── BrcmFirmwareInjector2_0489_e087.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e087.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e096
│ ├── BCM43142A0_001.001.011.0311.0340_v4436.zhx
│ ├── BrcmFirmwareInjector2_0489_e096.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e096.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0489_e0a1
│ ├── BCM20703A1_001.001.005.0214.0414_v4510.zhx
│ ├── BrcmFirmwareInjector2_0489_e0a1.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0489_e0a1.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2003
│ ├── BCM20702A1_001.002.014.1443.1488_v5584.zhx
│ ├── BrcmFirmwareInjector2_04ca_2003.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2003.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2004
│ ├── BCM20702A1_001.002.014.1443.1489_v5585.zhx
│ ├── BrcmFirmwareInjector2_04ca_2004.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2004.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2005
│ ├── BCM20702A1_001.002.014.1443.1490_v5586.zhx
│ ├── BrcmFirmwareInjector2_04ca_2005.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2005.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2006
│ ├── BCM43142A0_001.001.011.0311.0327_v4423.zhx
│ ├── BrcmFirmwareInjector2_04ca_2006.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2006.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2007
│ ├── BCM43142A0_001.001.011.0277.0279_v4375.zhx
│ ├── BrcmFirmwareInjector2_04ca_2007.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2007.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2009
│ ├── BCM43142A0_001.001.011.0311.0330_v4426.zhx
│ ├── BrcmFirmwareInjector2_04ca_2009.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2009.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_200a
│ ├── BCM20702A1_001.002.014.1443.1492_v5588.zhx
│ ├── BrcmFirmwareInjector2_04ca_200a.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_200a.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_200b
│ ├── BCM20702A1_001.002.014.1443.1493_v5589.zhx
│ ├── BrcmFirmwareInjector2_04ca_200b.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_200b.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_200c
│ ├── BCM20702A1_001.002.014.1443.1494_v5590.zhx
│ ├── BrcmFirmwareInjector2_04ca_200c.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_200c.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_200e
│ ├── BCM20702A1_001.002.014.1443.1499_v5595.zhx
│ ├── BrcmFirmwareInjector2_04ca_200e.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_200e.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_200f
│ ├── BCM20702A1_001.002.014.1443.1521_v5617.zhx
│ ├── BrcmFirmwareInjector2_04ca_200f.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_200f.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2012
│ ├── BCM43142A0_001.001.011.0311.0339_v4435.zhx
│ ├── BrcmFirmwareInjector2_04ca_2012.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2012.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04ca_2016
│ ├── BCM4335C0_003.001.009.0066.0121_v4217.zhx
│ ├── BrcmFirmwareInjector2_04ca_2016.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04ca_2016.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04f2_b49d
│ ├── BCM43142A0_001.001.011.0277.0308_v4404.zhx
│ ├── BrcmFirmwareInjector2_04f2_b49d.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04f2_b49d.kext
│ │ └── Contents
│ │ └── Info.plist
├── 04f2_b4a1
│ ├── BCM43142A0_001.001.011.0311.0316_v4412.zhx
│ ├── BrcmFirmwareInjector2_04f2_b4a1.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_04f2_b4a1.kext
│ │ └── Contents
│ │ └── Info.plist
├── 050d_065a
│ ├── BCM20702A1_001.002.014.1443.1482_v5578.zhx
│ ├── BrcmFirmwareInjector2_050d_065a.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_050d_065a.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_021e
│ ├── BCM20702A1_001.002.014.1502.1759_v5855.zhx
│ ├── BrcmFirmwareInjector2_0930_021e.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_021e.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_021f
│ ├── BCM43142A0_001.001.011.0311.0335_v4431.zhx
│ ├── BrcmFirmwareInjector2_0930_021f.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_021f.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_0221
│ ├── BCM20702A1_001.002.014.1502.1762_v5858.zhx
│ ├── BrcmFirmwareInjector2_0930_0221.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_0221.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_0223
│ ├── BCM20702A1_001.002.014.1502.1763_v5859.zhx
│ ├── BrcmFirmwareInjector2_0930_0223.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_0223.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_0225
│ ├── BCM43142A0_001.001.011.0311.0334_v4430.zhx
│ ├── BrcmFirmwareInjector2_0930_0225.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_0225.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0930_0229
│ ├── BCM4335C0_003.001.009.0066.0104_v4200.zhx
│ ├── BrcmFirmwareInjector2_0930_0229.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0930_0229.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_2167
│ ├── BCM43142A0_001.001.011.0249.0265_v4361.zhx
│ ├── BrcmFirmwareInjector2_0a5c_2167.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_2167.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_2168
│ ├── BCM4335C0_003.001.009.0066.0108_v4204.zhx
│ ├── BrcmFirmwareInjector2_0a5c_2168.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_2168.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_2169
│ ├── BCM20702A1_001.002.014.1443.1462_v5558.zhx
│ ├── BrcmFirmwareInjector2_0a5c_2169.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_2169.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216a
│ ├── BCM43142A0_001.001.011.0311.0336_v4432.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216a.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216a.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216b
│ ├── BCM20702A1_001.002.014.1502.1768_v5864.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216b.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216b.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216c
│ ├── BCM43142A0_001.001.011.0311.0328_v4424.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216c.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216c.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216d
│ ├── BCM43142A0_001.001.011.0311.0329_v4425.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216d.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216d.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216e
│ ├── BCM4335C0_003.001.009.0066.0105_v4201.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216e.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216e.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_216f
│ ├── BCM20702A1_001.002.014.1443.1572_v5668.zhx
│ ├── BrcmFirmwareInjector2_0a5c_216f.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_216f.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21d3
│ ├── BCM43142A0_001.001.011.0197.0218_v4314.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21d3.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21d3.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21d6
│ ├── BCM43142A0_001.001.011.0197.0220_v4316.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21d6.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21d6.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21d7
│ ├── BCM43142A0_001.001.011.0311.0341_v4437.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21d7.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21d7.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21d8
│ ├── BCM43142A0_001.001.011.0197.0222_v4318.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21d8.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21d8.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21dc
│ ├── BCM43142A0_001.001.011.0161.0187_v4283.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21dc.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21dc.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21de
│ ├── BCM20702A1_001.002.014.1443.1461_v5557.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21de.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21de.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21e1
│ ├── BCM20702A1_001.002.014.1502.1770_v5866.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21e1.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21e1.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21e3
│ ├── BCM20702A1_001.002.014.1502.1767_v5863.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21e3.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21e3.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21e6
│ ├── BCM20702A1_001.002.014.1502.1757_v5853.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21e6.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21e6.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21e8
│ ├── BCM20702A1_001.002.014.1502.1764_v5860.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21e8.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21e8.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21ec
│ ├── BCM20702A1_001.002.014.1443.1460_v5556.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21ec.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21ec.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21f1
│ ├── BCM20702A1_001.002.014.1502.1765_v5861.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21f1.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21f1.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21f3
│ ├── BCM20702A1_001.002.014.1502.1761_v5857.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21f3.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21f3.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21f4
│ ├── BCM20702A1_001.002.014.1502.1760_v5856.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21f4.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21f4.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21fb
│ ├── BCM20702A1_001.002.014.1502.1766_v5862.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21fb.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21fb.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21fd
│ ├── BCM20702A1_001.002.014.1443.1463_v5559.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21fd.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21fd.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_21fe
│ ├── BCM43142A0_001.001.011.0161.0186_v4282.zhx
│ ├── BrcmFirmwareInjector2_0a5c_21fe.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_21fe.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_640b
│ ├── BCM20702A1_001.002.014.1502.1769_v5865.zhx
│ ├── BrcmFirmwareInjector2_0a5c_640b.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_640b.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6410
│ ├── BCM20703A1_001.001.005.0214.0422_v4518.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6410.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6410.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6412
│ ├── BCM4350C5_003.006.007.0222.4689_v4689.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6412.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6412.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6413
│ ├── BCM4350C5_003.006.007.0120.2118_v6214.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6413.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6413.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6414
│ ├── BCM4350C5_003.006.007.0145.2724_v6820.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6414.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6414.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6417
│ ├── BCM20702A1_001.002.014.1502.1780_v5876.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6417.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6417.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_6418
│ ├── BCM4371C2_001.003.015.0093.0116_v4212.zhx
│ ├── BrcmFirmwareInjector2_0a5c_6418.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_6418.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0a5c_7460
│ ├── BCM20703A1_001.001.005.0214.0473_v4569.zhx
│ ├── BrcmFirmwareInjector2_0a5c_7460.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0a5c_7460.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0b05_17b5
│ ├── BCM20702A1_001.002.014.1443.1468_v5564.zhx
│ ├── BrcmFirmwareInjector2_0b05_17b5.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0b05_17b5.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0b05_17cb
│ ├── BCM20702A1_001.002.014.1443.1467_v5563.zhx
│ ├── BrcmFirmwareInjector2_0b05_17cb.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0b05_17cb.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0b05_17cf
│ ├── BCM20702A1_001.002.014.1443.1469_v5565.zhx
│ ├── BrcmFirmwareInjector2_0b05_17cf.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0b05_17cf.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0b05_180a
│ ├── BCM20702A1_001.002.014.1443.1714_v5810.zhx
│ ├── BrcmFirmwareInjector2_0b05_180a.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0b05_180a.kext
│ │ └── Contents
│ │ └── Info.plist
├── 0bb4_0306
│ ├── BCM20703A1_001.001.005.0214.0481_v4577.zhx
│ ├── BrcmFirmwareInjector2_0bb4_0306.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_0bb4_0306.kext
│ │ └── Contents
│ │ └── Info.plist
├── 105b_e065
│ ├── BCM43142A0_001.001.011.0311.0312_v4408.zhx
│ ├── BrcmFirmwareInjector2_105b_e065.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_105b_e065.kext
│ │ └── Contents
│ │ └── Info.plist
├── 105b_e066
│ ├── BCM20702A1_001.002.014.1443.1487_v5583.zhx
│ ├── BrcmFirmwareInjector2_105b_e066.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_105b_e066.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3384
│ ├── BCM20702A1_001.002.014.1443.1477_v5573.zhx
│ ├── BrcmFirmwareInjector2_13d3_3384.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3384.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3388
│ ├── BCM43142A0_001.001.011.0311.0332_v4428.zhx
│ ├── BrcmFirmwareInjector2_13d3_3388.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3388.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3389
│ ├── BCM43142A0_001.001.011.0311.0333_v4429.zhx
│ ├── BrcmFirmwareInjector2_13d3_3389.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3389.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3392
│ ├── BCM20702A1_001.002.014.1443.1478_v5574.zhx
│ ├── BrcmFirmwareInjector2_13d3_3392.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3392.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3404
│ ├── BCM20702A1_001.002.014.1443.1479_v5575.zhx
│ ├── BrcmFirmwareInjector2_13d3_3404.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3404.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3411
│ ├── BCM20702A1_001.002.014.1443.1450_v5546.zhx
│ ├── BrcmFirmwareInjector2_13d3_3411.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3411.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3413
│ ├── BCM20702A1_001.002.014.1443.1481_v5577.zhx
│ ├── BrcmFirmwareInjector2_13d3_3413.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3413.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3418
│ ├── BCM20702A1_001.002.014.1443.1480_v5576.zhx
│ ├── BrcmFirmwareInjector2_13d3_3418.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3418.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3435
│ ├── BCM20702A1_001.002.014.1443.1501_v5597.zhx
│ ├── BrcmFirmwareInjector2_13d3_3435.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3435.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3456
│ ├── BCM20702A1_001.002.014.1443.1502_v5598.zhx
│ ├── BrcmFirmwareInjector2_13d3_3456.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3456.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3482
│ ├── BCM43142A0_001.001.011.0311.0346_v4442.zhx
│ ├── BrcmFirmwareInjector2_13d3_3482.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3482.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3484
│ ├── BCM43142A0_001.001.011.0311.0347_v4443.zhx
│ ├── BrcmFirmwareInjector2_13d3_3484.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3484.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3504
│ ├── BCM4371C2_001.003.015.0093.0118_v4214.zhx
│ ├── BrcmFirmwareInjector2_13d3_3504.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3504.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3508
│ ├── BCM4371C2_001.003.015.0093.0117_v4213.zhx
│ ├── BrcmFirmwareInjector2_13d3_3508.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3508.kext
│ │ └── Contents
│ │ └── Info.plist
├── 13d3_3517
│ ├── BCM20702A1_001.002.014.1502.1786_v5882.zhx
│ ├── BrcmFirmwareInjector2_13d3_3517.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_13d3_3517.kext
│ │ └── Contents
│ │ └── Info.plist
├── 145f_01a3
│ ├── BCM20702A1_001.002.014.1443.1483_v5579.zhx
│ ├── BrcmFirmwareInjector2_145f_01a3.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_145f_01a3.kext
│ │ └── Contents
│ │ └── Info.plist
├── 185f_2167
│ ├── BCM43142A0_001.001.011.0277.0292_v4388.zhx
│ ├── BrcmFirmwareInjector2_185f_2167.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_185f_2167.kext
│ │ └── Contents
│ │ └── Info.plist
├── 19ff_0239
│ ├── BCM20702B0_002.001.014.0527.0557_v4653.zhx
│ ├── BrcmFirmwareInjector2_19ff_0239.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_19ff_0239.kext
│ │ └── Contents
│ │ └── Info.plist
├── 413c_8143
│ ├── BCM20702A1_001.002.014.1443.1449_v5545.zhx
│ ├── BrcmFirmwareInjector2_413c_8143.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_413c_8143.kext
│ │ └── Contents
│ │ └── Info.plist
├── 413c_8197
│ ├── BCM20702A1_001.002.014.1443.1447_v5543.zhx
│ ├── BrcmFirmwareInjector2_413c_8197.kext
│ │ └── Contents
│ │ │ └── Info.plist
│ └── BrcmFirmwareInjector_413c_8197.kext
│ │ └── Contents
│ │ └── Info.plist
├── BCM20702A1_001.002.014.1055.1061_v5157.zhx
├── BCM20702A1_001.002.014.1443.1447_v5543.zhx
├── BCM20702A1_001.002.014.1443.1449_v5545.zhx
├── BCM20702A1_001.002.014.1443.1450_v5546.zhx
├── BCM20702A1_001.002.014.1443.1460_v5556.zhx
├── BCM20702A1_001.002.014.1443.1461_v5557.zhx
├── BCM20702A1_001.002.014.1443.1462_v5558.zhx
├── BCM20702A1_001.002.014.1443.1463_v5559.zhx
├── BCM20702A1_001.002.014.1443.1465_v5561.zhx
├── BCM20702A1_001.002.014.1443.1466_v5562.zhx
├── BCM20702A1_001.002.014.1443.1467_v5563.zhx
├── BCM20702A1_001.002.014.1443.1468_v5564.zhx
├── BCM20702A1_001.002.014.1443.1469_v5565.zhx
├── BCM20702A1_001.002.014.1443.1477_v5573.zhx
├── BCM20702A1_001.002.014.1443.1478_v5574.zhx
├── BCM20702A1_001.002.014.1443.1479_v5575.zhx
├── BCM20702A1_001.002.014.1443.1480_v5576.zhx
├── BCM20702A1_001.002.014.1443.1481_v5577.zhx
├── BCM20702A1_001.002.014.1443.1482_v5578.zhx
├── BCM20702A1_001.002.014.1443.1483_v5579.zhx
├── BCM20702A1_001.002.014.1443.1484_v5580.zhx
├── BCM20702A1_001.002.014.1443.1485_v5581.zhx
├── BCM20702A1_001.002.014.1443.1486_v5582.zhx
├── BCM20702A1_001.002.014.1443.1487_v5583.zhx
├── BCM20702A1_001.002.014.1443.1488_v5584.zhx
├── BCM20702A1_001.002.014.1443.1489_v5585.zhx
├── BCM20702A1_001.002.014.1443.1490_v5586.zhx
├── BCM20702A1_001.002.014.1443.1492_v5588.zhx
├── BCM20702A1_001.002.014.1443.1493_v5589.zhx
├── BCM20702A1_001.002.014.1443.1494_v5590.zhx
├── BCM20702A1_001.002.014.1443.1499_v5595.zhx
├── BCM20702A1_001.002.014.1443.1501_v5597.zhx
├── BCM20702A1_001.002.014.1443.1502_v5598.zhx
├── BCM20702A1_001.002.014.1443.1521_v5617.zhx
├── BCM20702A1_001.002.014.1443.1532_v5628.zhx
├── BCM20702A1_001.002.014.1443.1572_v5668.zhx
├── BCM20702A1_001.002.014.1443.1714_v5810.zhx
├── BCM20702A1_001.002.014.1483.1651_v5747.zhx
├── BCM20702A1_001.002.014.1502.1757_v5853.zhx
├── BCM20702A1_001.002.014.1502.1758_v5854.zhx
├── BCM20702A1_001.002.014.1502.1759_v5855.zhx
├── BCM20702A1_001.002.014.1502.1760_v5856.zhx
├── BCM20702A1_001.002.014.1502.1761_v5857.zhx
├── BCM20702A1_001.002.014.1502.1762_v5858.zhx
├── BCM20702A1_001.002.014.1502.1763_v5859.zhx
├── BCM20702A1_001.002.014.1502.1764_v5860.zhx
├── BCM20702A1_001.002.014.1502.1765_v5861.zhx
├── BCM20702A1_001.002.014.1502.1766_v5862.zhx
├── BCM20702A1_001.002.014.1502.1767_v5863.zhx
├── BCM20702A1_001.002.014.1502.1768_v5864.zhx
├── BCM20702A1_001.002.014.1502.1769_v5865.zhx
├── BCM20702A1_001.002.014.1502.1770_v5866.zhx
├── BCM20702A1_001.002.014.1502.1780_v5876.zhx
├── BCM20702A1_001.002.014.1502.1786_v5882.zhx
├── BCM20702B0_002.001.014.0527.0557_v4653.zhx
├── BCM20703A1_001.001.005.0214.0414_v4510.zhx
├── BCM20703A1_001.001.005.0214.0422_v4518.zhx
├── BCM20703A1_001.001.005.0214.0473_v4569.zhx
├── BCM20703A1_001.001.005.0214.0481_v4577.zhx
├── BCM43142A0_001.001.011.0161.0186_v4282.zhx
├── BCM43142A0_001.001.011.0161.0187_v4283.zhx
├── BCM43142A0_001.001.011.0197.0218_v4314.zhx
├── BCM43142A0_001.001.011.0197.0220_v4316.zhx
├── BCM43142A0_001.001.011.0197.0222_v4318.zhx
├── BCM43142A0_001.001.011.0249.0265_v4361.zhx
├── BCM43142A0_001.001.011.0277.0279_v4375.zhx
├── BCM43142A0_001.001.011.0277.0280_v4376.zhx
├── BCM43142A0_001.001.011.0277.0292_v4388.zhx
├── BCM43142A0_001.001.011.0277.0308_v4404.zhx
├── BCM43142A0_001.001.011.0311.0312_v4408.zhx
├── BCM43142A0_001.001.011.0311.0316_v4412.zhx
├── BCM43142A0_001.001.011.0311.0327_v4423.zhx
├── BCM43142A0_001.001.011.0311.0328_v4424.zhx
├── BCM43142A0_001.001.011.0311.0329_v4425.zhx
├── BCM43142A0_001.001.011.0311.0330_v4426.zhx
├── BCM43142A0_001.001.011.0311.0331_v4427.zhx
├── BCM43142A0_001.001.011.0311.0332_v4428.zhx
├── BCM43142A0_001.001.011.0311.0333_v4429.zhx
├── BCM43142A0_001.001.011.0311.0334_v4430.zhx
├── BCM43142A0_001.001.011.0311.0335_v4431.zhx
├── BCM43142A0_001.001.011.0311.0336_v4432.zhx
├── BCM43142A0_001.001.011.0311.0339_v4435.zhx
├── BCM43142A0_001.001.011.0311.0340_v4436.zhx
├── BCM43142A0_001.001.011.0311.0341_v4437.zhx
├── BCM43142A0_001.001.011.0311.0346_v4442.zhx
├── BCM43142A0_001.001.011.0311.0347_v4443.zhx
├── BCM4335C0_003.001.009.0066.0104_v4200.zhx
├── BCM4335C0_003.001.009.0066.0105_v4201.zhx
├── BCM4335C0_003.001.009.0066.0108_v4204.zhx
├── BCM4335C0_003.001.009.0066.0115_v4211.zhx
├── BCM4335C0_003.001.009.0066.0121_v4217.zhx
├── BCM4350C5_003.006.007.0120.2118_v6214.zhx
├── BCM4350C5_003.006.007.0145.2724_v6820.zhx
├── BCM4350C5_003.006.007.0222.4689_v4689.zhx
├── BCM4371C2_001.003.015.0093.0116_v4212.zhx
├── BCM4371C2_001.003.015.0093.0117_v4213.zhx
├── BCM4371C2_001.003.015.0093.0118_v4214.zhx
├── firmwares.md
├── firmwares.plist
├── firmwares2.plist
└── firmwares3.plist
└── generate_firmware_data.sh
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | pull_request:
6 | workflow_dispatch:
7 | release:
8 | types: [published]
9 |
10 | env:
11 | PROJECT_TYPE: KEXT
12 |
13 | jobs:
14 | build:
15 | name: Build
16 | runs-on: macos-latest
17 | env:
18 | JOB_TYPE: BUILD
19 | steps:
20 | - uses: actions/checkout@v3
21 | - uses: actions/checkout@v3
22 | with:
23 | repository: acidanthera/MacKernelSDK
24 | path: MacKernelSDK
25 | - name: CI Bootstrap
26 | run: |
27 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1
28 | - name: Lilu Bootstrap
29 | run: |
30 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1
31 |
32 | - run: xcodebuild -jobs 1 -target Package -configuration Debug
33 | - run: xcodebuild -jobs 1 -target Package -configuration Release
34 |
35 | - name: Upload to Artifacts
36 | uses: actions/upload-artifact@v3
37 | with:
38 | name: Artifacts
39 | path: build/*/*/*.zip
40 | - name: Upload to Release
41 | if: github.event_name == 'release'
42 | uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d
43 | with:
44 | repo_token: ${{ secrets.GITHUB_TOKEN }}
45 | file: build/*/*/*.zip
46 | tag: ${{ github.ref }}
47 | file_glob: true
48 |
49 | analyze-clang:
50 | name: Analyze Clang
51 | runs-on: macos-latest
52 | env:
53 | JOB_TYPE: ANALYZE
54 | steps:
55 | - uses: actions/checkout@v3
56 | - uses: actions/checkout@v3
57 | with:
58 | repository: acidanthera/MacKernelSDK
59 | path: MacKernelSDK
60 | - name: CI Bootstrap
61 | run: |
62 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1
63 | - name: Lilu Bootstrap
64 | run: |
65 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1
66 |
67 | - run: xcodebuild analyze -quiet -scheme Package -target Package -configuration Debug CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ]
68 | - run: xcodebuild clean -quiet -scheme Package
69 | - run: xcodebuild analyze -quiet -scheme Package -target Package -configuration Release CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ]
70 |
71 | analyze-coverity:
72 | name: Analyze Coverity
73 | runs-on: macos-latest
74 | env:
75 | JOB_TYPE: COVERITY
76 | if: github.repository_owner == 'acidanthera' && github.event_name != 'pull_request'
77 | steps:
78 | - uses: actions/checkout@v3
79 | - uses: actions/checkout@v3
80 | with:
81 | repository: acidanthera/MacKernelSDK
82 | path: MacKernelSDK
83 | - name: CI Bootstrap
84 | run: |
85 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1
86 | - name: Lilu Bootstrap
87 | run: |
88 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1
89 |
90 | - name: Run Coverity
91 | run: |
92 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/coverity/covstrap.sh) && eval "$src" || exit 1
93 | env:
94 | COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
95 | COVERITY_SCAN_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }}
96 | COVERITY_BUILD_COMMAND: xcodebuild -target Package -configuration Release
97 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Build
2 | build
3 | DerivedData
4 | Distribute
5 | Index
6 | Logs
7 | TextIndex
8 | xcuserdata
9 | xcshareddata
10 | project.xcworkspace
11 | scm.plist
12 | *.xccheckout
13 | .DS_Store
14 | ModuleCache
15 | GeneratedFirmwares.cpp
16 | GeneratedFirmwaresMD5.txt
17 | /MacKernelSDK
18 | /Lilu.kext
19 |
--------------------------------------------------------------------------------
/BrcmNonPatchRAM-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | $(PRODUCT_BUNDLE_IDENTIFIER)
7 | CFBundleInfoDictionaryVersion
8 | 6.0
9 | CFBundleName
10 | $(PRODUCT_NAME)
11 | CFBundlePackageType
12 | KEXT
13 | CFBundleShortVersionString
14 | ${CURRENT_PROJECT_VERSION}
15 | CFBundleSignature
16 | ????
17 | CFBundleVersion
18 | ${CURRENT_PROJECT_VERSION}
19 | IOKitPersonalities
20 |
21 | 03f0_231d no firmware legacy
22 |
23 | #FirmwareKey
24 | only load and unload native bluetooth
25 | CFBundleIdentifier
26 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
27 | DisplayName
28 | HP 231d (ProBook BT built-in firmware)
29 | IOClass
30 | BrcmPatchRAM
31 | IOMatchCategory
32 | BrcmPatchRAM
33 | IOProviderClass
34 | IOUSBDevice
35 | idProduct
36 | 8989
37 | idVendor
38 | 1008
39 |
40 | 0489_e030 no firmware legacy - 2
41 |
42 | #FirmwareKey
43 | only load and unload native bluetooth
44 | CFBundleIdentifier
45 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
46 | DisplayName
47 | Foxconn AW-NB290
48 | IOClass
49 | BrcmPatchRAM
50 | IOMatchCategory
51 | BrcmPatchRAM
52 | IOProviderClass
53 | IOUSBDevice
54 | idProduct
55 | 57392
56 | idVendor
57 | 1161
58 |
59 | 0a5c_219a no firmware legacy
60 |
61 | #FirmwareKey
62 | only load and unload native bluetooth
63 | CFBundleIdentifier
64 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
65 | DisplayName
66 | Broadcom BCM2070 0a5c_219a (BT on BCM43225HMB)
67 | IOClass
68 | BrcmPatchRAM
69 | IOMatchCategory
70 | BrcmPatchRAM
71 | IOProviderClass
72 | IOUSBDevice
73 | idProduct
74 | 2652
75 | idVendor
76 | 8602
77 |
78 | 0b05_1788 no firmware legacy
79 |
80 | #FirmwareKey
81 | only load and unload native bluetooth
82 | CFBundleIdentifier
83 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
84 | DisplayName
85 | Asus BT-270(20702A built-in firmware)
86 | IOClass
87 | BrcmPatchRAM
88 | IOMatchCategory
89 | BrcmPatchRAM
90 | IOProviderClass
91 | IOUSBDevice
92 | idProduct
93 | 6024
94 | idVendor
95 | 2821
96 |
97 | 0b05_178a no firmware legacy
98 |
99 | #FirmwareKey
100 | only load and unload native bluetooth
101 | CFBundleIdentifier
102 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
103 | DisplayName
104 | HP EliteBook NB-290 (built-in firmware)
105 | IOClass
106 | BrcmPatchRAM
107 | IOMatchCategory
108 | BrcmPatchRAM
109 | IOProviderClass
110 | IOUSBDevice
111 | idProduct
112 | 6026
113 | idVendor
114 | 2821
115 |
116 | 13d3_3295 no firmware legacy
117 |
118 | #FirmwareKey
119 | only load and unload native bluetooth
120 | CFBundleIdentifier
121 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
122 | DisplayName
123 | Azurewave BCM943225 (20702A built-in firmware)
124 | IOClass
125 | BrcmPatchRAM
126 | IOMatchCategory
127 | BrcmPatchRAM
128 | IOProviderClass
129 | IOUSBDevice
130 | idProduct
131 | 12949
132 | idVendor
133 | 5075
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/BrcmNonPatchRAM2-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | $(PRODUCT_BUNDLE_IDENTIFIER)
7 | CFBundleInfoDictionaryVersion
8 | 6.0
9 | CFBundleName
10 | $(PRODUCT_NAME)
11 | CFBundlePackageType
12 | KEXT
13 | CFBundleShortVersionString
14 | ${CURRENT_PROJECT_VERSION}
15 | CFBundleSignature
16 | ????
17 | CFBundleVersion
18 | ${CURRENT_PROJECT_VERSION}
19 | IOKitPersonalities
20 |
21 | 03f0_231d native
22 |
23 | CFBundleIdentifier
24 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
25 | IOClass
26 | BroadcomBluetoothHostControllerUSBTransport
27 | IOProviderClass
28 | IOUSBHostDevice
29 | idProduct
30 | 8989
31 | idVendor
32 | 1008
33 |
34 | 0489_e030 no firmware
35 |
36 | CFBundleIdentifier
37 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
38 | IOClass
39 | BroadcomBluetoothHostControllerUSBTransport
40 | IOProviderClass
41 | IOUSBHostDevice
42 | idProduct
43 | 57392
44 | idVendor
45 | 1161
46 |
47 | 03f0_231d no firmware
48 |
49 | #FirmwareKey
50 | only load and unload native bluetooth
51 | CFBundleIdentifier
52 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
53 | DisplayName
54 | HP 231d (ProBook BT built-in firmware)
55 | IOClass
56 | BrcmPatchRAM2
57 | IOMatchCategory
58 | BrcmPatchRAM2
59 | IOProviderClass
60 | IOUSBHostDevice
61 | idProduct
62 | 8989
63 | idVendor
64 | 1008
65 |
66 | 0489_e030 native
67 |
68 | CFBundleIdentifier
69 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
70 | IOClass
71 | BroadcomBluetoothHostControllerUSBTransport
72 | IOProviderClass
73 | IOUSBHostDevice
74 | idProduct
75 | 57392
76 | idVendor
77 | 1161
78 |
79 | 0489_e030 no firmware
80 |
81 | #FirmwareKey
82 | only load and unload native bluetooth
83 | CFBundleIdentifier
84 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
85 | DisplayName
86 | Foxconn AW-NB290
87 | IOClass
88 | BrcmPatchRAM2
89 | IOMatchCategory
90 | BrcmPatchRAM2
91 | IOProviderClass
92 | IOUSBHostDevice
93 | idProduct
94 | 57392
95 | idVendor
96 | 1161
97 |
98 | 0a5c_219a native
99 |
100 | CFBundleIdentifier
101 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
102 | IOClass
103 | BroadcomBluetoothHostControllerUSBTransport
104 | IOProviderClass
105 | IOUSBHostDevice
106 | idProduct
107 | 2652
108 | idVendor
109 | 8602
110 |
111 | 0a5c_219a no firmware
112 |
113 | #FirmwareKey
114 | only load and unload native bluetooth
115 | CFBundleIdentifier
116 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
117 | DisplayName
118 | Broadcom BCM2070 0a5c_219a (BT on BCM43225HMB)
119 | IOClass
120 | BrcmPatchRAM2
121 | IOMatchCategory
122 | BrcmPatchRAM2
123 | IOProviderClass
124 | IOUSBHostDevice
125 | idProduct
126 | 2652
127 | idVendor
128 | 8602
129 |
130 | 0b05_1788 native
131 |
132 | CFBundleIdentifier
133 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
134 | IOClass
135 | BroadcomBluetoothHostControllerUSBTransport
136 | IOProviderClass
137 | IOUSBHostDevice
138 | idProduct
139 | 6024
140 | idVendor
141 | 2821
142 |
143 | 0b05_1788 no firmware
144 |
145 | #FirmwareKey
146 | only load and unload native bluetooth
147 | CFBundleIdentifier
148 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
149 | DisplayName
150 | Asus BT-270(20702A built-in firmware)
151 | IOClass
152 | BrcmPatchRAM2
153 | IOMatchCategory
154 | BrcmPatchRAM2
155 | IOProviderClass
156 | IOUSBHostDevice
157 | idProduct
158 | 6024
159 | idVendor
160 | 2821
161 |
162 | 0b05_178a native
163 |
164 | CFBundleIdentifier
165 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
166 | IOClass
167 | BroadcomBluetoothHostControllerUSBTransport
168 | IOProviderClass
169 | IOUSBHostDevice
170 | idProduct
171 | 6026
172 | idVendor
173 | 2821
174 |
175 | 0b05_178a no firmware
176 |
177 | #FirmwareKey
178 | only load and unload native bluetooth
179 | CFBundleIdentifier
180 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
181 | DisplayName
182 | HP EliteBook NB-290 (built-in firmware)
183 | IOClass
184 | BrcmPatchRAM2
185 | IOMatchCategory
186 | BrcmPatchRAM2
187 | IOProviderClass
188 | IOUSBHostDevice
189 | idProduct
190 | 6026
191 | idVendor
192 | 2821
193 |
194 | 13d3_3295 native
195 |
196 | CFBundleIdentifier
197 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
198 | IOClass
199 | BroadcomBluetoothHostControllerUSBTransport
200 | IOProviderClass
201 | IOUSBHostDevice
202 | idProduct
203 | 12949
204 | idVendor
205 | 5075
206 |
207 | 13d3_3295 no firmware
208 |
209 | #FirmwareKey
210 | only load and unload native bluetooth
211 | CFBundleIdentifier
212 | as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)
213 | DisplayName
214 | Azurewave BCM943225 (20702A built-in firmware)
215 | IOClass
216 | BrcmPatchRAM2
217 | IOMatchCategory
218 | BrcmPatchRAM2
219 | IOProviderClass
220 | IOUSBHostDevice
221 | idProduct
222 | 12949
223 | idVendor
224 | 5075
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BlueToolFixup-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | KEXT
17 | CFBundleShortVersionString
18 | $(MODULE_VERSION)
19 | CFBundleVersion
20 | $(MODULE_VERSION)
21 | IOKitPersonalities
22 |
23 | BlueToolFixup
24 |
25 | CFBundleIdentifier
26 | $(PRODUCT_BUNDLE_IDENTIFIER)
27 | IOClass
28 | $(PRODUCT_NAME:rfc1034identifier)
29 | IOMatchCategory
30 | $(PRODUCT_NAME:rfc1034identifier)
31 | IOProviderClass
32 | IOResources
33 | IOResourceMatch
34 | IOKit
35 |
36 |
37 | OSBundleLibraries
38 |
39 | as.vit9696.Lilu
40 | 1.4.7
41 | com.apple.kpi.bsd
42 | 12.0.0
43 | com.apple.kpi.dsep
44 | 12.0.0
45 | com.apple.kpi.iokit
46 | 12.0.0
47 | com.apple.kpi.libkern
48 | 12.0.0
49 | com.apple.kpi.mach
50 | 12.0.0
51 | com.apple.kpi.unsupported
52 | 12.0.0
53 |
54 | OSBundleRequired
55 | Root
56 |
57 |
58 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BlueToolFixup.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // BlueToolFixup.cpp
3 | // BrcmPatchRAM
4 | //
5 | // Created by Dhinak G on 6/11/21.
6 | //
7 |
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 |
17 | #define MODULE_SHORT "btlfx"
18 |
19 |
20 | class EXPORT BlueToolFixup : public IOService {
21 | OSDeclareDefaultStructors(BlueToolFixup)
22 | public:
23 | IOService *probe(IOService *provider, SInt32 *score) override;
24 | bool start(IOService *provider) override;
25 | };
26 |
27 | OSDefineMetaClassAndStructors(BlueToolFixup, IOService)
28 |
29 |
30 | IOService *BlueToolFixup::probe(IOService *provider, SInt32 *score) {
31 | return ADDPR(startSuccess) ? IOService::probe(provider, score) : nullptr;
32 | }
33 |
34 | bool BlueToolFixup::start(IOService *provider) {
35 | if (!IOService::start(provider)) {
36 | SYSLOG("init", "failed to start the parent");
37 | return false;
38 | }
39 | setProperty("VersionInfo", kextVersion);
40 | registerService();
41 |
42 | return true;
43 | }
44 |
45 |
46 | #pragma mark - Patches
47 |
48 | static const uint8_t kSkipUpdateFilePathOriginal[] = "/etc/bluetool/SkipBluetoothAutomaticFirmwareUpdate";
49 | static const uint8_t kSkipUpdateFilePathPatched[] = "/System/Library/CoreServices/boot.efi";
50 |
51 |
52 | // Workaround 12.4 Beta 3+ bug where macOS may detect the Bluetooth chipset twice
53 | // Once as internal, and second as an external dongle:
54 | // 'ERROR -- Third Party Dongle has the same address as the internal module'
55 | // Mainly applicable for BCM2046 and BCM2070 chipsets (BT2.1)
56 | static const uint8_t kSkipAddressCheckOriginal[] =
57 | {
58 | 0x48, 0x89, 0xF3, // mov rbx, rsi
59 | 0xE8, 0x00, 0x00, 0x00, 0x00, // call
60 | 0x85, 0xC0, // test eax, eax
61 | 0x74, 0x1D, // je
62 | };
63 |
64 | static const uint8_t kSkipAddressCheckPatched[] =
65 | {
66 | 0x48, 0x89, 0xF3, // mov rbx, rsi
67 | 0xE8, 0x00, 0x00, 0x00, 0x00, // call
68 | 0x85, 0xC0, // test eax, eax
69 | 0x72, 0x1D, // jb short
70 | };
71 |
72 | static const uint8_t kSkipAddressCheckMask[] =
73 | {
74 | 0xFF, 0xFF, 0xFF,
75 | 0xFF, 0x00, 0x00, 0x00, 0x00,
76 | 0xFF, 0xFF,
77 | 0xFF, 0xFF,
78 | };
79 |
80 | static const uint8_t kVendorCheckOriginal[] =
81 | {
82 | 0x81, 0xFA, // cmp edx
83 | 0x5C, 0x0A, 0x00, 0x00, // Vendor BRCM,
84 | 0x74 // jnz short
85 | };
86 |
87 | static const uint8_t kVendorCheckPatched[] =
88 | {
89 | 0x81, 0xFA, // cmp edx
90 | 0x5C, 0x0A, 0x00, 0x00, // Vendor BRCM,
91 | 0xEB // jmp short
92 | };
93 |
94 | // Workaround for bugged chipset range check that
95 | // doesn't consider 0 "THIRD_PARTY_DONGLE" as valid.
96 | // This patch allows bluetooth to turn back on after the first power cycle.
97 | // See https://github.com/acidanthera/BrcmPatchRAM/pull/18 for more details.
98 | static const uint8_t kBadChipsetCheckOriginal[] =
99 | {
100 | 0x81, 0xF9, // cmp ecx
101 | 0xCF, 0x07, 0x00, 0x00, // int 1999
102 | 0x72 // jb short
103 | };
104 |
105 | static const uint8_t kBadChipsetCheckPatched[] =
106 | {
107 | 0x81, 0xF9, // cmp ecx
108 | 0xCF, 0x07, 0x00, 0x00, // int 1999
109 | 0xEB // jmp short
110 | };
111 |
112 | static const uint8_t kBadChipsetCheckOriginal13_3[] =
113 | {
114 | 0x81, 0xF9, // cmp ecx
115 | 0x9E, 0x0F, 0x00, 0x00, // int 3998
116 | 0x77, 0x1A // ja short
117 | };
118 |
119 | static const uint8_t kBadChipsetCheckPatched13_3[] =
120 | {
121 | 0x90, 0x90,
122 | 0x90, 0x90, 0x90, 0x90,
123 | 0x90, 0x90
124 | };
125 |
126 | static const uint8_t kSkipInternalControllerNVRAMCheck13_3[] =
127 | {
128 | 0x41, 0x80, 0x00, 0x01, // xor r15b, 1
129 | 0x75, 0x00, // jnz short
130 | 0x84, 0xDB, // test bl, bl
131 | 0x75, 0x00 // jnz short
132 | };
133 |
134 | static const uint8_t kSkipInternalControllerNVRAMCheckMask13_3[] =
135 | {
136 | 0xFF, 0xFF, 0x00, 0xFF,
137 | 0xFF, 0x00,
138 | 0xFF, 0xFF,
139 | 0xFF, 0x00
140 | };
141 |
142 | static const uint8_t kSkipInternalControllerNVRAMCheckPatched13_3[] =
143 | {
144 | 0x90, 0x90, 0x90, 0x90,
145 | 0x90, 0x90,
146 | 0x90, 0x90,
147 | 0x90, 0x90
148 | };
149 |
150 | static bool shouldPatchBoardId = false;
151 | static bool shouldPatchAddress = false;
152 |
153 | static constexpr size_t kBoardIdSize = sizeof("Mac-F60DEB81FF30ACF6");
154 | static constexpr size_t kBoardIdSizeLegacy = sizeof("Mac-F22586C8");
155 |
156 | static const char boardIdsWithUSBBluetooth[][kBoardIdSize] = {
157 | "Mac-F60DEB81FF30ACF6",
158 | "Mac-9F18E312C5C2BF0B",
159 | "Mac-937CB26E2E02BB01",
160 | "Mac-E43C1C25D4880AD6",
161 | "Mac-06F11FD93F0323C5",
162 | "Mac-06F11F11946D27C5",
163 | "Mac-A369DDC4E67F1C45",
164 | "Mac-FFE5EF870D7BA81A",
165 | "Mac-DB15BD556843C820",
166 | "Mac-B809C3757DA9BB8D",
167 | "Mac-65CE76090165799A",
168 | "Mac-4B682C642B45593E",
169 | "Mac-77F17D7DA9285301",
170 | "Mac-BE088AF8C5EB4FA2"
171 | };
172 |
173 | static mach_vm_address_t orig_cs_validate {};
174 |
175 | #pragma mark - Kernel patching code
176 |
177 | static inline void searchAndPatch(const void *haystack, size_t haystackSize, const char *path, const void *needle, size_t findSize, const void *patch, size_t replaceSize) {
178 | if (KernelPatcher::findAndReplace(const_cast(haystack), haystackSize, needle, findSize, patch, replaceSize))
179 | DBGLOG(MODULE_SHORT, "found string to patch at %s!", path);
180 | }
181 |
182 | template
183 | static inline void searchAndPatch(const void *haystack, size_t haystackSize, const char *path, const T (&needle)[findSize], const T (&patch)[replaceSize]) {
184 | searchAndPatch(haystack, haystackSize, path, needle, findSize * sizeof(T), patch, replaceSize * sizeof(T));
185 | }
186 |
187 | static inline void searchAndPatchWithMask(const void *haystack, size_t haystackSize, const char *path, const void *needle, size_t findSize, const void *findMask, size_t findMaskSize, const void *patch, size_t replaceSize, const void *patchMask, size_t replaceMaskSize) {
188 | if (KernelPatcher::findAndReplaceWithMask(const_cast(haystack), haystackSize, needle, findSize, findMask, findMaskSize, patch, replaceSize, patchMask, replaceMaskSize))
189 | DBGLOG(MODULE_SHORT, "found string to patch at %s!", path);
190 | }
191 |
192 | template
193 | static inline void searchAndPatchWithMask(const void *haystack, size_t haystackSize, const char *path, const T (&needle)[findSize], const T (&findMask)[findMaskSize], const T (&patch)[replaceSize], const T (&patchMask)[replaceMaskSize]) {
194 | searchAndPatchWithMask(haystack, haystackSize, path, needle, findSize * sizeof(T), findMask, findMaskSize * sizeof(T), patch, replaceSize * sizeof(T), patchMask, replaceSize * sizeof(T));
195 | }
196 |
197 |
198 | #pragma mark - Patched functions
199 |
200 | static void patched_cs_validate_page(vnode_t vp, memory_object_t pager, memory_object_offset_t page_offset, const void *data, int *validated_p, int *tainted_p, int *nx_p) {
201 | char path[PATH_MAX];
202 | int pathlen = PATH_MAX;
203 | FunctionCast(patched_cs_validate_page, orig_cs_validate)(vp, pager, page_offset, data, validated_p, tainted_p, nx_p);
204 | static constexpr size_t dirLength = sizeof("/usr/sbin/")-1;
205 | if (vn_getpath(vp, path, &pathlen) == 0 && UNLIKELY(strncmp(path, "/usr/sbin/", dirLength) == 0)) {
206 | if (strcmp(path + dirLength, "BlueTool") == 0) {
207 | searchAndPatch(data, PAGE_SIZE, path, kSkipUpdateFilePathOriginal, kSkipUpdateFilePathPatched);
208 | if (shouldPatchBoardId)
209 | searchAndPatch(data, PAGE_SIZE, path, boardIdsWithUSBBluetooth[0], kBoardIdSize, BaseDeviceInfo::get().boardIdentifier, kBoardIdSize);
210 | }
211 | else if (strcmp(path + dirLength, "bluetoothd") == 0) {
212 | searchAndPatch(data, PAGE_SIZE, path, kVendorCheckOriginal, kVendorCheckPatched);
213 | searchAndPatch(data, PAGE_SIZE, path, kBadChipsetCheckOriginal, kBadChipsetCheckPatched);
214 | searchAndPatch(data, PAGE_SIZE, path, kBadChipsetCheckOriginal13_3, kBadChipsetCheckPatched13_3);
215 | searchAndPatchWithMask(data, PAGE_SIZE, path, kSkipInternalControllerNVRAMCheck13_3, sizeof(kSkipInternalControllerNVRAMCheck13_3), kSkipInternalControllerNVRAMCheckMask13_3, sizeof(kSkipInternalControllerNVRAMCheckMask13_3), kSkipInternalControllerNVRAMCheckPatched13_3, sizeof(kSkipInternalControllerNVRAMCheckPatched13_3), nullptr, 0);
216 | if (shouldPatchBoardId)
217 | searchAndPatch(data, PAGE_SIZE, path, boardIdsWithUSBBluetooth[0], kBoardIdSize, BaseDeviceInfo::get().boardIdentifier, kBoardIdSize);
218 | if (shouldPatchAddress)
219 | searchAndPatchWithMask(data, PAGE_SIZE, path, kSkipAddressCheckOriginal, kSkipAddressCheckMask, kSkipAddressCheckPatched, kSkipAddressCheckMask);
220 | }
221 | }
222 | }
223 |
224 |
225 | #pragma mark - Patches on start/stop
226 |
227 | static void pluginStart() {
228 | SYSLOG(MODULE_SHORT, "start");
229 | // There is no point in routing cs_validate_range, because this kext should only be running on Monterey+
230 | if (getKernelVersion() >= KernelVersion::Monterey) {
231 | lilu.onPatcherLoadForce([](void *user, KernelPatcher &patcher) {
232 | auto boardId = BaseDeviceInfo::get().boardIdentifier;
233 | auto boardIdSize = strlen(boardId) + 1;
234 | shouldPatchBoardId = boardIdSize == kBoardIdSize || boardIdSize == kBoardIdSizeLegacy;
235 | if (shouldPatchBoardId)
236 | for (size_t i = 0; i < arrsize(boardIdsWithUSBBluetooth); i++)
237 | if (strcmp(boardIdsWithUSBBluetooth[i], boardId) == 0) {
238 | shouldPatchBoardId = false;
239 | break;
240 | }
241 | if ((getKernelVersion() == KernelVersion::Monterey && getKernelMinorVersion() >= 5) || getKernelVersion() > KernelVersion::Monterey)
242 | // 12.4 Beta 3+, XNU 21.5
243 | shouldPatchAddress = checkKernelArgument("-btlfxallowanyaddr");
244 | KernelPatcher::RouteRequest csRoute = KernelPatcher::RouteRequest("_cs_validate_page", patched_cs_validate_page, orig_cs_validate);
245 | if (!patcher.routeMultipleLong(KernelPatcher::KernelID, &csRoute, 1))
246 | SYSLOG(MODULE_SHORT, "failed to route cs validation pages");
247 | });
248 | }
249 | }
250 |
251 | // Boot args.
252 | static const char *bootargOff[] {
253 | "-btlfxoff"
254 | };
255 | static const char *bootargDebug[] {
256 | "-btlfxdbg"
257 | };
258 | static const char *bootargBeta[] {
259 | "-btlfxbeta"
260 | };
261 |
262 | // Plugin configuration.
263 | PluginConfiguration ADDPR(config) {
264 | xStringify(PRODUCT_NAME),
265 | parseModuleVersion(xStringify(MODULE_VERSION)),
266 | LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery | LiluAPI::AllowSafeMode,
267 | bootargOff,
268 | arrsize(bootargOff),
269 | bootargDebug,
270 | arrsize(bootargDebug),
271 | bootargBeta,
272 | arrsize(bootargBeta),
273 | KernelVersion::Monterey,
274 | KernelVersion::Sonoma,
275 | pluginStart
276 | };
277 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BrcmFirmwareData-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | $(EXECUTABLE_NAME)
7 | CFBundleIdentifier
8 | $(PRODUCT_BUNDLE_IDENTIFIER)
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | $(PRODUCT_NAME)
13 | CFBundlePackageType
14 | KEXT
15 | CFBundleShortVersionString
16 | ${CURRENT_PROJECT_VERSION}
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | ${CURRENT_PROJECT_VERSION}
21 | IOKitPersonalities
22 |
23 | BrcmFirmwareStore
24 |
25 | CFBundleIdentifier
26 | as.acidanthera.BrcmFirmwareStore
27 | IOClass
28 | BrcmFirmwareStore
29 | IOMatchCategory
30 | BrcmFirmwareStore
31 | IOProviderClass
32 | IOResources
33 |
34 |
35 | OSBundleCompatibleVersion
36 | ${CURRENT_PROJECT_VERSION}
37 | OSBundleLibraries
38 |
39 | com.apple.kpi.iokit
40 | 9.0
41 | com.apple.kpi.libkern
42 | 9.0
43 | com.apple.kpi.mach
44 | 9.0
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BrcmFirmwareRepo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | $(EXECUTABLE_NAME)
7 | CFBundleIdentifier
8 | $(PRODUCT_BUNDLE_IDENTIFIER)
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | $(PRODUCT_NAME)
13 | CFBundlePackageType
14 | KEXT
15 | CFBundleShortVersionString
16 | ${CURRENT_PROJECT_VERSION}
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | ${CURRENT_PROJECT_VERSION}
21 | IOKitPersonalities
22 |
23 | BrcmFirmwareStore
24 |
25 | CFBundleIdentifier
26 | as.acidanthera.BrcmFirmwareStore
27 | IOClass
28 | BrcmFirmwareStore
29 | IOMatchCategory
30 | BrcmFirmwareStore
31 | IOProviderClass
32 | IOResources
33 |
34 |
35 | OSBundleCompatibleVersion
36 | ${CURRENT_PROJECT_VERSION}
37 | OSBundleLibraries
38 |
39 | com.apple.kpi.iokit
40 | 9.0
41 | com.apple.kpi.libkern
42 | 9.0
43 | com.apple.kpi.mach
44 | 9.0
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BrcmFirmwareStore.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | * Zlib implementation based on /apple/xnu/libkern/c++/OSKext.cpp
19 | */
20 |
21 | #include "Common.h"
22 | #include "BrcmFirmwareStore.h"
23 | #ifdef FIRMWAREDATA
24 | #include "FirmwareData.h"
25 | #endif
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | /***************************************
32 | * Zlib Decompression
33 | ***************************************/
34 | #include
35 | #include
36 |
37 | extern "C"
38 | {
39 | static void* z_alloc(void*, u_int items, u_int size);
40 | static void z_free(void*, void *ptr);
41 |
42 | typedef struct z_mem
43 | {
44 | UInt32 alloc_size;
45 | UInt8 data[0];
46 | } z_mem;
47 |
48 | /*
49 | * Space allocation and freeing routines for use by zlib routines.
50 | */
51 | void* z_alloc(void* notused __unused, u_int num_items, u_int size)
52 | {
53 | void* result = NULL;
54 | z_mem* zmem = NULL;
55 | UInt32 total = num_items * size;
56 | UInt32 allocSize = total + sizeof(zmem);
57 |
58 | zmem = (z_mem*)IOMalloc(allocSize);
59 |
60 | if (zmem)
61 | {
62 | zmem->alloc_size = allocSize;
63 | result = (void*)&(zmem->data);
64 | }
65 |
66 | return result;
67 | }
68 |
69 | void z_free(void* notused __unused, void* ptr)
70 | {
71 | UInt32* skipper = (UInt32 *)ptr - 1;
72 | z_mem* zmem = (z_mem*)skipper;
73 | IOFree((void*)zmem, zmem->alloc_size);
74 | }
75 | };
76 |
77 | /*
78 | * Decompress the firmware using zlib inflate (If not compressed, return data normally)
79 | */
80 | OSData* BrcmFirmwareStore::decompressFirmware(OSData* firmware)
81 | {
82 | z_stream zstream;
83 | int zlib_result;
84 | int bufferSize = 0;
85 | void* buffer = NULL;
86 | OSData* result = NULL;
87 |
88 | // Verify if the data is compressed
89 | UInt16* magic = (UInt16*)firmware->getBytesNoCopy();
90 |
91 | if (*magic != 0x0178 // Zlib no compression
92 | && *magic != 0x9c78 // Zlib default compression
93 | && *magic != 0xda78) // Zlib maximum compression
94 | {
95 | // Return the data as-is
96 | firmware->retain();
97 | return firmware;
98 | }
99 |
100 | bufferSize = firmware->getLength() * 4;
101 |
102 | buffer = IOMalloc(bufferSize);
103 |
104 | bzero(&zstream, sizeof(zstream));
105 |
106 | zstream.next_in = (unsigned char*)firmware->getBytesNoCopy();
107 | zstream.avail_in = firmware->getLength();
108 |
109 | zstream.next_out = (unsigned char*)buffer;
110 | zstream.avail_out = bufferSize;
111 |
112 | zstream.zalloc = z_alloc;
113 | zstream.zfree = z_free;
114 |
115 | zlib_result = inflateInit(&zstream);
116 |
117 | if (zlib_result != Z_OK)
118 | {
119 | IOFree(buffer, bufferSize);
120 | return NULL;
121 | }
122 |
123 | zlib_result = inflate(&zstream, Z_FINISH);
124 |
125 | if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)
126 | // Allocate final result
127 | result = OSData::withBytes(buffer, (unsigned int)zstream.total_out);
128 |
129 | inflateEnd(&zstream);
130 | IOFree(buffer, bufferSize);
131 |
132 | return result;
133 | }
134 |
135 | /**********************************************
136 | * IntelHex firmware parsing
137 | **********************************************/
138 | #define HEX_LINE_PREFIX ':'
139 | #define HEX_HEADER_SIZE 4
140 |
141 | #define REC_TYPE_DATA 0 // Data
142 | #define REC_TYPE_EOF 1 // End of File
143 | #define REC_TYPE_ESA 2 // Extended Segment Address
144 | #define REC_TYPE_SSA 3 // Start Segment Address
145 | #define REC_TYPE_ELA 4 // Extended Linear Address
146 | #define REC_TYPE_SLA 5 // Start Linear Address
147 |
148 | /*
149 | * Validate if the current character is a valid hexadecimal character
150 | */
151 | static inline bool validHexChar(UInt8 hex)
152 | {
153 | return (hex >= 'a' && hex <= 'f') || (hex >= 'A' && hex <= 'F') || (hex >= '0' && hex <= '9');
154 | }
155 |
156 | /*
157 | * Convert char '0-9,A-F' to hexadecimal values
158 | */
159 | static inline void hex_nibble(UInt8 hex, UInt8 &output)
160 | {
161 | output <<= 4;
162 |
163 | if (hex >= 'a')
164 | output |= (0x0A + (hex - 'a')) & 0x0F;
165 | if (hex >= 'A')
166 | output |= (0x0A + (hex - 'A')) & 0x0F;
167 | else
168 | output |= (hex - '0') & 0x0F;
169 | }
170 |
171 | /*
172 | * Two's complement checksum
173 | */
174 | static char check_sum(const UInt8* data, UInt16 len)
175 | {
176 | UInt32 crc = 0;
177 |
178 | for (int i = 0; i < len; i++)
179 | crc += *(data + i);
180 |
181 | return (~crc + 1) & 0xFF;
182 | }
183 |
184 | OSArray* BrcmFirmwareStore::parseFirmware(OSData* firmwareData)
185 | {
186 | // Vendor Specific: Launch RAM
187 | UInt8 HCI_VSC_LAUNCH_RAM[] = { 0x4c, 0xfc };
188 |
189 | OSArray* instructions = OSArray::withCapacity(1);
190 | if (!instructions)
191 | return NULL;
192 |
193 | UInt8* data = (UInt8*)firmwareData->getBytesNoCopy();
194 | UInt32 address = 0;
195 | UInt8 binary[0x110];
196 |
197 | if (*data != HEX_LINE_PREFIX)
198 | {
199 | DebugLog("parseFirmware - Invalid firmware data.\n");
200 | goto exit_error;
201 | }
202 |
203 | while (*data == HEX_LINE_PREFIX)
204 | {
205 | bzero(binary, sizeof(binary));
206 | data++;
207 |
208 | int offset = 0;
209 |
210 | // Read all hex characters for this line
211 | while (validHexChar(*data))
212 | {
213 | hex_nibble(*data++, binary[offset]);
214 | hex_nibble(*data++, binary[offset++]);
215 | }
216 |
217 | // Parse line data
218 | UInt8 length = binary[0];
219 | UInt16 addr = binary[1] << 8 | binary[2];
220 | UInt8 record_type = binary[3];
221 | UInt8 checksum = binary[HEX_HEADER_SIZE + length];
222 |
223 | UInt8 calc_checksum = check_sum(binary, HEX_HEADER_SIZE + length);
224 |
225 | if (checksum != calc_checksum)
226 | {
227 | DebugLog("parseFirmware - Invalid firmware, checksum mismatch.\n");
228 | goto exit_error;
229 | }
230 |
231 | // ParseFirmware class only supports I32HEX format
232 | switch (record_type)
233 | {
234 | // Data
235 | case REC_TYPE_DATA:
236 | {
237 | address = (address & 0xFFFF0000) | addr;
238 |
239 | // Reserved 4 bytes for the address
240 | length += 4;
241 |
242 | // Allocate instruction (Opcode - 2 bytes, length - 1 byte)
243 | OSData* instruction = OSData::withCapacity(3 + length);
244 | if (!instruction)
245 | goto exit_error;
246 |
247 | instruction->appendBytes(HCI_VSC_LAUNCH_RAM, sizeof(HCI_VSC_LAUNCH_RAM));
248 | instruction->appendBytes(&length, sizeof(length));
249 | instruction->appendBytes(&address, sizeof(address));
250 | instruction->appendBytes(&binary[4], length - 4);
251 |
252 | instructions->setObject(instruction);
253 | instruction->release();
254 | break;
255 | }
256 | // End of File
257 | case REC_TYPE_EOF:
258 | return instructions;
259 | // Extended Segment Address
260 | case REC_TYPE_ESA:
261 | // Segment address multiplied by 16
262 | address = binary[4] << 8 | binary[5];
263 | address <<= 4;
264 | break;
265 | // Start Segment Address
266 | case REC_TYPE_SSA:
267 | // Set CS:IP register for 80x86
268 | DebugLog("parseFirmware - Invalid firmware, unsupported start segment address instruction.\n");
269 | goto exit_error;
270 | // Extended Linear Address
271 | case REC_TYPE_ELA:
272 | // Set new higher 16 bits of the current address
273 | address = binary[4] << 24 | binary[5] << 16;
274 | break;
275 | // Start Linear Address
276 | case REC_TYPE_SLA:
277 | // Set EIP of 80386 and higher
278 | DebugLog("parseFirmware - Invalid firmware, unsupported start linear address instruction.\n");
279 | goto exit_error;
280 | default:
281 | DebugLog("parseFirmware - Invalid firmware, unknown record type encountered: 0x%02x.\n", record_type);
282 | goto exit_error;
283 | }
284 |
285 | // Skip over any trailing newlines / whitespace
286 | while (!validHexChar(*data) && !(*data == HEX_LINE_PREFIX))
287 | data++;
288 | }
289 |
290 | DebugLog("parseFirmware - Invalid firmware.\n");
291 |
292 | exit_error:
293 | OSSafeReleaseNULL(instructions);
294 | return NULL;
295 | }
296 |
297 | OSDefineMetaClassAndStructors(BrcmFirmwareStore, IOService)
298 |
299 | bool BrcmFirmwareStore::start(IOService *provider)
300 | {
301 | DebugLog("Firmware store start\n");
302 |
303 | if (!super::start(provider))
304 | return false;
305 |
306 | mFirmwares = OSDictionary::withCapacity(1);
307 | if (!mFirmwares)
308 | return false;
309 |
310 | mCompletionLock = IOLockAlloc();
311 | if (!mCompletionLock)
312 | return false;
313 |
314 | mDataLock = IOLockAlloc();
315 | if (!mDataLock)
316 | return false;
317 |
318 | registerService();
319 |
320 | return true;
321 | }
322 |
323 | void BrcmFirmwareStore::stop(IOService *provider)
324 | {
325 | DebugLog("Firmware store stop\n");
326 |
327 | OSSafeReleaseNULL(mFirmwares);
328 |
329 | if (mCompletionLock)
330 | {
331 | IOLockFree(mCompletionLock);
332 | mCompletionLock = NULL;
333 | }
334 |
335 | if (mDataLock)
336 | {
337 | IOLockFree(mDataLock);
338 | mDataLock = NULL;
339 | }
340 |
341 | super::stop(provider);
342 | }
343 |
344 | void BrcmFirmwareStore::requestResourceCallback(OSKextRequestTag requestTag, OSReturn result, const void * resourceData, uint32_t resourceDataLength, void* context1)
345 | {
346 | ResourceCallbackContext *context = (ResourceCallbackContext*)context1;
347 |
348 | IOLockLock(context->me->mCompletionLock);
349 |
350 | if (kOSReturnSuccess == result)
351 | {
352 | DebugLog("OSKextRequestResource Callback: %d bytes of data.\n", resourceDataLength);
353 |
354 | context->firmware = OSData::withBytes(resourceData, resourceDataLength);
355 | }
356 | else
357 | DebugLog("OSKextRequestResource Callback: %08x.\n", result);
358 |
359 | IOLockUnlock(context->me->mCompletionLock);
360 |
361 | // wake waiting task in performUpgrade (in IOLockSleep)...
362 | IOLockWakeup(context->me->mCompletionLock, context->me, true);
363 | }
364 |
365 | OSData* BrcmFirmwareStore::loadFirmwareFile(const char* filename, const char* suffix)
366 | {
367 | IOLockLock(mCompletionLock);
368 |
369 | ResourceCallbackContext context = { .me = this, .firmware = NULL };
370 |
371 | char path[PATH_MAX];
372 | snprintf(path, PATH_MAX, "%s.%s", filename, suffix);
373 |
374 | OSReturn ret = OSKextRequestResource(OSKextGetCurrentIdentifier(),
375 | path,
376 | requestResourceCallback,
377 | &context,
378 | NULL);
379 | (void) ret;
380 | DebugLog("OSKextRequestResource: %08x\n", ret);
381 |
382 | // wait for completion of the async read
383 | IOLockSleep(mCompletionLock, this, 0);
384 |
385 | IOLockUnlock(mCompletionLock);
386 |
387 | if (context.firmware)
388 | {
389 | AlwaysLog("Loaded firmware \"%s\" from resources.\n", path);
390 | return context.firmware;
391 | }
392 |
393 | return NULL;
394 | }
395 |
396 | OSData* BrcmFirmwareStore::loadFirmwareFiles(UInt16 vendorId, UInt16 productId, OSString* firmwareKey)
397 | {
398 | char filename[PATH_MAX];
399 | snprintf(filename, PATH_MAX, "%04x_%04x", vendorId, productId);
400 |
401 | OSData* result = loadFirmwareFile(filename, kBrcmFirmwareCompressed);
402 |
403 | if (!result)
404 | result = loadFirmwareFile(filename, kBrmcmFirwareUncompressed);
405 |
406 | if (!result)
407 | result = loadFirmwareFile(firmwareKey->getCStringNoCopy(), kBrcmFirmwareCompressed);
408 |
409 | if (!result)
410 | result = loadFirmwareFile(firmwareKey->getCStringNoCopy(), kBrmcmFirwareUncompressed);
411 |
412 | return result;
413 | }
414 |
415 | OSArray* BrcmFirmwareStore::loadFirmware(UInt16 vendorId, UInt16 productId, OSString* firmwareKey)
416 | {
417 | #ifdef FIRMWAREDATA
418 | char filename[PATH_MAX];
419 | // Try to load from internal binary data
420 | DebugLog("loadFirmware from internal binary data %s\n", firmwareKey->getCStringNoCopy());
421 | snprintf(filename, PATH_MAX, "%s.%s", firmwareKey->getCStringNoCopy(), kBrcmFirmwareCompressed);
422 | OSData* configuredData = lookupFirmware(filename);
423 | if (configuredData)
424 | AlwaysLog("Loaded compressed embedded firmware for key \"%s\".\n", firmwareKey->getCStringNoCopy());
425 | if (!configuredData)
426 | {
427 | snprintf(filename, PATH_MAX, "%s.%s", firmwareKey->getCStringNoCopy(), kBrmcmFirwareUncompressed);
428 | configuredData = lookupFirmware(filename);
429 | if (configuredData)
430 | AlwaysLog("Loaded compressed embedded firmware for key \"%s\".\n", firmwareKey->getCStringNoCopy());
431 | }
432 | #else
433 | // Try to load firmware from disk
434 | DebugLog("loadFirmware from disk data %s\n", firmwareKey->getCStringNoCopy());
435 | OSData* configuredData = loadFirmwareFiles(vendorId, productId, firmwareKey);
436 | #endif
437 |
438 | // Next try to load firmware from configuration
439 | if (!configuredData)
440 | {
441 | OSDictionary* firmwares = OSDynamicCast(OSDictionary, this->getProperty("Firmwares"));
442 |
443 | if (!firmwares)
444 | {
445 | AlwaysLog("Unable to locate BrcmFirmwareStore configured firmwares.\n");
446 | return NULL;
447 | }
448 |
449 | configuredData = OSDynamicCast(OSData, firmwares->getObject(firmwareKey));
450 |
451 | if (configuredData)
452 | {
453 | configuredData->retain();
454 | AlwaysLog("Retrieved firmware \"%s\" from internal configuration.\n", firmwareKey->getCStringNoCopy());
455 | }
456 | }
457 |
458 | if (!configuredData)
459 | {
460 | AlwaysLog("No firmware available for firmware key \"%s\".\n", firmwareKey->getCStringNoCopy());
461 | return NULL;
462 | }
463 |
464 | OSData* firmwareData = decompressFirmware(configuredData);
465 |
466 | if (!firmwareData)
467 | {
468 | configuredData->release();
469 | AlwaysLog("Failed to decompress firmware.\n");
470 | return NULL;
471 | }
472 |
473 | if (configuredData->getLength() < firmwareData->getLength())
474 | AlwaysLog("Decompressed firmware (%d bytes --> %d bytes).\n", configuredData->getLength(), firmwareData->getLength());
475 | else
476 | AlwaysLog("Non-compressed firmware.\n");
477 |
478 | configuredData->release();
479 |
480 | #ifdef DEBUG
481 | SHA1_CTX ctx;
482 | uint8_t hash[SHA1_RESULTLEN];
483 | SHA1Init(&ctx);
484 | SHA1Update(&ctx, firmwareData->getBytesNoCopy(), firmwareData->getLength());
485 | SHA1Final(hash, &ctx);
486 | DebugLog("Firmware SHA1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
487 | hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9],
488 | hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);
489 | #endif
490 |
491 | OSArray* instructions = parseFirmware(firmwareData);
492 | firmwareData->release();
493 |
494 | if (!instructions)
495 | {
496 | AlwaysLog("Firmware is not valid IntelHex firmware.\n");
497 | return NULL;
498 | }
499 |
500 | AlwaysLog("Firmware is valid IntelHex firmware.\n");
501 |
502 | return instructions;
503 | }
504 |
505 | OSArray* BrcmFirmwareStore::getFirmware(UInt16 vendorId, UInt16 productId, OSString* firmwareKey)
506 | {
507 | DebugLog("getFirmware\n");
508 |
509 | if (!firmwareKey || firmwareKey->getLength() == 0)
510 | {
511 | AlwaysLog("Current device has no FirmwareKey configured.\n");
512 | return NULL;
513 | }
514 |
515 | IOLockLock(mDataLock);
516 | OSArray* instructions = OSDynamicCast(OSArray, mFirmwares->getObject(firmwareKey));
517 |
518 | // Cached instructions found for firmwareKey?
519 | if (!instructions)
520 | {
521 | // Load instructions for firmwareKey
522 | instructions = loadFirmware(vendorId, productId, firmwareKey);
523 |
524 | // Add instructions to the firmwares cache
525 | if (instructions)
526 | {
527 | mFirmwares->setObject(firmwareKey, instructions);
528 | instructions->release();
529 | }
530 | }
531 | else
532 | DebugLog("Retrieved cached firmware for \"%s\".\n", firmwareKey->getCStringNoCopy());
533 |
534 | IOLockUnlock(mDataLock);
535 |
536 | return instructions;
537 | }
538 |
539 |
540 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BrcmFirmwareStore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #ifndef __BrcmPatchRAM__BrcmFirmwareStore__
21 | #define __BrcmPatchRAM__BrcmFirmwareStore__
22 |
23 | #include
24 | #include
25 | #include
26 |
27 | #define kBrcmFirmwareCompressed "zhx"
28 | #define kBrmcmFirwareUncompressed "hex"
29 |
30 | #define kBrcmFirmwareStoreService "BrcmFirmwareStore"
31 |
32 | class BrcmFirmwareStore : public IOService
33 | {
34 | private:
35 | typedef IOService super;
36 | OSDeclareDefaultStructors(BrcmFirmwareStore);
37 |
38 | struct ResourceCallbackContext
39 | {
40 | BrcmFirmwareStore* me;
41 | OSData* firmware;
42 | };
43 |
44 | IOLock* mDataLock;
45 | OSDictionary* mFirmwares;
46 | IOLock* mCompletionLock = NULL;
47 |
48 | OSData* decompressFirmware(OSData* firmware);
49 | OSArray* parseFirmware(OSData* firmwareData);
50 | static void requestResourceCallback(OSKextRequestTag requestTag, OSReturn result, const void * resourceData, uint32_t resourceDataLength, void* context);
51 | OSData* loadFirmwareFile(const char* filename, const char* suffix);
52 | OSData* loadFirmwareFiles(UInt16 vendorId, UInt16 productId, OSString* firmwareIdentifier);
53 | OSArray* loadFirmware(UInt16 vendorId, UInt16 productId, OSString* firmwareIdentifier);
54 |
55 | public:
56 | bool start(IOService *provider) override;
57 | void stop(IOService *provider) override;
58 |
59 | virtual OSArray* getFirmware(UInt16 vendorId, UInt16 productId, OSString* firmwareIdentifier);
60 | };
61 |
62 | #endif /* defined(__BrcmPatchRAM__BrcmFirmwareStore__) */
63 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/BrcmPatchRAM.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 | #ifndef __BrcmPatchRAM__
20 | #define __BrcmPatchRAM__
21 |
22 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
23 | // 10.11 works better if probe simply exits after updating firmware
24 | #define NON_RESIDENT 1
25 | #endif
26 |
27 | #include
28 | #include
29 |
30 | #include "BrcmFirmwareStore.h"
31 | #include "USBDeviceShim.h"
32 |
33 | #define kDisplayName "DisplayName"
34 | #define kBundleIdentifier "CFBundleIdentifier"
35 | #define kIOUSBDeviceClassName "IOUSBDevice"
36 | #ifndef kIOUSBHostDeviceClassName
37 | #define kIOUSBHostDeviceClassName "IOUSBHostDevice"
38 | #endif
39 | #define kAppleBundlePrefix "com.apple."
40 | #define kFirmwareKey "FirmwareKey"
41 | #define kFirmwareLoaded "FirmwareLoaded"
42 |
43 | enum DeviceState
44 | {
45 | kUnknown,
46 | kPreInitialize,
47 | kInitialize,
48 | kFirmwareVersion,
49 | kMiniDriverComplete,
50 | kInstructionWrite,
51 | kInstructionWritten,
52 | kFirmwareWritten,
53 | kResetWrite,
54 | kResetComplete,
55 | kUpdateComplete,
56 | kUpdateNotNeeded,
57 | kUpdateAborted,
58 | };
59 |
60 | typedef struct DeviceHskSupport
61 | {
62 | UInt16 vid;
63 | UInt16 did;
64 | } DeviceHskSupport;
65 |
66 | #if defined(TARGET_CATALINA)
67 | #define BrcmPatchRAM BrcmPatchRAM3
68 | #elif defined(TARGET_ELCAPITAN)
69 | #define BrcmPatchRAM BrcmPatchRAM2
70 | #endif
71 |
72 | extern "C"
73 | {
74 | kern_return_t BrcmPatchRAM_Start(kmod_info_t*, void*);
75 | kern_return_t BrcmPatchRAM_Stop(kmod_info_t*, void*);
76 | }
77 |
78 | class BrcmPatchRAM : public IOService
79 | {
80 | private:
81 | typedef IOService super;
82 | #if defined(TARGET_CATALINA)
83 | OSDeclareDefaultStructors(BrcmPatchRAM3);
84 | #elif defined(TARGET_ELCAPITAN)
85 | OSDeclareDefaultStructors(BrcmPatchRAM2);
86 | #else
87 | OSDeclareDefaultStructors(BrcmPatchRAM);
88 | #endif
89 |
90 | UInt16 mVendorId = 0xFFFF;
91 | UInt16 mProductId = 0xFFFF;
92 | #ifndef TARGET_CATALINA
93 | UInt32 mProbeDelay = 0;
94 | #endif
95 | UInt32 mPreResetDelay = 0;
96 | UInt32 mPostResetDelay = 0;
97 | UInt32 mInitialDelay = 0;
98 |
99 | USBDeviceShim mDevice;
100 | USBInterfaceShim mInterface;
101 | USBPipeShim mInterruptPipe;
102 | USBPipeShim mBulkPipe;
103 | BrcmFirmwareStore* mFirmwareStore = NULL;
104 | #ifndef NON_RESIDENT
105 | bool mStopping = false;
106 | #endif
107 | bool mSupportsHandshake = false;
108 |
109 | USBCOMPLETION mInterruptCompletion {};
110 | IOBufferMemoryDescriptor* mReadBuffer = NULL;
111 |
112 | volatile DeviceState mDeviceState = kInitialize;
113 | volatile uint16_t mFirmwareVersion = 0xFFFF;
114 | IOLock* mCompletionLock = NULL;
115 |
116 | #ifdef DEBUG
117 | static const char* getState(DeviceState deviceState);
118 | #endif
119 |
120 | #ifndef TARGET_CATALINA
121 | static OSString* brcmBundleIdentifier;
122 | static OSString* brcmIOClass;
123 | static OSString* brcmProviderClass;
124 | static void initBrcmStrings();
125 | #endif
126 |
127 | #ifdef DEBUG
128 | void printPersonalities();
129 | #endif
130 |
131 | #ifndef NON_RESIDENT
132 | UInt32 mBlurpWait = 0;
133 | IOTimerEventSource* mTimer = NULL;
134 | IOReturn onTimerEvent(void);
135 |
136 | static void uploadFirmwareThread(void* arg, wait_result_t wait);
137 | thread_t mWorker = 0;
138 |
139 | IOInterruptEventSource* mWorkSource = NULL;
140 | IOLock* mWorkLock = NULL;
141 | static IOLock* mLoadFirmwareLock;
142 | friend kern_return_t BrcmPatchRAM_Start(kmod_info_t*, void*);
143 | friend kern_return_t BrcmPatchRAM_Stop(kmod_info_t*, void*);
144 |
145 | enum WorkPending
146 | {
147 | kWorkLoadFirmware = 0x01,
148 | kWorkFinished = 0x02,
149 | };
150 | unsigned mWorkPending = 0;
151 | void scheduleWork(unsigned newWork);
152 | void processWorkQueue(IOInterruptEventSource*, int);
153 | #endif // #ifndef NON_RESIDENT
154 |
155 | #ifndef TARGET_CATALINA
156 | void publishPersonality();
157 | #endif
158 |
159 | #ifndef NON_RESIDENT
160 | #if (!defined(TARGET_ELCAPITAN)) && (!defined(TARGET_CATALINA))
161 | void removePersonality();
162 | #endif
163 | #endif
164 | #ifndef TARGET_CATALINA
165 | bool publishResourcePersonality(const char* classname);
166 | #endif
167 | BrcmFirmwareStore* getFirmwareStore();
168 | void uploadFirmware();
169 |
170 | void printDeviceInfo();
171 | int getDeviceStatus();
172 |
173 | bool setConfiguration(int configurationIndex);
174 |
175 | bool findInterface(USBInterfaceShim* interface);
176 | bool findPipe(USBPipeShim* pipe, uint8_t type, uint8_t direction);
177 |
178 | bool continuousRead();
179 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
180 | static void readCompletion(void* target, void* parameter, IOReturn status, uint32_t bytesTransferred);
181 | #else
182 | static void readCompletion(void* target, void* parameter, IOReturn status, UInt32 bufferSizeRemaining);
183 | #endif
184 |
185 | IOReturn hciCommand(void * command, uint16_t length);
186 | IOReturn hciParseResponse(void* response, uint16_t length, void* output, uint8_t* outputLength);
187 |
188 | IOReturn bulkWrite(const void* data, uint16_t length);
189 |
190 | uint16_t getFirmwareVersion();
191 |
192 | bool performUpgrade();
193 | bool supportsHandshake(UInt16 vid, UInt16 did);
194 | public:
195 | IOService* probe(IOService *provider, SInt32 *probeScore) override;
196 | #if defined(TARGET_CATALINA) || (!defined(NON_RESIDENT))
197 | bool start(IOService* provider) override;
198 | void stop(IOService* provider) override;
199 | IOReturn setPowerState(unsigned long which, IOService *whom) override;
200 | #endif
201 |
202 | const char* stringFromReturn(IOReturn rtn) override;
203 |
204 | #ifdef TARGET_CATALINA
205 | bool init(OSDictionary *properties) override;
206 | void free() override;
207 | #endif
208 | };
209 |
210 | #if defined(NON_RESIDENT) && (!defined(TARGET_CATALINA))
211 |
212 | #define kBrcmPatchRAMResidency "BrcmPatchRAMResidency"
213 | class BrcmPatchRAMResidency : public IOService
214 | {
215 | private:
216 | typedef IOService super;
217 | OSDeclareDefaultStructors(BrcmPatchRAMResidency);
218 |
219 | public:
220 | bool start(IOService *provider) override;
221 | };
222 |
223 | #endif //defined(NON_RESIDENT) && (!defined(TARGET_CATALINA))
224 |
225 | #endif //__BrcmPatchRAM__
226 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/Common.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #ifndef BRCMPatchRAM_Common_h
21 | #define BRCMPatchRAM_Common_h
22 |
23 | #ifndef TARGET_ELCAPITAN
24 | #define BRCMPATCHRAM_NAME "BrcmPatchRAM"
25 | #else
26 | #define BRCMPATCHRAM_NAME "BrcmPatchRAM2"
27 | #endif
28 |
29 | #ifdef DEBUG
30 | #define DebugLog(args...) do { IOLog(BRCMPATCHRAM_NAME ": " args); } while (0)
31 | #else
32 | #define DebugLog(args...) do { } while (0)
33 | #endif
34 | #define AlwaysLog(args...) do { IOLog(BRCMPATCHRAM_NAME ": " args); } while (0)
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/FirmwareData.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #include "Common.h"
21 | #include "FirmwareData.h"
22 | #include "../GeneratedFirmwares.cpp"
23 |
24 | #include
25 |
26 | OSData* lookupFirmware(const char* filename)
27 | {
28 | OSData* result = NULL;
29 | for (const FirmwareEntry* entry = firmwares; entry->filename != NULL; entry++)
30 | {
31 | if (0 == strcmp(filename, entry->filename))
32 | {
33 | result = OSData::withBytes(entry->firmwareData, (unsigned int)entry->firmwareSize);
34 | break;
35 | }
36 | }
37 | return result;
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/FirmwareData.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #ifndef _FIRMWAREDATA_H
21 | #define _FIRMWAREDATA_H
22 |
23 | #include
24 |
25 | struct FirmwareEntry
26 | {
27 | const char* filename;
28 | const unsigned char* firmwareData;
29 | size_t firmwareSize;
30 | };
31 |
32 | OSData* lookupFirmware(const char* filename);
33 |
34 | #endif//_FIRMWAREDATA_H
35 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/USBDeviceShim.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #include "USBDeviceShim.h"
21 | #include "Common.h"
22 |
23 | #include
24 |
25 | USBDeviceShim::USBDeviceShim()
26 | {
27 | m_pDevice = NULL;
28 | }
29 |
30 | void USBDeviceShim::setDevice(IOService* provider)
31 | {
32 | OSObject* prev = m_pDevice;
33 |
34 | m_pDevice = OSDynamicCast(IOUSBDevice, provider);
35 |
36 | if (m_pDevice)
37 | m_pDevice->retain();
38 |
39 | if (prev)
40 | prev->release();
41 | }
42 |
43 | UInt16 USBDeviceShim::getVendorID()
44 | {
45 | return m_pDevice->GetVendorID();
46 | }
47 |
48 | UInt16 USBDeviceShim::getProductID()
49 | {
50 | return m_pDevice->GetProductID();
51 | }
52 |
53 | OSObject* USBDeviceShim::getProperty(const char* name)
54 | {
55 | return m_pDevice->getProperty(name);
56 | }
57 |
58 | void USBDeviceShim::setProperty(const char* name, bool value)
59 | {
60 | m_pDevice->setProperty(name, value);
61 | }
62 |
63 | void USBDeviceShim::removeProperty(const char* name)
64 | {
65 | m_pDevice->removeProperty(name);
66 | }
67 |
68 | IOReturn USBDeviceShim::getStringDescriptor(UInt8 index, char *buf, int maxLen, UInt16 lang)
69 | {
70 | return m_pDevice->GetStringDescriptor(index, buf, maxLen, lang);
71 | }
72 |
73 | UInt16 USBDeviceShim::getDeviceRelease()
74 | {
75 | return m_pDevice->GetDeviceRelease();
76 | }
77 |
78 | IOReturn USBDeviceShim::getDeviceStatus(IOService* forClient, USBStatus *status)
79 | {
80 | return m_pDevice->GetDeviceStatus(status);
81 | }
82 |
83 | IOReturn USBDeviceShim::resetDevice()
84 | {
85 | return m_pDevice->ResetDevice();
86 | }
87 |
88 | UInt8 USBDeviceShim::getNumConfigurations()
89 | {
90 | return m_pDevice->GetNumConfigurations();
91 | }
92 |
93 | const USBCONFIGURATIONDESCRIPTOR* USBDeviceShim::getFullConfigurationDescriptor(UInt8 configIndex)
94 | {
95 | return m_pDevice->GetFullConfigurationDescriptor(configIndex);
96 | }
97 |
98 | IOReturn USBDeviceShim::getConfiguration(IOService* forClient, UInt8 *configNumber)
99 | {
100 | return m_pDevice->GetConfiguration(configNumber);
101 | }
102 |
103 | IOReturn USBDeviceShim::setConfiguration(IOService *forClient, UInt8 configValue, bool startInterfaceMatching)
104 | {
105 | return m_pDevice->SetConfiguration(forClient, configValue, startInterfaceMatching);
106 | }
107 |
108 | bool USBDeviceShim::findFirstInterface(USBInterfaceShim* shim)
109 | {
110 | DebugLog("USBDeviceShim::findFirstInterface\n");
111 |
112 | IOUSBFindInterfaceRequest request;
113 | request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
114 | request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
115 | request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
116 | request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
117 | IOUSBInterface* interface = m_pDevice->FindNextInterface(NULL, &request);
118 | DebugLog("FindNextInterface returns %p\n", interface);
119 | shim->setInterface(interface);
120 |
121 | DebugLog("getValidatedInterface returns %p\n", shim->getValidatedInterface());
122 | return shim->getValidatedInterface() != NULL;
123 | }
124 |
125 | bool USBDeviceShim::open(IOService *forClient, IOOptionBits options, void *arg)
126 | {
127 | return m_pDevice->open(forClient, options, arg);
128 | }
129 |
130 | void USBDeviceShim::close(IOService *forClient, IOOptionBits options)
131 | {
132 | return m_pDevice->close(forClient, options);
133 | }
134 |
135 | UInt8 USBDeviceShim::getManufacturerStringIndex()
136 | {
137 | return m_pDevice->GetManufacturerStringIndex();
138 | }
139 |
140 | UInt8 USBDeviceShim::getProductStringIndex()
141 | {
142 | return m_pDevice->GetProductStringIndex();
143 | }
144 | UInt8 USBDeviceShim::getSerialNumberStringIndex()
145 | {
146 | return m_pDevice->GetSerialNumberStringIndex();
147 | }
148 |
149 | USBInterfaceShim::USBInterfaceShim()
150 | {
151 | m_pInterface = NULL;
152 | }
153 |
154 | void USBInterfaceShim::setInterface(IOService* interface)
155 | {
156 | OSObject* prev = m_pInterface;
157 |
158 | m_pInterface = OSDynamicCast(IOUSBInterface, interface);
159 |
160 | if (m_pInterface)
161 | m_pInterface->retain();
162 | if (prev)
163 | prev->release();
164 | }
165 |
166 | bool USBInterfaceShim::open(IOService *forClient, IOOptionBits options, void *arg)
167 | {
168 | bool result = m_pInterface->open(forClient, options, arg);
169 | if (!result)
170 | AlwaysLog("USBInterfaceShim:open failed\n");
171 | return result;
172 | }
173 |
174 | void USBInterfaceShim::close(IOService *forClient, IOOptionBits options)
175 | {
176 | m_pInterface->close(forClient, options);
177 | }
178 |
179 | #ifdef DEBUG
180 | UInt8 USBInterfaceShim::getInterfaceNumber()
181 | {
182 | return m_pInterface->GetInterfaceNumber();
183 | }
184 |
185 | UInt8 USBInterfaceShim::getInterfaceClass()
186 | {
187 | return m_pInterface->GetInterfaceClass();
188 | }
189 |
190 | UInt8 USBInterfaceShim::getInterfaceSubClass()
191 | {
192 | return m_pInterface->GetInterfaceSubClass();
193 | }
194 |
195 | UInt8 USBInterfaceShim::getInterfaceProtocol()
196 | {
197 | return m_pInterface->GetInterfaceProtocol();
198 | }
199 | #endif
200 |
201 | bool USBInterfaceShim::findPipe(USBPipeShim* shim, UInt8 type, UInt8 direction)
202 | {
203 | IOUSBFindEndpointRequest findEndpointRequest;
204 | findEndpointRequest.type = type;
205 | findEndpointRequest.direction = direction;
206 | if (IOUSBPipe* pipe = m_pInterface->FindNextPipe(NULL, &findEndpointRequest))
207 | {
208 | shim->setPipe(pipe);
209 | return true;
210 | }
211 | return false;
212 | }
213 |
214 | IOReturn USBInterfaceShim::hciCommand(void* command, UInt16 length)
215 | {
216 | IOUSBDevRequest request =
217 | {
218 | .bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBDevice),
219 | .bRequest = 0,
220 | .wValue = 0,
221 | .wIndex = 0,
222 | .wLength = length,
223 | .pData = command
224 | };
225 | return m_pInterface->DeviceRequest(&request);
226 | }
227 |
228 | USBPipeShim::USBPipeShim()
229 | {
230 | m_pPipe = NULL;
231 | }
232 |
233 | void USBPipeShim::setPipe(OSObject* pipe)
234 | {
235 | OSObject* prev = m_pPipe;
236 | m_pPipe = OSDynamicCast(IOUSBPipe, pipe);
237 |
238 | if (m_pPipe)
239 | m_pPipe->retain();
240 | if (prev)
241 | prev->release();
242 | }
243 |
244 | IOReturn USBPipeShim::abort(void)
245 | {
246 | return m_pPipe->Abort();
247 | }
248 |
249 | /*!
250 | * @brief Issue an asynchronous I/O request
251 | *
252 | * @discussion See IOUSBHostIOSource::io for documentation
253 | *
254 | * @param completionTimeoutMs Must be 0 for interrupt endpoints.
255 | */
256 | //virtual IOReturn io(IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs = 0);
257 |
258 | /*!
259 | * @brief Issue a synchronous I/O request
260 | *
261 | * @discussion See IOUSBHostIOSource::io for documentation
262 | *
263 | * @param completionTimeoutMs Must be 0 for interrupt endpoints.
264 | */
265 | //virtual IOReturn io(IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, uint32_t& bytesTransferred, uint32_t completionTimeoutMs = 0);
266 |
267 | IOReturn USBPipeShim::read(IOMemoryDescriptor * buffer,
268 | UInt32 noDataTimeout,
269 | UInt32 completionTimeout,
270 | IOByteCount reqCount,
271 | USBCOMPLETION * completion,
272 | IOByteCount * bytesRead)
273 | {
274 | return m_pPipe->Read(buffer, noDataTimeout, completionTimeout, reqCount, completion, bytesRead);
275 | }
276 |
277 | IOReturn USBPipeShim::write(IOMemoryDescriptor * buffer,
278 | UInt32 noDataTimeout,
279 | UInt32 completionTimeout,
280 | IOByteCount reqCount,
281 | USBCOMPLETION * completion)
282 | {
283 | return m_pPipe->Write(buffer, noDataTimeout, completionTimeout, reqCount, completion);
284 | }
285 |
286 | const USBENDPOINTDESCRIPTOR* USBPipeShim::getEndpointDescriptor()
287 | {
288 | return m_pPipe->GetEndpointDescriptor();
289 | }
290 |
291 | IOReturn USBPipeShim::clearStall()
292 | {
293 | return m_pPipe->Reset();
294 | }
295 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/USBDeviceShim.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #ifndef __USBDeviceShim__
21 | #define __USBDeviceShim__
22 |
23 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
24 | #include
25 | #else
26 | #include
27 | #endif
28 |
29 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
30 | #define USBCOMPLETION IOUSBHostCompletion
31 | #define USBCONFIGURATIONDESCRIPTOR StandardUSB::ConfigurationDescriptor
32 | #define USBENDPOINTDESCRIPTOR StandardUSB::EndpointDescriptor
33 | #define USBStatus uint16_t
34 | #else
35 | #define USBCOMPLETION IOUSBCompletion
36 | #define USBCONFIGURATIONDESCRIPTOR IOUSBConfigurationDescriptor
37 | #define USBENDPOINTDESCRIPTOR IOUSBEndpointDescriptor
38 | #endif
39 |
40 | class USBPipeShim;
41 | class USBInterfaceShim;
42 |
43 | class USBDeviceShim
44 | {
45 | private:
46 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
47 | IOUSBHostDevice* m_pDevice; // 10.11+
48 | #else
49 | IOUSBDevice* m_pDevice;
50 | #endif
51 |
52 | public:
53 | USBDeviceShim();
54 | void setDevice(IOService* provider);
55 | inline IOService* getValidatedDevice() { return m_pDevice; }
56 |
57 | UInt16 getVendorID();
58 | UInt16 getProductID();
59 | OSObject* getProperty(const char* name);
60 | void setProperty(const char* name, bool value);
61 | void removeProperty(const char* name);
62 | IOReturn getStringDescriptor(UInt8 index, char *buf, int maxLen, UInt16 lang=0x409);
63 | UInt16 getDeviceRelease();
64 | IOReturn getDeviceStatus(IOService* forClient, USBStatus *status);
65 | IOReturn resetDevice();
66 | UInt8 getNumConfigurations();
67 | const USBCONFIGURATIONDESCRIPTOR* getFullConfigurationDescriptor(UInt8 configIndex);
68 | IOReturn getConfiguration(IOService* forClient, UInt8 *configNumber);
69 | IOReturn setConfiguration(IOService *forClient, UInt8 configValue, bool startInterfaceMatching=true);
70 | bool findFirstInterface(USBInterfaceShim* shim);
71 | bool open(IOService *forClient, IOOptionBits options = 0, void *arg = 0 );
72 | void close(IOService *forClient, IOOptionBits options = 0);
73 | UInt8 getManufacturerStringIndex();
74 | UInt8 getProductStringIndex();
75 | UInt8 getSerialNumberStringIndex();
76 | };
77 |
78 | class USBInterfaceShim
79 | {
80 | private:
81 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
82 | IOUSBHostInterface* m_pInterface; // 10.11+
83 | #else
84 | IOUSBInterface* m_pInterface;
85 | #endif
86 |
87 | public:
88 | USBInterfaceShim();
89 | void setInterface(IOService* interface);
90 | inline IOService* getValidatedInterface() { return (IOService*)m_pInterface; }
91 |
92 | bool open(IOService *forClient, IOOptionBits options = 0, void *arg = 0 );
93 | void close(IOService *forClient, IOOptionBits options = 0);
94 |
95 | #ifdef DEBUG
96 | UInt8 getInterfaceNumber();
97 | UInt8 getInterfaceClass();
98 | UInt8 getInterfaceSubClass();
99 | UInt8 getInterfaceProtocol();
100 | #endif
101 |
102 | bool findPipe(USBPipeShim* shim, uint8_t type, uint8_t direction);
103 |
104 | IOReturn hciCommand(void * command, UInt16 length);
105 | };
106 |
107 | class USBPipeShim
108 | {
109 | private:
110 | #if defined(TARGET_ELCAPITAN) || defined(TARGET_CATALINA)
111 | IOUSBHostPipe* m_pPipe; // 10.11+
112 | #else
113 | IOUSBPipe* m_pPipe;
114 | #endif
115 |
116 | public:
117 | USBPipeShim();
118 | void setPipe(OSObject* pipe);
119 | inline OSObject* getValidatedPipe() { return m_pPipe; }
120 |
121 | IOReturn abort(void);
122 |
123 | IOReturn read(IOMemoryDescriptor * buffer,
124 | UInt32 noDataTimeout,
125 | UInt32 completionTimeout,
126 | IOByteCount reqCount,
127 | USBCOMPLETION * completion = 0,
128 | IOByteCount * bytesRead = 0);
129 | IOReturn write(IOMemoryDescriptor * buffer,
130 | UInt32 noDataTimeout,
131 | UInt32 completionTimeout,
132 | IOByteCount reqCount,
133 | USBCOMPLETION * completion = 0);
134 | const USBENDPOINTDESCRIPTOR* getEndpointDescriptor();
135 | IOReturn clearStall(void);
136 | };
137 |
138 | #endif /* __USBDeviceShim__ */
139 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/USBHostDeviceShim.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #include "USBDeviceShim.h"
21 | #include "Common.h"
22 |
23 | #include
24 |
25 | #include
26 |
27 | USBDeviceShim::USBDeviceShim()
28 | {
29 | m_pDevice = NULL;
30 | }
31 |
32 | void USBDeviceShim::setDevice(IOService* provider)
33 | {
34 | OSObject* prev = m_pDevice;
35 |
36 | m_pDevice = OSDynamicCast(IOUSBHostDevice, provider);
37 |
38 | if (m_pDevice)
39 | m_pDevice->retain();
40 |
41 | if (prev)
42 | prev->release();
43 | }
44 |
45 | UInt16 USBDeviceShim::getVendorID()
46 | {
47 | return USBToHost16(m_pDevice->getDeviceDescriptor()->idVendor);
48 | }
49 |
50 | UInt16 USBDeviceShim::getProductID()
51 | {
52 | return USBToHost16(m_pDevice->getDeviceDescriptor()->idProduct);
53 | }
54 |
55 | OSObject* USBDeviceShim::getProperty(const char* name)
56 | {
57 | return m_pDevice->getProperty(name);
58 | }
59 |
60 | void USBDeviceShim::setProperty(const char* name, bool value)
61 | {
62 | m_pDevice->setProperty(name, value);
63 | }
64 |
65 | void USBDeviceShim::removeProperty(const char* name)
66 | {
67 | m_pDevice->removeProperty(name);
68 | }
69 |
70 | IOReturn USBDeviceShim::getStringDescriptor(UInt8 index, char *buf, int maxLen, UInt16 lang)
71 | {
72 | memset(buf, 0, maxLen);
73 |
74 | const StringDescriptor* desc = m_pDevice->getStringDescriptor(index);
75 |
76 | if (!desc)
77 | return kIOReturnBadArgument;
78 |
79 | if (desc->bLength <= StandardUSB::kDescriptorSize)
80 | return kIOReturnBadArgument;
81 |
82 | size_t utf8len = 0;
83 | utf8_encodestr(reinterpret_cast(desc->bString), desc->bLength - StandardUSB::kDescriptorSize, reinterpret_cast(buf), &utf8len, maxLen, '/', UTF_LITTLE_ENDIAN);
84 |
85 | return kIOReturnSuccess;
86 | }
87 |
88 | UInt16 USBDeviceShim::getDeviceRelease()
89 | {
90 | return USBToHost16(m_pDevice->getDeviceDescriptor()->bcdDevice);
91 | }
92 |
93 | IOReturn USBDeviceShim::getDeviceStatus(IOService* forClient, USBStatus *status)
94 | {
95 | uint16_t stat = 0;
96 | StandardUSB::DeviceRequest request;
97 | request.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionIn, kRequestTypeStandard, kRequestRecipientDevice);
98 | request.bRequest = kDeviceRequestGetStatus;
99 | request.wValue = 0;
100 | request.wIndex = 0;
101 | request.wLength = sizeof(stat);
102 | uint32_t bytesTransferred = 0;
103 | IOReturn result = m_pDevice->deviceRequest(forClient, request, &stat, bytesTransferred, kUSBHostStandardRequestCompletionTimeout);
104 | *status = stat;
105 | return result;
106 | }
107 |
108 | IOReturn USBDeviceShim::resetDevice()
109 | {
110 | // Setting configuration value 0 (unconfigured) releases all opened interfaces / pipes
111 | m_pDevice->setConfiguration(0);
112 | //m_pDevice->reset();
113 | return kIOReturnSuccess;
114 | }
115 |
116 | UInt8 USBDeviceShim::getNumConfigurations()
117 | {
118 | return m_pDevice->getDeviceDescriptor()->bNumConfigurations;
119 | }
120 |
121 | const USBCONFIGURATIONDESCRIPTOR* USBDeviceShim::getFullConfigurationDescriptor(UInt8 configIndex)
122 | {
123 | return m_pDevice->getConfigurationDescriptor(configIndex);
124 | }
125 |
126 | IOReturn USBDeviceShim::getConfiguration(IOService* forClient, UInt8 *configNumber)
127 | {
128 | uint8_t config = 0;
129 | StandardUSB::DeviceRequest request;
130 | request.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionIn, kRequestTypeStandard, kRequestRecipientDevice);
131 | request.bRequest = kDeviceRequestGetConfiguration;
132 | request.wValue = 0;
133 | request.wIndex = 0;
134 | request.wLength = sizeof(config);
135 | uint32_t bytesTransferred = 0;
136 | IOReturn result = m_pDevice->deviceRequest(forClient, request, &config, bytesTransferred, kUSBHostStandardRequestCompletionTimeout);
137 | *configNumber = config;
138 | return result;
139 | }
140 |
141 | IOReturn USBDeviceShim::setConfiguration(IOService *forClient, UInt8 configValue, bool startInterfaceMatching)
142 | {
143 | return m_pDevice->setConfiguration(configValue, startInterfaceMatching);
144 | }
145 |
146 | bool USBDeviceShim::findFirstInterface(USBInterfaceShim* shim)
147 | {
148 | DebugLog("USBDeviceShim::findFirstInterface\n");
149 |
150 | OSIterator* iterator = m_pDevice->getChildIterator(gIOServicePlane);
151 |
152 | if (!iterator)
153 | return false;
154 |
155 | while (OSObject* candidate = iterator->getNextObject())
156 | {
157 | if (IOUSBHostInterface* interface = OSDynamicCast(IOUSBHostInterface, candidate))
158 | {
159 | //if (interface->getInterfaceDescriptor()->bInterfaceClass != kUSBHubClass)
160 | {
161 | shim->setInterface(interface);
162 | break;
163 | }
164 | }
165 | }
166 |
167 | iterator->release();
168 |
169 | DebugLog("getValidatedInterface returns %p\n", shim->getValidatedInterface());
170 | return shim->getValidatedInterface() != NULL;
171 | }
172 |
173 | bool USBDeviceShim::open(IOService *forClient, IOOptionBits options, void *arg)
174 | {
175 | return m_pDevice->open(forClient, options, arg);
176 | }
177 |
178 | void USBDeviceShim::close(IOService *forClient, IOOptionBits options)
179 | {
180 | return m_pDevice->close(forClient, options);
181 | }
182 |
183 | UInt8 USBDeviceShim::getManufacturerStringIndex()
184 | {
185 | return m_pDevice->getDeviceDescriptor()->iManufacturer;
186 | }
187 |
188 | UInt8 USBDeviceShim::getProductStringIndex()
189 | {
190 | return m_pDevice->getDeviceDescriptor()->iProduct;
191 | }
192 |
193 | UInt8 USBDeviceShim::getSerialNumberStringIndex()
194 | {
195 | return m_pDevice->getDeviceDescriptor()->iSerialNumber;
196 | }
197 |
198 | USBInterfaceShim::USBInterfaceShim()
199 | {
200 | m_pInterface = NULL;
201 | }
202 |
203 | void USBInterfaceShim::setInterface(IOService* interface)
204 | {
205 | OSObject* prev = m_pInterface;
206 |
207 | m_pInterface = OSDynamicCast(IOUSBHostInterface, interface);
208 |
209 | if (m_pInterface)
210 | m_pInterface->retain();
211 | if (prev)
212 | prev->release();
213 | }
214 |
215 | bool USBInterfaceShim::open(IOService *forClient, IOOptionBits options, void *arg)
216 | {
217 | bool result = m_pInterface->open(forClient, options, arg);
218 | if (!result)
219 | AlwaysLog("USBInterfaceShim:open failed\n");
220 | return result;
221 | }
222 |
223 | void USBInterfaceShim::close(IOService *forClient, IOOptionBits options)
224 | {
225 | m_pInterface->close(forClient, options);
226 | }
227 |
228 | #ifdef DEBUG
229 | UInt8 USBInterfaceShim::getInterfaceNumber()
230 | {
231 | return m_pInterface->getInterfaceDescriptor()->bInterfaceNumber;
232 | }
233 |
234 | UInt8 USBInterfaceShim::getInterfaceClass()
235 | {
236 | return m_pInterface->getInterfaceDescriptor()->bInterfaceClass;
237 | }
238 |
239 | UInt8 USBInterfaceShim::getInterfaceSubClass()
240 | {
241 | return m_pInterface->getInterfaceDescriptor()->bInterfaceSubClass;
242 | }
243 |
244 | UInt8 USBInterfaceShim::getInterfaceProtocol()
245 | {
246 | return m_pInterface->getInterfaceDescriptor()->bInterfaceProtocol;
247 | }
248 | #endif
249 |
250 | bool USBInterfaceShim::findPipe(USBPipeShim* shim, UInt8 type, UInt8 direction)
251 | {
252 | // virtual IOUSBHostPipe* FindNextPipe(IOUSBHostPipe* current, IOUSBFindEndpointRequest* request) __attribute__((deprecated));
253 | // virtual IOUSBHostPipe* FindNextPipe(IOUSBHostPipe* current, IOUSBFindEndpointRequest* request, bool withRetain) __attribute__((deprecated));
254 | // Replacement: getInterfaceDescriptor and StandardUSB::getNextAssociatedDescriptorWithType to find an endpoint descriptor,
255 | // then use copyPipe to retrieve the pipe object
256 | // virtual const StandardUSB::InterfaceDescriptor* getInterfaceDescriptor();
257 | // const Descriptor* getNextAssociatedDescriptorWithType(const ConfigurationDescriptor* configurationDescriptor, const Descriptor* parentDescriptor, const Descriptor* currentDescriptor, const uint8_t type);
258 |
259 | //
260 | /*!
261 | * @brief Return the configuration descriptor in which this interface is defined
262 | *
263 | * @return Pointer to the configuration descriptor
264 | */
265 | //virtual const StandardUSB::ConfigurationDescriptor* getConfigurationDescriptor();
266 |
267 | /*!
268 | * @brief Return the pipe whose bEndpointAddress
matches address
269 | *
270 | * @discussion This method will return the pipe whose bEndpointAddress
matches address
. If
271 | * the pipe doesn't exist yet, but is part of the interface, it will first be created. This method returns a
272 | * retain()
ed object that must be release()
ed by the caller.
273 | *
274 | * @param address Address of the pipe
275 | *
276 | * @return Pointer to a retain()ed IOUSBHostPipe object or NULL
277 | */
278 | //virtual IOUSBHostPipe* copyPipe(uint8_t address);
279 |
280 | // USB 2.0 9.5: Descriptors
281 | //struct Descriptor
282 | //{
283 | // uint8_t bLength;
284 | // uint8_t bDescriptorType;
285 | //} __attribute__((packed));
286 | //
287 | //typedef struct Descriptor Descriptor;
288 |
289 | // USB 2.0 9.6.5: Interface
290 | //struct InterfaceDescriptor : public Descriptor
291 | //{
292 | // uint8_t bInterfaceNumber;
293 | // uint8_t bAlternateSetting;
294 | // uint8_t bNumEndpoints;
295 | // uint8_t bInterfaceClass;
296 | // uint8_t bInterfaceSubClass;
297 | // uint8_t bInterfaceProtocol;
298 | // uint8_t iInterface;
299 | //} __attribute__((packed));
300 | //typedef struct InterfaceDescriptor InterfaceDescriptor;
301 |
302 | // USB 2.0 9.6.6: Endpoint
303 | //struct EndpointDescriptor : public Descriptor
304 | //{
305 | // uint8_t bEndpointAddress;
306 | // uint8_t bmAttributes;
307 | // uint16_t wMaxPacketSize;
308 | // uint8_t bInterval;
309 | //} __attribute__((packed));
310 | //typedef struct EndpointDescriptor EndpointDescriptor;
311 |
312 | //const EndpointDescriptor* getNextEndpointDescriptor(const ConfigurationDescriptor* configurationDescriptor, const InterfaceDescriptor* interfaceDescriptor, const Descriptor* currentDescriptor);
313 |
314 | DebugLog("findPipe: direction = %d, type = %d\n", direction, type);
315 | const StandardUSB::ConfigurationDescriptor* configDesc = m_pInterface->getConfigurationDescriptor();
316 | const StandardUSB::InterfaceDescriptor* ifaceDesc = m_pInterface->getInterfaceDescriptor();
317 | if (!configDesc || !ifaceDesc)
318 | {
319 | DebugLog("configDesc = %p, ifaceDesc = %p\n", configDesc, ifaceDesc);
320 | return false;
321 | }
322 | const EndpointDescriptor* ep = NULL;
323 | while ((ep = StandardUSB::getNextEndpointDescriptor(configDesc, ifaceDesc, ep)))
324 | {
325 | // check if endpoint matches type and direction
326 | uint8_t epDirection = StandardUSB::getEndpointDirection(ep);
327 | uint8_t epType = StandardUSB::getEndpointType(ep);
328 | DebugLog("endpoint found: epDirection = %d, epType = %d\n", epDirection, epType);
329 | if (direction == epDirection && type == epType)
330 | {
331 | DebugLog("found matching endpoint\n");
332 |
333 | // matches... try to make a pipe from the endpoint address
334 | IOUSBHostPipe* pipe = m_pInterface->copyPipe(StandardUSB::getEndpointAddress(ep));
335 | if (pipe == NULL)
336 | {
337 | DebugLog("copyPipe failed\n");
338 | return false;
339 | }
340 |
341 | // set it in the shim
342 | shim->setPipe(pipe);
343 | pipe->release();
344 | return true;
345 | }
346 | }
347 | DebugLog("findPipe: no matching endpoint found");
348 | return false;
349 | }
350 |
351 | IOReturn USBInterfaceShim::hciCommand(void* command, UInt16 length)
352 | {
353 | StandardUSB::DeviceRequest request =
354 | {
355 | .bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, kRequestTypeClass, kRequestRecipientDevice),
356 | .bRequest = 0,
357 | .wValue = 0,
358 | .wIndex = 0,
359 | .wLength = length
360 | };
361 |
362 | uint32_t bytesTransfered;
363 | return m_pInterface->deviceRequest(request, command, bytesTransfered, 0);
364 | }
365 |
366 | USBPipeShim::USBPipeShim()
367 | {
368 | m_pPipe = NULL;
369 | }
370 |
371 | void USBPipeShim::setPipe(OSObject* pipe)
372 | {
373 | OSObject* prev = m_pPipe;
374 | m_pPipe = OSDynamicCast(IOUSBHostPipe, pipe);
375 |
376 | if (m_pPipe)
377 | m_pPipe->retain();
378 | if (prev)
379 | prev->release();
380 | }
381 |
382 | IOReturn USBPipeShim::abort(void)
383 | {
384 | return m_pPipe->abort();
385 | }
386 |
387 | /*!
388 | * @brief Issue an asynchronous I/O request
389 | *
390 | * @discussion See IOUSBHostIOSource::io for documentation
391 | *
392 | * @param completionTimeoutMs Must be 0 for interrupt endpoints.
393 | */
394 | //virtual IOReturn io(IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs = 0);
395 |
396 | /*!
397 | * @brief Issue a synchronous I/O request
398 | *
399 | * @discussion See IOUSBHostIOSource::io for documentation
400 | *
401 | * @param completionTimeoutMs Must be 0 for interrupt endpoints.
402 | */
403 | //virtual IOReturn io(IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, uint32_t& bytesTransferred, uint32_t completionTimeoutMs = 0);
404 |
405 | IOReturn USBPipeShim::read(IOMemoryDescriptor * buffer,
406 | UInt32 noDataTimeout,
407 | UInt32 completionTimeout,
408 | IOByteCount reqCount,
409 | USBCOMPLETION * completion,
410 | IOByteCount * bytesRead)
411 | {
412 | IOReturn result;
413 | if (completion)
414 | result = m_pPipe->io(buffer, (uint32_t)reqCount, completion, completionTimeout);
415 | else
416 | {
417 | uint32_t bytesTransfered;
418 | result = m_pPipe->io(buffer, (uint32_t)reqCount, bytesTransfered, completionTimeout);
419 | if (bytesRead) *bytesRead = bytesTransfered;
420 | }
421 | return result;
422 | }
423 |
424 | IOReturn USBPipeShim::write(IOMemoryDescriptor * buffer,
425 | UInt32 noDataTimeout,
426 | UInt32 completionTimeout,
427 | IOByteCount reqCount,
428 | USBCOMPLETION * completion)
429 | {
430 | IOReturn result;
431 | if (completion)
432 | result = m_pPipe->io(buffer, (uint32_t)reqCount, completion, completionTimeout);
433 | else
434 | {
435 | uint32_t bytesTransfered;
436 | result = m_pPipe->io(buffer, (uint32_t)reqCount, bytesTransfered, completionTimeout);
437 | }
438 | return result;
439 | }
440 |
441 | const USBENDPOINTDESCRIPTOR* USBPipeShim::getEndpointDescriptor()
442 | {
443 | return m_pPipe->getEndpointDescriptor();
444 | }
445 |
446 | IOReturn USBPipeShim::clearStall()
447 | {
448 | return m_pPipe->clearStall(false);
449 | }
450 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/hci.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Released under "The GNU General Public License (GPL-2.0)"
3 | *
4 | * This program is free software; you can redistribute it and/or modify it
5 | * under the terms of the GNU General Public License as published by the
6 | * Free Software Foundation; either version 2 of the License, or (at your
7 | * option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 | * for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License along
15 | * with this program; if not, write to the Free Software Foundation, Inc.,
16 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 | *
18 | */
19 |
20 | #ifndef BRCMPatchRAM_hci_h
21 | #define BRCMPatchRAM_hci_h
22 |
23 | typedef enum
24 | {
25 | HCI_COMMAND = 0x01,
26 | HCI_ACL = 0x02,
27 | HCI_SCL = 0x03,
28 | HCI_EVENT = 0x04
29 | } HCI_PACKET_TYPE;
30 |
31 | typedef enum
32 | {
33 | HCI_EVENT_CONN_COMPLETE = 0x03,
34 | HCI_EVENT_DISCONN_COMPLETE = 0x05,
35 | HCI_EVENT_COMMAND_COMPLETE = 0x0e,
36 | HCI_EVENT_HARDWARE_ERROR = 0x10,
37 | HCI_EVENT_NUM_COMPLETED_PACKETS = 0x13,
38 | HCI_EVENT_MODE_CHANGE = 0x14,
39 | HCI_EVENT_LE_META = 0x3e,
40 | HCI_EVENT_VENDOR = 0xff
41 | } HCI_EVENT_TYPE;
42 |
43 | typedef struct __attribute__((packed))
44 | {
45 | union
46 | {
47 | uint16_t opcode;
48 | struct
49 | {
50 | uint16_t ocf: 10;
51 | uint16_t ogf: 6;
52 | } op;
53 | };
54 | unsigned char length;
55 | } HCI_PACKET;
56 |
57 | typedef struct __attribute__((packed))
58 | {
59 | unsigned char eventCode;
60 | unsigned char length;
61 | } HCI_RESPONSE;
62 |
63 | struct __attribute__((packed)) HCI_COMMAND_COMPLETE: HCI_RESPONSE
64 | {
65 | unsigned char numCommands;
66 | union
67 | {
68 | uint16_t opcode;
69 | struct
70 | {
71 | uint16_t ocf: 10;
72 | uint16_t ogf: 6;
73 | } op;
74 | };
75 | unsigned char status;
76 | };
77 |
78 | #define HCI_OPCODE_RESET 0x0c03
79 | #define HCI_OPCODE_READ_VERBOSE_CONFIG 0xfc79
80 | #define HCI_OPCODE_DOWNLOAD_MINIDRIVER 0xfc2e
81 | #define HCI_OPCODE_LAUNCH_RAM 0xfc4c
82 | #define HCI_OPCODE_END_OF_RECORD 0xfc4e
83 | #define HCI_OPCODE_WAKEUP 0xfc53
84 |
85 | // Standard HCI commands
86 | uint8_t HCI_LOCAL_VERSION[] = { 0x01, 0x10, 0x00 };
87 | uint8_t HCI_READ_LOCAL_COMMANDS[] = { 0x02, 0x10, 0x00 };
88 | uint8_t HCI_READ_FEATURES[] = { 0x03, 0x10, 0x00 };
89 | uint8_t HCI_READ_LOCAL_FEATURES[] = { 0x04, 0x10, 0x00 };
90 | uint8_t HCI_RESET[] = { 0x03, 0x0c, 0x00 };
91 |
92 | // Broadcom vendor specific commands
93 |
94 | // Vendor Specific: Read chip-id and other Broadcom specific configuration variables
95 | uint8_t HCI_VSC_READ_VERBOSE_CONFIG[] = { 0x79, 0xfc, 0x00 };
96 |
97 | // Vendor Specific: Download mini driver
98 | uint8_t HCI_VSC_DOWNLOAD_MINIDRIVER[] = { 0x2e, 0xfc, 0x00 };
99 |
100 | // Vendor Specific: End of Record
101 | uint8_t HCI_VSC_END_OF_RECORD[] = { 0x4e, 0xfc, 0x04, 0xff, 0xff, 0xff, 0xff };
102 |
103 | // Vendor Specific: Wake up
104 | uint8_t HCI_VSC_WAKEUP[] = { 0x53, 0xfc, 0x01, 0x13 };
105 |
106 | #endif
107 |
--------------------------------------------------------------------------------
/BrcmPatchRAM/package.tool:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "${TARGET_BUILD_DIR}" = "" ]; then
4 | echo "This must not be run outside of Xcode"
5 | exit 1
6 | fi
7 |
8 | cd "${TARGET_BUILD_DIR}"
9 |
10 | # clean / build
11 | if [ "$1" != "analyze" ]; then
12 | rm -rf *.zip || exit 1
13 | fi
14 |
15 | if [ "$1" != "" ]; then
16 | echo "Got action $1, skipping!"
17 | exit 0
18 | fi
19 |
20 | for kext in BrcmBluetoothInjector.kext BrcmBluetoothInjectorLegacy.kext; do
21 | rm -rf "$kext"
22 | cp -a "$PROJECT_DIR/$kext" "$kext" || exit 1
23 | done
24 |
25 | dist=()
26 | if [ -d "$DWARF_DSYM_FILE_NAME" ]; then dist+=("$DWARF_DSYM_FILE_NAME"); fi
27 |
28 | for kext in *.kext; do
29 | dist+=("$kext")
30 | done
31 |
32 | archive="BrcmPatchRAM-${CURRENT_PROJECT_VERSION}-$(echo $CONFIGURATION | tr /a-z/ /A-Z/).zip"
33 | rm -rf *.zip
34 | zip -qry -FS "${archive}" "${dist[@]}"
35 |
--------------------------------------------------------------------------------
/Changelog.md:
--------------------------------------------------------------------------------
1 | BrcmPatchRAM Changelog
2 | ======================
3 | #### v2.6.8
4 | - Added vendor callback patch for Bluetooth power status toggling on macOS 13.3+ (thx @zxystd)
5 | - Added patch that skips Internal Bluetooth Controller NVRAM checking (thx @zxystd)
6 |
7 | #### v2.6.7
8 | - Added constants for macOS 14 support
9 |
10 | #### v2.6.6
11 | - Added firmware for legacy BCM20702A1 (thx @chapuza)
12 |
13 | #### v2.6.5
14 | - Fixed legacy Mac compatibility (thx @AsdMonio)
15 |
16 | #### v2.6.4
17 | - Improve compatibility with BCM43142A0 on macOS Big Sur (thx lalithkota)
18 |
19 | #### v2.6.3
20 | - Added constants for macOS 13 support
21 | - Fixed Skip Address Check patch for 13.0 Beta 1 and newer
22 |
23 | #### v2.6.2
24 | - Added Skip Address Check patch for 12.4 Beta 3 and newer (thx @khronokernel)
25 |
26 | #### v2.6.1
27 | - Improved BlueToolFixup compatibility with macOS 12b10 (thx @dhinakg, @williambj1)
28 | - Fixed bluetooth support on MBP15,4 and other similar boards (thx @dhinakg, @usr-sse2)
29 | - Fixed bluetooth not working on macOS 12 after the first power cycle (thx @williambj1, @zxystd)
30 |
31 | #### v2.6.0
32 | - Added BlueToolFixup for macOS 12 compatibility
33 |
34 | #### v2.5.9
35 | - Added BCM94352Z identifiers for injection
36 |
37 | #### v2.5.8
38 | - Added BCM94360Z3 identifiers for injection
39 |
40 | #### v2.5.7
41 | - Added BCM94360Z4 identifiers for injection
42 |
43 | #### v2.5.6
44 | - Added inject Laird BT851 Bluetooth 5.0 USB dongle
45 | - Added legacy Bluetooth injection kext
46 |
47 | #### v2.5.5
48 | - Initial MacKernelSDK and Xcode 12 compatibility
49 | - Added bundled BrcmPatchRAM.kext to the binaries
50 |
51 | #### v2.5.4
52 | - Added inject BCM2070 - BCM943224HMB, BCM943225HMB Combo
53 |
54 | #### v2.5.3
55 | - Fix parsing firmware versions (e.g. 8785 is 4689)
56 | - Use 4689 firmware for DW1820A [0a5c:6412]
57 | - Log uncompressed firmware SHA-1 in DEBUG builds
58 | - Reworked device reset to improve compatibility (thx @mishurov)
59 |
60 | #### v2.5.2
61 | - Revert DW1820A from 8785 to 8784 [0a5c:6412]
62 | - Add older firmwares from 12.0.1.1012
63 | - Add `bpr_handshake` boot argument to override handshake support mode
64 | - Change `bpr_preresetdelay=0` behaviour to no longer imply `bpr_handshake=1`
65 |
66 | #### v2.5.1
67 | - Add Lenovo 00JT494 [0a5c:6414]
68 |
69 | #### v2.5.0
70 | - Initial import based on @headkaze [2.2.12](https://github.com/headkaze/OS-X-BrcmPatchRAM/releases)
71 | - Merged BrcmPatchRAM3 improvements authored by @Mieze
72 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README-Mac.md:
--------------------------------------------------------------------------------
1 | ##### BrcmPatchRAM on Apple Mac
2 |
3 | The instructions in the readme are for a [Hackintosh](http://en.wikipedia.org/wiki/OSx86), a normal PC modified to run macOS.
4 |
5 | You should __not__ follow the original instructions on a real Mac as it might inadvertently break things.
6 |
7 | BrcmPatchRAM.kext, BrcmPatchRAM2.kext, BrcmFirmwareRepo.kext, and BrcmFirmwareData.kext are all unsigned kernel extensions.
8 |
9 | In order to use them, unsigned kernel extensions need to be enabled. Refer to [this page](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html) for more details. Hint: you need to disable System Integrity Protection.
10 |
11 | For macOS older than 10.11, install the required kexts inside /System/Library/Extensions.
12 | ```
13 | sudo cp -R ~/Downloads/BrcmPatchRAM.kext /System/Library/Extensions
14 | sudo cp -R ~/Downloads/BrcmFirmwareRepo.kext /System/Library/Extensions
15 | sudo touch /System/Library/Extensions
16 | ```
17 |
18 | Or for 10.11 and later, to /Library/Extensions:
19 | ```
20 | sudo cp -R ~/Downloads/BrcmPatchRAM2.kext /Library/Extensions
21 | sudo cp -R ~/Downloads/BrcmFirmwareRepo.kext /Library/Extensions
22 | sudo touch /Library/Extensions
23 | ```
24 |
25 | Wait about a minute before rebooting the Mac again.
26 |
27 | If all works properly the firmware version in the Bluetooth profiler will now show a higher version than v4096 (4096 means its non-upgraded).
28 |
29 | Additionally its possible to confirm BrcmPatchRAM did its job by executing the following in the terminal:
30 | ```
31 | sudo cat /var/log/system.log | grep -i brcm[fp]
32 | ```
33 |
34 | This will show a log excerpt of BrcmPatchRAM output during startup.
35 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | BrcmPatchRAM
2 | ============
3 |
4 | [](https://github.com/acidanthera/BrcmPatchRAM/actions) [](https://scan.coverity.com/projects/22191)
5 |
6 | #### 翻译语言
7 |
8 | - 简体中文
9 | - [English](./README.md)
10 |
11 | 大多数Broadcom USB蓝牙设备都使用称为RAMUSB的系统。 RAMUSB允许动态更新设备的固件,但是在关闭计算机时,先前应用的任何更新都会丢失。
12 |
13 | Broadcom Windows驱动程序将在每次启动时将固件上载到Broadcom蓝牙设备中,但是,对于macOS,此功能不可用。 `BrcmPatchRAM` kext是一个macOS驱动程序,适用于基于Broadcom RAMUSB的设备的PatchRAM更新。 每次启动/唤醒时,它将固件更新应用于Broadcom蓝牙设备,与Windows驱动程序相同。 应用的固件是从Windows驱动程序中提取的,并且功能应与Windows相同。
14 |
15 | 请注意,原始的Apple Broadcom蓝牙设备不是RAMUSB设备,因此没有相同的固件机制。
16 |
17 | ### 安装
18 |
19 | __请注意,如果您有Apple MacBook / iMac / Mac Pro等,请按照 [Mac instructions](https://github.com/acidanthera/BrcmPatchRAM/blob/master/README-Mac.md)__
20 |
21 | 根据macOS版本安装`BrcmPatchRAM.kext`或`BrcmPatchRAM2.kext`或`BrcmPatchRAM3.kext`其中之一,决不要三者都安装。
22 |
23 | * `BrcmPatchRAM.kext`: 适用于 10.10 或更早版本.
24 |
25 | * `BrcmPatchRAM2.kext`: 适用于 10.11-10.14.
26 |
27 | * `BrcmPatchRAM3.kext`: 适用于 10.15 或更高版本
28 |
29 | 另外,根据安装位置安装一个固件kext BrcmFirmwareData.kext或BrcmFirmwareRepo.kext,决不要同时安装。
30 |
31 | * `BrcmFirmwareData.kext`: 最适合引导加载程序注入。 这是首选配置。
32 |
33 | * `BrcmFirmwareRepo.kext`: 安装到`/System/Library/Extensions`(在10.11及更高版本上为`/Library/Extensions`)。 该kext的内存效率比`BrcmFirmwareData.kext`略高,但是不能由引导加载程序注入。
34 |
35 | * 高级用户:对于自定义固件注入器,请安装注入器以及`BrcmFirmwareRepo.kext`。 这可以从`/System/Library/Extensions`或通过引导加载程序注入工作。 (可选)您可以从`BrcmFirmwareRepo.kext/Contents/Resources`中删除所有固件。 如果通过引导加载程序使用注入器,则必须将`BrcmFirmwareRepo.kext`的`Info.plist`中的`IOProviderClass`从`disabled_IOResources`更改为`IOResources`。
36 |
37 | 另外,如果您有非PatchRAM设备(或者不确定),请安装macOS版本的`BrcmNonPatchRAM.kext`或`BrcmNonPatchRAM2.kext`之一,请不要同时安装两者。尽管这些kext不安装任何固件(这些设备内置固件),但它们仍依赖`BrcmPatchRAM.kext` / `BrcmPatchRAM2.kext`。
38 |
39 | * `BrcmNonPatchRAM.kext`: 适用于 10.10 或更早版本.
40 |
41 | * `BrcmNonPatchRAM2.kext`: 适用于 10.11 或更高版本.
42 |
43 | ### BrcmBluetoothInjector.kext
44 |
45 | 用于macOS 10.11或更高版本,对于较旧的系统,请使用`BrcmBluetoothInjectorLetacy.kext`;使用`BrcmPatchRAM3.kext`还需要`BrcmBluetoothInjector.kext`,因为macOS Catalina(10.15)中的更改要求使用单独的注射器注入到kext。 这是由于删除了以下IOCatalogue方法:
46 |
47 | ```bash
48 | IOCatalogue::addDrivers, IOCatalogue::removeDrivers and IOCatalogue::startMatching
49 | ```
50 |
51 | 因此,为了使设备(`BroadcomBluetoothHostControllerUSBTransport`)加载本机BT驱动程序,我们使用IOProbeScore稍低于BrcmPatchRAM3的plist进行注入,因此它不会在固件上传之前进行探测。
52 |
53 | `BrcmBluetoothInjector.kext`是[无代码内核扩展](https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptAnatomy/kext_anatomy.html),它使用plist注入BT硬件数据; 它不包含固件上载器。 如果希望查看您的设备在没有固件上传器的情况下是否可以运行,则可能还需要尝试此kext。
54 |
55 | 请勿在此kext上使用`BrcmPatchRAM`或`BrcmPatchRAM2`。
56 |
57 | `BrcmBluetoothInjector` 支持的设备:
58 |
59 | * ``[0489:e032]`` 20702 E032 Combo
60 | * ``[0489:e042]`` 20702A1 Lenovo China standalone
61 | * ``[0489:e046]`` 20702A1 Acer 43228+20702 combo card
62 | * ``[0489:e04f]`` 20702A1 Lenovo China 43227 WLAN + 20702A1 Combo card
63 | * ``[0489:e052]`` 20702 non-UHE Generic
64 | * ``[0489:e055]`` 43142A0 Acer combo
65 | * ``[0489:e059]`` Acer 43228 + 20702A1 combo
66 | * ``[0489:e079]`` Lenovo China 43162 NGFF
67 | * ``[0489:e07a]`` Lenovo China 4352+20702 NGFF
68 | * ``[0489:e087]`` Acer 43228 NGFF combo module
69 | * ``[0489:e096]`` BCM43142A0
70 | * ``[0489:e097]`` Acer Foxconn BCM4356A2 NGFF
71 | * ``[0489:e0a1]`` 20703A1 Lenovo 43602 NGFF combo
72 | * ``[04ca:2003]`` 20702A1 Lenovo China standalone
73 | * ``[04ca:2004]`` LiteOn 43228+20702 combo
74 | * ``[04ca:2005]`` LiteOn 43228+20702 combo
75 | * ``[04ca:2006]`` LiteOn 43142 combo
76 | * ``[04ca:2009]`` LiteOn 43142 combo
77 | * ``[04ca:200a]`` LiteOn 4352 combo
78 | * ``[04ca:200b]`` LiteOn 4352 combo
79 | * ``[04ca:200c]`` LiteOn 4352 combo
80 | * ``[04ca:200e]`` Liteon 43228 NGFF combo
81 | * ``[04ca:200f]`` Acer_LiteOn BCM20702A1_4352
82 | * ``[04ca:2012]`` Acer BCM943142Y NGFF
83 | * ``[04ca:2013]`` Acer LiteOn BCM4356A2 NGFF
84 | * ``[04ca:2014]`` Asus LiteOn BCM4356A2 NGFF
85 | * ``[04ca:2016]`` Lenovo 43162 NGFF combo module
86 | * ``[04f2:b4a1]`` ASUS Chicony BCM43142A0 NGFF
87 | * ``[04f2:b4a2]`` BCM4356A2
88 | * ``[050d:065a]`` 20702 standalone
89 | * ``[0930:021e]`` 20702A1 Toshiba standalone
90 | * ``[0930:021f]`` Toshiba 43142
91 | * ``[0930:0221]`` 20702A1 Toshiba 4352
92 | * ``[0930:0223]`` 20702A1 Toshiba 4352
93 | * ``[0930:0225]`` Toshiba 43142 combo NGFF
94 | * ``[0930:0226]`` Toshiba 43142 combo NGFF
95 | * ``[0930:0229]`` 43162 combo NGFF
96 | * ``[0a5c:2168]`` BRCM Generic 43162Z
97 | * ``[0a5c:2169]`` BRCM Generic 43228z
98 | * ``[0a5c:216a]`` Dell DW1708 43142Y combo
99 | * ``[0a5c:216b]`` HP Rapture 4352z ngff combo
100 | * ``[0a5c:216c]`` HP Harrier 43142
101 | * ``[0a5c:216d]`` HP Hornet 43142Y ngff combo
102 | * ``[0a5c:216e]`` HP Blackbird 43162 NGFF
103 | * ``[0a5c:216f]`` Dell DW1560 4352+20702 M.2
104 | * ``[0a5c:217d]`` BCM2070 - BCM943224HMB, BCM943225HMB Combo
105 | * ``[0a5c:21d7]`` BRCM Generic 43142A0 RAMUSB
106 | * ``[0a5c:21de]`` 4352+20702A1 combo
107 | * ``[0a5c:21e1]`` 20702A1 non-UHE HP SoftSailing
108 | * ``[0a5c:21e3]`` 20702A1 non-UHE 4313 combo HP Valentine
109 | * ``[0a5c:21e6]`` 20702 non-UHE Lenovo Japan
110 | * ``[0a5c:21e8]`` 20702A1 dongles
111 | * ``[0a5c:21ec]`` 20702A1 REF6 OTP module standalone
112 | * ``[0a5c:21f1]`` 43228 combo
113 | * ``[0a5c:21f3]`` Lenovo Edge 43228 + 20702A1 combo
114 | * ``[0a5c:21f4]`` Lenovo Edge 4313 + 20702A1 combo
115 | * ``[0a5c:21fb]`` HP Supra 4352 20702A1 combo
116 | * ``[0a5c:21fd]`` BRCM Generic 4352z RAMUSB
117 | * ``[0a5c:640a]`` BRCM Generic Reference 4356
118 | * ``[0a5c:640b]`` HP Luffy 43228 + 20702 M.2
119 | * ``[0a5c:640e]`` Lenovo 4356 NGFF combo
120 | * ``[0a5c:6410]`` 20703A1 RAM download - DW1830 43602
121 | * ``[0a5c:6412]`` Dell 4350C5
122 | * ``[0a5c:6413]`` Broadcom Generic 4350C5
123 | * ``[0a5c:6414]`` Lenovo 4350C5
124 | * ``[0a5c:6417]`` Zebra 4352
125 | * ``[0a5c:6418]`` HP Brook 2x2ac
126 | * ``[0a5c:7460]`` 20703A1 RAM download
127 | * ``[0a5c:828d]`` Fenvi BCM94352Z
128 | * ``[0b05:17b5]`` Asus 43228+20702A1 combo
129 | * ``[0b05:17cb]`` 20702 standalone
130 | * ``[0b05:17cf]`` Asus 4352_20702A1 combo
131 | * ``[0b05:180a]`` Azurewave 4360+20702 combo
132 | * ``[0b05:181d]`` Asus AZUREWAVE MB BCM4356A2
133 | * ``[0bb4:0306]`` 20703A1 HTC runtime RAM dongle
134 | * ``[105b:e065]`` LenovoChina 43142A0 combo
135 | * ``[105b:e066]`` LenovoChina 43228+20702 combo
136 | * ``[13d3:3384]`` 20702A1 Azurewave standalone
137 | * ``[13d3:3388]`` BRCM Generic 43142A0 RAMUSB
138 | * ``[13d3:3389]`` BRCM Generic 43142A0 RAMUSB
139 | * ``[13d3:3392]`` Azurewave 43228+20702
140 | * ``[13d3:3404]`` 4352HMB Azurewave Module
141 | * ``[13d3:3411]`` Dell Alienware 4352 20702A1 combo
142 | * ``[13d3:3413]`` Azurewave 4360+20702 combo
143 | * ``[13d3:3418]`` Azurewave 4352+20702 combo module
144 | * ``[13d3:3427]`` Toshiba 43142 combo NGFF
145 | * ``[13d3:3435]`` AZUREWAVE BCM20702A1_4352
146 | * ``[13d3:3456]`` AZUREWAVE BCM20702A1_4352
147 | * ``[13d3:3473]`` Asus AZUREWAVE BCM4356A2 NGFF
148 | * ``[13d3:3482]`` AZUREWAVE BCM43142A0 NGFF
149 | * ``[13d3:3484]`` Acer AZUREWAVE BCM43142A0 NGFF
150 | * ``[13d3:3485]`` Asus AZUREWAVE BCM4356A2 NB 2217NF
151 | * ``[13d3:3488]`` Asus AZUREWAVE BCM4356A2 NB 2210
152 | * ``[13d3:3492]`` Asus AZUREWAVE BCM4356A2 NGFF
153 | * ``[13d3:3504]`` AW CM217NF BCM4371C2
154 | * ``[13d3:3508]`` AW ASUS CM217NF BCM4371C2
155 | * ``[13d3:3517]`` AW CE160H BCM20702
156 | * ``[145f:01a3]`` 20702A1 Asus Trust standalone
157 | * ``[2b54:5600]`` Emdoor AP6356SD BCM4356A2
158 | * ``[2b54:5601]`` Asus AP6356SDP1A BCM4356A2
159 | * ``[2b54:5602]`` AMPAK AP6356SDP2A BCM4356A2
160 | * ``[33ba:03e8]`` TOULINEUA BCM94360Z4 4360+20702 combo
161 | * ``[33ba:03e9]`` TOULINEUA BCM94360Z3 4360+20702 combo
162 | * ``[413c:8143]`` DW1550 4352+20702 combo
163 | * ``[413c:8197]`` Dell DW380 Nancy Blakes standalone
164 |
165 | 如果你的设备不在支持设备中,请根据需要修改 Info.plist 。
166 |
167 | ### BlueToolFixup.kext
168 |
169 | 需要 macOS 12 或者更新的版本,在 macOS 12 中,Apple 已经将部分蓝牙堆栈从内核空间改为用户空间,更多详情请看 [acidanthera/bugtracker#1669](https://github.com/acidanthera/bugtracker/issues/1669)。
170 |
171 | 请不要在 macOS 12 或者更新的版本上将它和 `BrcmBluetoothInjector` 一起使用。
172 |
173 | ### 支持的设备
174 |
175 | `BrcmPatchRAM`支持任何基于BCM20702芯片组的Broadcom USB蓝牙设备(可能也支持其他芯片组,但是尚未经过测试)。
176 |
177 | 目前支持以下设备:
178 |
179 | * 标有 ***** 的设备已成功测试
180 |
181 | 非PatchRAM设备(BrcmPatchRAM用于加速睡眠后的恢复):
182 |
183 | * ``[03f0:231d]`` HP 231d (ProBook BT built-in firmware)
184 | * ``[13d3:3295]`` Azurewave BCM943225 (20702A bult-in firmware)
185 |
186 | 经过测试的PatchRAM设备:
187 | * ``[0489:e032]`` 20702 Combo USB
188 | * ``[0489:e042]`` 20702A1 Lenovo China *
189 | * ``[0489:e079]`` Lenovo China 43162 NGFF
190 | * ``[0489:e07a]`` Lenovo NGFF (4352 / 20702)
191 | * ``[04ca:2003]`` 20702A1 Lenovo China
192 | * ``[04ca:200a]`` LiteOn (4352 Combo)
193 | * ``[04ca:200b]`` LiteOn (4352 Combo) *
194 | * ``[04ca:200c]`` LiteOn (4352 Combo)
195 | * ``[04ca:200f]`` Acer / LiteOn (4352 Combo)
196 | * ``[050d:065a]`` Belkin (20702)
197 | * ``[0930:0221]`` Toshiba (4352 / 20702)
198 | * ``[0930:0223]`` Toshiba NGFF (4352 / 20702) *
199 | * ``[0a5c:216b]`` HP Rapture 4352Z NGFF Combo
200 | * ``[0a5c:216e]`` HP Blackbird 43162 NGFF
201 | * ``[0a5c:216f]`` Dell DW1560 (4352/20702)
202 | * ``[0a5c:21de]`` 4352/20702A1 combo
203 | * ``[0a5c:21e1]`` HP Softsailing (20702A1)
204 | * ``[0a5c:21e6]`` non-UHE Lenovo Bluetooth (20702)
205 | * ``[0a5c:21e8]`` Bluetooth USB Dongle (20702A1) *
206 | * ``[0a5c:21ec]`` Inateck Bluetooth (20702A1)
207 | * ``[0a5c:21fb]`` HP Supra 4352 (20702A1 Combo)
208 | * ``[0a5c:21fd]`` Broadcom 4352Z
209 | * ``[0a5c:22be]`` Broadcom BCM20702 Bluetooth 4.0 USB Device
210 | * ``[0a5c:6410]`` Dell Wireless 1830 Bluetooth 4.1 LE
211 | * ``[0a5c:6412]`` Dell Wireless 1820 Bluetooth 4.1 LE
212 | * ``[0a5c:828d]`` Fenvi BCM94352Z
213 | * ``[0b05:17cb]`` Asus BT-400 (20702 stand-alone) *
214 | * ``[0b05:17cf]`` Asus (4352/20702A1 combo) *
215 | * ``[0b05:180a]`` Azurewave (4360/20702 combo)
216 | * ``[13d3:3404]`` Azurewave (4352HMB) *
217 | * ``[13d3:3411]`` Dell Alienware (4352/20702A1 combo) *
218 | * ``[13d3:3413]`` Azurewave (4360/20702 combo)
219 | * ``[13d3:3418]`` Azurewave (4352/20702 combo)
220 | * ``[13d3:3435]`` Azurewave (4352/20702 combo)
221 | * ``[13d3:3456]`` Azurewave (4352/20702 combo)
222 | * ``[413c:8143]`` Dell DW1550 (4352/20702 combo)
223 |
224 | Windows软件包中的所有固件都存在于kext中,并自动与其供应商/设备ID关联。 它们有望工作,但尚未得到确认。 如果您可以确认上面未列出的工作设备,请通过github上的issues数据库进行通知。固件已更新到版本12.0.1.1105。
225 |
226 | ### 更多安装细节
227 |
228 | `BrcmPatchRAM.kext`或`BrcmPatchRAM2.kext`或`BrcmPatchRAM3.kext`可以通过引导加载程序kext注入安装,也可以放置在`/System/Library/Extensions`(在10.11及更高版本中为`/Library/Extensions`)中。
229 | 根据系统版本,仅安装一个,而不是安装三个。
230 |
231 | `BrcmFirmwareRepo.kext`不适用于bootloader kext注入,除非使用特定于设备的固件注入器。
232 | `BrcmFirmwareData.kext`可以与bootloader kext注入一起使用。
233 |
234 | 您还可以使用特定于设备的固件注入器(与`BrcmFirmwareRepo.kext`结合使用)。 在这种情况下,`BrcmFirmwareRepo.kext`确实可以从引导加载程序kexts中工作。
235 |
236 | 您可以在git存储库的`firmwares`目录中找到设备专用注射器。 它们不包含在发行版ZIP中。
237 |
238 | ### 配置
239 |
240 | 使用以下内核引导参数可以更改许多延迟。 如果发现在固件加载期间`BrcmPatchRAM`挂起,则可以更改这些值。 有关这些延迟的更多详细信息,请参阅源。
241 |
242 | - `bpr_initialdelay`:更改`mInitialDelay`,即与设备进行任何通信之前的延迟(以毫秒为单位)。预设值为`100`
243 | - `bpr_handshake`:覆盖`mSupportsHandshake`,固件上传的握手支持状态。` 0`表示在上传固件后等待`bpr_preresetdelay` 毫秒,然后重置设备。 `1`表示等待来自设备的特定响应,然后重置设备。默认值取决于设备标识符。
244 | - `bpr_preresetdelay`:更改`mPreResetDelay`,即设备接受固件所需的延迟(以毫秒为单位)。当`bpr_handshake`为`1`(根据设备标识符手动传递或自动应用)时,该值未使用。默认值为`250`
245 | - `bpr_postresetdelay`:更改`mPostResetDelay`,即固件上传后重置设备后,固件初始化所需的延迟(以毫秒为单位)。预设值为`100`
246 | - `bpr_probedelay`:更改`mProbeDelay`(已在BrcmPatchRAM3中删除),即探测设备之前的延迟(以毫秒为单位)。预设值为`0`
247 |
248 | 例如,要将`mPostResetDelay`更改为400ms,请使用内核标志:`bpr_postresetdelay=400`。
249 |
250 | 注意:一些典型的“从睡眠中唤醒”问题报告成功:`bpr_probedelay=100 bpr_initialdelay=300 bpr_postresetdelay=300`。 或稍长的延迟:`bpr_probedelay=200 bpr_initialdelay=400 bpr_postresetdelay=400`。
251 |
252 | ### 细节
253 |
254 | `BrcmPatchRAM`包含2个部分:
255 |
256 | * `BrcmPatchRAM`本身与受支持的Broadcom蓝牙USB设备(在`Info.plist`中配置)进行通信,并检测它们是否需要固件更新。
257 |
258 | 如果需要固件更新,则匹配的固件数据将被上载到设备并重置设备。
259 |
260 |
261 | * `BrcmFirmwareStore`(由`BrcmFirmwareData.kext`或`BrcmFirmwareRepo.kext`实现)是共享资源,其中包含用于不同Broadcom蓝牙USB设备的所有已配置固件。
262 |
263 | 某些设备需要特定于设备的固件,而其他设备可以使用Windows驱动程序中可用的最新版本。
264 |
265 | 会定期添加/配置新固件以支持设备,因此请确保遵循发行更新,或者如果发现不支持设备,请记录问题。
266 |
267 | 可以使用zlib压缩存储固件,以使配置大小易于管理。
268 |
269 | 上传设备固件后,设备控件将移交给Apple的`BroadcomBluetoothHostControllerUSBTransport`。
270 | 这意味着,出于所有意图和目的,您的设备将是macOS上的本地设备,并且完全支持所有功能。
271 |
272 | 可以通过引导加载程序或通过BrcmPatchRAM与Continuity Activation Patch结合使用 [BT4LEContinuityFixup](https://github.com/acidanthera/BT4LEContinuityFixup), 或通过dokterdok的脚本 [Continuity-Activation-Tool](https://github.com/dokterdok/Continuity-Activation-Tool)
273 |
274 | [OpenCore](https://github.com/acidanthera/OpenCorePkg) 用户可以使用`config.plist`中的quirk参数 `ExtendBTFeatureFlags`进行修补。
275 |
276 | ### 故障排除
277 |
278 | 安装`BrcmPatchRAM`之后,即使您的蓝牙图标可能出现,也可能是固件未正确更新。
279 |
280 | 通过转到系统信息并在蓝牙信息面板下检查蓝牙固件版本号来验证固件是否已更新。
281 |
282 | 如果版本号为` 4096`,则意味着您的设备没有更新固件,并且将无法正常工作。
283 |
284 | 通过在终端中运行以下命令来验证系统日志中的任何错误:
285 |
286 | ```bash
287 | # 10.12或者更新的系统:
288 | log show --last boot | grep -i brcm[fp]
289 | # 对于旧的macOS版本:
290 | cat /var/log/system.log | grep -i brcm[fp]
291 | ```
292 | 确保只检查最新的引导消息,因为`system.log`可能会追溯几天。
293 |
294 | 如果固件上传失败并显示错误,请尝试安装`BrcmPatchRAM`的`debug`版本,以便在日志中获取更多详细信息。
295 |
296 | 为了报告错误,请在github上用以下信息记录问题:
297 |
298 | * Device product ID
299 | * Device vendor ID
300 | * 使用的`BrcmPatchRAM`版本
301 | * `/var/log/system.log`中的`BrcmPatchRAM`调试输出转储,显示固件上传失败
302 |
303 | ### 固件兼容性
304 |
305 | 某些USB设备专用于固件,尝试将同一芯片组的任何其他固件上载到它们中都会失败。
306 |
307 | 通常在系统日志中显示为:
308 | ```bash
309 | BrcmPatchRAM: Version 0.5 starting.
310 | BrcmPatchRAM: USB [0a5c:21e8 5CF3706267E9 v274] "BCM20702A0" by "Broadcom Corp"
311 | BrcmPatchRAM: Retrieved firmware for firmware key "BCM20702A1_001.002.014.1443.1612_v5708".
312 | BrcmPatchRAM: Decompressed firmware (29714 bytes --> 70016 bytes).
313 | BrcmPatchRAM: device request failed (0xe000404f).
314 | BrcmPatchRAM: Failed to reset the device (0xe00002d5).
315 | BrcmPatchRAM: Unable to get device status (0xe000404f).
316 | BrcmPatchRAM: Firmware upgrade completed successfully.
317 | ```
318 |
319 | 两次之间的错误表示固件未成功上传,并且设备很可能需要配置特定的固件。
320 |
321 | 对于其他设备,可用的最新固件(即使未在Windows驱动程序中专门指定)也可以正常工作。
322 |
323 | ### 新设备
324 |
325 | 为了支持新设备,需要从现有Windows驱动程序中提取该设备的固件。
326 |
327 | 可在以下位置找到最新(最新)的Broadcom USB蓝牙驱动程序的副本:
328 | http://drivers.softpedia.com/get/BLUETOOTH/Broadcom/ASUS-X99-DELUXE-Broadcom-Bluetooth-Driver-6515800-12009860.shtml#download
329 |
330 | *如果您遇到的驱动程序比12.0.0.9860更新,请告诉我。*
331 |
332 | 为了获取设备专用的设备固件,请执行以下步骤:
333 |
334 | * 查找您的USB设备供应商和产品ID,在此示例中,我们将使用BCM94352Z PCI NGFF WiFi/BT组合卡,其供应商为0930,产品ID为0233。
335 | * 解压缩Windows蓝牙驱动程序包并打开bcbtums-win8x64-brcm.inf文件
336 | * 在.inf文件中找到您的供应商/设备ID组合
337 | ```dosini
338 | %BRCM20702.DeviceDesc%=BlueRAMUSB0223, USB\VID_0930&PID_0223 ; 20702A1 Toshiba 4352
339 | ```
340 | * 在.inf文件中找到提到的`RAMUSB0223`设备:
341 | ```dosini
342 | ;;;;;;;;;;;;;RAMUSB0223;;;;;;;;;;;;;;;;;
343 | [RAMUSB0223.CopyList]
344 | bcbtums.sys
345 | btwampfl.sys
346 | BCM20702A1_001.002.014.1443.1457.hex
347 | ```
348 |
349 | * 在这种情况下,请从Windows软件包中复制与设备匹配的固件十六进制文件。`BCM20702A1_001.002.014.1443.1457.hex`
350 |
351 | * 现在可以选择使用随附的zlib.pl脚本压缩固件文件:
352 | ```bash
353 | zlib.pl deflate BCM20702A1_001.002.014.1443.1457.hex > BCM20702A1_001.002.014.1443.1457.zhx
354 | ```
355 | * 之后,可以创建一个十六进制转储,以粘贴到plist编辑器中:
356 | ```bash
357 | xxd -ps BCM20702A1_001.002.014.1443.1457.zhx|tr '\n' ' ' > BCM20702A1_001.002.014.1443.1457.dmp
358 | ```
359 | * *使用plist编辑器在* *`BcmFirmwareStore/Firmwares`*词典下创建一个新的固件密钥。
360 |
361 | 请注意,macOS中显示的版本号是文件名中的最后一个数字(在我们的示例中为1457)+ 4096。
362 |
363 | 因此,在这种情况下,macOS中的固件版本为:*`c14 v5553`*。
364 |
365 | * 在*`BcmFirmwareStore/Firmwares`*下配置密钥后,将设备ID添加为`BrcmPatchRAM`的新设备。
366 |
367 | 固件也可以直接通过`BrcmFirmwareRepo.kext/Contents/Resources`加载,可以通过固件密钥名称(请参见上文),也可以仅使用供应商和设备ID命名文件。 例如,`0930_0223.hex`(未压缩)或`0930_0223.zhx`(压缩)。
368 |
369 | 复制现有的IOKit个性化并修改其属性是最简单的方法。
370 | 使用其唯一的固件密钥配置较早的固件。
371 |
372 | ### 支持和讨论
373 |
374 | [InsanelyMac topic](https://www.insanelymac.com/forum/topic/339175-brcmpatchram2-for-1015-catalina-broadcom-bluetooth-firmware-upload/) in English
375 | [AppleLife topic](https://applelife.ru/threads/bluetooth.2944352/) in Russian
376 |
377 |
--------------------------------------------------------------------------------
/extra_firmwares/0a5c_6412/BCM4350C5_003.006.007.0222.4689_v8785.zhx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxystd/BrcmPatchRAM/9abe4f74ae2d5e57b91326513955511424c64873/extra_firmwares/0a5c_6412/BCM4350C5_003.006.007.0222.4689_v8785.zhx
--------------------------------------------------------------------------------
/firmware.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 |
3 | require 'base64'
4 | require 'fileutils'
5 | require 'optparse'
6 | require 'ostruct'
7 | require 'zlib'
8 | require 'rexml/document'
9 | include REXML
10 |
11 | def add_element(parent, name, text)
12 | element = Element.new(name, parent)
13 | element.text = text
14 | end
15 |
16 | def add_key_value(dict, key, type, value)
17 | add_element(dict, "key", key)
18 | add_element(dict, type, value)
19 | end
20 |
21 | def parse_inf(inf_path)
22 | devices = Array.new
23 | in_device_block = 0
24 | device = nil
25 |
26 | if !File.exist?(inf_path)
27 | puts "Error: bcbtums.inf not found in firmware input folder."
28 | exit
29 | end
30 |
31 | File.open(inf_path).each do |line|
32 |
33 | # When in the device block, parse all devices
34 | if in_device_block == 1 and line =~ /^%([\w\.]*)%=.*(RAMUSB\w*),\s*USB\\VID_([0-9A-F]{4})\&PID_([0-9A-F]{4})\s*;\s(.*?)\r\n$/
35 | # Example match: %BRCM20702.DeviceDesc%=BlueRAMUSB21E8, USB\VID_0A5C&PID_21E8 ; 20702A1 dongles
36 | # new Example: %BRCM20702.DeviceDesc%=RAMUSB21E8, USB\VID_0A5C&PID_21E8 ; 20702A1 dongles
37 | device = OpenStruct.new
38 |
39 | device.stringKey = $1
40 | device.deviceKey = $2
41 | device.vendorId = $3.hex
42 | device.productId = $4.hex
43 | device.comment = $5
44 |
45 | new_device = devices.find { |f| f.deviceKey.casecmp(device.deviceKey) == 0 }
46 |
47 | # Skip drivers from Windows 8 when we have drivers from Windows 10.
48 | if new_device == nil
49 | devices << device
50 | end
51 |
52 | device = nil
53 | end
54 |
55 | # Extract the firmware file name from the current device block
56 | if device and line =~ /^(BCM.*\.hex)/
57 | device.firmware = $1
58 | device.firmwareVersion = $1[-8..-1].chomp(".hex").to_i
59 |
60 | if device.firmwareVersion < 4096
61 | device.firmwareVersion += 4096
62 | end
63 |
64 | if device.firmware.start_with?("BCM4356A2")
65 | devices.delete(device)
66 | end
67 |
68 | device = nil
69 | end
70 |
71 | # Determine the firmware filename for each device
72 | if line =~ /^\[(RAMUSB[0-9A-F_]{4,})\.CopyList\]/
73 | # Example matches:
74 | # [RAMUSB21E8.CopyList]
75 | # [RAMUSB185F_2167.CopyList]
76 |
77 | # Locate the device information for this RAMUSB device in the firmware array
78 | device = devices.find { |f| f.deviceKey.casecmp($1) == 0 }
79 | end
80 |
81 | # Extract device descriptions
82 | if line =~ /^(\w*\.DeviceDesc)\=\s*"(.*)"/
83 | matches = devices.each.select { |f| f.stringKey.casecmp($1) == 0 }
84 |
85 | matches.each do |match|
86 | match.description = $2
87 | end
88 | end
89 |
90 | # Found start of Windows 10 drivers block
91 | if line =~ /^\[Broadcom\.NT\w*\.10\.0\]/
92 | in_device_block = 1
93 | end
94 |
95 | # Found end of all drivers blocks
96 | if line =~ /^\[DestinationDirs\]/
97 | in_device_block = 0
98 | end
99 | end
100 |
101 | return devices
102 | end
103 |
104 | def create_firmwares(devices, input_path, output_path)
105 | # Create output folder
106 | FileUtils::makedirs output_path
107 | FileUtils::chdir output_path
108 |
109 | # Wipe any existing symbolic links - Ignore exceptions
110 | begin
111 | FileUtils::remove(Dir.glob(File.join(output_path, "*.zhx")))
112 | rescue
113 | end
114 |
115 | # Prune and rename existing firmwares
116 | Dir.glob(File.join(input_path, "*.hex")).each do |firmware|
117 | basename = File.basename(firmware)
118 |
119 | # Validate if we have a matching firmware definition
120 | device = devices.find { |d| d.firmware != nil && d.firmware.casecmp(basename) == 0 }
121 |
122 | if device
123 | output_file = "#{File.basename(firmware, File.extname(firmware))}_v#{device.firmwareVersion}.zhx"
124 | data_to_compress = File.read(firmware)
125 | data_compressed = Zlib::Deflate.deflate(data_to_compress, Zlib::BEST_COMPRESSION)
126 |
127 | puts "Compressed firmware #{output_file} (#{data_to_compress.size} --> #{data_compressed.size})"
128 |
129 | device_folder = "%04x_%04x" % [ device.vendorId, device.productId ]
130 | device_path = File.join(output_path, device_folder)
131 |
132 | FileUtils::makedirs(device_path)
133 | File.write(File.join(device_path, output_file), data_compressed)
134 |
135 | # Determine latest firmware for the current device and symlink
136 | latest_firmware = Dir.glob(File.join(device_path, "*.zhx")).sort_by{ |f| f[-8..1] }.reverse.each.first
137 |
138 | if File.exist?(File.basename(latest_firmware))
139 | puts "Firmware symlink #{File.basename(latestfirmware)} already created for another device."
140 | else
141 | FileUtils::symlink("./" + File.join(device_folder, File.basename(latest_firmware)), File.basename(latest_firmware))
142 | end
143 |
144 | create_injector(device, false, data_compressed, device_path)
145 | create_injector(device, true, data_compressed, device_path)
146 | else
147 | puts "Firmware file %s is not matched against devices in INF file... skipping." % basename
148 | end
149 | end
150 | end
151 |
152 | def create_injector(device, for_usbhost, compressed_data, output_path)
153 | xml = Document.new('');
154 |
155 | root_dict = Element.new("dict", xml.root)
156 | add_key_value(root_dict, "CFBundleIdentifier", "string", "as.acidanthera.BrcmInjector.%04x.%04x" % [ device.vendorId, device.productId ])
157 | add_key_value(root_dict, "CFBundleInfoDictionaryVersion", "string", "6.0")
158 | add_key_value(root_dict, "CFBundleName", "string", "BrcmInjector.%04x.%04x" % [ device.vendorId, device.productId ])
159 | add_key_value(root_dict, "CFBundlePackageType", "string", "KEXT")
160 | add_key_value(root_dict, "CFBundleShortVersionString", "string", "2.1.0")
161 | add_key_value(root_dict, "CFBundleSignature", "string", "????")
162 | add_key_value(root_dict, "CFBundleVersion", "string", "2.1.0")
163 |
164 | add_element(root_dict, "key", "IOKitPersonalities")
165 | iokit_dict = Element.new("dict", root_dict)
166 |
167 | add_element(iokit_dict, "key", "%04x_%04x" % [ device.vendorId, device.productId ])
168 |
169 | device_dict = Element.new("dict", iokit_dict);
170 | add_key_value(device_dict, "CFBundleIdentifier", "string", for_usbhost ? "as.acidanthera.BrcmPatchRAM2" : "as.acidanthera.BrcmPatchRAM")
171 | add_key_value(device_dict, "DisplayName", "string", device.description)
172 | add_key_value(device_dict, "FirmwareKey", "string", "%04x_%04x_v%4d" % [ device.vendorId, device.productId, device.firmwareVersion ])
173 | add_key_value(device_dict, "IOClass", "string", for_usbhost ? "BrcmPatchRAM2" : "BrcmPatchRAM" )
174 | add_key_value(device_dict, "IOMatchCategory", "string", for_usbhost ? "BrcmPatchRAM2" : "BrcmPatchRAM")
175 | add_key_value(device_dict, "IOProbeScore", "integer", "2000")
176 | add_key_value(device_dict, "IOProviderClass", "string", for_usbhost ? "IOUSBHostDevice" : "IOUSBDevice")
177 | add_key_value(device_dict, "idProduct", "integer", device.productId.to_i())
178 | add_key_value(device_dict, "idVendor", "integer", device.vendorId.to_i())
179 |
180 | add_element(iokit_dict, "key", "BrcmFirmwareStore")
181 |
182 | firmware_dict = Element.new("dict", iokit_dict)
183 | add_key_value(firmware_dict, "CFBundleIdentifier", "string", "as.acidanthera.BrcmFirmwareStore")
184 | add_element(firmware_dict, "key", "Firmwares")
185 |
186 | firmwares_dict = Element.new("dict", firmware_dict)
187 | add_key_value(firmwares_dict, "%04x_%04x_v%4d" % [ device.vendorId, device.productId, device.firmwareVersion ], "data", Base64.encode64(compressed_data))
188 |
189 | add_key_value(firmware_dict, "IOClass", "string", "BrcmFirmwareStore")
190 | add_key_value(firmware_dict, "IOMatchCategory", "string", "BrcmFirmwareStore")
191 | add_key_value(firmware_dict, "IOProbeScore", "integer", "2000")
192 | add_key_value(firmware_dict, "IOProviderClass", "string", "IOResources")
193 |
194 | injector_path = File.join(output_path, "BrcmFirmwareInjector%s_%04x_%04x.kext/Contents" % [ for_usbhost ? "2" : "", device.vendorId, device.productId, device.version ])
195 |
196 | FileUtils::makedirs(injector_path)
197 |
198 | formatter = REXML::Formatters::Pretty.new
199 | formatter.compact = true
200 | File.open(File.join(injector_path, "Info.plist"), "w") { |file| file.puts formatter.write(xml.root, "") }
201 | end
202 |
203 | def create_plist(devices, output_path, version)
204 | # Generate plist XML snippet
205 | xml = Document.new ""
206 |
207 | Element.new("key", xml.root).text = "IOKitPersonalities"
208 | fws_xml = Element.new("dict", xml.root)
209 |
210 | devices.sort_by{|d| [d.vendorId, d.productId]}.each do |device|
211 | if device.firmware == nil
212 | puts "Failed to parse firmware path for %s, skipping..." % device
213 | next
214 | end
215 |
216 | Element.new("key", fws_xml).text = "%04x_%04x" % [ device.vendorId, device.productId ]
217 |
218 | device_xml = Element.new("dict", fws_xml)
219 |
220 | add_key_value(device_xml, "CFBundleIdentifier", "string", "as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)")
221 | add_key_value(device_xml, "DisplayName", "string", device.description)
222 | add_key_value(device_xml, "FirmwareKey", "string", "#{device.firmware.chomp(".hex")}_v#{device.firmwareVersion}")
223 | if version >= 2
224 | add_key_value(device_xml, "IOClass", "string", "BrcmPatchRAM%d" % version)
225 | add_key_value(device_xml, "IOMatchCategory", "string", "BrcmPatchRAM%d" % version)
226 | add_key_value(device_xml, "IOProbeScore", "integer", 4000)
227 | add_key_value(device_xml, "IOProviderClass", "string", "IOUSBHostDevice")
228 | else
229 | add_key_value(device_xml, "IOClass", "string", "BrcmPatchRAM")
230 | add_key_value(device_xml, "IOMatchCategory", "string", "BrcmPatchRAM")
231 | add_key_value(device_xml, "IOProbeScore", "integer", 4000)
232 | add_key_value(device_xml, "IOProviderClass", "string", "IOUSBDevice")
233 | end
234 | add_key_value(device_xml, "idProduct", "integer", device.productId)
235 | add_key_value(device_xml, "idVendor", "integer", device.vendorId)
236 | end
237 |
238 | if version >= 2
239 | Element.new("key", fws_xml).text = "BrcmPatchRAMResidency"
240 | residency_xml = Element.new("dict", fws_xml)
241 | add_key_value(residency_xml, "CFBundleIdentifier", "string", "as.acidanthera.$(PRODUCT_NAME:rfc1034identifier)")
242 | add_key_value(residency_xml, "IOClass", "string", "BrcmPatchRAMResidency")
243 | add_key_value(residency_xml, "IOMatchCategory", "string", "BrcmPatchRAMResidency")
244 | add_key_value(residency_xml, "IOProviderClass", "string", "disabled_IOResources")
245 | end
246 |
247 | formatter = REXML::Formatters::Pretty.new
248 | formatter.compact = true
249 | if version >= 2
250 | firmwares = "firmwares%d.plist" % version
251 | else
252 | firmwares = "firmwares.plist"
253 | end
254 | File.open(File.join(output_path, firmwares), "w") { |file| file.puts formatter.write(xml.root, "") }
255 | end
256 |
257 | def create_readme(devices, output_path)
258 | File.open(File.join(output_path, "firmwares.md"), "w") do |file|
259 |
260 | devices.sort_by{|d| [d.vendorId, d.productId]}.each do |device|
261 | device_folder = "%04x_%04x" % [ device.vendorId, device.productId ]
262 | device_path = File.join(output_path, device_folder)
263 |
264 | if Dir.exists?(device_path)
265 | file.puts "* [`%04x:%04x`] %s (%s)" % [ device.vendorId, device.productId, device.comment, device.description ]
266 |
267 |
268 | Dir.glob(File.join(device_path, "*.zhx")).each do |firmware|
269 | firmware = File.basename(firmware).chomp(".zhx")
270 | file.puts(" * %s (v%s)" % [ firmware[0..-7], firmware[-4..-1] ])
271 | end
272 | end
273 | end
274 | end
275 | end
276 |
277 | if ARGV.length != 2
278 | puts "Usage: firmware.rb