├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── config.yml ├── README-zh_Hans.md └── workflows │ └── main.yml ├── .gitignore ├── IntelBTPatcher ├── Info.plist ├── IntelBTPatcher.cpp └── IntelBTPatcher.hpp ├── IntelBluetoothFirmware.xcodeproj └── project.pbxproj ├── IntelBluetoothFirmware ├── BtIntel.cpp ├── BtIntel.h ├── BtIntelFw.cpp ├── BtIntelVSC.cpp ├── FwData.h ├── Hci.h ├── Info.plist ├── IntelBluetoothFirmware.cpp ├── IntelBluetoothFirmware.hpp ├── IntelBluetoothOpsGen1.cpp ├── IntelBluetoothOpsGen1.hpp ├── IntelBluetoothOpsGen2.cpp ├── IntelBluetoothOpsGen2.hpp ├── IntelBluetoothOpsGen3.cpp ├── IntelBluetoothOpsGen3.hpp ├── Log.h ├── USBDeviceController.cpp ├── USBDeviceController.hpp ├── fw │ ├── ibt-0040-0041.ddc │ ├── ibt-0040-0041.sfi │ ├── ibt-0040-1020.ddc │ ├── ibt-0040-1020.sfi │ ├── ibt-0040-1050.ddc │ ├── ibt-0040-1050.sfi │ ├── ibt-0040-2120.ddc │ ├── ibt-0040-2120.sfi │ ├── ibt-0040-4150.ddc │ ├── ibt-0040-4150.sfi │ ├── ibt-0041-0041.ddc │ ├── ibt-0041-0041.sfi │ ├── ibt-0180-0041.ddc │ ├── ibt-0180-0041.sfi │ ├── ibt-0180-1050.ddc │ ├── ibt-0180-1050.sfi │ ├── ibt-0180-4150.ddc │ ├── ibt-0180-4150.sfi │ ├── ibt-0291-0291.ddc │ ├── ibt-0291-0291.sfi │ ├── ibt-1040-0041.ddc │ ├── ibt-1040-0041.sfi │ ├── ibt-1040-1020.ddc │ ├── ibt-1040-1020.sfi │ ├── ibt-1040-1050.ddc │ ├── ibt-1040-1050.sfi │ ├── ibt-1040-2120.ddc │ ├── ibt-1040-2120.sfi │ ├── ibt-1040-4150.ddc │ ├── ibt-1040-4150.sfi │ ├── ibt-11-5.ddc │ ├── ibt-11-5.sfi │ ├── ibt-12-16.ddc │ ├── ibt-12-16.sfi │ ├── ibt-17-0-1.ddc │ ├── ibt-17-0-1.sfi │ ├── ibt-17-1.ddc │ ├── ibt-17-1.sfi │ ├── ibt-17-16-1.ddc │ ├── ibt-17-16-1.sfi │ ├── ibt-17-2.ddc │ ├── ibt-17-2.sfi │ ├── ibt-18-0-1.ddc │ ├── ibt-18-0-1.sfi │ ├── ibt-18-1.ddc │ ├── ibt-18-1.sfi │ ├── ibt-18-16-1.ddc │ ├── ibt-18-16-1.sfi │ ├── ibt-18-2.ddc │ ├── ibt-18-2.sfi │ ├── ibt-19-0-0.ddc │ ├── ibt-19-0-0.sfi │ ├── ibt-19-0-1.ddc │ ├── ibt-19-0-1.sfi │ ├── ibt-19-0-3.ddc │ ├── ibt-19-0-3.sfi │ ├── ibt-19-0-4.ddc │ ├── ibt-19-0-4.sfi │ ├── ibt-19-16-4.ddc │ ├── ibt-19-16-4.sfi │ ├── ibt-19-240-1.ddc │ ├── ibt-19-240-1.sfi │ ├── ibt-19-240-4.ddc │ ├── ibt-19-240-4.sfi │ ├── ibt-19-32-0.ddc │ ├── ibt-19-32-0.sfi │ ├── ibt-19-32-1.ddc │ ├── ibt-19-32-1.sfi │ ├── ibt-19-32-4.ddc │ ├── ibt-19-32-4.sfi │ ├── ibt-20-0-3.ddc │ ├── ibt-20-0-3.sfi │ ├── ibt-20-1-3.ddc │ ├── ibt-20-1-3.sfi │ ├── ibt-20-1-4.ddc │ ├── ibt-20-1-4.sfi │ ├── ibt-hw-37.7.10-fw-1.0.1.2d.d.bseq │ ├── ibt-hw-37.7.10-fw-1.0.2.3.d.bseq │ ├── ibt-hw-37.7.10-fw-1.80.1.2d.d.bseq │ ├── ibt-hw-37.7.10-fw-1.80.2.3.d.bseq │ ├── ibt-hw-37.7.bseq │ ├── ibt-hw-37.8.10-fw-1.10.2.27.d.bseq │ ├── ibt-hw-37.8.10-fw-1.10.3.11.e.bseq │ ├── ibt-hw-37.8.10-fw-22.50.19.14.f.bseq │ └── ibt-hw-37.8.bseq ├── linux.h ├── zutil.c └── zutil.h ├── IntelBluetoothInjector └── Info.plist ├── LICENSE ├── README.md ├── iwlwifi-firmware-license └── scripts ├── fw_gen.sh └── zlib_compress_fw.py /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this bug report! 9 | 10 | - type: dropdown 11 | id: docs 12 | attributes: 13 | label: Have you read the docs? 14 | options: 15 | - 'No' 16 | - 'Yes' 17 | validations: 18 | required: true 19 | 20 | - type: input 21 | id: macos-ver 22 | attributes: 23 | label: macOS Version 24 | description: Which version of macOS are you using? 25 | placeholder: macOS 12 26 | validations: 27 | required: true 28 | 29 | - type: input 30 | id: kext-ver 31 | attributes: 32 | label: Kext Version 33 | description: Which version of the Kext are you using? 34 | placeholder: v2.2.0 35 | validations: 36 | required: true 37 | 38 | - type: input 39 | id: card-model 40 | attributes: 41 | label: Wireless Adapter Model and USB Product ID 42 | description: USB Product ID can be obtained from Hackintool when using macOS versions prior to Monterey or only when Bluetooth is working on macOS Monterey and newer.
When bluetooth is not working on macOS Monterey and newer, the only method to obtain the USB Product ID is through IORegistry. 43 | placeholder: Intel 9560AC (0xAAA) 44 | validations: 45 | required: true 46 | 47 | - type: textarea 48 | id: description 49 | attributes: 50 | label: Description 51 | description: A clear and concise description of what the bug is 52 | validations: 53 | required: true 54 | 55 | - type: textarea 56 | id: info 57 | attributes: 58 | label: Info in System Report - Bluetooth 59 | description: Copy and paste all contents with sensitive information removed down below
(Text in this field will be automatically formatted into code, so no need for backticks.) 60 | render: shell 61 | validations: 62 | required: true 63 | 64 | - type: textarea 65 | id: logs 66 | attributes: 67 | label: Relevant log output 68 | description: Output of `sudo dmesg | grep -i IntelBluetooth` with DebugEnhancer.kext installed.
(Text in this field will be automatically formatted into code, so no need for backticks.) 69 | render: shell 70 | validations: 71 | required: true 72 | 73 | - type: textarea 74 | id: panic-logs 75 | attributes: 76 | label: Kernel Panic Logs 77 | description: In case there is a kernel panic, add `keepsyms=1` in boot-args then paste the panic info below
(Text in this field will be automatically formatted into code, so no need for backticks.) 78 | render: shell 79 | validations: 80 | required: false 81 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Documentation 4 | url: https://openintelwireless.github.io/IntelBluetoothFirmware/ 5 | about: Install guides and FAQ 6 | - name: Gitter Chat Room 7 | url: https://gitter.im/OpenIntelWireless/IntelBluetoothFirmware 8 | about: Community chat room for IntelBluetoothFirmware 9 | -------------------------------------------------------------------------------- /.github/README-zh_Hans.md: -------------------------------------------------------------------------------- 1 | # IntelBluetoothFirmware 2 | 3 | ![CI](https://github.com/OpenIntelWireless/IntelBluetoothFirmware/workflows/CI/badge.svg) 4 | 5 | - [English](/README.md) 6 | - **简体中文** 7 | 8 | ## 简介 9 | 10 | IntelBluetoothFirmware 是一个用于在 macOS 中启用原生蓝牙的固件上传驱动,固件的二进制文件来自 Linux。 11 | 12 | 经过数月的测试后,这个驱动已经被证实可以正常稳定工作。 13 | 14 | [![Join the chat at https://gitter.im/OpenIntelWireless/itlwm](https://badges.gitter.im/OpenIntelWireless/IntelBluetoothFirmware.svg)](https://gitter.im/OpenIntelWireless/IntelBluetoothFirmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 15 | 16 | ## 文档 17 | 18 | **请在使用驱动或提交 issue 之前仔细阅读文档!** 19 | 20 | - [支持列表](https://openintelwireless.github.io/IntelBluetoothFirmware/Compat.html) 21 | - [安装方法](https://openintelwireless.github.io/IntelBluetoothFirmware/Installation.html) 22 | - [常见疑问](https://openintelwireless.github.io/IntelBluetoothFirmware/FAQ.html) 23 | - [排错方法](https://openintelwireless.github.io/IntelBluetoothFirmware/Troubleshooting.html) 24 | 25 | ## 参考资料 26 | 27 | - [torvalds/linux](https://github.com/torvalds/linux) 28 | - [acidanthera/BrcmPatchRAM](https://github.com/acidanthera/BrcmPatchRAM) 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | 7 | build: 8 | 9 | runs-on: macos-latest 10 | 11 | steps: 12 | 13 | - uses: actions/checkout@v4 14 | 15 | - name: Get Lilu SHA 16 | id: get-lilu-sha 17 | run: | 18 | echo "hash=$(git ls-remote https://github.com/acidanthera/Lilu.git HEAD | awk '{ print $1 }')" >> "$GITHUB_OUTPUT" 19 | 20 | - name: Cache Lilu 21 | id: cache-lilu 22 | uses: actions/cache@v4 23 | with: 24 | path: Lilu.kext 25 | key: Lilu-${{ steps.get-lilu-sha.outputs.hash }} 26 | 27 | - name: Install MacKernelSDK 28 | run: | 29 | git clone --depth=1 https://github.com/acidanthera/MacKernelSDK.git 30 | 31 | - name: Install Lilu SDK 32 | if: steps.cache-lilu.outputs.cache-hit != 'true' 33 | run: | 34 | git clone --depth=1 https://github.com/acidanthera/Lilu.git 35 | cd Lilu || exit 1 36 | ln -s ../MacKernelSDK MacKernelSDK 37 | xcodebuild -configuration Debug -arch x86_64 | xcpretty && ret=${PIPESTATUS[0]} 38 | if [[ $ret -ne 0 || ! -d build/Debug/Lilu.kext ]]; then 39 | exit 1 40 | fi 41 | cp -R build/Debug/Lilu.kext ../ 42 | 43 | - name: Debug Build 44 | run: | 45 | xcodebuild -alltargets -configuration Debug | xcpretty && exit ${PIPESTATUS[0]} 46 | 47 | - name: Release Build 48 | run: | 49 | xcodebuild -alltargets -configuration Release | xcpretty && exit ${PIPESTATUS[0]} 50 | 51 | - name: Upload to Artifacts 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: ${{ github.event.repository.name }} 55 | path: build/*/*.zip 56 | if-no-files-found: error 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | DerivedData 3 | build 4 | xcuserdata 5 | xcshareddata 6 | project.xcworkspace 7 | FwBinary.cpp 8 | MacKernelSDK 9 | Lilu.kext 10 | zlib_compress_fw.pyc 11 | -------------------------------------------------------------------------------- /IntelBTPatcher/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | IOKitPersonalities 22 | 23 | IntelBTPatcher 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 | NSHumanReadableCopyright 38 | Copyright © 2022 zxystd. All rights reserved. 39 | OSBundleLibraries 40 | 41 | as.vit9696.Lilu 42 | 1.2.0 43 | com.apple.iokit.IOUSBHostFamily 44 | 1.2 45 | com.apple.kpi.bsd 46 | 12.0.0 47 | com.apple.kpi.dsep 48 | 12.0.0 49 | com.apple.kpi.iokit 50 | 12.0.0 51 | com.apple.kpi.libkern 52 | 12.0.0 53 | com.apple.kpi.mach 54 | 12.0.0 55 | com.apple.kpi.unsupported 56 | 12.0.0 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /IntelBTPatcher/IntelBTPatcher.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBTPatcher.cpp 3 | // IntelBTPatcher 4 | // 5 | // Created by zxystd on 2021/2/8. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "IntelBTPatcher.hpp" 13 | 14 | static CIntelBTPatcher ibtPatcher; 15 | static CIntelBTPatcher *callbackIBTPatcher = nullptr; 16 | 17 | static const char *bootargOff[] { 18 | "-ibtcompatoff" 19 | }; 20 | 21 | static const char *bootargDebug[] { 22 | "-ibtcompatdbg" 23 | }; 24 | 25 | static const char *bootargBeta[] { 26 | "-ibtcompatbeta" 27 | }; 28 | 29 | PluginConfiguration ADDPR(config) { 30 | xStringify(PRODUCT_NAME), 31 | parseModuleVersion(xStringify(MODULE_VERSION)), 32 | LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery | LiluAPI::AllowSafeMode, 33 | bootargOff, 34 | arrsize(bootargOff), 35 | bootargDebug, 36 | arrsize(bootargDebug), 37 | bootargBeta, 38 | arrsize(bootargBeta), 39 | KernelVersion::MountainLion, 40 | KernelVersion::Sequoia, 41 | []() { 42 | ibtPatcher.init(); 43 | } 44 | }; 45 | 46 | static const char *IntelBTPatcher_IOBluetoothFamily[] { "/System/Library/Extensions/IOBluetoothFamily.kext/Contents/MacOS/IOBluetoothFamily" }; 47 | 48 | static KernelPatcher::KextInfo IntelBTPatcher_IOBluetoothInfo { 49 | "com.apple.iokit.IOBluetoothFamily", 50 | IntelBTPatcher_IOBluetoothFamily, 51 | 1, 52 | {true, true}, 53 | {}, 54 | KernelPatcher::KextInfo::Unloaded 55 | }; 56 | 57 | static const char *IntelBTPatcher_IOUSBHostFamily[] { 58 | "/System/Library/Extensions/IOUSBHostFamily.kext/Contents/MacOS/IOUSBHostFamily" }; 59 | 60 | static KernelPatcher::KextInfo IntelBTPatcher_IOUsbHostInfo { 61 | "com.apple.iokit.IOUSBHostFamily", 62 | IntelBTPatcher_IOUSBHostFamily, 63 | 1, 64 | {true, true}, 65 | {}, 66 | KernelPatcher::KextInfo::Unloaded 67 | }; 68 | 69 | bool CIntelBTPatcher::_randomAddressInit = false; 70 | 71 | bool CIntelBTPatcher::init() 72 | { 73 | DBGLOG(DRV_NAME, "%s", __PRETTY_FUNCTION__); 74 | callbackIBTPatcher = this; 75 | if (getKernelVersion() < KernelVersion::Monterey) { 76 | lilu.onKextLoadForce(&IntelBTPatcher_IOBluetoothInfo, 1, 77 | [](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) { 78 | callbackIBTPatcher->processKext(patcher, index, address, size); 79 | }, this); 80 | } else { 81 | lilu.onKextLoadForce(&IntelBTPatcher_IOUsbHostInfo, 1, 82 | [](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) { 83 | callbackIBTPatcher->processKext(patcher, index, address, size); 84 | }, this); 85 | } 86 | return true; 87 | } 88 | 89 | void CIntelBTPatcher::free() 90 | { 91 | DBGLOG(DRV_NAME, "%s", __PRETTY_FUNCTION__); 92 | } 93 | 94 | void CIntelBTPatcher::processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) 95 | { 96 | DBGLOG(DRV_NAME, "%s", __PRETTY_FUNCTION__); 97 | if (getKernelVersion() < KernelVersion::Monterey) { 98 | if (IntelBTPatcher_IOBluetoothInfo.loadIndex == index) { 99 | DBGLOG(DRV_NAME, "%s", IntelBTPatcher_IOBluetoothInfo.id); 100 | 101 | KernelPatcher::RouteRequest findQueueRequestRequest { 102 | "__ZN25IOBluetoothHostController17FindQueuedRequestEtP22BluetoothDeviceAddresstbPP21IOBluetoothHCIRequest", 103 | newFindQueueRequest, 104 | oldFindQueueRequest 105 | }; 106 | patcher.routeMultiple(index, &findQueueRequestRequest, 1, address, size); 107 | if (patcher.getError() == KernelPatcher::Error::NoError) { 108 | DBGLOG(DRV_NAME, "routed %s", findQueueRequestRequest.symbol); 109 | } else { 110 | SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", findQueueRequestRequest.symbol, patcher.getError()); 111 | patcher.clearError(); 112 | } 113 | 114 | } 115 | } else { 116 | if (IntelBTPatcher_IOUsbHostInfo.loadIndex == index) { 117 | SYSLOG(DRV_NAME, "%s", IntelBTPatcher_IOUsbHostInfo.id); 118 | 119 | KernelPatcher::RouteRequest hostDeviceRequest { 120 | "__ZN15IOUSBHostDevice13deviceRequestEP9IOServiceRN11StandardUSB13DeviceRequestEPvP18IOMemoryDescriptorRjP19IOUSBHostCompletionj", 121 | newHostDeviceRequest, 122 | oldHostDeviceRequest 123 | }; 124 | patcher.routeMultiple(index, &hostDeviceRequest, 1, address, size); 125 | if (patcher.getError() == KernelPatcher::Error::NoError) { 126 | SYSLOG(DRV_NAME, "routed %s", hostDeviceRequest.symbol); 127 | } else { 128 | SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", hostDeviceRequest.symbol, patcher.getError()); 129 | patcher.clearError(); 130 | } 131 | } 132 | } 133 | } 134 | 135 | #pragma mark - For Bigsur-, patch unhandled 0x2019 opcode 136 | 137 | #define HCI_OP_LE_START_ENCRYPTION 0x2019 138 | 139 | IOReturn CIntelBTPatcher::newFindQueueRequest(void *that, unsigned short arg1, void *addr, unsigned short arg2, bool arg3, void **hciRequestPtr) 140 | { 141 | IOReturn ret = FunctionCast(newFindQueueRequest, callbackIBTPatcher->oldFindQueueRequest)(that, arg1, addr, arg2, arg3, hciRequestPtr); 142 | if (ret != 0 && arg1 == HCI_OP_LE_START_ENCRYPTION) { 143 | ret = FunctionCast(newFindQueueRequest, callbackIBTPatcher->oldFindQueueRequest)(that, arg1, addr, 0xffff, arg3, hciRequestPtr); 144 | DBGLOG(DRV_NAME, "%s ret: %d arg1: 0x%04x arg2: 0x%04x arg3: %d ptr: %p", __FUNCTION__, ret, arg1, arg2, arg3, *hciRequestPtr); 145 | } 146 | return ret; 147 | } 148 | 149 | #pragma mark - For Monterey+ patch for intercept HCI REQ and RESP 150 | 151 | StandardUSB::DeviceRequest randomAddressRequest; 152 | // Hardcoded Random Address HCI Command 153 | const uint8_t randomAddressHci[9] = {0x05, 0x20, 0x06, 0x94, 0x50, 0x64, 0xD0, 0x78, 0x6B}; 154 | IOBufferMemoryDescriptor *writeHCIDescriptor = nullptr; 155 | 156 | #define MAX_HCI_BUF_LEN 255 157 | #define HCI_OP_RESET 0x0c03 158 | #define HCI_OP_LE_SET_SCAN_PARAM 0x200B 159 | #define HCI_OP_LE_SET_SCAN_ENABLE 0x200C 160 | 161 | IOReturn CIntelBTPatcher::newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length, IOUSBHostCompletion *completion, unsigned int timeout) 162 | { 163 | HciCommandHdr *hdr = nullptr; 164 | uint32_t hdrLen = 0; 165 | char hciBuf[MAX_HCI_BUF_LEN] = {0}; 166 | 167 | if (data == nullptr) { 168 | if (descriptor != nullptr && 169 | (getKernelVersion() < KernelVersion::Sequoia || !descriptor->prepare(kIODirectionOut))) { 170 | if (descriptor->getLength() > 0) { 171 | descriptor->readBytes(0, hciBuf, min(descriptor->getLength(), MAX_HCI_BUF_LEN)); 172 | hdrLen = (uint32_t)min(descriptor->getLength(), MAX_HCI_BUF_LEN); 173 | } 174 | if (getKernelVersion() >= KernelVersion::Sequoia) 175 | descriptor->complete(kIODirectionOut); 176 | } 177 | hdr = (HciCommandHdr *)hciBuf; 178 | if (hdr->opcode == HCI_OP_LE_SET_SCAN_PARAM) { 179 | if (!_randomAddressInit) { 180 | randomAddressRequest.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, kRequestTypeClass, kRequestRecipientInterface); 181 | randomAddressRequest.bRequest = 0xE0; 182 | randomAddressRequest.wIndex = 0; 183 | randomAddressRequest.wValue = 0; 184 | randomAddressRequest.wLength = 9; 185 | length = 9; 186 | if (writeHCIDescriptor == nullptr) 187 | writeHCIDescriptor = IOBufferMemoryDescriptor::withBytes(randomAddressHci, 9, kIODirectionOut); 188 | writeHCIDescriptor->prepare(kIODirectionOut); 189 | IOReturn ret = FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, randomAddressRequest, nullptr, writeHCIDescriptor, length, nullptr, timeout); 190 | writeHCIDescriptor->complete(); 191 | const char *randAddressDump = _hexDumpHCIData((uint8_t *)randomAddressHci, 9); 192 | if (randAddressDump) { 193 | SYSLOG(DRV_NAME, "[PATCH] Sending Random Address HCI %lld %s", ret, randAddressDump); 194 | IOFree((void *)randAddressDump, 9 * 3 + 1); 195 | } 196 | _randomAddressInit = true; 197 | SYSLOG(DRV_NAME, "[PATCH] Resend LE SCAN PARAM HCI %lld", ret); 198 | } 199 | } 200 | } else { 201 | hdr = (HciCommandHdr *)data; 202 | hdrLen = request.wLength - 3; 203 | } 204 | if (hdr) { 205 | // HCI reset, we need to send Random address again 206 | if (hdr->opcode == HCI_OP_RESET) 207 | _randomAddressInit = false; 208 | #if DEBUG 209 | DBGLOG(DRV_NAME, "[%s] bRequest: 0x%x direction: %s type: %s recipient: %s wValue: 0x%02x wIndex: 0x%02x opcode: 0x%04x len: %d length: %d async: %d", provider->getName(), request.bRequest, requestDirectionNames[(request.bmRequestType & kDeviceRequestDirectionMask) >> kDeviceRequestDirectionPhase], requestRecipientNames[(request.bmRequestType & kDeviceRequestRecipientMask) >> kDeviceRequestRecipientPhase], requestTypeNames[(request.bmRequestType & kDeviceRequestTypeMask) >> kDeviceRequestTypePhase], request.wValue, request.wIndex, hdr->opcode, hdr->len, request.wLength, completion != nullptr); 210 | if (hdrLen) { 211 | const char *dump = _hexDumpHCIData((uint8_t *)hdr, hdrLen); 212 | if (dump) { 213 | DBGLOG(DRV_NAME, "[Request]: %s", dump); 214 | IOFree((void *)dump, hdrLen * 3 + 1); 215 | } 216 | } 217 | #endif 218 | } 219 | return FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, request, data, descriptor, length, completion, timeout); 220 | } 221 | -------------------------------------------------------------------------------- /IntelBTPatcher/IntelBTPatcher.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBTPatcher.h 3 | // IntelBTPatcher 4 | // 5 | // Created by zxystd on 2021/2/8. 6 | // 7 | 8 | #ifndef IntelBTPatcher_h 9 | #define IntelBTPatcher_h 10 | 11 | #include 12 | 13 | #include 14 | 15 | #define DRV_NAME "ibtp" 16 | 17 | class BluetoothDeviceAddress; 18 | 19 | typedef struct { 20 | void *owner; 21 | IOMemoryDescriptor *dataBuffer; 22 | IOUSBHostCompletionAction action; 23 | } AsyncOwnerData; 24 | 25 | typedef struct __attribute__((packed)) 26 | { 27 | uint16_t opcode; /* OCF & OGF */ 28 | uint8_t len; 29 | uint8_t data[]; 30 | } HciCommandHdr; 31 | 32 | typedef struct __attribute__((packed)) 33 | { 34 | uint8_t evt; 35 | uint8_t len; 36 | } HciEventHdr; 37 | 38 | typedef struct __attribute__((packed)) 39 | { 40 | HciEventHdr evt; 41 | uint8_t numCommands; 42 | uint16_t opcode; 43 | uint8_t data[]; 44 | } HciResponse; 45 | 46 | const char *requestDirectionNames[] = { 47 | "OUT", 48 | "IN" 49 | }; 50 | 51 | const char *requestTypeNames[] = { 52 | "Standard", 53 | "Class", 54 | "Vendor" 55 | }; 56 | 57 | const char *requestRecipientNames[] = { 58 | "Device", 59 | "Interface", 60 | "Endpoint", 61 | "Other" 62 | }; 63 | 64 | const char* _hexDumpHCIData(uint8_t *buf, size_t len) 65 | { 66 | ssize_t str_len = len * 3 + 1; 67 | char *str = (char*)IOMalloc(str_len); 68 | if (!str) 69 | return nullptr; 70 | for (size_t i = 0; i < len; i++) 71 | snprintf(str + 3 * i, (len - i) * 3, "%02x ", buf[i]); 72 | str[MAX(str_len - 2, 0)] = 0; 73 | return str; 74 | } 75 | 76 | class CIntelBTPatcher { 77 | public: 78 | bool init(); 79 | void free(); 80 | 81 | void processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size); 82 | static IOReturn newFindQueueRequest(void *that, unsigned short arg1, void *addr, unsigned short arg2, bool arg3, void **hciRequestPtr); 83 | 84 | static IOReturn newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length,IOUSBHostCompletion *completion, unsigned int timeout); 85 | 86 | 87 | mach_vm_address_t oldFindQueueRequest {}; 88 | mach_vm_address_t oldHostDeviceRequest {}; 89 | 90 | private: 91 | static bool _randomAddressInit; 92 | }; 93 | 94 | #endif /* IntelBTPatcher_h */ 95 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/BtIntel.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // BtIntel.cpp 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/11/17. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #include "BtIntel.h" 15 | #include "Log.h" 16 | 17 | #define super OSObject 18 | OSDefineMetaClassAndAbstractStructors(BtIntel, OSObject) 19 | 20 | bool BtIntel:: 21 | initWithDevice(IOService *client, IOUSBHostDevice *dev) 22 | { 23 | XYLog("%s\n", __PRETTY_FUNCTION__); 24 | if (!super::init()) { 25 | return false; 26 | } 27 | 28 | m_pUSBDeviceController = new USBDeviceController(); 29 | if (!m_pUSBDeviceController->init(client, dev)) { 30 | return false; 31 | } 32 | if (!m_pUSBDeviceController->initConfiguration()) { 33 | return false; 34 | } 35 | if (!m_pUSBDeviceController->findInterface()) { 36 | return false; 37 | } 38 | if (!m_pUSBDeviceController->findPipes()) { 39 | return false; 40 | } 41 | return true; 42 | } 43 | 44 | void BtIntel:: 45 | free() 46 | { 47 | XYLog("%s\n", __PRETTY_FUNCTION__); 48 | OSSafeReleaseNULL(m_pUSBDeviceController); 49 | super::free(); 50 | } 51 | 52 | bool BtIntel:: 53 | intelSendHCISync(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, int timeout) 54 | { 55 | // XYLog("%s cmd: 0x%02x len: %d\n", __PRETTY_FUNCTION__, cmd->opcode, cmd->len); 56 | IOReturn ret; 57 | if ((ret = m_pUSBDeviceController->sendHCIRequest(cmd, timeout)) != kIOReturnSuccess) { 58 | XYLog("%s sendHCIRequest failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 59 | return false; 60 | } 61 | if ((ret = m_pUSBDeviceController->interruptPipeRead(event, eventBufSize, size, timeout)) != kIOReturnSuccess) { 62 | XYLog("%s interruptPipeRead failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 63 | return false; 64 | } 65 | return true; 66 | } 67 | 68 | bool BtIntel:: 69 | intelSendHCISyncEvent(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, uint8_t syncEvent, int timeout) 70 | { 71 | IOReturn ret; 72 | if ((ret = m_pUSBDeviceController->sendHCIRequest(cmd, timeout)) != kIOReturnSuccess) { 73 | XYLog("%s sendHCIRequest failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 74 | return false; 75 | } 76 | do { 77 | ret = m_pUSBDeviceController->interruptPipeRead(event, eventBufSize, size, timeout); 78 | if (ret != kIOReturnSuccess) { 79 | XYLog("%s interruptPipeRead failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 80 | break; 81 | } 82 | if (*(uint8_t *)event == syncEvent) { 83 | return true; 84 | } 85 | } while (true); 86 | return false; 87 | } 88 | 89 | bool BtIntel:: 90 | intelBulkHCISync(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, int timeout) 91 | { 92 | // XYLog("%s cmd: 0x%02x len: %d\n", __FUNCTION__, cmd->opcode, cmd->len); 93 | IOReturn ret; 94 | if ((ret = m_pUSBDeviceController->bulkWrite(cmd, HCI_COMMAND_HDR_SIZE + cmd->len, timeout)) != kIOReturnSuccess) { 95 | XYLog("%s bulkWrite failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 96 | return false; 97 | } 98 | if ((ret = m_pUSBDeviceController->bulkPipeRead(event, eventBufSize, size, timeout)) != kIOReturnSuccess) { 99 | XYLog("%s bulkPipeRead failed: %s %d\n", __FUNCTION__, m_pUSBDeviceController->stringFromReturn(ret), ret); 100 | return false; 101 | } 102 | return true; 103 | } 104 | 105 | bool BtIntel:: 106 | securedSend(uint8_t fragmentType, uint32_t len, const uint8_t *fragment) 107 | { 108 | bool ret = true; 109 | uint8_t buf[CMD_BUF_MAX_SIZE]; 110 | HciCommandHdr *hciCommand = (HciCommandHdr *)buf; 111 | 112 | while (len > 0) { 113 | uint8_t fragment_len = (len > 252) ? 252 : len; 114 | 115 | memset(buf, 0, sizeof(buf)); 116 | hciCommand->opcode = OSSwapHostToLittleInt16(0xfc09); 117 | hciCommand->len = fragment_len + 1; 118 | hciCommand->data[0] = fragmentType; 119 | memcpy(hciCommand->data + 1, fragment, fragment_len); 120 | 121 | if (!(ret = intelBulkHCISync(hciCommand, NULL, 0, NULL, HCI_INIT_TIMEOUT))) { 122 | XYLog("secure send failed\n"); 123 | return ret; 124 | } 125 | 126 | len -= fragment_len; 127 | fragment += fragment_len; 128 | } 129 | 130 | return ret; 131 | } 132 | 133 | bool BtIntel:: 134 | intelVersionInfo(IntelVersion *ver) 135 | { 136 | const char *variant; 137 | 138 | /* The hardware platform number has a fixed value of 0x37 and 139 | * for now only accept this single value. 140 | */ 141 | if (ver->hw_platform != 0x37) { 142 | XYLog("Unsupported Intel hardware platform (%u)\n", 143 | ver->hw_platform); 144 | return false; 145 | } 146 | 147 | /* Check for supported iBT hardware variants of this firmware 148 | * loading method. 149 | * 150 | * This check has been put in place to ensure correct forward 151 | * compatibility options when newer hardware variants come along. 152 | */ 153 | switch (ver->hw_variant) { 154 | case 0x0b: /* SfP */ 155 | case 0x0c: /* WsP */ 156 | case 0x11: /* JfP */ 157 | case 0x12: /* ThP */ 158 | case 0x13: /* HrP */ 159 | case 0x14: /* CcP */ 160 | break; 161 | default: 162 | XYLog("Unsupported Intel hardware variant (%u)\n", 163 | ver->hw_variant); 164 | return false; 165 | } 166 | 167 | switch (ver->fw_variant) { 168 | case 0x06: 169 | variant = "Bootloader"; 170 | break; 171 | case 0x23: 172 | variant = "Firmware"; 173 | break; 174 | default: 175 | XYLog("Unsupported firmware variant(%02x)\n", ver->fw_variant); 176 | return false; 177 | } 178 | 179 | XYLog("%s revision %u.%u build %u week %u %u\n", 180 | variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, 181 | ver->fw_build_num, ver->fw_build_ww, 182 | 2000 + ver->fw_build_yy); 183 | 184 | return true; 185 | } 186 | 187 | bool BtIntel:: 188 | intelBoot(uint32_t bootAddr) 189 | { 190 | uint8_t buf[CMD_BUF_MAX_SIZE]; 191 | uint32_t actLen = 0; 192 | HciResponse *resp = (HciResponse *)buf; 193 | 194 | if (!sendIntelReset(bootAddr)) { 195 | XYLog("Intel Soft Reset failed\n"); 196 | resetToBootloader(); 197 | return false; 198 | } 199 | 200 | /* The bootloader will not indicate when the device is ready. This 201 | * is done by the operational firmware sending bootup notification. 202 | * 203 | * Booting into operational firmware should not take longer than 204 | * 1 second. However if that happens, then just fail the setup 205 | * since something went wrong. 206 | */ 207 | IOReturn ret = m_pUSBDeviceController->interruptPipeRead(buf, sizeof(buf), &actLen, 1000); 208 | if (ret != kIOReturnSuccess || actLen <= 0) { 209 | XYLog("Intel boot failed\n"); 210 | if (ret == kIOReturnTimeout) { 211 | XYLog("Reset to bootloader\n"); 212 | resetToBootloader(); 213 | } 214 | return false; 215 | } 216 | if (resp->evt.evt == 0xff && resp->numCommands == 0x02) { 217 | XYLog("Notify: Device reboot done\n"); 218 | return true; 219 | } 220 | return false; 221 | } 222 | 223 | bool BtIntel:: 224 | loadDDCConfig(const char *ddcFileName) 225 | { 226 | const uint8_t *fw_ptr; 227 | uint8_t buf[CMD_BUF_MAX_SIZE]; 228 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 229 | 230 | OSData *fwData = requestFirmwareData(ddcFileName); 231 | 232 | if (fwData == NULL) { 233 | XYLog("DDC file not found: %s\n", ddcFileName); 234 | return false; 235 | } 236 | 237 | XYLog("Load DDC config: %s %d\n", ddcFileName, fwData->getLength()); 238 | 239 | fw_ptr = (uint8_t *)fwData->getBytesNoCopy(); 240 | 241 | /* DDC file contains one or more DDC structure which has 242 | * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). 243 | */ 244 | while (fwData->getLength() > fw_ptr - (uint8_t *)fwData->getBytesNoCopy()) { 245 | uint8_t cmd_plen = fw_ptr[0] + sizeof(uint8_t); 246 | 247 | cmd->opcode = OSSwapHostToLittleInt16(0xfc8b); 248 | cmd->len = cmd_plen; 249 | memcpy(cmd->data, fw_ptr, cmd->len); 250 | if (!intelSendHCISync(cmd, NULL, 0, NULL, HCI_INIT_TIMEOUT)) { 251 | XYLog("Failed to send Intel_Write_DDC\n"); 252 | return false; 253 | } 254 | 255 | fw_ptr += cmd_plen; 256 | } 257 | OSSafeReleaseNULL(fwData); 258 | 259 | XYLog("Load DDC config done\n"); 260 | return true; 261 | } 262 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/BtIntel.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // BtIntel.h 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/11/17. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #ifndef BtIntel_h 15 | #define BtIntel_h 16 | 17 | #include 18 | #include 19 | 20 | #include "USBDeviceController.hpp" 21 | #include "Hci.h" 22 | 23 | typedef struct __attribute__((packed)) { 24 | uint8_t status; 25 | uint8_t hw_platform; 26 | uint8_t hw_variant; 27 | uint8_t hw_revision; 28 | uint8_t fw_variant; 29 | uint8_t fw_revision; 30 | uint8_t fw_build_num; 31 | uint8_t fw_build_ww; 32 | uint8_t fw_build_yy; 33 | uint8_t fw_patch_num; 34 | } IntelVersion; 35 | 36 | typedef struct __attribute__((packed)) { 37 | uint8_t result; 38 | uint16_t opcode; 39 | uint8_t status; 40 | } IntelSecureSendResult; 41 | 42 | typedef struct __attribute__((packed)) { 43 | uint8_t reset_type; 44 | uint8_t patch_enable; 45 | uint8_t ddc_reload; 46 | uint8_t boot_option; 47 | uint32_t boot_param; 48 | } IntelReset; 49 | 50 | typedef struct __attribute__((packed)) { 51 | uint8_t b[6]; 52 | } bdaddr_t; 53 | 54 | typedef struct __attribute__((packed)) { 55 | uint8_t type; 56 | uint8_t len; 57 | uint8_t val[]; 58 | } IntelTLV; 59 | 60 | typedef struct __attribute__((packed)) { 61 | uint32_t cnvi_top; 62 | uint32_t cnvr_top; 63 | uint32_t cnvi_bt; 64 | uint32_t cnvr_bt; 65 | uint16_t dev_rev_id; 66 | uint8_t img_type; 67 | uint16_t timestamp; 68 | uint8_t build_type; 69 | uint32_t build_num; 70 | uint8_t secure_boot; 71 | uint8_t otp_lock; 72 | uint8_t api_lock; 73 | uint8_t debug_lock; 74 | uint8_t min_fw_build_nn; 75 | uint8_t min_fw_build_cw; 76 | uint8_t min_fw_build_yy; 77 | uint8_t limited_cce; 78 | uint8_t sbe_type; 79 | uint32_t git_sha1; 80 | bdaddr_t otp_bd_addr; 81 | } IntelVersionTLV; 82 | 83 | typedef struct __attribute__((packed)) { 84 | uint8_t zero; 85 | uint8_t num_cmds; 86 | uint8_t source; 87 | uint8_t reset_type; 88 | uint8_t reset_reason; 89 | uint8_t ddc_status; 90 | } IntelBootUp; 91 | 92 | typedef struct __attribute__((packed)) { 93 | uint8_t status; 94 | uint8_t otp_format; 95 | uint8_t otp_content; 96 | uint8_t otp_patch; 97 | uint16_t dev_revid; 98 | uint8_t secure_boot; 99 | uint8_t key_from_hdr; 100 | uint8_t key_type; 101 | uint8_t otp_lock; 102 | uint8_t api_lock; 103 | uint8_t debug_lock; 104 | bdaddr_t otp_bdaddr; 105 | uint8_t min_fw_build_nn; 106 | uint8_t min_fw_build_cw; 107 | uint8_t min_fw_build_yy; 108 | uint8_t limited_cce; 109 | uint8_t unlocked_state; 110 | } IntelBootParams; 111 | 112 | typedef struct __attribute__((packed)) { 113 | uint8_t page1[16]; 114 | } IntelDebugFeatures; 115 | 116 | typedef struct __attribute__((packed)) 117 | { 118 | uint16_t opcode; /* OCF & OGF */ 119 | uint8_t len; 120 | } FWCommandHdr; 121 | 122 | #define HCI_OP_INTEL_VERSION 0xfc05 123 | #define HCI_OP_INTEL_RESET 0xfc52 124 | #define HCI_OP_INTEL_RESET_BOOT 0xfc01 125 | 126 | #define HCI_OP_INTEL_ENTER_MFG 0xfc11 127 | #define HCI_OP_READ_INTEL_BOOT_PARAMS 0xfc0d 128 | #define HCI_OP_INTEL_EVENT_MASK 0xfc52 129 | 130 | #define INTEL_HW_PLATFORM(cnvx_bt) ((uint8_t)(((cnvx_bt) & 0x0000ff00) >> 8)) 131 | #define INTEL_HW_VARIANT(cnvx_bt) ((uint8_t)(((cnvx_bt) & 0x003f0000) >> 16)) 132 | #define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff) 133 | #define INTEL_CNVX_TOP_STEP(cnvx_top) (((cnvx_top) & 0x0f000000) >> 24) 134 | #define INTEL_CNVX_TOP_PACK_SWAB(t, s) OSSwapInt16(((uint16_t)(((t) << 4) | (s)))) 135 | 136 | #define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) 137 | #define RSA_HEADER_LEN 644 138 | #define CSS_HEADER_OFFSET 8 139 | #define ECDSA_OFFSET 644 140 | #define ECDSA_HEADER_LEN 320 141 | 142 | #define CMD_BUF_MAX_SIZE 256 143 | 144 | class BtIntel : public OSObject { 145 | OSDeclareAbstractStructors(BtIntel) 146 | public: 147 | 148 | virtual bool initWithDevice(IOService *client, IOUSBHostDevice *dev); 149 | 150 | virtual void free() override; 151 | 152 | virtual bool setup() = 0; 153 | 154 | virtual bool shutdown() = 0; 155 | 156 | virtual bool getFirmwareName(char *fwname, size_t len) = 0; 157 | 158 | bool securedSend(uint8_t fragmentType, uint32_t len, const uint8_t *fragment); 159 | 160 | bool enterMfg(); 161 | 162 | bool exitMfg(bool reset, bool patched); 163 | 164 | bool setEventMask(bool debug); 165 | 166 | bool setEventMaskMfg(bool debug); 167 | 168 | bool readVersion(IntelVersion *version); 169 | 170 | bool sendIntelReset(uint32_t bootParam); 171 | 172 | bool readBootParams(IntelBootParams *params); 173 | 174 | bool resetToBootloader(); 175 | 176 | bool intelVersionInfo(IntelVersion *ver); 177 | 178 | bool intelBoot(uint32_t bootAddr); 179 | 180 | bool readDebugFeatures(IntelDebugFeatures *features); 181 | 182 | bool setDebugFeatures(IntelDebugFeatures *features); 183 | 184 | bool loadDDCConfig(const char *ddcFileName); 185 | 186 | OSData *firmwareConvertion(OSData *originalFirmware); 187 | 188 | OSData *requestFirmwareData(const char *fwName, bool noWarn = false); 189 | 190 | protected: 191 | 192 | bool intelSendHCISync(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, int timeout); 193 | 194 | bool intelSendHCISyncEvent(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, uint8_t syncEvent, int timeout); 195 | 196 | bool intelBulkHCISync(HciCommandHdr *cmd, void *event, uint32_t eventBufSize, uint32_t *size, int timeout); 197 | 198 | protected: 199 | USBDeviceController *m_pUSBDeviceController; 200 | }; 201 | 202 | #endif /* BtIntel_h */ 203 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/BtIntelFw.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BtIntelFirmware.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/16. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "Log.h" 10 | #include "BtIntel.h" 11 | #include "FwData.h" 12 | 13 | OSData *BtIntel:: 14 | firmwareConvertion(OSData *originalFirmware) 15 | { 16 | unsigned int numBytes = originalFirmware->getLength() * 4; 17 | unsigned int actualBytes = numBytes; 18 | OSData *fwData = NULL; 19 | unsigned char* _fwBytes = (unsigned char *)IOMalloc(numBytes); 20 | if (!uncompressFirmware(_fwBytes, &actualBytes, (unsigned char *)originalFirmware->getBytesNoCopy(), originalFirmware->getLength())) { 21 | IOFree(_fwBytes, numBytes); 22 | return NULL; 23 | } 24 | fwData = OSData::withBytes(_fwBytes, actualBytes); 25 | IOFree(_fwBytes, numBytes); 26 | return fwData; 27 | } 28 | 29 | OSData *BtIntel:: 30 | requestFirmwareData(const char *fwName, bool noWarn) 31 | { 32 | OSData * _fwData = getFWDescByName(fwName); 33 | if (!_fwData) { 34 | if (!noWarn) 35 | XYLog("Firmware: %s Not found!\n", fwName); 36 | return NULL; 37 | } 38 | XYLog("Found device firmware %s \n", fwName); 39 | OSData *fwData = firmwareConvertion(_fwData); 40 | OSSafeReleaseNULL(_fwData); 41 | if (fwData == NULL) { 42 | XYLog("Firmware %s uncompress fail!\n", fwName); 43 | return NULL; 44 | } 45 | return fwData; 46 | } 47 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/BtIntelVSC.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BtIntelVSC.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/16. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "Log.h" 10 | #include "BtIntel.h" 11 | 12 | bool BtIntel:: 13 | enterMfg() 14 | { 15 | uint8_t buf[CMD_BUF_MAX_SIZE]; 16 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 17 | 18 | memset(buf, 0, sizeof(buf)); 19 | cmd->opcode = OSSwapHostToLittleInt16(0xfc11); 20 | cmd->len = 2; 21 | cmd->data[0] = 0x01; 22 | cmd->data[1] = 0x00; 23 | 24 | return intelSendHCISync(cmd, NULL, 0, NULL, HCI_CMD_TIMEOUT); 25 | } 26 | 27 | bool BtIntel:: 28 | exitMfg(bool reset, bool patched) 29 | { 30 | uint8_t buf[CMD_BUF_MAX_SIZE]; 31 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 32 | 33 | memset(buf, 0, sizeof(buf)); 34 | cmd->opcode = OSSwapHostToLittleInt16(0xfc11); 35 | cmd->len = 2; 36 | cmd->data[0] = 0x00; 37 | cmd->data[1] = 0x00; 38 | 39 | /* The 2nd command parameter specifies the manufacturing exit method: 40 | * 0x00: Just disable the manufacturing mode (0x00). 41 | * 0x01: Disable manufacturing mode and reset with patches deactivated. 42 | * 0x02: Disable manufacturing mode and reset with patches activated. 43 | */ 44 | if (reset) 45 | cmd->data[1] |= patched ? 0x02 : 0x01; 46 | 47 | return intelSendHCISync(cmd, NULL, 0, NULL, HCI_CMD_TIMEOUT); 48 | } 49 | 50 | bool BtIntel:: 51 | setEventMask(bool debug) 52 | { 53 | uint8_t buf[CMD_BUF_MAX_SIZE]; 54 | uint8_t mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 55 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 56 | 57 | if (debug) 58 | mask[1] |= 0x62; 59 | memset(buf, 0, sizeof(buf)); 60 | cmd->opcode = OSSwapHostToLittleInt16(0xfc52); 61 | cmd->len = 8; 62 | memcpy(cmd->data, mask, 8); 63 | 64 | return intelSendHCISync(cmd, NULL, 0, NULL, HCI_INIT_TIMEOUT); 65 | } 66 | 67 | bool BtIntel:: 68 | setEventMaskMfg(bool debug) 69 | { 70 | bool ret; 71 | if (!enterMfg()) { 72 | return false; 73 | } 74 | 75 | ret = setEventMask(debug); 76 | 77 | if (!exitMfg(false, false)) { 78 | return false; 79 | } 80 | 81 | return ret; 82 | } 83 | 84 | bool BtIntel:: 85 | readVersion(IntelVersion *version) 86 | { 87 | uint32_t actLen = 0; 88 | HciCommandHdr cmd = { 89 | .opcode = OSSwapHostToLittleInt16(0xfc05), 90 | .len = 0, 91 | }; 92 | uint8_t buf[CMD_BUF_MAX_SIZE]; 93 | HciResponse *resp = (HciResponse *)buf; 94 | 95 | memset(buf, 0, sizeof(buf)); 96 | if (!intelSendHCISync(&cmd, resp, sizeof(buf), &actLen, HCI_CMD_TIMEOUT)) { 97 | XYLog("Reading Intel version information failed\n"); 98 | return false; 99 | } 100 | 101 | if (actLen - 5 != sizeof(*version)) { 102 | XYLog("Intel version event size mismatch (act: %d, ver: %d)\n", actLen, (int)sizeof(*version)); 103 | return false; 104 | } 105 | 106 | memcpy(version, resp->data, actLen - 5); 107 | 108 | return true; 109 | } 110 | 111 | bool BtIntel:: 112 | sendIntelReset(uint32_t bootParam) 113 | { 114 | uint8_t buf[CMD_BUF_MAX_SIZE]; 115 | IntelReset params = { 116 | 0x00, 0x01, 0x00, 0x01, 0x00000000 117 | }; 118 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 119 | 120 | params.boot_param = OSSwapHostToLittleInt32(bootParam); 121 | 122 | cmd->opcode = OSSwapHostToLittleInt16(0xfc01); 123 | cmd->len = sizeof(params); 124 | memcpy(cmd->data, ¶ms, sizeof(params)); 125 | return m_pUSBDeviceController->sendHCIRequest(cmd, HCI_INIT_TIMEOUT) == kIOReturnSuccess; 126 | } 127 | 128 | bool BtIntel:: 129 | readBootParams(IntelBootParams *params) 130 | { 131 | uint32_t actLen = 0; 132 | HciCommandHdr cmd = { 133 | .opcode = OSSwapHostToLittleInt16(0xfc0d), 134 | .len = 0, 135 | }; 136 | uint8_t buf[CMD_BUF_MAX_SIZE]; 137 | HciResponse *resp = (HciResponse *)buf; 138 | 139 | memset(buf, 0, sizeof(buf)); 140 | if (!intelSendHCISync(&cmd, resp, sizeof(buf), &actLen, HCI_INIT_TIMEOUT)) { 141 | XYLog("Reading Intel boot parameters failed\n"); 142 | return false; 143 | } 144 | 145 | if (actLen - 5 != sizeof(*params)) { 146 | XYLog("Intel boot parameters size mismatch\n"); 147 | return false; 148 | } 149 | 150 | memcpy(params, resp->data, actLen - 5); 151 | 152 | if (params->status) { 153 | XYLog("Intel boot parameters command failed (%02x)\n", params->status); 154 | return false; 155 | } 156 | 157 | XYLog("Device revision is %u\n", 158 | OSSwapLittleToHostInt16(params->dev_revid)); 159 | 160 | XYLog("Secure boot is %s\n", 161 | params->secure_boot ? "enabled" : "disabled"); 162 | 163 | XYLog("OTP lock is %s\n", 164 | params->otp_lock ? "enabled" : "disabled"); 165 | 166 | XYLog("API lock is %s\n", 167 | params->api_lock ? "enabled" : "disabled"); 168 | 169 | XYLog("Debug lock is %s\n", 170 | params->debug_lock ? "enabled" : "disabled"); 171 | 172 | XYLog("Minimum firmware build %u week %u %u\n", 173 | params->min_fw_build_nn, params->min_fw_build_cw, 174 | 2000 + params->min_fw_build_yy); 175 | 176 | return true; 177 | } 178 | 179 | bool BtIntel:: 180 | resetToBootloader() 181 | { 182 | XYLog("%s\n", __FUNCTION__); 183 | bool ret; 184 | uint8_t buf[CMD_BUF_MAX_SIZE]; 185 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 186 | IntelReset params; 187 | 188 | /* Send Intel Reset command. This will result in 189 | * re-enumeration of BT controller. 190 | * 191 | * Intel Reset parameter description: 192 | * reset_type : 0x00 (Soft reset), 193 | * 0x01 (Hard reset) 194 | * patch_enable : 0x00 (Do not enable), 195 | * 0x01 (Enable) 196 | * ddc_reload : 0x00 (Do not reload), 197 | * 0x01 (Reload) 198 | * boot_option: 0x00 (Current image), 199 | * 0x01 (Specified boot address) 200 | * boot_param: Boot address 201 | * 202 | */ 203 | params.reset_type = 0x01; 204 | params.patch_enable = 0x01; 205 | params.ddc_reload = 0x01; 206 | params.boot_option = 0x00; 207 | params.boot_param = OSSwapHostToLittleInt32(0x00000000); 208 | 209 | cmd->opcode = OSSwapHostToLittleInt16(0xfc01); 210 | cmd->len = sizeof(params); 211 | memcpy(cmd->data, ¶ms, sizeof(params)); 212 | 213 | ret = m_pUSBDeviceController->sendHCIRequest(cmd, HCI_INIT_TIMEOUT); 214 | 215 | /* Current Intel BT controllers(ThP/JfP) hold the USB reset 216 | * lines for 2ms when it receives Intel Reset in bootloader mode. 217 | * Whereas, the upcoming Intel BT controllers will hold USB reset 218 | * for 150ms. To keep the delay generic, 150ms is chosen here. 219 | */ 220 | IOSleep(150); 221 | 222 | return ret; 223 | } 224 | 225 | bool BtIntel:: 226 | readDebugFeatures(IntelDebugFeatures *features) 227 | { 228 | uint8_t buf[CMD_BUF_MAX_SIZE], temp[CMD_BUF_MAX_SIZE]; 229 | uint actLen = 0; 230 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 231 | HciResponse *resp = (HciResponse *)temp; 232 | uint8_t page_no = 1; 233 | 234 | memset(buf, 0, sizeof(buf)); 235 | cmd->opcode = OSSwapHostToLittleInt16(0xfca6); 236 | cmd->len = sizeof(page_no); 237 | cmd->data[0] = page_no; 238 | 239 | if (!intelSendHCISync(cmd, resp, sizeof(temp), &actLen, HCI_INIT_TIMEOUT)) { 240 | XYLog("Reading supported features failed\n"); 241 | return false; 242 | } 243 | 244 | if (actLen - 5 != sizeof(features->page1) + 3) { 245 | XYLog("Supported features event size mismatch\n"); 246 | return false; 247 | } 248 | 249 | memcpy(features->page1, resp->data + 3, sizeof(features->page1)); 250 | XYLog("Read debug features done\n"); 251 | 252 | return true; 253 | } 254 | 255 | bool BtIntel:: 256 | setDebugFeatures(IntelDebugFeatures *features) 257 | { 258 | uint8_t buf[CMD_BUF_MAX_SIZE]; 259 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 260 | uint8_t mask[11] = { 0x0a, 0x92, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 261 | 0x00, 0x00, 0x00 }; 262 | 263 | if (!features) { 264 | XYLog("No debug features!\n"); 265 | return false; 266 | } 267 | 268 | if (!(features->page1[0] & 0x3f)) { 269 | XYLog("Telemetry exception format not supported\n"); 270 | return false; 271 | } 272 | 273 | memset(buf, 0, sizeof(buf)); 274 | cmd->opcode = OSSwapHostToLittleInt16(0xfc8b); 275 | cmd->len = 11; 276 | memcpy(cmd->data, mask, 11); 277 | 278 | if (!intelSendHCISync(cmd, NULL, 0, NULL, HCI_INIT_TIMEOUT)) { 279 | XYLog("Setting Intel telemetry ddc write event mask failed\n"); 280 | return false; 281 | } 282 | 283 | XYLog("Set debug features done\n"); 284 | 285 | return true; 286 | } 287 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/FwData.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // FwData.h 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/12/22. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #ifndef FwData_h 15 | #define FwData_h 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | struct FwDesc { 22 | const char *name; 23 | const unsigned char *var; 24 | const long int size; 25 | }; 26 | 27 | #define IBT_FW(fw_name, fw_var, fw_size) \ 28 | .name = fw_name, .var = fw_var, .size = fw_size 29 | 30 | 31 | extern const struct FwDesc fwList[]; 32 | extern const int fwNumber; 33 | 34 | static inline OSData *getFWDescByName(const char* name) { 35 | for (int i = 0; i < fwNumber; i++) { 36 | if (strcmp(fwList[i].name, name) == 0) { 37 | FwDesc desc = fwList[i]; 38 | return OSData::withBytes(desc.var, (unsigned int)desc.size); 39 | } 40 | } 41 | return NULL; 42 | } 43 | 44 | static inline bool uncompressFirmware(unsigned char *dest, uint *destLen, unsigned char *source, uint sourceLen) 45 | { 46 | z_stream stream; 47 | int err; 48 | 49 | stream.next_in = source; 50 | stream.avail_in = sourceLen; 51 | stream.next_out = dest; 52 | stream.avail_out = *destLen; 53 | stream.zalloc = zcalloc; 54 | stream.zfree = zcfree; 55 | err = inflateInit(&stream); 56 | if (err != Z_OK) { 57 | return false; 58 | } 59 | err = inflate(&stream, Z_FINISH); 60 | if (err != Z_STREAM_END) { 61 | inflateEnd(&stream); 62 | return false; 63 | } 64 | *destLen = (uint)stream.total_out; 65 | 66 | err = inflateEnd(&stream); 67 | return err == Z_OK; 68 | } 69 | 70 | #endif /* FwData_h */ 71 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/Hci.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // Hci.h 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/11/17. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #ifndef Hci_h 15 | #define Hci_h 16 | 17 | typedef struct __attribute__((packed)) 18 | { 19 | uint16_t opcode; /* OCF & OGF */ 20 | uint8_t len; 21 | uint8_t data[]; 22 | } HciCommandHdr; 23 | 24 | typedef struct __attribute__((packed)) 25 | { 26 | uint8_t evt; 27 | uint8_t len; 28 | } HciEventHdr; 29 | 30 | typedef struct __attribute__((packed)) 31 | { 32 | HciEventHdr evt; 33 | uint8_t numCommands; 34 | uint16_t opcode; 35 | uint8_t data[]; 36 | } HciResponse; 37 | 38 | typedef struct __attribute__((packed)) 39 | { 40 | uint8_t status; 41 | uint8_t numCommands; 42 | uint16_t opcode; 43 | } HciCmdStatus; 44 | 45 | /* ---- HCI Events ---- */ 46 | #define HCI_EV_INQUIRY_COMPLETE 0x01 47 | #define HCI_EV_INQUIRY_RESULT 0x02 48 | #define HCI_EV_CONN_COMPLETE 0x03 49 | #define HCI_EV_CONN_REQUEST 0x04 50 | #define HCI_EV_DISCONN_COMPLETE 0x05 51 | #define HCI_EV_AUTH_COMPLETE 0x06 52 | #define HCI_EV_REMOTE_NAME 0x07 53 | #define HCI_EV_ENCRYPT_CHANGE 0x08 54 | #define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 55 | #define HCI_EV_REMOTE_FEATURES 0x0b 56 | #define HCI_EV_REMOTE_VERSION 0x0c 57 | #define HCI_EV_QOS_SETUP_COMPLETE 0x0d 58 | #define HCI_EV_CMD_COMPLETE 0x0e 59 | #define HCI_EV_CMD_STATUS 0x0f 60 | #define HCI_EV_HARDWARE_ERROR 0x10 61 | #define HCI_EV_ROLE_CHANGE 0x12 62 | #define HCI_EV_NUM_COMP_PKTS 0x13 63 | #define HCI_EV_MODE_CHANGE 0x14 64 | #define HCI_EV_PIN_CODE_REQ 0x16 65 | #define HCI_EV_LINK_KEY_REQ 0x17 66 | #define HCI_EV_LINK_KEY_NOTIFY 0x18 67 | #define HCI_EV_CLOCK_OFFSET 0x1c 68 | #define HCI_EV_PKT_TYPE_CHANGE 0x1d 69 | #define HCI_EV_PSCAN_REP_MODE 0x20 70 | #define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 71 | #define HCI_EV_REMOTE_EXT_FEATURES 0x23 72 | #define HCI_EV_SYNC_CONN_COMPLETE 0x2c 73 | #define HCI_EV_SYNC_CONN_CHANGED 0x2d 74 | #define HCI_EV_SNIFF_SUBRATE 0x2e 75 | #define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f 76 | #define HCI_EV_KEY_REFRESH_COMPLETE 0x30 77 | #define HCI_EV_IO_CAPA_REQUEST 0x31 78 | #define HCI_EV_IO_CAPA_REPLY 0x32 79 | #define HCI_EV_USER_CONFIRM_REQUEST 0x33 80 | #define HCI_EV_USER_PASSKEY_REQUEST 0x34 81 | #define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35 82 | #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 83 | #define HCI_EV_USER_PASSKEY_NOTIFY 0x3b 84 | #define HCI_EV_KEYPRESS_NOTIFY 0x3c 85 | #define HCI_EV_REMOTE_HOST_FEATURES 0x3d 86 | #define HCI_EV_LE_META 0x3e 87 | #define HCI_EV_PHY_LINK_COMPLETE 0x40 88 | #define HCI_EV_CHANNEL_SELECTED 0x41 89 | #define HCI_EV_DISCONN_PHY_LINK_COMPLETE 0x42 90 | #define HCI_EV_LOGICAL_LINK_COMPLETE 0x45 91 | #define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE 0x46 92 | #define HCI_EV_NUM_COMP_BLOCKS 0x48 93 | #define HCI_EV_SYNC_TRAIN_COMPLETE 0x4F 94 | #define HCI_EV_SLAVE_PAGE_RESP_TIMEOUT 0x54 95 | 96 | /* HCI timeouts */ 97 | #define HCI_DISCONN_TIMEOUT 2000 /* 2 seconds */ 98 | #define HCI_PAIRING_TIMEOUT 60000 /* 60 seconds */ 99 | #define HCI_INIT_TIMEOUT 10000 /* 10 seconds */ 100 | #define HCI_CMD_TIMEOUT 2000 /* 2 seconds */ 101 | #define HCI_ACL_TX_TIMEOUT 45000 /* 45 seconds */ 102 | #define HCI_AUTO_OFF_TIMEOUT 2000 /* 2 seconds */ 103 | #define HCI_POWER_OFF_TIMEOUT 5000 /* 5 seconds */ 104 | #define HCI_LE_CONN_TIMEOUT 20000 /* 20 seconds */ 105 | #define HCI_LE_AUTOCONN_TIMEOUT 4000 /* 4 seconds */ 106 | 107 | /* HCI data types */ 108 | #define HCI_COMMAND_PKT 0x01 109 | #define HCI_ACLDATA_PKT 0x02 110 | #define HCI_SCODATA_PKT 0x03 111 | #define HCI_EVENT_PKT 0x04 112 | #define HCI_DIAG_PKT 0xf0 113 | #define HCI_VENDOR_PKT 0xff 114 | 115 | /* ----- HCI Commands ---- */ 116 | #define HCI_OP_NOP 0x0000 117 | #define HCI_OP_INQUIRY 0x0401 118 | #define HCI_OP_INQUIRY_CANCEL 0x0402 119 | #define HCI_OP_PERIODIC_INQ 0x0403 120 | #define HCI_OP_EXIT_PERIODIC_INQ 0x0404 121 | #define HCI_OP_CREATE_CONN 0x0405 122 | #define HCI_OP_DISCONNECT 0x0406 123 | #define HCI_OP_ADD_SCO 0x0407 124 | #define HCI_OP_CREATE_CONN_CANCEL 0x0408 125 | #define HCI_OP_ACCEPT_CONN_REQ 0x0409 126 | #define HCI_OP_REJECT_CONN_REQ 0x040a 127 | #define HCI_OP_LINK_KEY_REPLY 0x040b 128 | #define HCI_OP_LINK_KEY_NEG_REPLY 0x040c 129 | #define HCI_OP_PIN_CODE_REPLY 0x040d 130 | #define HCI_OP_PIN_CODE_NEG_REPLY 0x040e 131 | #define HCI_OP_CHANGE_CONN_PTYPE 0x040f 132 | #define HCI_OP_AUTH_REQUESTED 0x0411 133 | #define HCI_OP_SET_CONN_ENCRYPT 0x0413 134 | #define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 135 | #define HCI_OP_REMOTE_NAME_REQ 0x0419 136 | #define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a 137 | #define HCI_OP_READ_REMOTE_FEATURES 0x041b 138 | #define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c 139 | #define HCI_OP_READ_REMOTE_VERSION 0x041d 140 | #define HCI_OP_READ_CLOCK_OFFSET 0x041f 141 | #define HCI_OP_SETUP_SYNC_CONN 0x0428 142 | #define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 143 | #define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a 144 | #define HCI_OP_IO_CAPABILITY_REPLY 0x042b 145 | #define HCI_OP_USER_CONFIRM_REPLY 0x042c 146 | #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d 147 | #define HCI_OP_USER_PASSKEY_REPLY 0x042e 148 | #define HCI_OP_USER_PASSKEY_NEG_REPLY 0x042f 149 | #define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430 150 | #define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433 151 | #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 152 | #define HCI_OP_CREATE_PHY_LINK 0x0435 153 | #define HCI_OP_ACCEPT_PHY_LINK 0x0436 154 | #define HCI_OP_DISCONN_PHY_LINK 0x0437 155 | #define HCI_OP_CREATE_LOGICAL_LINK 0x0438 156 | #define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439 157 | #define HCI_OP_DISCONN_LOGICAL_LINK 0x043a 158 | #define HCI_OP_LOGICAL_LINK_CANCEL 0x043b 159 | #define HCI_OP_SET_CSB 0x0441 160 | #define HCI_OP_START_SYNC_TRAIN 0x0443 161 | #define HCI_OP_REMOTE_OOB_EXT_DATA_REPLY 0x0445 162 | #define HCI_OP_SNIFF_MODE 0x0803 163 | #define HCI_OP_EXIT_SNIFF_MODE 0x0804 164 | #define HCI_OP_ROLE_DISCOVERY 0x0809 165 | #define HCI_OP_SWITCH_ROLE 0x080b 166 | #define HCI_OP_READ_LINK_POLICY 0x080c 167 | #define HCI_OP_WRITE_LINK_POLICY 0x080d 168 | #define HCI_OP_READ_DEF_LINK_POLICY 0x080e 169 | #define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f 170 | #define HCI_OP_SNIFF_SUBRATE 0x0811 171 | #define HCI_OP_SET_EVENT_MASK 0x0c01 172 | #define HCI_OP_RESET 0x0c03 173 | #define HCI_OP_SET_EVENT_FLT 0x0c05 174 | 175 | /* Command opcode pack/unpack */ 176 | #define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10))) 177 | #define hci_opcode_ogf(op) (op >> 10) 178 | #define hci_opcode_ocf(op) (op & 0x03ff) 179 | 180 | /* ---- HCI Packet structures ---- */ 181 | #define HCI_COMMAND_HDR_SIZE 3 182 | #define HCI_EVENT_HDR_SIZE 2 183 | #define HCI_ACL_HDR_SIZE 4 184 | #define HCI_SCO_HDR_SIZE 3 185 | 186 | #endif /* Hci_h */ 187 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/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 | IntelBluetoothFirmware_0026 24 | 25 | CFBundleIdentifier 26 | com.zxystd.IntelBluetoothFirmware 27 | IOClass 28 | IntelBluetoothFirmware 29 | IOMatchCategory 30 | IntelBluetoothFirmware 31 | IOProbeScore 32 | 4000 33 | IOProviderClass 34 | IOUSBHostDevice 35 | idProduct 36 | 38 37 | idVendor 38 | 32903 39 | 40 | IntelBluetoothFirmware_0032 41 | 42 | CFBundleIdentifier 43 | com.zxystd.IntelBluetoothFirmware 44 | IOClass 45 | IntelBluetoothFirmware 46 | IOMatchCategory 47 | IntelBluetoothFirmware 48 | IOProbeScore 49 | 4000 50 | IOProviderClass 51 | IOUSBHostDevice 52 | idProduct 53 | 50 54 | idVendor 55 | 32903 56 | 57 | IntelBluetoothFirmware_0035 58 | 59 | CFBundleIdentifier 60 | com.zxystd.IntelBluetoothFirmware 61 | IOClass 62 | IntelBluetoothFirmware 63 | IOMatchCategory 64 | IntelBluetoothFirmware 65 | IOProbeScore 66 | 4000 67 | IOProviderClass 68 | IOUSBHostDevice 69 | idProduct 70 | 53 71 | idVendor 72 | 32903 73 | 74 | IntelBluetoothFirmware_0036 75 | 76 | CFBundleIdentifier 77 | com.zxystd.IntelBluetoothFirmware 78 | IOClass 79 | IntelBluetoothFirmware 80 | IOMatchCategory 81 | IntelBluetoothFirmware 82 | IOProbeScore 83 | 4000 84 | IOProviderClass 85 | IOUSBHostDevice 86 | idProduct 87 | 54 88 | idVendor 89 | 32903 90 | 91 | IntelBluetoothFirmware_0038 92 | 93 | CFBundleIdentifier 94 | com.zxystd.IntelBluetoothFirmware 95 | IOClass 96 | IntelBluetoothFirmware 97 | IOMatchCategory 98 | IntelBluetoothFirmware 99 | IOProbeScore 100 | 4000 101 | IOProviderClass 102 | IOUSBHostDevice 103 | idProduct 104 | 56 105 | idVendor 106 | 32903 107 | 108 | IntelBluetoothFirmware_3165 109 | 110 | CFBundleIdentifier 111 | com.zxystd.IntelBluetoothFirmware 112 | IOClass 113 | IntelBluetoothFirmware 114 | IOMatchCategory 115 | IntelBluetoothFirmware 116 | IOProbeScore 117 | 4000 118 | IOProviderClass 119 | IOUSBHostDevice 120 | idProduct 121 | 2602 122 | idVendor 123 | 32903 124 | 125 | IntelBluetoothFirmware_3168 126 | 127 | CFBundleIdentifier 128 | com.zxystd.IntelBluetoothFirmware 129 | IOClass 130 | IntelBluetoothFirmware 131 | IOMatchCategory 132 | IntelBluetoothFirmware 133 | IOProbeScore 134 | 4000 135 | IOProviderClass 136 | IOUSBHostDevice 137 | idProduct 138 | 2727 139 | idVendor 140 | 32903 141 | 142 | IntelBluetoothFirmware_726x 143 | 144 | CFBundleIdentifier 145 | com.zxystd.IntelBluetoothFirmware 146 | IOClass 147 | IntelBluetoothFirmware 148 | IOMatchCategory 149 | IntelBluetoothFirmware 150 | IOProbeScore 151 | 4000 152 | IOProviderClass 153 | IOUSBHostDevice 154 | idProduct 155 | 2012 156 | idVendor 157 | 32903 158 | 159 | IntelBluetoothFirmware_8265 160 | 161 | CFBundleIdentifier 162 | com.zxystd.IntelBluetoothFirmware 163 | IOClass 164 | IntelBluetoothFirmware 165 | IOMatchCategory 166 | IntelBluetoothFirmware 167 | IOProbeScore 168 | 4000 169 | IOProviderClass 170 | IOUSBHostDevice 171 | idProduct 172 | 2603 173 | idVendor 174 | 32903 175 | 176 | IntelBluetoothFirmware_926x 177 | 178 | CFBundleIdentifier 179 | com.zxystd.IntelBluetoothFirmware 180 | IOClass 181 | IntelBluetoothFirmware 182 | IOMatchCategory 183 | IntelBluetoothFirmware 184 | IOProbeScore 185 | 4000 186 | IOProviderClass 187 | IOUSBHostDevice 188 | idProduct 189 | 37 190 | idVendor 191 | 32903 192 | 193 | IntelBluetoothFirmware_9560 194 | 195 | CFBundleIdentifier 196 | com.zxystd.IntelBluetoothFirmware 197 | IOClass 198 | IntelBluetoothFirmware 199 | IOMatchCategory 200 | IntelBluetoothFirmware 201 | IOProbeScore 202 | 4000 203 | IOProviderClass 204 | IOUSBHostDevice 205 | idProduct 206 | 2730 207 | idVendor 208 | 32903 209 | 210 | IntelBluetoothFirmware_ax200 211 | 212 | CFBundleIdentifier 213 | com.zxystd.IntelBluetoothFirmware 214 | IOClass 215 | IntelBluetoothFirmware 216 | IOMatchCategory 217 | IntelBluetoothFirmware 218 | IOProbeScore 219 | 4000 220 | IOProviderClass 221 | IOUSBHostDevice 222 | idProduct 223 | 41 224 | idVendor 225 | 32903 226 | 227 | IntelBluetoothFirmware_ax210 228 | 229 | CFBundleIdentifier 230 | com.zxystd.IntelBluetoothFirmware 231 | IOClass 232 | IntelBluetoothFirmware 233 | IOMatchCategory 234 | IntelBluetoothFirmware 235 | IOProbeScore 236 | 4000 237 | IOProviderClass 238 | IOUSBHostDevice 239 | idProduct 240 | 51 241 | idVendor 242 | 32903 243 | 244 | 245 | NSHumanReadableCopyright 246 | Copyright © 2019 钟先耀. All rights reserved. 247 | OSBundleLibraries 248 | 249 | com.apple.iokit.IOUSBHostFamily 250 | 1.2 251 | com.apple.kpi.iokit 252 | 16.7 253 | com.apple.kpi.libkern 254 | 16.7 255 | com.apple.kpi.mach 256 | 16.7 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothFirmware.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothFirmware.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by zxystd on 2019/11/17. 6 | // Copyright © 2019 zxystd. All rights reserved. 7 | // 8 | 9 | #include "BtIntel.h" 10 | 11 | #include "IntelBluetoothFirmware.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "Hci.h" 18 | #include "linux.h" 19 | #include "Log.h" 20 | 21 | #include "IntelBluetoothOpsGen1.hpp" 22 | #include "IntelBluetoothOpsGen2.hpp" 23 | #include "IntelBluetoothOpsGen3.hpp" 24 | 25 | #define super IOService 26 | OSDefineMetaClassAndStructors(IntelBluetoothFirmware, IOService) 27 | 28 | //com.apple.iokit.IOBluetoothHostControllerUSBTransport 29 | 30 | enum { kMyOffPowerState = 0, kMyOnPowerState = 1 }; 31 | 32 | #define kIOPMPowerOff 0 33 | 34 | static IOPMPowerState myTwoStates[2] = 35 | { 36 | {1, kIOPMPowerOff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37 | {1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0} 38 | }; 39 | 40 | bool IntelBluetoothFirmware::init(OSDictionary *dictionary) 41 | { 42 | XYLog("Driver init()\n"); 43 | return super::init(dictionary); 44 | } 45 | 46 | void IntelBluetoothFirmware::free() { 47 | XYLog("Driver free()\n"); 48 | super::free(); 49 | } 50 | 51 | bool IntelBluetoothFirmware::start(IOService *provider) 52 | { 53 | XYLog("Driver Start()\n"); 54 | char fwName[64]; 55 | m_pDevice = OSDynamicCast(IOUSBHostDevice, provider); 56 | if (m_pDevice == NULL) { 57 | XYLog("Driver Start fail, not usb device\n"); 58 | return false; 59 | } 60 | PMinit(); 61 | registerPowerDriver(this, myTwoStates, 2); 62 | provider->joinPMtree(this); 63 | makeUsable(); 64 | 65 | if (!super::start(provider)) { 66 | return false; 67 | } 68 | 69 | if (!m_pDevice->open(this)) { 70 | XYLog("start fail, can not open device\n"); 71 | cleanUp(); 72 | stop(this); 73 | return false; 74 | } 75 | if (currentType == kTypeGen1) { 76 | m_pBTIntel = new IntelBluetoothOpsGen1(); 77 | } else { 78 | m_pBTIntel = new IntelBluetoothOpsGen3(); 79 | } 80 | if (!m_pBTIntel->initWithDevice(this, m_pDevice)) { 81 | XYLog("start fail, can not init device\n"); 82 | cleanUp(); 83 | stop(this); 84 | return false; 85 | } 86 | XYLog("BT init succeed\n"); 87 | if (!m_pBTIntel->setup()) { 88 | cleanUp(); 89 | stop(this); 90 | return false; 91 | } 92 | m_pBTIntel->getFirmwareName(fwName, sizeof(fwName)); 93 | publishReg(true, fwName); 94 | cleanUp(); 95 | return true; 96 | } 97 | 98 | void IntelBluetoothFirmware::publishReg(bool isSucceed, const char *fwName) 99 | { 100 | m_pDevice->setProperty("FirmwareLoaded", isSucceed); 101 | if (isSucceed) 102 | setProperty("fw_name", OSString::withCString(fwName)); 103 | // Monterey+ 104 | if (version_major >= 21) 105 | m_pDevice->setName("Bluetooth USB Host Controller"); 106 | } 107 | 108 | void IntelBluetoothFirmware::cleanUp() 109 | { 110 | XYLog("Clean up...\n"); 111 | OSSafeReleaseNULL(m_pBTIntel); 112 | if (m_pDevice) { 113 | if (m_pDevice->isOpen(this)) { 114 | m_pDevice->close(this); 115 | } 116 | m_pDevice = NULL; 117 | } 118 | } 119 | 120 | IOReturn IntelBluetoothFirmware::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) 121 | { 122 | // XYLog("setPowerState powerStateOrdinal=%lu\n", powerStateOrdinal); 123 | return IOPMAckImplied; 124 | } 125 | 126 | void IntelBluetoothFirmware::stop(IOService *provider) 127 | { 128 | XYLog("Driver Stop()\n"); 129 | PMstop(); 130 | super::stop(provider); 131 | } 132 | 133 | IOService * IntelBluetoothFirmware::probe(IOService *provider, SInt32 *score) 134 | { 135 | XYLog("Driver Probe()\n"); 136 | if (!super::probe(provider, score)) { 137 | XYLog("super probe failed\n"); 138 | return NULL; 139 | } 140 | m_pDevice = OSDynamicCast(IOUSBHostDevice, provider); 141 | if (!m_pDevice) { 142 | XYLog("is not usb device\n"); 143 | return NULL; 144 | } 145 | UInt16 vendorID = USBToHost16(m_pDevice->getDeviceDescriptor()->idVendor); 146 | UInt16 productID = USBToHost16(m_pDevice->getDeviceDescriptor()->idProduct); 147 | XYLog("name=%s, class=%s, vendorID=0x%04X, productID=0x%04X\n", m_pDevice->getName(), provider->metaClass->getClassName(), vendorID, productID); 148 | if (productID == 0x07dc || productID == 0x0a2a || productID == 0x0aa7) { 149 | currentType = kTypeGen1; 150 | } else if (productID == 0x0032 || productID == 0x0033 || productID == 0x0035 151 | || productID == 0x0036 || productID == 0x0038) { 152 | currentType = kTypeGen3; 153 | } else { 154 | currentType = kTypeGen2; 155 | } 156 | m_pDevice = NULL; 157 | return this; 158 | } 159 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothFirmware.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // IntelBluetoothFirmware.hpp 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/11/17. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #ifndef IntelBluetoothFirmware_H 15 | #define IntelBluetoothFirmware_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "BtIntel.h" 26 | 27 | enum BTType { 28 | kTypeGen1, 29 | kTypeGen2, 30 | kTypeGen3, 31 | } ; 32 | 33 | class IntelBluetoothFirmware : public IOService 34 | { 35 | OSDeclareDefaultStructors (IntelBluetoothFirmware) 36 | 37 | public: 38 | 39 | bool init(OSDictionary *dictionary = NULL) override; 40 | 41 | void free() override; 42 | 43 | bool start(IOService *provider) override; 44 | 45 | void stop(IOService *provider) override; 46 | 47 | IOService * probe(IOService *provider, SInt32 *score) override; 48 | 49 | IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) override; 50 | 51 | void cleanUp(); 52 | 53 | void publishReg(bool isSucceed, const char *fwName); 54 | 55 | private: 56 | BTType currentType; 57 | BtIntel *m_pBTIntel; 58 | IOUSBHostDevice* m_pDevice; 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen1.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothGen1.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "IntelBluetoothOpsGen1.hpp" 10 | #include "Log.h" 11 | #include "Hci.h" 12 | 13 | OSDefineMetaClassAndStructors(IntelBluetoothOpsGen1, BtIntel) 14 | 15 | bool IntelBluetoothOpsGen1:: 16 | setup() 17 | { 18 | const uint8_t *fw_ptr; 19 | bool disablePatch; 20 | IntelVersion ver; 21 | OSData *fwData = NULL; 22 | char fwname[64]; 23 | 24 | /* The controller has a bug with the first HCI command sent to it 25 | * returning number of completed commands as zero. This would stall the 26 | * command processing in the Bluetooth core. 27 | * 28 | * As a workaround, send HCI Reset command first which will reset the 29 | * number of completed commands and allow normal command processing 30 | * from now on. 31 | */ 32 | if (!hciReset()) { 33 | XYLog("sending initial HCI reset command failed\n"); 34 | return false; 35 | } 36 | 37 | /* Read Intel specific controller version first to allow selection of 38 | * which firmware file to load. 39 | * 40 | * The returned information are hardware variant and revision plus 41 | * firmware variant, revision and build number. 42 | */ 43 | if (!readVersion(&ver)) { 44 | XYLog("Read version failed: %d\n", __LINE__); 45 | return false; 46 | } 47 | 48 | XYLog("read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 49 | ver.hw_platform, ver.hw_variant, ver.hw_revision, 50 | ver.fw_variant, ver.fw_revision, ver.fw_build_num, 51 | ver.fw_build_ww, ver.fw_build_yy, ver.fw_patch_num); 52 | 53 | /* Opens the firmware patch file based on the firmware version read 54 | * from the controller. If it fails to open the matching firmware 55 | * patch file, it tries to open the default firmware patch file. 56 | * If no patch file is found, allow the device to operate without 57 | * a patch. 58 | */ 59 | fwData = getFirmware(&ver, fwname, sizeof(fwname)); 60 | 61 | strncpy(this->loadedFirmwareName, fwname, sizeof(this->loadedFirmwareName)); 62 | 63 | /* fw_patch_num indicates the version of patch the device currently 64 | * have. If there is no patch data in the device, it is always 0x00. 65 | * So, if it is other than 0x00, no need to patch the device again. 66 | */ 67 | if (ver.fw_patch_num) { 68 | XYLog("Intel device is already patched. patch num: %02x\n", ver.fw_patch_num); 69 | goto complete; 70 | } 71 | 72 | if (!fwData) { 73 | goto complete; 74 | } 75 | 76 | fw_ptr = (uint8_t *)fwData->getBytesNoCopy(); 77 | 78 | /* Enable the manufacturer mode of the controller. 79 | * Only while this mode is enabled, the driver can download the 80 | * firmware patch data and configuration parameters. 81 | */ 82 | if (!enterMfg()) { 83 | XYLog("Enter mfg failed: %d\n", __LINE__); 84 | OSSafeReleaseNULL(fwData); 85 | return false; 86 | } 87 | 88 | disablePatch = true; 89 | 90 | /* The firmware data file consists of list of Intel specific HCI 91 | * commands and its expected events. The first byte indicates the 92 | * type of the message, either HCI command or HCI event. 93 | * 94 | * It reads the command and its expected event from the firmware file, 95 | * and send to the controller. Once __hci_cmd_sync_ev() returns, 96 | * the returned event is compared with the event read from the firmware 97 | * file and it will continue until all the messages are downloaded to 98 | * the controller. 99 | * 100 | * Once the firmware patching is completed successfully, 101 | * the manufacturer mode is disabled with reset and activating the 102 | * downloaded patch. 103 | * 104 | * If the firmware patching fails, the manufacturer mode is 105 | * disabled with reset and deactivating the patch. 106 | * 107 | * If the default patch file is used, no reset is done when disabling 108 | * the manufacturer. 109 | */ 110 | while (fwData->getLength() > fw_ptr - (uint8_t *)fwData->getBytesNoCopy()) { 111 | if (!patching(fwData, &fw_ptr, &disablePatch)) 112 | goto exit_mfg_deactivate; 113 | } 114 | 115 | XYLog("Patch file download done\n"); 116 | 117 | OSSafeReleaseNULL(fwData); 118 | 119 | if (disablePatch) 120 | goto exit_mfg_disable; 121 | 122 | /* Patching completed successfully and disable the manufacturer mode 123 | * with reset and activate the downloaded firmware patches. 124 | */ 125 | if (!exitMfg(true, true)) { 126 | XYLog("Exit mfg failed: %d\n", __LINE__); 127 | return false; 128 | } 129 | 130 | /* Need build number for downloaded fw patches in 131 | * every power-on boot 132 | */ 133 | if (!readVersion(&ver)) { 134 | XYLog("Read version failed: %d\n", __LINE__); 135 | return false; 136 | } 137 | 138 | XYLog("Intel BT fw patch 0x%02x completed & activated\n", 139 | ver.fw_patch_num); 140 | 141 | goto complete; 142 | 143 | exit_mfg_disable: 144 | /* Disable the manufacturer mode without reset */ 145 | if (!exitMfg(false, false)) { 146 | XYLog("Exit mfg failed: %d\n", __LINE__); 147 | return false; 148 | } 149 | 150 | XYLog("Intel firmware patch completed\n"); 151 | goto complete; 152 | 153 | exit_mfg_deactivate: 154 | /* Patching failed. Disable the manufacturer mode with reset and 155 | * deactivate the downloaded firmware patches. 156 | */ 157 | if (!exitMfg(true, false)) { 158 | XYLog("Exit mfg failed %d\n", __LINE__); 159 | return false; 160 | } 161 | XYLog("Intel firmware patch completed and deactivated\n"); 162 | 163 | complete: 164 | OSSafeReleaseNULL(fwData); 165 | /* Set the event mask for Intel specific vendor events. This enables 166 | * a few extra events that are useful during general operation. 167 | */ 168 | setEventMaskMfg(false); 169 | 170 | return true; 171 | } 172 | 173 | bool IntelBluetoothOpsGen1:: 174 | shutdown() 175 | { 176 | return true; 177 | } 178 | 179 | bool IntelBluetoothOpsGen1:: 180 | getFirmwareName(char *fwname, size_t len) 181 | { 182 | strncpy(fwname, this->loadedFirmwareName, len - 1); 183 | fwname[len - 1] = '\0'; 184 | return true; 185 | } 186 | 187 | bool IntelBluetoothOpsGen1:: 188 | hciReset() 189 | { 190 | HciCommandHdr cmd = { 191 | .opcode = OSSwapHostToLittleInt16(HCI_OP_RESET), 192 | .len = 0, 193 | }; 194 | 195 | return intelSendHCISync(&cmd, NULL, 0, NULL, HCI_INIT_TIMEOUT); 196 | } 197 | 198 | OSData *IntelBluetoothOpsGen1:: 199 | getFirmware(IntelVersion *ver, char *fwname, size_t len) 200 | { 201 | OSData *fwData; 202 | 203 | snprintf(fwname, len, 204 | "ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq", 205 | ver->hw_platform, ver->hw_variant, ver->hw_revision, 206 | ver->fw_variant, ver->fw_revision, ver->fw_build_num, 207 | ver->fw_build_ww, ver->fw_build_yy); 208 | fwData = requestFirmwareData(fwname); 209 | if (!fwData) { 210 | XYLog("failed to open Intel firmware file: %s\n", fwname); 211 | /* If the correct firmware patch file is not found, use the 212 | * default firmware patch file instead 213 | */ 214 | snprintf(fwname, len, "ibt-hw-%x.%x.bseq", 215 | ver->hw_platform, ver->hw_variant); 216 | fwData = requestFirmwareData(fwname); 217 | } 218 | XYLog("Intel Bluetooth firmware file: %s\n", fwname); 219 | return fwData; 220 | } 221 | 222 | bool IntelBluetoothOpsGen1:: 223 | patching(OSData *fwData, const uint8_t **fw_ptr, bool *disablePatch) 224 | { 225 | const uint8_t *cmdParam; 226 | FWCommandHdr *cmd = NULL; 227 | const uint8_t *evtParam = NULL; 228 | HciEventHdr *evt = NULL; 229 | uint8_t sendBuf[CMD_BUF_MAX_SIZE]; 230 | uint8_t respBuf[CMD_BUF_MAX_SIZE]; 231 | HciCommandHdr *hciCmd = (HciCommandHdr *)sendBuf; 232 | HciResponse *resp = (HciResponse *)respBuf; 233 | uint32_t actRespLen = 0; 234 | int remain = (int)(fwData->getLength() - (*fw_ptr - (uint8_t *)fwData->getBytesNoCopy())); 235 | 236 | /* The first byte indicates the types of the patch command or event. 237 | * 0x01 means HCI command and 0x02 is HCI event. If the first bytes 238 | * in the current firmware buffer doesn't start with 0x01 or 239 | * the size of remain buffer is smaller than HCI command header, 240 | * the firmware file is corrupted and it should stop the patching 241 | * process. 242 | */ 243 | if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) { 244 | XYLog("Intel fw corrupted: invalid cmd read\n"); 245 | return false; 246 | } 247 | (*fw_ptr)++; 248 | remain--; 249 | 250 | cmd = (FWCommandHdr *)(*fw_ptr); 251 | *fw_ptr += sizeof(*cmd); 252 | remain -= sizeof(*cmd); 253 | 254 | /* Ensure that the remain firmware data is long enough than the length 255 | * of command parameter. If not, the firmware file is corrupted. 256 | */ 257 | if (remain < cmd->len) { 258 | XYLog("Intel fw corrupted: invalid cmd len\n"); 259 | return false; 260 | } 261 | /* If there is a command that loads a patch in the firmware 262 | * file, then enable the patch upon success, otherwise just 263 | * disable the manufacturer mode, for example patch activation 264 | * is not required when the default firmware patch file is used 265 | * because there are no patch data to load. 266 | */ 267 | if (*disablePatch && OSSwapLittleToHostInt16(cmd->opcode) == 0xfc8e) 268 | *disablePatch = false; 269 | 270 | cmdParam = *fw_ptr; 271 | *fw_ptr += cmd->len; 272 | remain -= cmd->len; 273 | 274 | /* This reads the expected events when the above command is sent to the 275 | * device. Some vendor commands expects more than one events, for 276 | * example command status event followed by vendor specific event. 277 | * For this case, it only keeps the last expected event. so the command 278 | * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of 279 | * last expected event. 280 | */ 281 | while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) { 282 | (*fw_ptr)++; 283 | remain--; 284 | 285 | evt = (HciEventHdr *)(*fw_ptr); 286 | *fw_ptr += sizeof(*evt); 287 | remain -= sizeof(*evt); 288 | 289 | if (remain < evt->len) { 290 | XYLog("Intel fw corrupted: invalid evt len\n"); 291 | return false; 292 | } 293 | 294 | evtParam = *fw_ptr; 295 | *fw_ptr += evt->len; 296 | remain -= evt->len; 297 | } 298 | 299 | /* Every HCI commands in the firmware file has its correspond event. 300 | * If event is not found or remain is smaller than zero, the firmware 301 | * file is corrupted. 302 | */ 303 | if (!evt || !evtParam || remain < 0) { 304 | XYLog("Intel fw corrupted: invalid evt read\n"); 305 | return false; 306 | } 307 | 308 | memset(sendBuf, 0, sizeof(sendBuf)); 309 | memset(respBuf, 0, sizeof(respBuf)); 310 | hciCmd->opcode = OSSwapLittleToHostInt16(cmd->opcode); 311 | hciCmd->len = cmd->len; 312 | memcpy(hciCmd->data, cmdParam, hciCmd->len); 313 | 314 | if (!intelSendHCISyncEvent(hciCmd, resp, sizeof(respBuf), &actRespLen, evt->evt, HCI_INIT_TIMEOUT)) { 315 | XYLog("sending Intel patch command (0x%4.4x) failed\n", hciCmd->opcode); 316 | return false; 317 | } 318 | 319 | return true; 320 | } 321 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen1.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothGen1.hpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #ifndef IntelBluetoothOpsGen1_hpp 10 | #define IntelBluetoothOpsGen1_hpp 11 | 12 | #include "BtIntel.h" 13 | 14 | class IntelBluetoothOpsGen1 : public BtIntel { 15 | OSDeclareDefaultStructors(IntelBluetoothOpsGen1) 16 | 17 | public: 18 | 19 | virtual bool setup() override; 20 | 21 | virtual bool shutdown() override; 22 | 23 | virtual bool getFirmwareName(char *fwname, size_t len) override; 24 | 25 | private: 26 | 27 | bool patching(OSData *fwData, const uint8_t **fw_ptr, bool *disablePatch); 28 | 29 | bool hciReset(); 30 | 31 | OSData *getFirmware(IntelVersion *ver, char *, size_t); 32 | 33 | private: 34 | char loadedFirmwareName[64]; 35 | 36 | }; 37 | 38 | #endif /* IntelBluetoothOpsGen1_hpp */ 39 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothOpsGen2.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "IntelBluetoothOpsGen2.hpp" 10 | #include "Log.h" 11 | 12 | OSDefineMetaClassAndStructors(IntelBluetoothOpsGen2, BtIntel) 13 | 14 | bool IntelBluetoothOpsGen2:: 15 | bootloaderSetup(IntelVersion *ver) 16 | { 17 | IntelVersion newVer; 18 | IntelBootParams params; 19 | uint32_t bootParams; 20 | char ddcname[64]; 21 | 22 | /* Set the default boot parameter to 0x0 and it is updated to 23 | * SKU specific boot parameter after reading Intel_Write_Boot_Params 24 | * command while downloading the firmware. 25 | */ 26 | bootParams = 0x00000000; 27 | 28 | if (!downloadFirmware(ver, ¶ms, &bootParams)) { 29 | return false; 30 | } 31 | 32 | /* controller is already having an operational firmware */ 33 | if (ver->fw_variant == 0x23) { 34 | XYLog("Frimware is already running, finishing\n"); 35 | goto finish; 36 | } 37 | 38 | if (!intelBoot(bootParams)) { 39 | XYLog("Boot failed\n"); 40 | return false; 41 | } 42 | 43 | if (!getFirmware(ver, ¶ms, ddcname, sizeof(ddcname), "ddc")) { 44 | XYLog("Unsupported Intel firmware naming\n"); 45 | } else { 46 | /* Once the device is running in operational mode, it needs to 47 | * apply the device configuration (DDC) parameters. 48 | * 49 | * The device can work without DDC parameters, so even if it 50 | * fails to load the file, no need to fail the setup. 51 | */ 52 | loadDDCConfig(ddcname); 53 | } 54 | 55 | /* Read the Intel version information after loading the FW */ 56 | if (!readVersion(&newVer)) { 57 | return false; 58 | } 59 | 60 | intelVersionInfo(&newVer); 61 | 62 | finish: 63 | 64 | /* Set the event mask for Intel specific vendor events. This enables 65 | * a few extra events that are useful during general operation. It 66 | * does not enable any debugging related events. 67 | * 68 | * The device will function correctly without these events enabled 69 | * and thus no need to fail the setup. 70 | */ 71 | setEventMask(false); 72 | 73 | return true; 74 | } 75 | 76 | bool IntelBluetoothOpsGen2:: 77 | setup() 78 | { 79 | IntelVersion ver; 80 | 81 | /* Read the Intel version information to determine if the device 82 | * is in bootloader mode or if it already has operational firmware 83 | * loaded. 84 | */ 85 | if (!readVersion(&ver)) { 86 | XYLog("Intel Read version failed\n"); 87 | resetToBootloader(); 88 | return false; 89 | } 90 | 91 | if (!intelVersionInfo(&ver)) { 92 | return false; 93 | } 94 | 95 | return bootloaderSetup(&ver); 96 | } 97 | 98 | bool IntelBluetoothOpsGen2:: 99 | downloadFirmware(IntelVersion *ver, IntelBootParams *params, uint32_t *bootParams) 100 | { 101 | OSData *fwData; 102 | char fwname[64]; 103 | IOReturn ior; 104 | uint32_t actSize = 0; 105 | uint8_t buf[CMD_BUF_MAX_SIZE]; 106 | HciResponse *resp = (HciResponse *)buf; 107 | bool firmwareMode = false; 108 | bool ret = true; 109 | 110 | if (!ver || !params) { 111 | return false; 112 | } 113 | 114 | /* The firmware variant determines if the device is in bootloader 115 | * mode or is running operational firmware. The value 0x06 identifies 116 | * the bootloader and the value 0x23 identifies the operational 117 | * firmware. 118 | * 119 | * When the operational firmware is already present, then only 120 | * the check for valid Bluetooth device address is needed. This 121 | * determines if the device will be added as configured or 122 | * unconfigured controller. 123 | * 124 | * It is not possible to use the Secure Boot Parameters in this 125 | * case since that command is only available in bootloader mode. 126 | */ 127 | if (ver->fw_variant == 0x23) { 128 | 129 | firmwareMode = true; 130 | 131 | /* SfP and WsP don't seem to update the firmware version on file 132 | * so version checking is currently possible. 133 | */ 134 | switch (ver->hw_variant) { 135 | case 0x0b: /* SfP */ 136 | case 0x0c: /* WsP */ 137 | return true; 138 | } 139 | 140 | /* Proceed to download to check if the version matches */ 141 | goto download; 142 | } 143 | 144 | /* Read the secure boot parameters to identify the operating 145 | * details of the bootloader. 146 | */ 147 | if (!readBootParams(params)) { 148 | return false; 149 | } 150 | 151 | /* It is required that every single firmware fragment is acknowledged 152 | * with a command complete event. If the boot parameters indicate 153 | * that this bootloader does not send them, then abort the setup. 154 | */ 155 | if (params->limited_cce != 0x00) { 156 | XYLog("Unsupported Intel firmware loading method (%u)\n", 157 | params->limited_cce); 158 | return false; 159 | } 160 | 161 | download: 162 | /* With this Intel bootloader only the hardware variant and device 163 | * revision information are used to select the right firmware for SfP 164 | * and WsP. 165 | * 166 | * The firmware filename is ibt--.sfi. 167 | * 168 | * Currently the supported hardware variants are: 169 | * 11 (0x0b) for iBT3.0 (LnP/SfP) 170 | * 12 (0x0c) for iBT3.5 (WsP) 171 | * 172 | * For ThP/JfP and for future SKU's, the FW name varies based on HW 173 | * variant, HW revision and FW revision, as these are dependent on CNVi 174 | * and RF Combination. 175 | * 176 | * 17 (0x11) for iBT3.5 (JfP) 177 | * 18 (0x12) for iBT3.5 (ThP) 178 | * 179 | * The firmware file name for these will be 180 | * ibt---.sfi. 181 | * 182 | */ 183 | if (!getFirmware(ver, params, fwname, sizeof(fwname), "sfi")) { 184 | if (firmwareMode) { 185 | /* Firmware has already been loaded */ 186 | return true; 187 | } 188 | XYLog("Unsupported Intel firmware naming\n"); 189 | return false; 190 | } 191 | 192 | strncpy(this->loadedFirmwareName, fwname, sizeof(this->loadedFirmwareName)); 193 | 194 | fwData = requestFirmwareData(fwname, true); 195 | if (!fwData) { 196 | if (firmwareMode) { 197 | /* Firmware has already been loaded */ 198 | return true; 199 | } 200 | XYLog("Failed to load Intel firmware file %s\n", fwname); 201 | return false; 202 | } 203 | 204 | if (fwData->getLength() < 644) { 205 | XYLog("Invalid size of firmware file (%zu)\n", 206 | (size_t)fwData->getLength()); 207 | ret = false; 208 | goto done; 209 | } 210 | 211 | /* Start firmware downloading and get boot parameter */ 212 | if ((ior = downloadFirmwareData(ver, fwData, bootParams)) != kIOReturnSuccess) { 213 | if (ior == -EALREADY) { 214 | /* Firmware has already been loaded */ 215 | ret = true; 216 | goto done; 217 | } 218 | 219 | /* When FW download fails, send Intel Reset to retry 220 | * FW download. 221 | */ 222 | resetToBootloader(); 223 | goto done; 224 | } 225 | 226 | /* Before switching the device into operational mode and with that 227 | * booting the loaded firmware, wait for the bootloader notification 228 | * that all fragments have been successfully received. 229 | * 230 | * When the event processing receives the notification, then the 231 | * BTUSB_DOWNLOADING flag will be cleared. 232 | * 233 | * The firmware loading should not take longer than 5 seconds 234 | * and thus just timeout if that happens and fail the setup 235 | * of this device. 236 | */ 237 | memset(buf, 0, sizeof(buf)); 238 | ior = m_pUSBDeviceController->interruptPipeRead(resp, sizeof(buf), &actSize, 5000); 239 | if (ior != kIOReturnSuccess) { 240 | XYLog("waiting for firmware download done timeout\n"); 241 | resetToBootloader(); 242 | ret = false; 243 | goto done; 244 | } 245 | 246 | if (resp->evt.evt == 0xff && resp->numCommands == 0x06) { 247 | XYLog("Notify: Firmware download done\n"); 248 | goto done; 249 | } 250 | 251 | ret = false; 252 | 253 | done: 254 | OSSafeReleaseNULL(fwData); 255 | return ret; 256 | } 257 | 258 | IOReturn IntelBluetoothOpsGen2:: 259 | downloadFirmwareData(IntelVersion *ver, OSData *fwData, uint32_t *bootParams) 260 | { 261 | /* SfP and WsP don't seem to update the firmware version on file 262 | * so version checking is currently not possible. 263 | */ 264 | switch (ver->hw_variant) { 265 | case 0x0b: /* SfP */ 266 | case 0x0c: /* WsP */ 267 | /* Skip version checking */ 268 | break; 269 | default: 270 | 271 | /* Skip download if firmware has the same version */ 272 | if (firmwareVersion(ver->fw_build_num, 273 | ver->fw_build_ww, ver->fw_build_yy, 274 | fwData, bootParams)) { 275 | XYLog("Firmware already loaded\n"); 276 | /* Return -EALREADY to indicate that the firmware has 277 | * already been loaded. 278 | */ 279 | return -EALREADY; 280 | } 281 | } 282 | 283 | /* The firmware variant determines if the device is in bootloader 284 | * mode or is running operational firmware. The value 0x06 identifies 285 | * the bootloader and the value 0x23 identifies the operational 286 | * firmware. 287 | * 288 | * If the firmware version has changed that means it needs to be reset 289 | * to bootloader when operational so the new firmware can be loaded. 290 | */ 291 | if (ver->fw_variant == 0x23) { 292 | XYLog("Unsupported fw variant: %d\n", ver->fw_variant); 293 | return kIOReturnInvalid; 294 | } 295 | 296 | if (!rsaHeaderSecureSend(fwData)) { 297 | XYLog("Send RSA header failed\n"); 298 | return kIOReturnError; 299 | } 300 | 301 | return downloadFirmwarePayload(fwData, RSA_HEADER_LEN) ? kIOReturnSuccess : kIOReturnError; 302 | } 303 | 304 | bool IntelBluetoothOpsGen2:: 305 | getFirmware(IntelVersion *ver, IntelBootParams *params, 306 | char *name, size_t len, const char *suffix) 307 | { 308 | switch (ver->hw_variant) { 309 | case 0x0b: /* SfP */ 310 | case 0x0c: /* WsP */ 311 | snprintf(name, len, "ibt-%u-%u.%s", 312 | OSSwapLittleToHostInt16(ver->hw_variant), 313 | OSSwapLittleToHostInt16(params->dev_revid), 314 | suffix); 315 | break; 316 | case 0x11: /* JfP */ 317 | case 0x12: /* ThP */ 318 | case 0x13: /* HrP */ 319 | case 0x14: /* CcP */ 320 | snprintf(name, len, "ibt-%u-%u-%u.%s", 321 | OSSwapLittleToHostInt16(ver->hw_variant), 322 | OSSwapLittleToHostInt16(ver->hw_revision), 323 | OSSwapLittleToHostInt16(ver->fw_revision), 324 | suffix); 325 | break; 326 | default: 327 | return false; 328 | } 329 | 330 | return true; 331 | } 332 | 333 | bool IntelBluetoothOpsGen2:: 334 | rsaHeaderSecureSend(OSData *fwData) 335 | { 336 | /* Start the firmware download transaction with the Init fragment 337 | * represented by the 128 bytes of CSS header. 338 | */ 339 | XYLog("send firmware header\n"); 340 | if (!securedSend(0x00, 128, (const uint8_t *)fwData->getBytesNoCopy())) { 341 | XYLog("Failed to send firmware header\n"); 342 | return false; 343 | } 344 | XYLog("send firmware header done\n"); 345 | 346 | /* Send the 256 bytes of public key information from the firmware 347 | * as the PKey fragment. 348 | */ 349 | XYLog("send firmware pkey\n"); 350 | if (!securedSend(0x03, 256, (const uint8_t *)fwData->getBytesNoCopy() + 128)) { 351 | XYLog("Failed to send firmware pkey\n"); 352 | return false; 353 | } 354 | XYLog("send firmware pkey done\n"); 355 | 356 | /* Send the 256 bytes of signature information from the firmware 357 | * as the Sign fragment. 358 | */ 359 | XYLog("send firmware signature\n"); 360 | if (!securedSend(0x02, 256, (const uint8_t *)fwData->getBytesNoCopy() + 388)) { 361 | XYLog("Failed to send firmware signature\n"); 362 | return false; 363 | } 364 | XYLog("send firmware signature done\n"); 365 | 366 | return true; 367 | } 368 | 369 | bool IntelBluetoothOpsGen2:: 370 | downloadFirmwarePayload(OSData *fwData, size_t offset) 371 | { 372 | XYLog("send firmware payload\n"); 373 | uint32_t frag_len; 374 | bool ret = true; 375 | const uint8_t *fw_ptr = (uint8_t *)fwData->getBytesNoCopy() + offset; 376 | frag_len = 0; 377 | 378 | while (fw_ptr - (uint8_t *)fwData->getBytesNoCopy() < fwData->getLength()) { 379 | HciCommandHdr *cmd = (HciCommandHdr *)(fw_ptr + frag_len); 380 | 381 | frag_len += sizeof(*cmd) + cmd->len; 382 | 383 | /* The parameter length of the secure send command requires 384 | * a 4 byte alignment. It happens so that the firmware file 385 | * contains proper Intel_NOP commands to align the fragments 386 | * as needed. 387 | * 388 | * Send set of commands with 4 byte alignment from the 389 | * firmware data buffer as a single Data fragement. 390 | */ 391 | if (!(frag_len % 4)) { 392 | if (!securedSend(0x01, frag_len, fw_ptr)) { 393 | XYLog("Failed to send firmware data\n"); 394 | ret = false; 395 | goto done; 396 | } 397 | 398 | fw_ptr += frag_len; 399 | frag_len = 0; 400 | } 401 | } 402 | 403 | done: 404 | XYLog("send firmware payload done\n"); 405 | return ret; 406 | } 407 | 408 | bool IntelBluetoothOpsGen2:: 409 | firmwareVersion(uint8_t num, uint8_t ww, uint8_t yy, OSData *fwData, uint32_t *bootAddr) 410 | { 411 | const uint8_t *fw_ptr = (const uint8_t *)fwData->getBytesNoCopy(); 412 | 413 | while (fw_ptr - (uint8_t *)fwData->getBytesNoCopy() < fwData->getLength()) { 414 | FWCommandHdr *cmd = (FWCommandHdr *)(fw_ptr); 415 | 416 | /* Each SKU has a different reset parameter to use in the 417 | * HCI_Intel_Reset command and it is embedded in the firmware 418 | * data. So, instead of using static value per SKU, check 419 | * the firmware data and save it for later use. 420 | */ 421 | if (OSSwapLittleToHostConstInt16(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) { 422 | struct cmd_write_boot_params *params; 423 | 424 | params = (struct cmd_write_boot_params *)(fw_ptr + sizeof(*cmd)); 425 | 426 | *bootAddr = OSSwapLittleToHostConstInt32(params->boot_addr); 427 | 428 | XYLog("Boot Address: 0x%x\n", *bootAddr); 429 | 430 | XYLog("Firmware Version: %u-%u.%u\n", 431 | params->fw_build_num, params->fw_build_ww, 432 | params->fw_build_yy); 433 | 434 | return (num == params->fw_build_num && 435 | ww == params->fw_build_ww && 436 | yy == params->fw_build_yy); 437 | } 438 | 439 | fw_ptr += sizeof(*cmd) + cmd->len; 440 | } 441 | 442 | return false; 443 | } 444 | 445 | bool IntelBluetoothOpsGen2:: 446 | shutdown() 447 | { 448 | return true; 449 | } 450 | 451 | bool IntelBluetoothOpsGen2:: 452 | getFirmwareName(char *fwname, size_t len) 453 | { 454 | strncpy(fwname, this->loadedFirmwareName, len - 1); 455 | fwname[len - 1] = '\0'; 456 | return true; 457 | } 458 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen2.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothOpsGen2.hpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #ifndef IntelBluetoothOpsGen2_hpp 10 | #define IntelBluetoothOpsGen2_hpp 11 | 12 | #include "BtIntel.h" 13 | 14 | #define CMD_WRITE_BOOT_PARAMS 0xfc0e 15 | struct cmd_write_boot_params { 16 | uint32_t boot_addr; 17 | uint8_t fw_build_num; 18 | uint8_t fw_build_ww; 19 | uint8_t fw_build_yy; 20 | } __attribute__((packed)); 21 | 22 | class IntelBluetoothOpsGen2 : public BtIntel { 23 | OSDeclareDefaultStructors(IntelBluetoothOpsGen2) 24 | 25 | public: 26 | 27 | virtual bool setup() override; 28 | 29 | virtual bool shutdown() override; 30 | 31 | virtual bool getFirmwareName(char *fwname, size_t len) override; 32 | 33 | protected: 34 | 35 | bool downloadFirmwarePayload(OSData *fwData, size_t offset); 36 | 37 | bool rsaHeaderSecureSend(OSData *fwData); 38 | 39 | bool firmwareVersion(uint8_t num, uint8_t ww, uint8_t yy, OSData *fwData, uint32_t *bootAddr); 40 | 41 | bool bootloaderSetup(IntelVersion *ver); 42 | 43 | private: 44 | 45 | bool getFirmware(IntelVersion *ver, IntelBootParams *params, char *name, size_t len, const char *suffix); 46 | 47 | IOReturn downloadFirmwareData(IntelVersion *ver, OSData *fwData, uint32_t *bootParams); 48 | 49 | bool downloadFirmware(IntelVersion *ver, IntelBootParams *params, uint32_t *bootParams); 50 | 51 | private: 52 | char loadedFirmwareName[64]; 53 | 54 | }; 55 | 56 | #endif /* IntelBluetoothOpsGen2_hpp */ 57 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothOpsGen3.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "IntelBluetoothOpsGen3.hpp" 10 | #include "Log.h" 11 | #include "linux.h" 12 | 13 | OSDefineMetaClassAndStructors(IntelBluetoothOpsGen3, IntelBluetoothOpsGen2) 14 | 15 | int IntelBluetoothOpsGen3:: 16 | readVersionTyP(void *version) 17 | { 18 | uint8_t buf[CMD_BUF_MAX_SIZE], temp[CMD_BUF_MAX_SIZE]; 19 | uint actLen = 0; 20 | HciCommandHdr *cmd = (HciCommandHdr *)buf; 21 | HciResponse *resp = (HciResponse *)temp; 22 | 23 | memset(temp, 0, sizeof(temp)); 24 | cmd->opcode = OSSwapHostToLittleInt16(0xfc05); 25 | cmd->len = 1; 26 | cmd->data[0] = 0xFF; 27 | if (!intelSendHCISync(cmd, resp, sizeof(buf), &actLen, HCI_CMD_TIMEOUT)) { 28 | XYLog("Reading Intel version information failed\n"); 29 | return 0; 30 | } 31 | 32 | if (actLen - 5 <= 0 || actLen - 5 > CMD_BUF_MAX_SIZE) { 33 | XYLog("Intel version size invalid (act: %d)\n", actLen); 34 | return 0; 35 | } 36 | 37 | memcpy(version, resp->data, actLen - 5); 38 | 39 | return actLen - 5; 40 | } 41 | 42 | bool IntelBluetoothOpsGen3:: 43 | bootloaderSetupTLV(IntelVersionTLV *verTLV) 44 | { 45 | uint32_t bootParams; 46 | char ddcname[64]; 47 | IntelVersionTLV newVerTLV; 48 | 49 | /* Set the default boot parameter to 0x0 and it is updated to 50 | * SKU specific boot parameter after reading Intel_Write_Boot_Params 51 | * command while downloading the firmware. 52 | */ 53 | bootParams = 0x00000000; 54 | 55 | if (!downloadFirmware(verTLV, &bootParams)) { 56 | XYLog("Download firmware failed\n"); 57 | return false; 58 | } 59 | 60 | /* check if controller is already having an operational firmware */ 61 | if (verTLV->img_type == 0x03) { 62 | XYLog("Frimware is already running, finishing\n"); 63 | goto finish; 64 | } 65 | 66 | if (!intelBoot(bootParams)) { 67 | XYLog("Boot failed\n"); 68 | return false; 69 | } 70 | 71 | getFirmware(verTLV, ddcname, sizeof(ddcname), "ddc"); 72 | 73 | /* Once the device is running in operational mode, it needs to 74 | * apply the device configuration (DDC) parameters. 75 | * 76 | * The device can work without DDC parameters, so even if it 77 | * fails to load the file, no need to fail the setup. 78 | */ 79 | loadDDCConfig(ddcname); 80 | 81 | /* Read the Intel version information after loading the FW */ 82 | if (!readVersionTLV(&newVerTLV)) { 83 | XYLog("Intel Read TLV version failed %d\n", __LINE__); 84 | return false; 85 | } 86 | 87 | versionInfoTLV(&newVerTLV); 88 | 89 | finish: 90 | /* Set the event mask for Intel specific vendor events. This enables 91 | * a few extra events that are useful during general operation. It 92 | * does not enable any debugging related events. 93 | * 94 | * The device will function correctly without these events enabled 95 | * and thus no need to fail the setup. 96 | */ 97 | setEventMask(false); 98 | 99 | return true; 100 | } 101 | 102 | bool IntelBluetoothOpsGen3:: 103 | setup() 104 | { 105 | uint8_t v[CMD_BUF_MAX_SIZE]; 106 | IntelVersion *verPtr = reinterpret_cast(v); 107 | IntelVersionTLV verTLV; 108 | 109 | /* Starting from TyP device, the command parameter and response are 110 | * changed even though the OCF for HCI_Intel_Read_Version command 111 | * remains same. The legacy devices can handle even if the 112 | * command has a parameter and returns a correct version information. 113 | * So, it uses new format to support both legacy and new format. 114 | */ 115 | int actLen = readVersionTyP(verPtr); 116 | 117 | if (actLen <= 0) { 118 | XYLog("Reading Intel version command failed\n"); 119 | return false; 120 | } 121 | 122 | /* For Legacy device, check the HW platform value and size */ 123 | if (actLen == sizeof(IntelVersion)) { 124 | XYLog("Read the legacy Intel version information\n"); 125 | 126 | /* Display version information */ 127 | intelVersionInfo(verPtr); 128 | 129 | /* Check for supported iBT hardware variants of this firmware 130 | * loading method. 131 | * 132 | * This check has been put in place to ensure correct forward 133 | * compatibility options when newer hardware variants come 134 | * along. 135 | */ 136 | 137 | switch (verPtr->hw_variant) { 138 | case 0x0b: /* SfP */ 139 | case 0x0c: /* WsP */ 140 | case 0x11: /* JfP */ 141 | case 0x12: /* ThP */ 142 | case 0x13: /* HrP */ 143 | case 0x14: /* CcP */ 144 | 145 | if (!bootloaderSetup(verPtr)) { 146 | return false; 147 | } 148 | break; 149 | 150 | default: 151 | XYLog("Unsupported Intel hw variant (%u)\n", verPtr->hw_variant); 152 | return false; 153 | } 154 | 155 | return true; 156 | } 157 | 158 | /* memset ver_tlv to start with clean state as few fields are exclusive 159 | * to bootloader mode and are not populated in operational mode 160 | */ 161 | memset(&verTLV, 0, sizeof(verTLV)); 162 | 163 | if (!parseVersionTLV(&verTLV, v, actLen)) { 164 | XYLog("Failed to parse TLV version information\n"); 165 | return false; 166 | } 167 | 168 | if (INTEL_HW_PLATFORM(verTLV.cnvi_bt) != 0x37) { 169 | XYLog("Unsupported Intel hardware platform (0x%2x)\n", 170 | INTEL_HW_PLATFORM(verTLV.cnvi_bt)); 171 | // TODO: We found that the Gen 2 bluetooth may return different size with IntelVersion when in OPERATIONAL mode, then the code will go here, considering we will not attach the really unsupported device to this driver, so we fake it as firmware loaded done here. 172 | return true; 173 | } 174 | 175 | /* Check for supported iBT hardware variants of this firmware 176 | * loading method. 177 | * 178 | * This check has been put in place to ensure correct forward 179 | * compatibility options when newer hardware variants come 180 | * along. 181 | */ 182 | switch (INTEL_HW_VARIANT(verTLV.cnvi_bt)) { 183 | case 0x11: /* JfP */ 184 | case 0x12: /* ThP */ 185 | case 0x13: /* HrP */ 186 | case 0x14: /* CcP */ 187 | 188 | XYLog("Legacy bootloader with new firmware\n"); 189 | 190 | /* Some legacy bootloader devices starting from JfP, 191 | * the operational firmware supports both old and TLV based 192 | * HCI_Intel_Read_Version command based on the command 193 | * parameter. 194 | * 195 | * For upgrading firmware case, the TLV based version cannot 196 | * be used because the firmware filename for legacy bootloader 197 | * is based on the old format. 198 | * 199 | * Also, it is not easy to convert TLV based version from the 200 | * legacy version format. 201 | * 202 | * So, as a workaround for those devices, use the legacy 203 | * HCI_Intel_Read_Version to get the version information and 204 | * run the legacy bootloader setup. 205 | */ 206 | if (!readVersion(verPtr)) { 207 | XYLog("Intel Read version failed\n"); 208 | return false; 209 | } 210 | 211 | if (!bootloaderSetup(verPtr)) { 212 | return false; 213 | } 214 | break; 215 | case 0x17: 216 | case 0x18: 217 | case 0x19: 218 | case 0x1b: 219 | case 0x1c: 220 | /* Display version information of TLV type */ 221 | versionInfoTLV(&verTLV); 222 | 223 | if (!bootloaderSetupTLV(&verTLV)) { 224 | return false; 225 | } 226 | break; 227 | default: 228 | XYLog("Unsupported Intel hw variant (%u)\n", 229 | INTEL_HW_VARIANT(verTLV.cnvi_bt)); 230 | return false; 231 | } 232 | 233 | return true; 234 | } 235 | 236 | bool IntelBluetoothOpsGen3:: 237 | downloadFirmware(IntelVersionTLV *ver, uint32_t *bootParams) 238 | { 239 | char fwname[64]; 240 | OSData *fwData = NULL; 241 | IOReturn ior; 242 | uint32_t actSize = 0; 243 | uint8_t buf[CMD_BUF_MAX_SIZE]; 244 | HciResponse *resp = (HciResponse *)buf; 245 | bool firmwareMode = false; 246 | bool ret = true; 247 | 248 | if (!ver || !bootParams) { 249 | return false; 250 | } 251 | 252 | /* The firmware variant determines if the device is in bootloader 253 | * mode or is running operational firmware. The value 0x03 identifies 254 | * the bootloader and the value 0x23 identifies the operational 255 | * firmware. 256 | * 257 | * When the operational firmware is already present, then only 258 | * the check for valid Bluetooth device address is needed. This 259 | * determines if the device will be added as configured or 260 | * unconfigured controller. 261 | * 262 | * It is not possible to use the Secure Boot Parameters in this 263 | * case since that command is only available in bootloader mode. 264 | */ 265 | if (ver->img_type == 0x03) { 266 | firmwareMode = true; 267 | } 268 | 269 | getFirmware(ver, fwname, sizeof(fwname), "sfi"); 270 | 271 | strncpy(this->loadedFirmwareName, fwname, sizeof(this->loadedFirmwareName)); 272 | 273 | fwData = requestFirmwareData(fwname, true); 274 | if (!fwData) { 275 | if (firmwareMode) { 276 | /* Firmware has already been loaded */ 277 | return true; 278 | } 279 | XYLog("Failed to load Intel firmware file %s\n", fwname); 280 | return false; 281 | } 282 | 283 | XYLog("Found device firmware: %s\n", fwname); 284 | 285 | if (fwData->getLength() < 644) { 286 | XYLog("Invalid size of firmware file (%zu)", 287 | (size_t)fwData->getLength()); 288 | ret = false; 289 | goto done; 290 | } 291 | 292 | /* Start firmware downloading and get boot parameter */ 293 | if ((ior = downloadFirmwareData(ver, fwData, bootParams, 294 | INTEL_HW_VARIANT(ver->cnvi_bt), ver->sbe_type)) != kIOReturnSuccess) { 295 | if (ior == -EALREADY) { 296 | /* Firmware has already been loaded */ 297 | ret = true; 298 | goto done; 299 | } 300 | 301 | /* When FW download fails, send Intel Reset to retry 302 | * FW download. 303 | */ 304 | resetToBootloader(); 305 | goto done; 306 | } 307 | 308 | /* Before switching the device into operational mode and with that 309 | * booting the loaded firmware, wait for the bootloader notification 310 | * that all fragments have been successfully received. 311 | * 312 | * When the event processing receives the notification, then the 313 | * BTUSB_DOWNLOADING flag will be cleared. 314 | * 315 | * The firmware loading should not take longer than 5 seconds 316 | * and thus just timeout if that happens and fail the setup 317 | * of this device. 318 | */ 319 | memset(buf, 0, sizeof(buf)); 320 | ior = m_pUSBDeviceController->interruptPipeRead(resp, sizeof(buf), &actSize, 5000); 321 | if (ior != kIOReturnSuccess) { 322 | XYLog("waiting for firmware download done timeout\n"); 323 | resetToBootloader(); 324 | ret = false; 325 | goto done; 326 | } 327 | 328 | if (resp->evt.evt == 0xff && resp->numCommands == 0x06) { 329 | XYLog("Notify: Firmware download done\n"); 330 | goto done; 331 | } 332 | 333 | ret = false; 334 | 335 | done: 336 | OSSafeReleaseNULL(fwData); 337 | return ret; 338 | } 339 | 340 | IOReturn IntelBluetoothOpsGen3:: 341 | downloadFirmwareData(IntelVersionTLV *ver, OSData *fwData, uint32_t *bootParams, uint8_t hwVariant, uint8_t sbeType) 342 | { 343 | uint32_t cssHeaderVer; 344 | 345 | /* Skip download if firmware has the same version */ 346 | if (firmwareVersion(ver->min_fw_build_nn, 347 | ver->min_fw_build_cw, 348 | ver->min_fw_build_yy, 349 | fwData, bootParams)) { 350 | XYLog("Firmware already loaded\n"); 351 | /* Return -EALREADY to indicate that firmware has 352 | * already been loaded. 353 | */ 354 | return -EALREADY; 355 | } 356 | 357 | /* The firmware variant determines if the device is in bootloader 358 | * mode or is running operational firmware. The value 0x01 identifies 359 | * the bootloader and the value 0x03 identifies the operational 360 | * firmware. 361 | * 362 | * If the firmware version has changed that means it needs to be reset 363 | * to bootloader when operational so the new firmware can be loaded. 364 | */ 365 | if (ver->img_type == 0x03) 366 | return kIOReturnError; 367 | 368 | /* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support 369 | * only RSA secure boot engine. Hence, the corresponding sfi file will 370 | * have RSA header of 644 bytes followed by Command Buffer. 371 | * 372 | * iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA 373 | * secure boot engine. As a result, the corresponding sfi file will 374 | * have RSA header of 644, ECDSA header of 320 bytes followed by 375 | * Command Buffer. 376 | * 377 | * CSS Header byte positions 0x08 to 0x0B represent the CSS Header 378 | * version: RSA(0x00010000) , ECDSA (0x00020000) 379 | */ 380 | cssHeaderVer = get_unaligned_le32((uint8_t *)fwData->getBytesNoCopy() + CSS_HEADER_OFFSET); 381 | 382 | if (cssHeaderVer != 0x00010000) { 383 | XYLog("Invalid CSS Header version: %d %d\n", cssHeaderVer, __LINE__); 384 | return kIOReturnError; 385 | } 386 | 387 | XYLog("%s hwVariant: %d sbeType: %d\n", __FUNCTION__, hwVariant, sbeType); 388 | 389 | if (hwVariant <= 0x14) { 390 | if (sbeType != 0x00) { 391 | XYLog("Invalid SBE type for hardware variant (%d)", 392 | hwVariant); 393 | return kIOReturnError; 394 | } 395 | 396 | if (!rsaHeaderSecureSend(fwData)) { 397 | XYLog("Send RSA header failed\n"); 398 | return kIOReturnError; 399 | } 400 | 401 | if (!downloadFirmwarePayload(fwData, RSA_HEADER_LEN)) { 402 | return kIOReturnError; 403 | } 404 | 405 | } else if (hwVariant >= 0x17) { 406 | /* Check if CSS header for ECDSA follows the RSA header */ 407 | if (((uint8_t *)fwData->getBytesNoCopy())[ECDSA_OFFSET] != 0x06) 408 | return -EINVAL; 409 | 410 | /* Check if the CSS Header version is ECDSA(0x00020000) */ 411 | cssHeaderVer = get_unaligned_le32((uint8_t *)fwData->getBytesNoCopy() + ECDSA_OFFSET + CSS_HEADER_OFFSET); 412 | if (cssHeaderVer != 0x00020000) { 413 | XYLog("Invalid CSS Header version: %d %d\n", cssHeaderVer, __LINE__); 414 | return kIOReturnError; 415 | } 416 | 417 | if (sbeType == 0x00) { 418 | if (!rsaHeaderSecureSend(fwData)) { 419 | XYLog("Send RSA header failed\n"); 420 | return kIOReturnError; 421 | } 422 | 423 | if (!downloadFirmwarePayload(fwData, RSA_HEADER_LEN + ECDSA_HEADER_LEN)) { 424 | return kIOReturnError; 425 | } 426 | } else if (sbeType == 0x01) { 427 | if (!ecdsaHeaderSecureSend(fwData)) { 428 | XYLog("Send ECDSA header failed\n"); 429 | return kIOReturnError; 430 | } 431 | 432 | if (!downloadFirmwarePayload(fwData, RSA_HEADER_LEN + ECDSA_HEADER_LEN)) { 433 | return kIOReturnError; 434 | } 435 | } 436 | } 437 | 438 | return kIOReturnSuccess; 439 | } 440 | 441 | bool IntelBluetoothOpsGen3:: 442 | ecdsaHeaderSecureSend(OSData *fwData) 443 | { 444 | /* Start the firmware download transaction with the Init fragment 445 | * represented by the 128 bytes of CSS header. 446 | */ 447 | XYLog("send firmware header\n"); 448 | if (!securedSend(0x00, 128, (const uint8_t *)fwData->getBytesNoCopy() + 644)) { 449 | XYLog("Failed to send firmware header\n"); 450 | return false; 451 | } 452 | XYLog("send firmware header done\n"); 453 | 454 | /* Send the 96 bytes of public key information from the firmware 455 | * as the PKey fragment. 456 | */ 457 | XYLog("send firmware pkey\n"); 458 | if (!securedSend(0x03, 96, (const uint8_t *)fwData->getBytesNoCopy() + 644 + 128)) { 459 | XYLog("Failed to send firmware pkey\n"); 460 | return false; 461 | } 462 | XYLog("send firmware pkey done\n"); 463 | 464 | /* Send the 96 bytes of signature information from the firmware 465 | * as the Sign fragment 466 | */ 467 | XYLog("send firmware signature\n"); 468 | if (!securedSend(0x02, 96, (const uint8_t *)fwData->getBytesNoCopy() + 644 + 224)) { 469 | XYLog("Failed to send firmware signature\n"); 470 | return false; 471 | } 472 | XYLog("send firmware signature done\n"); 473 | 474 | return true; 475 | } 476 | 477 | bool IntelBluetoothOpsGen3:: 478 | parseVersionTLV(IntelVersionTLV *version, const uint8_t *versionDataPtr, int len) 479 | { 480 | IntelTLV *tlv; 481 | 482 | /* Consume Command Complete Status field */ 483 | versionDataPtr++; 484 | len--; 485 | 486 | /* Event parameters contatin multiple TLVs. Read each of them 487 | * and only keep the required data. Also, it use existing legacy 488 | * version field like hw_platform, hw_variant, and fw_variant 489 | * to keep the existing setup flow 490 | */ 491 | while (len > 0) { 492 | tlv = (IntelTLV *)versionDataPtr; 493 | switch (tlv->type) { 494 | case INTEL_TLV_CNVI_TOP: 495 | version->cnvi_top = get_unaligned_le32(tlv->val); 496 | break; 497 | case INTEL_TLV_CNVR_TOP: 498 | version->cnvr_top = get_unaligned_le32(tlv->val); 499 | break; 500 | case INTEL_TLV_CNVI_BT: 501 | version->cnvi_bt = get_unaligned_le32(tlv->val); 502 | break; 503 | case INTEL_TLV_CNVR_BT: 504 | version->cnvr_bt = get_unaligned_le32(tlv->val); 505 | break; 506 | case INTEL_TLV_DEV_REV_ID: 507 | version->dev_rev_id = get_unaligned_le16(tlv->val); 508 | break; 509 | case INTEL_TLV_IMAGE_TYPE: 510 | version->img_type = tlv->val[0]; 511 | break; 512 | case INTEL_TLV_TIME_STAMP: 513 | /* If image type is Operational firmware (0x03), then 514 | * running FW Calendar Week and Year information can 515 | * be extracted from Timestamp information 516 | */ 517 | version->min_fw_build_cw = tlv->val[0]; 518 | version->min_fw_build_yy = tlv->val[1]; 519 | version->timestamp = get_unaligned_le16(tlv->val); 520 | break; 521 | case INTEL_TLV_BUILD_TYPE: 522 | version->build_type = tlv->val[0]; 523 | break; 524 | case INTEL_TLV_BUILD_NUM: 525 | /* If image type is Operational firmware (0x03), then 526 | * running FW build number can be extracted from the 527 | * Build information 528 | */ 529 | version->min_fw_build_nn = tlv->val[0]; 530 | version->build_num = get_unaligned_le32(tlv->val); 531 | break; 532 | case INTEL_TLV_SECURE_BOOT: 533 | version->secure_boot = tlv->val[0]; 534 | break; 535 | case INTEL_TLV_OTP_LOCK: 536 | version->otp_lock = tlv->val[0]; 537 | break; 538 | case INTEL_TLV_API_LOCK: 539 | version->api_lock = tlv->val[0]; 540 | break; 541 | case INTEL_TLV_DEBUG_LOCK: 542 | version->debug_lock = tlv->val[0]; 543 | break; 544 | case INTEL_TLV_MIN_FW: 545 | version->min_fw_build_nn = tlv->val[0]; 546 | version->min_fw_build_cw = tlv->val[1]; 547 | version->min_fw_build_yy = tlv->val[2]; 548 | break; 549 | case INTEL_TLV_LIMITED_CCE: 550 | version->limited_cce = tlv->val[0]; 551 | break; 552 | case INTEL_TLV_SBE_TYPE: 553 | version->sbe_type = tlv->val[0]; 554 | break; 555 | case INTEL_TLV_OTP_BDADDR: 556 | memcpy(&version->otp_bd_addr, tlv->val, tlv->len); 557 | break; 558 | case INTEL_TLV_GIT_SHA1: 559 | version->git_sha1 = get_unaligned_le32(tlv->val); 560 | break; 561 | default: 562 | /* Ignore rest of information */ 563 | break; 564 | } 565 | 566 | len -= (sizeof(IntelTLV) + tlv->len); 567 | versionDataPtr += (sizeof(IntelTLV) + tlv->len); 568 | } 569 | 570 | return true; 571 | } 572 | 573 | bool IntelBluetoothOpsGen3:: 574 | readVersionTLV(IntelVersionTLV *version) 575 | { 576 | uint32_t actLen = 0; 577 | uint8_t sendBuf[CMD_BUF_MAX_SIZE]; 578 | uint8_t respBuf[CMD_BUF_MAX_SIZE]; 579 | HciResponse *resp = (HciResponse *)respBuf; 580 | HciCommandHdr *cmd = (HciCommandHdr *)sendBuf; 581 | const uint8_t *versionDataPtr; 582 | int len = 0; 583 | 584 | memset(sendBuf, 0, sizeof(sendBuf)); 585 | cmd->opcode = OSSwapHostToLittleInt16(0xfc05); 586 | cmd->len = 1; 587 | cmd->data[0] = 0xFF; 588 | 589 | memset(respBuf, 0, sizeof(respBuf)); 590 | if (!intelSendHCISync(cmd, resp, sizeof(respBuf), &actLen, HCI_CMD_TIMEOUT)) { 591 | XYLog("Reading Intel version information failed\n"); 592 | return false; 593 | } 594 | 595 | if (actLen < 5) { 596 | XYLog("Invalid size %d\n", actLen); 597 | return false; 598 | } 599 | 600 | versionDataPtr = resp->data; 601 | len = actLen - 5; 602 | 603 | parseVersionTLV(version, versionDataPtr, len); 604 | 605 | return true; 606 | } 607 | 608 | bool IntelBluetoothOpsGen3:: 609 | versionInfoTLV(IntelVersionTLV *version) 610 | { 611 | const char *variant; 612 | 613 | /* The hardware platform number has a fixed value of 0x37 and 614 | * for now only accept this single value. 615 | */ 616 | if (INTEL_HW_PLATFORM(version->cnvi_bt) != 0x37) { 617 | XYLog("Unsupported Intel hardware platform (0x%2x)\n", 618 | INTEL_HW_PLATFORM(version->cnvi_bt)); 619 | return false; 620 | } 621 | 622 | /* Check for supported iBT hardware variants of this firmware 623 | * loading method. 624 | * 625 | * This check has been put in place to ensure correct forward 626 | * compatibility options when newer hardware variants come along. 627 | */ 628 | switch (INTEL_HW_VARIANT(version->cnvi_bt)) { 629 | case 0x17: /* TyP */ 630 | case 0x18: /* Slr */ 631 | case 0x19: /* Slr-F */ 632 | case 0x1b: /* Mgr */ 633 | case 0x1c: /* Gale Peak (GaP) */ 634 | break; 635 | default: 636 | XYLog("Unsupported Intel hardware variant (0x%x)\n", 637 | INTEL_HW_VARIANT(version->cnvi_bt)); 638 | return false; 639 | } 640 | 641 | switch (version->img_type) { 642 | case 0x01: 643 | variant = "Bootloader"; 644 | /* It is required that every single firmware fragment is acknowledged 645 | * with a command complete event. If the boot parameters indicate 646 | * that this bootloader does not send them, then abort the setup. 647 | */ 648 | if (version->limited_cce != 0x00) { 649 | XYLog("Unsupported Intel firmware loading method (0x%x)\n", 650 | version->limited_cce); 651 | return false; 652 | } 653 | 654 | /* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */ 655 | if (version->sbe_type > 0x01) { 656 | XYLog("Unsupported Intel secure boot engine type (0x%x)\n", 657 | version->sbe_type); 658 | return false; 659 | } 660 | 661 | XYLog("Device revision is %u\n", version->dev_rev_id); 662 | XYLog("Secure boot is %s\n", 663 | version->secure_boot ? "enabled" : "disabled"); 664 | XYLog("OTP lock is %s\n", 665 | version->otp_lock ? "enabled" : "disabled"); 666 | XYLog("API lock is %s\n", 667 | version->api_lock ? "enabled" : "disabled"); 668 | XYLog("Debug lock is %s\n", 669 | version->debug_lock ? "enabled" : "disabled"); 670 | XYLog("Minimum firmware build %u week %u %u\n", 671 | version->min_fw_build_nn, version->min_fw_build_cw, 672 | 2000 + version->min_fw_build_yy); 673 | break; 674 | case 0x03: 675 | variant = "Firmware"; 676 | break; 677 | default: 678 | XYLog("Unsupported image type(%02x)\n", version->img_type); 679 | return false; 680 | } 681 | 682 | XYLog("%s timestamp %u.%u buildtype %u build %u\n", variant, 683 | 2000 + (version->timestamp >> 8), version->timestamp & 0xff, 684 | version->build_type, version->build_num); 685 | 686 | if (version->img_type == 0x03) 687 | XYLog("Firmware SHA1: 0x%8.8x\n", version->git_sha1); 688 | 689 | return true; 690 | } 691 | 692 | bool IntelBluetoothOpsGen3:: 693 | getFirmware(IntelVersionTLV *tlv, char *name, size_t len, const char *suffix) 694 | { 695 | /* The firmware file name for new generation controllers will be 696 | * ibt-- 697 | */ 698 | snprintf(name, len, "ibt-%04x-%04x.%s", 699 | INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(tlv->cnvi_top), 700 | INTEL_CNVX_TOP_STEP(tlv->cnvi_top)), 701 | INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(tlv->cnvr_top), 702 | INTEL_CNVX_TOP_STEP(tlv->cnvr_top)), 703 | suffix); 704 | return true; 705 | } 706 | 707 | bool IntelBluetoothOpsGen3:: 708 | shutdown() 709 | { 710 | return true; 711 | } 712 | 713 | bool IntelBluetoothOpsGen3:: 714 | getFirmwareName(char *fwname, size_t len) 715 | { 716 | strncpy(fwname, this->loadedFirmwareName, len - 1); 717 | fwname[len - 1] = '\0'; 718 | return true; 719 | } 720 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/IntelBluetoothOpsGen3.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // IntelBluetoothOpsGen3.hpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/6/17. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #ifndef IntelBluetoothOpsGen3_hpp 10 | #define IntelBluetoothOpsGen3_hpp 11 | 12 | #include "IntelBluetoothOpsGen2.hpp" 13 | 14 | /* List of tlv type */ 15 | enum { 16 | INTEL_TLV_CNVI_TOP = 0x10, 17 | INTEL_TLV_CNVR_TOP, 18 | INTEL_TLV_CNVI_BT, 19 | INTEL_TLV_CNVR_BT, 20 | INTEL_TLV_CNVI_OTP, 21 | INTEL_TLV_CNVR_OTP, 22 | INTEL_TLV_DEV_REV_ID, 23 | INTEL_TLV_USB_VENDOR_ID, 24 | INTEL_TLV_USB_PRODUCT_ID, 25 | INTEL_TLV_PCIE_VENDOR_ID, 26 | INTEL_TLV_PCIE_DEVICE_ID, 27 | INTEL_TLV_PCIE_SUBSYSTEM_ID, 28 | INTEL_TLV_IMAGE_TYPE, 29 | INTEL_TLV_TIME_STAMP, 30 | INTEL_TLV_BUILD_TYPE, 31 | INTEL_TLV_BUILD_NUM, 32 | INTEL_TLV_FW_BUILD_PRODUCT, 33 | INTEL_TLV_FW_BUILD_HW, 34 | INTEL_TLV_FW_STEP, 35 | INTEL_TLV_BT_SPEC, 36 | INTEL_TLV_MFG_NAME, 37 | INTEL_TLV_HCI_REV, 38 | INTEL_TLV_LMP_SUBVER, 39 | INTEL_TLV_OTP_PATCH_VER, 40 | INTEL_TLV_SECURE_BOOT, 41 | INTEL_TLV_KEY_FROM_HDR, 42 | INTEL_TLV_OTP_LOCK, 43 | INTEL_TLV_API_LOCK, 44 | INTEL_TLV_DEBUG_LOCK, 45 | INTEL_TLV_MIN_FW, 46 | INTEL_TLV_LIMITED_CCE, 47 | INTEL_TLV_SBE_TYPE, 48 | INTEL_TLV_OTP_BDADDR, 49 | INTEL_TLV_UNLOCKED_STATE, 50 | INTEL_TLV_GIT_SHA1 51 | }; 52 | 53 | class IntelBluetoothOpsGen3 : public IntelBluetoothOpsGen2 { 54 | OSDeclareDefaultStructors(IntelBluetoothOpsGen3) 55 | 56 | public: 57 | 58 | virtual bool setup() override; 59 | 60 | virtual bool shutdown() override; 61 | 62 | virtual bool getFirmwareName(char *fwname, size_t len) override; 63 | 64 | protected: 65 | 66 | bool ecdsaHeaderSecureSend(OSData *fwData); 67 | 68 | bool bootloaderSetupTLV(IntelVersionTLV *ver); 69 | 70 | private: 71 | 72 | int readVersionTyP(void *version); 73 | 74 | bool versionInfoTLV(IntelVersionTLV *version); 75 | 76 | bool readVersionTLV(IntelVersionTLV *version); 77 | 78 | bool parseVersionTLV(IntelVersionTLV *version, const uint8_t *versionDataPtr, int len); 79 | 80 | bool getFirmware(IntelVersionTLV *tlv, char *name, size_t len, const char *suffix); 81 | 82 | bool downloadFirmware(IntelVersionTLV *ver, uint32_t *bootParams); 83 | 84 | IOReturn downloadFirmwareData(IntelVersionTLV *ver, OSData *fwData, uint32_t *bootParams, uint8_t hwVariant, uint8_t sbeType); 85 | 86 | private: 87 | char loadedFirmwareName[64]; 88 | }; 89 | 90 | #endif /* IntelBluetoothOpsGen3_hpp */ 91 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/Log.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | Copyright (c) 2020 zxystd. All rights reserved. 3 | SPDX-License-Identifier: GPL-3.0-only 4 | **/ 5 | 6 | // 7 | // Log.h 8 | // IntelBluetoothFirmware 9 | // 10 | // Created by zxystd on 2019/12/3. 11 | // Copyright © 2019 zxystd. All rights reserved. 12 | // 13 | 14 | #ifndef Log_h 15 | #define Log_h 16 | 17 | #include 18 | 19 | #define XYLog(fmt, x...)\ 20 | do\ 21 | {\ 22 | IOLog("%s: " fmt, "IntelFirmware", ##x);\ 23 | }while(0) 24 | 25 | #endif /* Log_h */ 26 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/USBDeviceController.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // USBHCIController.cpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/5/21. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #include "USBDeviceController.hpp" 10 | #include "Log.h" 11 | #include "Hci.h" 12 | 13 | #define super OSObject 14 | OSDefineMetaClassAndStructors(USBDeviceController, OSObject) 15 | 16 | #define kReadBufferSize 4096 17 | 18 | bool USBDeviceController:: 19 | init(IOService *client, IOUSBHostDevice *dev) 20 | { 21 | XYLog("%s\n", __PRETTY_FUNCTION__); 22 | if (!super::init()) { 23 | return false; 24 | } 25 | _hciLock = IOLockAlloc(); 26 | if (!_hciLock) { 27 | return false; 28 | } 29 | mReadBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task 30 | , kIODirectionIn, kReadBufferSize); 31 | if (!mReadBuffer) { 32 | XYLog("Fail to alloc read buffer\n"); 33 | return false; 34 | } 35 | 36 | mReadBuffer->prepare(kIODirectionIn); 37 | m_pDevice = dev; 38 | m_pClient = client; 39 | return true; 40 | } 41 | 42 | bool USBDeviceController:: 43 | findInterface() 44 | { 45 | XYLog("%s\n", __PRETTY_FUNCTION__); 46 | OSIterator* iterator = m_pDevice->getChildIterator(gIOServicePlane); 47 | OSObject* candidate = NULL; 48 | if (iterator == NULL) { 49 | XYLog("can not create child iterator\n"); 50 | return false; 51 | } 52 | while((candidate = iterator->getNextObject()) != NULL) { 53 | IOUSBHostInterface* interfaceCandidate = OSDynamicCast(IOUSBHostInterface, candidate); 54 | if(interfaceCandidate != NULL) { 55 | XYLog("Found interface!!!\n"); 56 | m_pInterface = interfaceCandidate; 57 | break; 58 | } 59 | } 60 | OSSafeReleaseNULL(iterator); 61 | if (m_pInterface == NULL) { 62 | return false; 63 | } 64 | if (!m_pInterface->open(m_pClient)) { 65 | XYLog("can not open interface\n"); 66 | return false; 67 | } 68 | return true; 69 | } 70 | 71 | void USBDeviceController:: 72 | free() 73 | { 74 | XYLog("%s\n", __PRETTY_FUNCTION__); 75 | if (m_pBulkWritePipe) { 76 | m_pBulkWritePipe->abort(); 77 | OSSafeReleaseNULL(m_pBulkWritePipe); 78 | } 79 | if (m_pBulkReadPipe) { 80 | m_pBulkReadPipe->abort(); 81 | OSSafeReleaseNULL(m_pBulkReadPipe); 82 | } 83 | if (m_pInterruptReadPipe) { 84 | m_pInterruptReadPipe->abort(); 85 | OSSafeReleaseNULL(m_pInterruptReadPipe); 86 | } 87 | if (mReadBuffer) { 88 | mReadBuffer->complete(kIODirectionIn); 89 | OSSafeReleaseNULL(mReadBuffer); 90 | } 91 | if (_hciLock) { 92 | IOLockFree(_hciLock); 93 | _hciLock = NULL; 94 | } 95 | if (m_pInterface) { 96 | if (m_pClient && m_pInterface->isOpen(m_pClient)) { 97 | m_pInterface->close(m_pClient); 98 | m_pClient = NULL; 99 | } 100 | m_pInterface = NULL; 101 | } 102 | m_pDevice = NULL; 103 | super::free(); 104 | } 105 | 106 | bool USBDeviceController:: 107 | initConfiguration() 108 | { 109 | XYLog("%s\n", __PRETTY_FUNCTION__); 110 | uint8_t configIndex = 0; 111 | uint8_t configNum = m_pDevice->getDeviceDescriptor()->bNumConfigurations; 112 | if (configNum < configIndex + configNum) { 113 | XYLog("config num error (num: %d)\n", configNum); 114 | return false; 115 | } 116 | const StandardUSB::ConfigurationDescriptor *configDescriptor = m_pDevice->getConfigurationDescriptor(configIndex); 117 | if (!configDescriptor) { 118 | XYLog("getConfigurationDescriptor(%d) failed\n", configIndex); 119 | return false; 120 | } 121 | XYLog("set configuration to %d\n", configDescriptor->bConfigurationValue); 122 | IOReturn ret = m_pDevice->setConfiguration(configDescriptor->bConfigurationValue); 123 | if (ret != kIOReturnSuccess) { 124 | XYLog("set device configuration to %d failed\n", configDescriptor->bConfigurationValue); 125 | return false; 126 | } 127 | return true; 128 | } 129 | 130 | bool USBDeviceController:: 131 | findPipes() 132 | { 133 | XYLog("%s\n", __PRETTY_FUNCTION__); 134 | const StandardUSB::ConfigurationDescriptor *configDescriptor; 135 | const StandardUSB::InterfaceDescriptor *interfaceDescriptor; 136 | const EndpointDescriptor *endpointDescriptor; 137 | uint8_t epDirection, epType; 138 | 139 | configDescriptor = m_pInterface->getConfigurationDescriptor(); 140 | interfaceDescriptor = m_pInterface->getInterfaceDescriptor(); 141 | if (configDescriptor == NULL || interfaceDescriptor == NULL) { 142 | XYLog("Find descriptor NULL\n"); 143 | return false; 144 | } 145 | endpointDescriptor = NULL; 146 | while ((endpointDescriptor = StandardUSB::getNextEndpointDescriptor(configDescriptor, interfaceDescriptor, endpointDescriptor))) { 147 | epDirection = StandardUSB::getEndpointDirection(endpointDescriptor); 148 | epType = StandardUSB::getEndpointType(endpointDescriptor); 149 | if (epDirection == kUSBIn && epType == kUSBInterrupt) { 150 | XYLog("Found Interrupt endpoint!\n"); 151 | m_pInterruptReadPipe = m_pInterface->copyPipe(StandardUSB::getEndpointAddress(endpointDescriptor)); 152 | if (m_pInterruptReadPipe == NULL) { 153 | XYLog("Copy InterruptReadPipe pipe fail\n"); 154 | return false; 155 | } 156 | m_pInterruptReadPipe->retain(); 157 | m_pInterruptReadPipe->release(); 158 | } else { 159 | if (epDirection == kUSBOut && epType == kUSBBulk) { 160 | XYLog("Found Bulk out endpoint!\n"); 161 | m_pBulkWritePipe = m_pInterface->copyPipe(StandardUSB::getEndpointAddress(endpointDescriptor)); 162 | if (m_pBulkWritePipe == NULL) { 163 | XYLog("Copy Bulk pipe fail\n"); 164 | return false; 165 | } 166 | m_pBulkWritePipe->retain(); 167 | m_pBulkWritePipe->release(); 168 | } else { 169 | if (epDirection == kUSBIn && epType == kUSBBulk) { 170 | XYLog("Found Bulk in endpoint!\n"); 171 | m_pBulkReadPipe = m_pInterface->copyPipe(StandardUSB::getEndpointAddress(endpointDescriptor)); 172 | if (m_pBulkReadPipe == NULL) { 173 | XYLog("Copy Bulk pipe fail\n"); 174 | return false; 175 | } 176 | m_pBulkReadPipe->retain(); 177 | m_pBulkReadPipe->release(); 178 | } 179 | } 180 | } 181 | } 182 | return (m_pInterruptReadPipe != NULL && m_pBulkWritePipe != NULL && m_pBulkReadPipe != NULL); 183 | } 184 | 185 | IOReturn USBDeviceController:: 186 | bulkPipeRead(void *buf, uint32_t buf_size, uint32_t *size, uint32_t timeout) 187 | { 188 | uint32_t actualLength = 0; 189 | IOReturn ret = m_pBulkReadPipe->io(mReadBuffer, (uint32_t)mReadBuffer->getLength(), actualLength, timeout); 190 | if (ret == kIOUSBPipeStalled) { 191 | m_pBulkReadPipe->clearStall(true); 192 | ret = m_pBulkReadPipe->io(mReadBuffer, (uint32_t)mReadBuffer->getLength(), actualLength, timeout); 193 | } 194 | if (ret == kIOReturnSuccess) { 195 | if (buf && actualLength > buf_size) { 196 | XYLog("%s buf size too small. buflen: %d act: %d\n", __FUNCTION__, buf_size, actualLength); 197 | } 198 | if (buf) { 199 | memcpy(buf, mReadBuffer->getBytesNoCopy(), min(actualLength, buf_size)); 200 | } 201 | if (size) { 202 | *size = min(actualLength, buf_size); 203 | } 204 | } else { 205 | XYLog("%s failed: %s %d\n", __FUNCTION__, stringFromReturn(ret), ret); 206 | } 207 | return ret; 208 | } 209 | 210 | void USBDeviceController:: 211 | interruptHandler(void *owner, void *parameter, IOReturn status, uint32_t bytesTransferred) 212 | { 213 | USBDeviceController *controller = OSDynamicCast(USBDeviceController, (OSObject *)owner); 214 | if (!controller || !parameter) { 215 | return; 216 | } 217 | switch (status) { 218 | case kIOReturnSuccess: 219 | break; 220 | case kIOReturnNotResponding: 221 | controller->m_pInterruptReadPipe->clearStall(false); 222 | default: 223 | XYLog("%s status: %s (%d) len: %d\n", __FUNCTION__, controller->stringFromReturn(status), status, bytesTransferred); 224 | break; 225 | } 226 | 227 | InterruptResp *resp = (InterruptResp *)parameter; 228 | resp->status = status; 229 | resp->dataLen = bytesTransferred; 230 | IOLockWakeup(controller->_hciLock, controller, true); 231 | } 232 | 233 | IOReturn USBDeviceController:: 234 | interruptPipeRead(void *buf, uint32_t buf_size, uint32_t *size, uint32_t timeout) 235 | { 236 | AbsoluteTime deadline; 237 | IOUSBHostCompletion comple; 238 | InterruptResp interrupResp; 239 | 240 | clock_interval_to_deadline(timeout, kMillisecondScale, reinterpret_cast (&deadline)); 241 | memset(&interrupResp, 0, sizeof(interrupResp)); 242 | comple.action = interruptHandler; 243 | comple.owner = this; 244 | comple.parameter = &interrupResp; 245 | 246 | IOReturn ret = m_pInterruptReadPipe->io(mReadBuffer, (uint32_t)mReadBuffer->getLength(), &comple, 0); 247 | if (ret == kIOUSBPipeStalled) { 248 | m_pInterruptReadPipe->clearStall(true); 249 | ret = m_pInterruptReadPipe->io(mReadBuffer, (uint32_t)mReadBuffer->getLength(), &comple, 0); 250 | } 251 | 252 | if (ret == kIOReturnSuccess) { 253 | IOLockLock(_hciLock); 254 | if (IOLockSleepDeadline(_hciLock, this, deadline, THREAD_INTERRUPTIBLE) != THREAD_AWAKENED) { 255 | IOLockUnlock(_hciLock); 256 | m_pInterruptReadPipe->abort(); 257 | XYLog("%s Timeout\n", __FUNCTION__); 258 | return kIOReturnTimeout; 259 | } 260 | if (interrupResp.dataLen <= 0) { 261 | IOLockUnlock(_hciLock); 262 | XYLog("%s invalid response size: %d\n", __FUNCTION__, interrupResp.dataLen); 263 | return kIOReturnError; 264 | } 265 | if (buf && interrupResp.dataLen > buf_size) { 266 | XYLog("%s buf size too small. buflen: %d act: %d\n", __FUNCTION__, buf_size, interrupResp.dataLen); 267 | } 268 | if (buf) { 269 | memcpy(buf, mReadBuffer->getBytesNoCopy(), min(interrupResp.dataLen, buf_size)); 270 | } 271 | if (size) { 272 | *size = min(interrupResp.dataLen, buf_size); 273 | } 274 | IOLockUnlock(_hciLock); 275 | } else { 276 | XYLog("%s failed: %s %d\n", __FUNCTION__, stringFromReturn(ret), ret); 277 | } 278 | return ret; 279 | } 280 | 281 | IOReturn USBDeviceController:: 282 | sendHCIRequest(HciCommandHdr *cmd, uint32_t timeout) 283 | { 284 | uint32_t actualLength; 285 | StandardUSB::DeviceRequest request = 286 | { 287 | .bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, kRequestTypeClass, kRequestRecipientDevice), 288 | .bRequest = 0, 289 | .wValue = 0, 290 | .wIndex = 0, 291 | .wLength = (uint16_t)(HCI_COMMAND_HDR_SIZE + cmd->len) 292 | }; 293 | 294 | return m_pInterface->deviceRequest(request, cmd, actualLength, timeout); 295 | } 296 | 297 | IOReturn USBDeviceController:: 298 | bulkWrite(const void *data, uint32_t length, uint32_t timeout) 299 | { 300 | IOMemoryDescriptor* buffer = IOMemoryDescriptor::withAddress((void *)data, length, kIODirectionOut); 301 | if (!buffer) { 302 | XYLog("Unable to allocate bulk write buffer.\n"); 303 | return kIOReturnNoMemory; 304 | } 305 | IOReturn ret; 306 | uint32_t actLen = 0; 307 | if ((ret = buffer->prepare(kIODirectionOut)) != kIOReturnSuccess) { 308 | XYLog("Failed to prepare bulk write memory buffer (error %d).\n", ret); 309 | buffer->release(); 310 | return ret; 311 | } 312 | if ((ret = m_pBulkWritePipe->io(buffer, (uint32_t)buffer->getLength(), actLen, timeout)) != kIOReturnSuccess) { 313 | XYLog("Failed to write to bulk pipe (error %d)\n", ret); 314 | buffer->complete(); 315 | buffer->release(); 316 | return ret; 317 | } 318 | if ((ret = buffer->complete(kIODirectionOut)) != kIOReturnSuccess) { 319 | XYLog("Failed to complete bulk write memory buffer (error %d)\n", ret); 320 | buffer->release(); 321 | return ret; 322 | } 323 | return ret; 324 | } 325 | 326 | const char* USBDeviceController:: 327 | stringFromReturn(IOReturn code) 328 | { 329 | return m_pDevice->stringFromReturn(code); 330 | } 331 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/USBDeviceController.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // USBHCIController.hpp 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/5/21. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #ifndef USBDeviceController_hpp 10 | #define USBDeviceController_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "Hci.h" 21 | 22 | typedef struct { 23 | int status; 24 | uint32_t dataLen; 25 | } InterruptResp; 26 | 27 | class USBDeviceController : public OSObject { 28 | OSDeclareDefaultStructors(USBDeviceController) 29 | 30 | public: 31 | 32 | virtual bool init(IOService *client, IOUSBHostDevice *dev); 33 | 34 | virtual void free() override; 35 | 36 | virtual bool initConfiguration(); 37 | 38 | virtual bool findInterface(); 39 | 40 | virtual bool findPipes(); 41 | 42 | IOReturn bulkPipeRead(void *buf, uint32_t buf_size, uint32_t *size, uint32_t timeout); 43 | 44 | IOReturn interruptPipeRead(void *buf, uint32_t buf_size, uint32_t *size, uint32_t timeout); 45 | 46 | IOReturn sendHCIRequest(HciCommandHdr *cmd, uint32_t timeout); 47 | 48 | IOReturn bulkWrite(const void *data, uint32_t length, uint32_t timeout); 49 | 50 | const char* stringFromReturn(IOReturn code); 51 | 52 | static void interruptHandler(void *owner, void *parameter, IOReturn status, uint32_t bytesTransferred); 53 | 54 | private: 55 | IOUSBHostDevice* m_pDevice; 56 | IOService* m_pClient; 57 | IOUSBHostInterface* m_pInterface; 58 | 59 | IOUSBHostPipe* m_pInterruptReadPipe; 60 | IOUSBHostPipe* m_pBulkWritePipe; 61 | IOUSBHostPipe* m_pBulkReadPipe; 62 | 63 | IOLock *_hciLock; 64 | IOBufferMemoryDescriptor* mReadBuffer; 65 | }; 66 | 67 | #endif /* USBDeviceController_hpp */ 68 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-0041.ddc: -------------------------------------------------------------------------------- 1 | ()0 -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-0041.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0040-0041.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-1020.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-1020.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0040-1020.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-1050.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-1050.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0040-1050.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-2120.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-2120.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0040-2120.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-4150.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0040-4150.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0040-4150.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0041-0041.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0041-0041.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0041-0041.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-0041.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-0041.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0180-0041.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-1050.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-1050.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0180-1050.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-4150.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0180-4150.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0180-4150.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0291-0291.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0291-0291.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-0291-0291.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-0291-0291.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-0041.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-0041.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-1040-0041.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-1020.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-1020.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-1040-1020.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-1050.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-1050.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-1040-1050.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-2120.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-2120.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-1040-2120.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-4150.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-1040-4150.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-1040-4150.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-11-5.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-11-5.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-11-5.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-11-5.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-12-16.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-12-16.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-12-16.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-12-16.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-0-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-0-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-0-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-0-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-16-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-16-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-16-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-16-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-2.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-2.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-17-2.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-17-2.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-0-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-0-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-0-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-0-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-16-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-16-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-16-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-16-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-2.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-2.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-18-2.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-18-2.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-0.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-0.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-0.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-0.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-3.ddc: -------------------------------------------------------------------------------- 1 | () -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-3.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-3.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-4.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-4.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-0-4.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-0-4.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-16-4.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-16-4.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-16-4.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-16-4.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-240-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-240-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-240-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-240-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-240-4.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-240-4.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-240-4.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-240-4.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-0.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-0.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-0.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-0.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-1.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-1.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-1.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-1.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-4.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-4.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-19-32-4.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-19-32-4.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-0-3.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-0-3.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-0-3.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-0-3.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-1-3.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-1-3.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-1-3.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-1-3.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-1-4.ddc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-1-4.ddc -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-20-1-4.sfi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-20-1-4.sfi -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.0.1.2d.d.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.0.1.2d.d.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.0.2.3.d.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.0.2.3.d.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.80.1.2d.d.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.80.1.2d.d.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.80.2.3.d.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.7.10-fw-1.80.2.3.d.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.7.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.7.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-1.10.2.27.d.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-1.10.2.27.d.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-22.50.19.14.f.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.8.10-fw-22.50.19.14.f.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/fw/ibt-hw-37.8.bseq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIntelWireless/IntelBluetoothFirmware/01cc1806d71f5cc64c464851b9f4811a3e7b4791/IntelBluetoothFirmware/fw/ibt-hw-37.8.bseq -------------------------------------------------------------------------------- /IntelBluetoothFirmware/linux.h: -------------------------------------------------------------------------------- 1 | // 2 | // linux.h 3 | // IntelBluetoothFirmware 4 | // 5 | // Created by qcwap on 2021/5/21. 6 | // Copyright © 2021 zxystd. All rights reserved. 7 | // 8 | 9 | #ifndef linux_h 10 | #define linux_h 11 | 12 | #include 13 | #include 14 | 15 | typedef UInt8 u8; 16 | typedef UInt16 u16; 17 | typedef UInt32 u32; 18 | typedef UInt64 u64; 19 | 20 | typedef u8 __u8; 21 | typedef u16 __u16; 22 | typedef u32 __u32; 23 | typedef u64 __u64; 24 | 25 | typedef __u16 __le16; 26 | typedef __u32 __le32; 27 | typedef __u64 __le64; 28 | 29 | typedef SInt8 s8; 30 | typedef SInt16 s16; 31 | typedef SInt32 s32; 32 | typedef SInt64 s64; 33 | 34 | typedef s8 __s8; 35 | typedef s16 __s16; 36 | typedef s32 __s32; 37 | typedef s64 __s64; 38 | 39 | #define __force 40 | 41 | static inline __u32 __le32_to_cpup(const __le32 *p) 42 | { 43 | return (__force __u32)*p; 44 | } 45 | 46 | static inline __u16 __le16_to_cpup(const __le16 *p) 47 | { 48 | return (__force __u16)*p; 49 | } 50 | 51 | #define le32_to_cpup __le32_to_cpup 52 | #define le16_to_cpup __le16_to_cpup 53 | 54 | static inline u32 get_unaligned_le32(const void *p) 55 | { 56 | return le32_to_cpup((__le32 *)p); 57 | } 58 | 59 | static inline u32 get_unaligned_le16(const void *p) 60 | { 61 | return le16_to_cpup((__le16 *)p); 62 | } 63 | 64 | #endif /* linux_h */ 65 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/zutil.c: -------------------------------------------------------------------------------- 1 | // 2 | // zutil.c 3 | // itlwm 4 | // 5 | // Created by qcwap on 2020/9/4. 6 | // Copyright © 2020 钟先耀. All rights reserved. 7 | // 8 | 9 | #include 10 | extern "C" { 11 | typedef struct z_mem 12 | { 13 | UInt32 alloc_size; 14 | UInt8 data[0]; 15 | } z_mem; 16 | 17 | void *zcalloc(void *opaque, uint items, uint size) 18 | { 19 | void* result = NULL; 20 | z_mem* zmem = NULL; 21 | UInt32 allocSize = items * size + sizeof(zmem); 22 | 23 | zmem = (z_mem*)IOMalloc(allocSize); 24 | 25 | if (zmem) 26 | { 27 | zmem->alloc_size = allocSize; 28 | result = (void*)&(zmem->data); 29 | } 30 | 31 | return result; 32 | } 33 | 34 | void zcfree(void *opaque, void *ptr) 35 | { 36 | UInt32* skipper = (UInt32 *)ptr - 1; 37 | z_mem* zmem = (z_mem*)skipper; 38 | IOFree((void*)zmem, zmem->alloc_size); 39 | } 40 | } 41 | 42 | int _stop(struct kmod_info*, void*) { 43 | IOLog("_stop(struct kmod_info*, void*) has been invoked\n"); 44 | return 0; 45 | }; 46 | int _start(struct kmod_info*, void*) { 47 | IOLog("_start(struct kmod_info*, void*) has been invoked\n"); 48 | return 0; 49 | }; 50 | -------------------------------------------------------------------------------- /IntelBluetoothFirmware/zutil.h: -------------------------------------------------------------------------------- 1 | // 2 | // zutil.h 3 | // itlwm 4 | // 5 | // Created by qcwap on 2020/9/4. 6 | // Copyright © 2020 钟先耀. All rights reserved. 7 | // 8 | 9 | #ifndef zutil_h 10 | #define zutil_h 11 | 12 | #include 13 | #include 14 | 15 | extern "C" { 16 | void *zcalloc(void *opaque, uint items, uint size); 17 | 18 | void zcfree(void *opaque, void *ptr); 19 | } 20 | 21 | #endif /* zutil_h */ 22 | -------------------------------------------------------------------------------- /IntelBluetoothInjector/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleIdentifier 8 | $(PRODUCT_BUNDLE_IDENTIFIER) 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundleName 12 | $(PRODUCT_NAME) 13 | CFBundlePackageType 14 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 15 | CFBundleShortVersionString 16 | $(MODULE_VERSION) 17 | CFBundleVersion 18 | $(MODULE_VERSION) 19 | IOKitPersonalities 20 | 21 | 0026 22 | 23 | CFBundleIdentifier 24 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 25 | IOClass 26 | BroadcomBluetoothHostControllerUSBTransport 27 | IOProbeScore 28 | 3000 29 | IOProviderClass 30 | IOUSBHostDevice 31 | idProduct 32 | 38 33 | idVendor 34 | 32903 35 | 36 | 0032 37 | 38 | CFBundleIdentifier 39 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 40 | IOClass 41 | BroadcomBluetoothHostControllerUSBTransport 42 | IOProbeScore 43 | 3000 44 | IOProviderClass 45 | IOUSBHostDevice 46 | idProduct 47 | 50 48 | idVendor 49 | 32903 50 | 51 | 0035 52 | 53 | CFBundleIdentifier 54 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 55 | IOClass 56 | BroadcomBluetoothHostControllerUSBTransport 57 | IOProbeScore 58 | 3000 59 | IOProviderClass 60 | IOUSBHostDevice 61 | idProduct 62 | 53 63 | idVendor 64 | 32903 65 | 66 | 0036 67 | 68 | CFBundleIdentifier 69 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 70 | IOClass 71 | BroadcomBluetoothHostControllerUSBTransport 72 | IOProbeScore 73 | 3000 74 | IOProviderClass 75 | IOUSBHostDevice 76 | idProduct 77 | 54 78 | idVendor 79 | 32903 80 | 81 | 0038 82 | 83 | CFBundleIdentifier 84 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 85 | IOClass 86 | BroadcomBluetoothHostControllerUSBTransport 87 | IOProbeScore 88 | 3000 89 | IOProviderClass 90 | IOUSBHostDevice 91 | idProduct 92 | 56 93 | idVendor 94 | 32903 95 | 96 | 3165ac 97 | 98 | CFBundleIdentifier 99 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 100 | IOClass 101 | BroadcomBluetoothHostControllerUSBTransport 102 | IOProbeScore 103 | 3000 104 | IOProviderClass 105 | IOUSBHostDevice 106 | idProduct 107 | 2602 108 | idVendor 109 | 32903 110 | 111 | 3168 112 | 113 | CFBundleIdentifier 114 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 115 | IOClass 116 | BroadcomBluetoothHostControllerUSBTransport 117 | IOProbeScore 118 | 3000 119 | IOProviderClass 120 | IOUSBHostDevice 121 | idProduct 122 | 2727 123 | idVendor 124 | 32903 125 | 126 | 726x 127 | 128 | CFBundleIdentifier 129 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 130 | IOClass 131 | BroadcomBluetoothHostControllerUSBTransport 132 | IOProbeScore 133 | 3000 134 | IOProviderClass 135 | IOUSBHostDevice 136 | idProduct 137 | 2012 138 | idVendor 139 | 32903 140 | 141 | 8265 142 | 143 | CFBundleIdentifier 144 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 145 | IOClass 146 | BroadcomBluetoothHostControllerUSBTransport 147 | IOProbeScore 148 | 3000 149 | IOProviderClass 150 | IOUSBHostDevice 151 | idProduct 152 | 2603 153 | idVendor 154 | 32903 155 | 156 | 926x 157 | 158 | CFBundleIdentifier 159 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 160 | IOClass 161 | BroadcomBluetoothHostControllerUSBTransport 162 | IOProbeScore 163 | 3000 164 | IOProviderClass 165 | IOUSBHostDevice 166 | idProduct 167 | 37 168 | idVendor 169 | 32903 170 | 171 | 9560 172 | 173 | CFBundleIdentifier 174 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 175 | IOClass 176 | BroadcomBluetoothHostControllerUSBTransport 177 | IOProbeScore 178 | 3000 179 | IOProviderClass 180 | IOUSBHostDevice 181 | idProduct 182 | 2730 183 | idVendor 184 | 32903 185 | 186 | ax200 187 | 188 | CFBundleIdentifier 189 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 190 | IOClass 191 | BroadcomBluetoothHostControllerUSBTransport 192 | IOProbeScore 193 | 3000 194 | IOProviderClass 195 | IOUSBHostDevice 196 | idProduct 197 | 41 198 | idVendor 199 | 32903 200 | 201 | ax210 202 | 203 | CFBundleIdentifier 204 | com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport 205 | IOClass 206 | BroadcomBluetoothHostControllerUSBTransport 207 | IOProbeScore 208 | 3000 209 | IOProviderClass 210 | IOUSBHostDevice 211 | idProduct 212 | 51 213 | idVendor 214 | 32903 215 | 216 | csr 217 | 218 | CFBundleIdentifier 219 | com.apple.iokit.CSRBluetoothHostControllerUSBTransport 220 | IOClass 221 | CSRBluetoothHostControllerUSBTransport 222 | IOProbeScore 223 | 3000 224 | IOProviderClass 225 | IOUSBHostDevice 226 | idProduct 227 | 2010 228 | idVendor 229 | 32903 230 | 231 | 232 | NSHumanReadableCopyright 233 | Copyright © 2020 钟先耀. All rights reserved. 234 | OSBundleRequired 235 | Root 236 | 237 | 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IntelBluetoothFirmware 2 | 3 | ![CI](https://github.com/OpenIntelWireless/IntelBluetoothFirmware/workflows/CI/badge.svg) 4 | 5 | - **English** 6 | - [简体中文](/.github/README-zh_Hans.md) 7 | 8 | ## Intro 9 | 10 | IntelBluetoothFirmware is a Kernel Extension that uploads Intel Wireless Bluetooth Firmware to provide native Bluetooth in macOS. 11 | The firmware binary files are from the Linux Open Source Project. 12 | 13 | After several months of public testing, it appears that the Kext is working well and stable. 14 | 15 | [![Join the chat at https://gitter.im/OpenIntelWireless/itlwm](https://badges.gitter.im/OpenIntelWireless/IntelBluetoothFirmware.svg)](https://gitter.im/OpenIntelWireless/IntelBluetoothFirmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 16 | 17 | ## Documentation 18 | 19 | **Please read the docs carefully before using the Kernel Extensions or submitting an Issue Report!** 20 | 21 | - [Supported Devices](https://openintelwireless.github.io/IntelBluetoothFirmware/Compat.html) 22 | - [Installation](https://openintelwireless.github.io/IntelBluetoothFirmware/Installation.html) 23 | - [Frequently Asked Questions](https://openintelwireless.github.io/IntelBluetoothFirmware/FAQ.html) 24 | - [Troubleshooting](https://openintelwireless.github.io/IntelBluetoothFirmware/Troubleshooting.html) 25 | 26 | ## Credits 27 | 28 | - [torvalds/linux](https://github.com/torvalds/linux) 29 | - [acidanthera/BrcmPatchRAM](https://github.com/acidanthera/BrcmPatchRAM) 30 | -------------------------------------------------------------------------------- /iwlwifi-firmware-license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Intel Corporation. 2 | All rights reserved. 3 | 4 | Redistribution. Redistribution and use in binary form, without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions must reproduce the above copyright notice and the 9 | following disclaimer in the documentation and/or other materials 10 | provided with the distribution. 11 | * Neither the name of Intel Corporation nor the names of its suppliers 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | * No reverse engineering, decompilation, or disassembly of this software 15 | is permitted. 16 | 17 | Limited patent license. Intel Corporation grants a world-wide, 18 | royalty-free, non-exclusive license under patents it now or hereafter 19 | owns or controls to make, have made, use, import, offer to sell and 20 | sell ("Utilize") this software, but solely to the extent that any 21 | such patent is necessary to Utilize the software alone, or in 22 | combination with an operating system licensed under an approved Open 23 | Source license as listed by the Open Source Initiative at 24 | http://opensource.org/licenses. The patent license shall not apply to 25 | any other combinations which include this software. No hardware per 26 | se is licensed hereunder. 27 | 28 | DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 29 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 30 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 32 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 33 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 34 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 35 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 37 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 38 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 39 | DAMAGE. 40 | -------------------------------------------------------------------------------- /scripts/fw_gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # fw_gen.sh 4 | # itlwm 5 | # 6 | # Created by qcwap on 2020/3/10. 7 | # Copyright © 2020 钟先耀. All rights reserved. 8 | target_file="${PROJECT_DIR}/include/FwBinary.cpp" 9 | if [ -f "$target_file" ]; then 10 | exit 0 11 | fi 12 | while [ $# -gt 0 ]; 13 | do 14 | case $1 in 15 | -P) fw_files=$2 16 | shift 17 | ;; 18 | 19 | esac 20 | shift 21 | done 22 | 23 | script_file="${PROJECT_DIR}/scripts/" 24 | python3 -c 'import sys;sys.path.append("'$script_file'");from zlib_compress_fw import *;process_files("'${target_file}'", "'$fw_files'")' 25 | -------------------------------------------------------------------------------- /scripts/zlib_compress_fw.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # zlib_compress_fw.py 4 | # 5 | # Created by qcwap on 2020/9/3. 6 | # Copyright © 2020 钟先耀. All rights reserved. 7 | 8 | import zlib 9 | import os 10 | import struct 11 | import hashlib 12 | 13 | copyright = ''' 14 | // itlwm 15 | // 16 | // Copyright © 2020 钟先耀. All rights reserved. 17 | #include "FwData.h" 18 | ''' 19 | 20 | def compress(data): 21 | return zlib.compress(data) 22 | 23 | def hash(data): 24 | sha1sum = hashlib.sha1() 25 | sha1sum.update(data) 26 | return sha1sum.hexdigest() 27 | 28 | def format_file_name(file_name): 29 | return file_name.replace(".", "_").replace("-", "_") 30 | 31 | def format_var_name(hash): 32 | return "firmware_" + hash 33 | 34 | def write_single_file(target_file, path, file, file_hash): 35 | src_file = open(path, "rb") 36 | src_data = src_file.read() 37 | src_hash = hash(src_data) 38 | fw_var_name = format_file_name(file) 39 | data_var_name = format_var_name(src_hash) 40 | 41 | if src_hash not in file_hash: 42 | file_hash.append(src_hash) 43 | src_data = compress(src_data) 44 | src_len = len(src_data) 45 | target_file.write("\nconst unsigned char ") 46 | target_file.write(data_var_name) 47 | target_file.write("[] = {") 48 | index = 0; 49 | block = [] 50 | while True: 51 | if index + 16 >= src_len: 52 | block = src_data[index:] 53 | else: 54 | block = src_data[index:index + 16] 55 | index += 16; 56 | if len(block) < 16: 57 | if len(block): 58 | for b in block: 59 | if type(b) is str: 60 | b = ord(b) 61 | target_file.write("0x{:02X}, ".format(b)) 62 | target_file.write("\n") 63 | break 64 | target_file.write("0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " 65 | "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " 66 | "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " 67 | "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X},\n" 68 | .format(*struct.unpack("BBBBBBBBBBBBBBBB", block))) 69 | target_file.write("};\n") 70 | 71 | target_file.write("\nconst unsigned char *") 72 | target_file.write(fw_var_name) 73 | target_file.write(" = ") 74 | target_file.write(data_var_name) 75 | target_file.write(";\n") 76 | target_file.write("const long int ") 77 | target_file.write(fw_var_name) 78 | target_file.write("_size = sizeof(") 79 | target_file.write(data_var_name) 80 | target_file.write(");\n") 81 | src_file.close() 82 | 83 | 84 | def process_files(target_file, dir): 85 | if not os.path.exists(target_file): 86 | if not os.path.exists(os.path.dirname(target_file)): 87 | os.mkdirs(os.path.dirname(target_file)) 88 | target_file_handle = open(target_file, "w") 89 | target_file_handle.write(copyright) 90 | for root, dirs, files in os.walk(dir): 91 | file_hash=[] 92 | for file in files: 93 | path = os.path.join(root, file) 94 | write_single_file(target_file_handle, path, file, file_hash) 95 | 96 | target_file_handle.write("\n") 97 | target_file_handle.write("const struct FwDesc fwList[] = {") 98 | 99 | for file in files: 100 | target_file_handle.write('{IBT_FW("') 101 | target_file_handle.write(file) 102 | target_file_handle.write('", ') 103 | fw_var_name = format_file_name(file) 104 | target_file_handle.write(fw_var_name) 105 | target_file_handle.write(", ") 106 | target_file_handle.write(fw_var_name) 107 | target_file_handle.write("_size)},\n") 108 | 109 | target_file_handle.write("};\n") 110 | target_file_handle.write("const int fwNumber = ") 111 | target_file_handle.write(str(len(files))) 112 | target_file_handle.write(";\n") 113 | 114 | target_file_handle.close() 115 | 116 | if __name__ == '__main__': 117 | print(compress("test")); 118 | --------------------------------------------------------------------------------