From 189b8523095d8495bbf1d04cbc48b65df8c50d7c Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> Date: Mon, 7 Aug 2023 09:49:48 +0300 Subject: [PATCH] Add HDMI audio support (#129) Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> --- NootedRed.xcodeproj/project.pbxproj | 12 +++- NootedRed/Info.plist | 44 ++++++++++++ NootedRed/kern_hdmi.cpp | 63 +++++++++++++++++ NootedRed/kern_hdmi.hpp | 14 ++++ NootedRed/kern_nred.cpp | 5 ++ NootedRed/kern_nred.hpp | 1 + NootedRed/kern_patches.hpp | 103 ++++++++++++++++++++++++++++ Scripts/NRedWrapGen.py | 1 + 8 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 NootedRed/kern_hdmi.cpp create mode 100644 NootedRed/kern_hdmi.hpp diff --git a/NootedRed.xcodeproj/project.pbxproj b/NootedRed.xcodeproj/project.pbxproj index c03a07a1..6c187d5f 100644 --- a/NootedRed.xcodeproj/project.pbxproj +++ b/NootedRed.xcodeproj/project.pbxproj @@ -24,6 +24,8 @@ 40FC5FDE29BF996900367F9D /* kern_hwlibs.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 40FC5FDC29BF996900367F9D /* kern_hwlibs.hpp */; }; 40FC5FE129BF9E2500367F9D /* kern_x6000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40FC5FDF29BF9E2500367F9D /* kern_x6000.cpp */; }; 40FC5FE229BF9E2500367F9D /* kern_x6000.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 40FC5FE029BF9E2500367F9D /* kern_x6000.hpp */; }; + 6C1B36662A407C6100B184DD /* kern_hdmi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6C1B36642A407C6100B184DD /* kern_hdmi.cpp */; }; + 6C1B36672A407C6200B184DD /* kern_hdmi.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6C1B36652A407C6100B184DD /* kern_hdmi.hpp */; }; CE405ED91E4A080700AA0B3D /* plugin_start.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE405ED81E4A080700AA0B3D /* plugin_start.cpp */; }; CE8DA0832517C41A008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA0822517C41A008C44E8 /* libkmod.a */; }; CEA03B5E20EE825A00BA842F /* kern_nred.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEA03B5C20EE825A00BA842F /* kern_nred.cpp */; }; @@ -74,6 +76,8 @@ 40FC5FDC29BF996900367F9D /* kern_hwlibs.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_hwlibs.hpp; sourceTree = ""; }; 40FC5FDF29BF9E2500367F9D /* kern_x6000.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = kern_x6000.cpp; sourceTree = ""; }; 40FC5FE029BF9E2500367F9D /* kern_x6000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_x6000.hpp; sourceTree = ""; }; + 6C1B36642A407C6100B184DD /* kern_hdmi.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = kern_hdmi.cpp; sourceTree = ""; }; + 6C1B36652A407C6100B184DD /* kern_hdmi.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_hdmi.hpp; sourceTree = ""; }; CE405EBA1E49DD7100AA0B3D /* kern_compression.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_compression.hpp; sourceTree = ""; }; CE405EBB1E49DD7100AA0B3D /* kern_disasm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_disasm.hpp; sourceTree = ""; }; CE405EBC1E49DD7100AA0B3D /* kern_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_file.hpp; sourceTree = ""; }; @@ -130,8 +134,12 @@ 408F201A288AC068002EEC15 /* Firmware */, 1C748C2E1C21952C0024EED2 /* Info.plist */, CEB402A71F181D8300716912 /* kern_amd.hpp */, + 4019EAE52A3488EC008D800B /* kern_dyld_patches.cpp */, + 4019EAE32A348852008D800B /* kern_dyld_patches.hpp */, 408F201F288ACBE6002EEC15 /* kern_fw.cpp */, 408F201E288ACBB0002EEC15 /* kern_fw.hpp */, + 6C1B36642A407C6100B184DD /* kern_hdmi.cpp */, + 6C1B36652A407C6100B184DD /* kern_hdmi.hpp */, 40FC5FDB29BF996900367F9D /* kern_hwlibs.cpp */, 40FC5FDC29BF996900367F9D /* kern_hwlibs.hpp */, 40364DB529B79DFD0070A2B4 /* kern_model.hpp */, @@ -149,8 +157,6 @@ 40FC5FE029BF9E2500367F9D /* kern_x6000.hpp */, 40FC5FD329BF995000367F9D /* kern_x6000fb.cpp */, 40FC5FD429BF995000367F9D /* kern_x6000fb.hpp */, - 4019EAE32A348852008D800B /* kern_dyld_patches.hpp */, - 4019EAE52A3488EC008D800B /* kern_dyld_patches.cpp */, ); path = NootedRed; sourceTree = ""; @@ -234,6 +240,7 @@ 40FC5FDE29BF996900367F9D /* kern_hwlibs.hpp in Headers */, 4019EAE42A348852008D800B /* kern_dyld_patches.hpp in Headers */, 4068898C2A229BF600028D22 /* kern_patcherplus.hpp in Headers */, + 6C1B36672A407C6200B184DD /* kern_hdmi.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -336,6 +343,7 @@ files = ( 40FC5FDD29BF996900367F9D /* kern_hwlibs.cpp in Sources */, 40FC5FD529BF995000367F9D /* kern_x6000fb.cpp in Sources */, + 6C1B36662A407C6100B184DD /* kern_hdmi.cpp in Sources */, 408F2020288ACBE6002EEC15 /* kern_fw.cpp in Sources */, 4068898B2A229BF600028D22 /* kern_patcherplus.cpp in Sources */, 40FC5FE129BF9E2500367F9D /* kern_x6000.cpp in Sources */, diff --git a/NootedRed/Info.plist b/NootedRed/Info.plist index 751120be..4719143e 100644 --- a/NootedRed/Info.plist +++ b/NootedRed/Info.plist @@ -22,6 +22,48 @@ $(MODULE_VERSION) IOKitPersonalities + AMD + + CFBundleIdentifier + com.apple.driver.AppleGFXHDA + DPAlwaysDisplayRouting + + 3 + 33 + 35 + 88 + + DPAudioDeviceExclusion + + + ManufacturerID + 1552 + ProductID + 10130 + + + HighFIFOLimitSupport + + IOClass + AppleGFXHDAEGController + IOPCIMatch + 0x15DE1002 0x16371002 + IOPCITunnelCompatible + + IOPCIUseDeviceMapper + + IOProviderClass + IOPCIDevice + RequireMaxBusStall + + + Layouts + + MaxBusStall + 15000 + + + AMDGPUWrangler CFBundleIdentifier @@ -51,6 +93,8 @@ 0x15DD1002 0x15D81002 0x15E71002 0x164C1002 0x16381002 0x16361002 IOPCITunnelCompatible + IOPCIUseDeviceMapper + IOProbeScore 6000 IOPropertyMatch diff --git a/NootedRed/kern_hdmi.cpp b/NootedRed/kern_hdmi.cpp new file mode 100644 index 00000000..d24342d9 --- /dev/null +++ b/NootedRed/kern_hdmi.cpp @@ -0,0 +1,63 @@ +// Copyright © 2022-2023 ChefKiss Inc. Licensed under the Thou Shalt Not Profit License version 1.0. See LICENSE for +// details. + +#include "kern_hdmi.hpp" +#include "kern_nred.hpp" +#include "kern_patcherplus.hpp" +#include "kern_patches.hpp" +#include "kern_patterns.hpp" +#include + +static const char *pathAppleGFXHDA = "/System/Library/Extensions/AppleGFXHDA.kext/Contents/MacOS/AppleGFXHDA"; +static const char *pathAppleHDA = "/System/Library/Extensions/AppleHDA.kext/Contents/MacOS/AppleHDA"; + +static KernelPatcher::KextInfo kextAppleGFXHDA {"com.apple.driver.AppleGFXHDA", &pathAppleGFXHDA, 1, {true}, {}, + KernelPatcher::KextInfo::Unloaded}; +static KernelPatcher::KextInfo kextAppleHDA {"com.apple.driver.AppleHDA", &pathAppleHDA, 1, {true}, {}, + KernelPatcher::KextInfo::Unloaded}; + +HDMI *HDMI::callback = nullptr; + +void HDMI::init() { + callback = this; + lilu.onKextLoadForce(&kextAppleGFXHDA); + lilu.onKextLoadForce(&kextAppleHDA); +} + +bool HDMI::processKext(KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size) { + if (kextAppleGFXHDA.loadIndex == id) { + const uint32_t probeFind = 0xAB381002; + const uint32_t probeRepl = NRed::callback->deviceId <= 0x15DD ? 0x15DE1002 : 0x16371002; + LookupPatchPlus patches[] = { + {&kextAppleGFXHDA, reinterpret_cast(&probeFind), + reinterpret_cast(&probeRepl), sizeof(probeFind), 1}, + {&kextAppleGFXHDA, kCreateAppleHDAFunctionGroup1Original, kCreateAppleHDAFunctionGroup1Patched, 1}, + {&kextAppleGFXHDA, kCreateAppleHDAFunctionGroup2Original, kCreateAppleHDAFunctionGroup2Patched, 1}, + {&kextAppleGFXHDA, kCreateAppleHDAWidget1Original, kCreateAppleHDAWidget1OriginalMask, + kCreateAppleHDAWidget1Patched, kCreateAppleHDAWidget1PatchedMask, 1}, + {&kextAppleGFXHDA, kCreateAppleHDAWidget2Original, kCreateAppleHDAWidget2OriginalMask, + kCreateAppleHDAWidget2Patched, 1}, + {&kextAppleGFXHDA, kCreateAppleHDAOriginal, kCreateAppleHDAOriginalMask, kCreateAppleHDAPatched, + kCreateAppleHDAPatchedMask, 2}, + {&kextAppleGFXHDA, kCreateAppleHDA2Original, kCreateAppleHDA2OriginalMask, kCreateAppleHDA2Patched, + kCreateAppleHDA2PatchedMask, 2}, + }; + PANIC_COND(!LookupPatchPlus::applyAll(patcher, patches, slide, size), "agfxhda", "Failed to apply patches: %d", + patcher.getError()); + + return true; + } else if (kextAppleHDA.loadIndex == id) { + LookupPatchPlus patches[] = { + {&kextAppleHDA, kAHDACreate1Original, kAHDACreate1Patched, 2}, + {&kextAppleHDA, kAHDACreate2Original, kAHDACreate2OriginalMask, kAHDACreate2Patched, + kAHDACreate2PatchedMask, 2}, + {&kextAppleHDA, kAHDACreate3Original, kAHDACreate3Mask, kAHDACreate3Patched, 2}, + }; + PANIC_COND(!LookupPatchPlus::applyAll(patcher, patches, slide, size), "ahda", "Failed to apply patches: %d", + patcher.getError()); + + return true; + } + + return false; +} diff --git a/NootedRed/kern_hdmi.hpp b/NootedRed/kern_hdmi.hpp new file mode 100644 index 00000000..b153a15d --- /dev/null +++ b/NootedRed/kern_hdmi.hpp @@ -0,0 +1,14 @@ +// Copyright © 2022-2023 ChefKiss Inc. Licensed under the Thou Shalt Not Profit License version 1.0. See LICENSE for +// details. + +#pragma once +#include "kern_amd.hpp" +#include +#include + +class HDMI { + public: + static HDMI *callback; + void init(); + bool processKext(KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size); +}; diff --git a/NootedRed/kern_nred.cpp b/NootedRed/kern_nred.cpp index 3664f43a..101fead3 100644 --- a/NootedRed/kern_nred.cpp +++ b/NootedRed/kern_nred.cpp @@ -3,6 +3,7 @@ #include "kern_nred.hpp" #include "kern_dyld_patches.hpp" +#include "kern_hdmi.hpp" #include "kern_hwlibs.hpp" #include "kern_model.hpp" #include "kern_patcherplus.hpp" @@ -32,6 +33,7 @@ static X5000HWLibs hwlibs; static X5000 x5000; static X6000 x6000; static DYLDPatches dyldpatches; +static HDMI agfxhda; void NRed::init() { SYSLOG("nred", "Copyright 2022-2023 ChefKiss Inc. If you've paid for this, you've been scammed."); @@ -40,6 +42,7 @@ void NRed::init() { lilu.onKextLoadForce(&kextAGDP); lilu.onKextLoadForce(&kextBacklight); lilu.onKextLoadForce(&kextMCCSControl); + agfxhda.init(); dyldpatches.init(); x6000fb.init(); hwlibs.init(); @@ -216,6 +219,8 @@ void NRed::processKext(KernelPatcher &patcher, size_t id, mach_vm_address_t slid }; patcher.routeMultiple(id, requests, slide, size); patcher.clearError(); + } else if (agfxhda.processKext(patcher, id, slide, size)) { + DBGLOG("nred", "Processed AppleGFXHDA"); } else if (x6000fb.processKext(patcher, id, slide, size)) { DBGLOG("nred", "Processed AMDRadeonX6000Framebuffer"); } else if (hwlibs.processKext(patcher, id, slide, size)) { diff --git a/NootedRed/kern_nred.hpp b/NootedRed/kern_nred.hpp index 50b1fe8e..751615a4 100644 --- a/NootedRed/kern_nred.hpp +++ b/NootedRed/kern_nred.hpp @@ -67,6 +67,7 @@ static bool checkAtomBios(const uint8_t *bios, size_t size) { } class NRed { + friend class HDMI; friend class DYLDPatches; friend class X6000FB; friend class X5000HWLibs; diff --git a/NootedRed/kern_patches.hpp b/NootedRed/kern_patches.hpp index 81567873..c9be98f3 100644 --- a/NootedRed/kern_patches.hpp +++ b/NootedRed/kern_patches.hpp @@ -521,3 +521,106 @@ static const uint8_t kGetHWEngineCallPatched[] = {0x00, 0x00, 0x00, 0xFF, 0x90, */ static const uint8_t kGetAMDHWHandlerCallOriginal[] = {0xFF, 0x90, 0xD0, 0x02, 0x00, 0x00}; static const uint8_t kGetAMDHWHandlerCallPatched[] = {0xFF, 0x90, 0xC8, 0x02, 0x00, 0x00}; + +/** + * `AppleGFXHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * AppleGFXHDA.kext + */ +static const uint8_t kCreateAppleHDAFunctionGroup1Original[] = {0x3D, 0xD7, 0xAA, 0x00, 0x00}; +static const uint8_t kCreateAppleHDAFunctionGroup1Patched[] = {0x3D, 0x00, 0x00, 0x00, 0x00}; +static_assert(arrsize(kCreateAppleHDAFunctionGroup1Original) == arrsize(kCreateAppleHDAFunctionGroup1Patched)); + +/** + * `AppleGFXHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * AppleGFXHDA.kext + */ +static const uint8_t kCreateAppleHDAFunctionGroup2Original[] = {0x3D, 0xF7, 0xAA, 0x00, 0x00, 0x7F}; +static const uint8_t kCreateAppleHDAFunctionGroup2Patched[] = {0x3D, 0xF7, 0xAA, 0x00, 0x00, 0xEB}; +static_assert(arrsize(kCreateAppleHDAFunctionGroup2Original) == arrsize(kCreateAppleHDAFunctionGroup2Patched)); + +/** + * `AppleGFXHDAWidgetFactory::createAppleHDAWidget` + * AppleGFXHDA.kext + * Force else path for `deviceID < 0xAA88` and `deviceID < 0xAAE0` check + */ +static const uint8_t kCreateAppleHDAWidget1Original[] = {0x3D, 0x87, 0xAA, 0x00, 0x00, 0x7E, 0x00, 0x3D, 0xDF, 0xAA, + 0x00, 0x00, 0x7F, 0x00}; +static const uint8_t kCreateAppleHDAWidget1OriginalMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00}; +static const uint8_t kCreateAppleHDAWidget1Patched[] = {0x66, 0x90, 0x66, 0x90, 0x66, 0x90, 0x90, 0x66, 0x90, 0x66, + 0x90, 0x90, 0xEB, 0x00}; +static const uint8_t kCreateAppleHDAWidget1PatchedMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00}; +static_assert(arrsize(kCreateAppleHDAWidget1Original) == arrsize(kCreateAppleHDAWidget1OriginalMask)); +static_assert(arrsize(kCreateAppleHDAWidget1Patched) == arrsize(kCreateAppleHDAWidget1PatchedMask)); +static_assert(arrsize(kCreateAppleHDAWidget1Original) == arrsize(kCreateAppleHDAWidget1Patched)); + +/** + * `AppleGFXHDAWidgetFactory::createAppleHDAWidget` + * AppleGFXHDA.kext + * Force else path for `deviceID < 0xAB20` check + */ +static const uint8_t kCreateAppleHDAWidget2Original[] = {0x3D, 0x1F, 0xAB, 0x00, 0x00, 0x7E, 0x00}; +static const uint8_t kCreateAppleHDAWidget2OriginalMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; +static const uint8_t kCreateAppleHDAWidget2Patched[] = {0x66, 0x90, 0x66, 0x90, 0x66, 0x90, 0x90}; +static_assert(arrsize(kCreateAppleHDAWidget2Original) == arrsize(kCreateAppleHDAWidget2OriginalMask)); +static_assert(arrsize(kCreateAppleHDAWidget2Original) == arrsize(kCreateAppleHDAWidget2Patched)); + +/** + * `AppleGFXHDAWidgetFactory::createAppleHDAWidget` + * `AppleGFXHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * AppleGFXHDA.kext + * Force else path for `0x18 < deviceID - 0xAB20` check + */ +static const uint8_t kCreateAppleHDAOriginal[] = {0x8D, 0x88, 0xE0, 0x54, 0xFF, 0xFF, 0x83, 0xF9, 0x18, 0x77, 0x00}; +static const uint8_t kCreateAppleHDAOriginalMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; +static const uint8_t kCreateAppleHDAPatched[] = {0x66, 0x90, 0x66, 0x90, 0x66, 0x90, 0x66, 0x90, 0x90, 0xEB, 0x00}; +static const uint8_t kCreateAppleHDAPatchedMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; +static_assert(arrsize(kCreateAppleHDAOriginal) == arrsize(kCreateAppleHDAOriginalMask)); +static_assert(arrsize(kCreateAppleHDAPatched) == arrsize(kCreateAppleHDAPatchedMask)); +static_assert(arrsize(kCreateAppleHDAOriginal) == arrsize(kCreateAppleHDAPatched)); + +/** + * `AppleGFXHDAWidgetFactory::createAppleHDAWidget` + * `AppleGFXHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * AppleGFXHDA.kext + * Force `deviceID == 0xA*F8` path + */ +static const uint8_t kCreateAppleHDA2Original[] = {0x3D, 0xF8, 0xA0, 0x00, 0x00, 0x74, 0x00}; +static const uint8_t kCreateAppleHDA2OriginalMask[] = {0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x00}; +static const uint8_t kCreateAppleHDA2Patched[] = {0x66, 0x90, 0x66, 0x90, 0x90, 0xEB, 0x00}; +static const uint8_t kCreateAppleHDA2PatchedMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; +static_assert(arrsize(kCreateAppleHDA2Original) == arrsize(kCreateAppleHDA2OriginalMask)); +static_assert(arrsize(kCreateAppleHDA2Patched) == arrsize(kCreateAppleHDA2PatchedMask)); +static_assert(arrsize(kCreateAppleHDA2Original) == arrsize(kCreateAppleHDA2Patched)); + +/** + * `AppleHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * `AppleHDAWidgetFactory::createAppleHDAWidget` + * AppleHDA.kext + */ +static const uint8_t kAHDACreate1Original[] = {0x87, 0xAA, 0x00, 0x00, 0x0F, 0x8F}; +static const uint8_t kAHDACreate1Patched[] = {0x66, 0x90, 0x66, 0x90, 0x48, 0xE9}; +static_assert(arrsize(kAHDACreate1Original) == arrsize(kAHDACreate1Patched)); + +/** + * `AppleHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * `AppleHDAWidgetFactory::createAppleHDAWidget` + * AppleHDA.kext + */ +static const uint8_t kAHDACreate2Original[] = {0x83, 0x00, 0x38, 0x77, 0x00, 0xB0}; +static const uint8_t kAHDACreate2OriginalMask[] = {0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xF0}; +static const uint8_t kAHDACreate2Patched[] = {0x66, 0x90, 0x90, 0xEB, 0x00, 0x00}; +static const uint8_t kAHDACreate2PatchedMask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; +static_assert(arrsize(kAHDACreate2Original) == arrsize(kAHDACreate2Patched)); + +/** + * `AppleHDAFunctionGroupFactory::createAppleHDAFunctionGroup` + * `AppleHDAWidgetFactory::createAppleHDAWidget` + * AppleHDA.kext + */ +static const uint8_t kAHDACreate3Original[] = {0xD8, 0xAA, 0x00, 0x00, 0x75, 0x00}; +static const uint8_t kAHDACreate3Mask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; +static const uint8_t kAHDACreate3Patched[] = {0x66, 0x90, 0x66, 0x90, 0x66, 0x90}; +static_assert(arrsize(kAHDACreate3Original) == arrsize(kAHDACreate3Mask)); +static_assert(arrsize(kAHDACreate3Original) == arrsize(kAHDACreate3Patched)); diff --git a/Scripts/NRedWrapGen.py b/Scripts/NRedWrapGen.py index 6d9c528e..1e3d8e11 100755 --- a/Scripts/NRedWrapGen.py +++ b/Scripts/NRedWrapGen.py @@ -86,6 +86,7 @@ def locate_line(lines: list[str], needle: str) -> int: "x5000": "X5000", "x6000": "X6000", "x6000fb": "X6000FB", + "agfxhda": "AppleGFXHDA" } module: str = input("Filename without extension: ./NootedRed/kern_")