<commit_before>//
//  kern_alc.cpp
//  AppleALC
//
//  Copyright © 2016-2017 vit9696. All rights reserved.
//

#include <Headers/kern_api.hpp>
#include <Headers/kern_devinfo.hpp>
#include <Headers/plugin_start.hpp>
#include <Library/LegacyIOService.h>
#include <mach/vm_map.h>

#include "kern_alc.hpp"
#include "kern_resources.hpp"

// Only used in apple-driven callbacks
static AlcEnabler *callbackAlc;

void AlcEnabler::init() {
	callbackAlc = this;

	lilu.onPatcherLoadForce(
	[](void *user, KernelPatcher &pathcer) {
		static_cast<AlcEnabler *>(user)->updateProperties();
	}, this);

	if (getKernelVersion() < KernelVersion::Mojave)
		ADDPR(kextList)[KextIdAppleGFXHDA].switchOff();

	lilu.onKextLoadForce(ADDPR(kextList), ADDPR(kextListSize),
	[](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
		static_cast<AlcEnabler *>(user)->processKext(patcher, index, address, size);
	}, this);

	if (getKernelVersion() >= KernelVersion::Sierra) {
		// Unlock custom audio engines by disabling Apple private entitlement verification
		// Recent macOS versions (e.g. 10.13.6) support legacy_hda_tools_support=1 boot argument, which works similarly.
		if (checkKernelArgument("-alcdhost")) {
			if (getKernelVersion() >= KernelVersion::HighSierra)
				SYSLOG("alc", "consider replacing -alcdhost with legacy_hda_tools_support=1 boot-arg!");
			lilu.onEntitlementRequestForce([](void *user, task_t task, const char *entitlement, OSObject *&original) {
				static_cast<AlcEnabler *>(user)->handleAudioClientEntitlement(task, entitlement, original);
			}, this);
		}
	}
}

void AlcEnabler::deinit() {
	controllers.deinit();
	codecs.deinit();
}

void AlcEnabler::updateProperties() {
	auto devInfo = DeviceInfo::create();
	if (devInfo) {
		// Assume that IGPU with connections means built-in digital audio.
		bool hasBuiltinDigitalAudio = !devInfo->reportedFramebufferIsConnectorLess && devInfo->videoBuiltin;

		// Respect desire to disable digital audio. This may be particularly useful for configurations
		// with broken digital audio, resulting in kernel panics. Ref: https://github.com/acidanthera/bugtracker/issues/513
		if (hasBuiltinDigitalAudio && devInfo->audioBuiltinAnalog && devInfo->audioBuiltinAnalog->getProperty("No-hda-gfx"))
			hasBuiltinDigitalAudio = false;

		// Firstly, update Haswell or Broadwell HDAU device for built-in digital audio.
		if (devInfo->audioBuiltinDigital && validateInjection(devInfo->audioBuiltinDigital)) {
			if (hasBuiltinDigitalAudio) {
				// This is a normal HDAU device for an IGPU with connectors.
				updateDeviceProperties(devInfo->audioBuiltinDigital, devInfo, "onboard-1", false);
				uint32_t dev = 0, rev = 0;
				if (WIOKit::getOSDataValue(devInfo->audioBuiltinDigital, "device-id", dev) &&
					WIOKit::getOSDataValue(devInfo->audioBuiltinDigital, "revision-id", rev))
					insertController(WIOKit::VendorID::Intel, dev, rev, nullptr != devInfo->audioBuiltinDigital->getProperty("no-controller-patch"), devInfo->reportedFramebufferId);
			} else {
				// Terminate built-in HDAU audio, as we are using no connectors!
				auto hda = OSDynamicCast(IOService, devInfo->audioBuiltinDigital);
				auto pci = OSDynamicCast(IOService, devInfo->audioBuiltinDigital->getParentEntry(gIOServicePlane));
				if (hda && pci) {
					if (hda->requestTerminate(pci, 0) && hda->terminate())
						hda->stop(pci);
					else
						SYSLOG("alc", "failed to terminate built-in digital audio");
				} else {
					SYSLOG("alc", "incompatible built-in hdau discovered");
				}
			}
		}

		// Secondly, update HDEF device and make it support digital audio
		if (devInfo->audioBuiltinAnalog && validateInjection(devInfo->audioBuiltinAnalog)) {
			const char *hdaGfx = nullptr;
			if (hasBuiltinDigitalAudio && !devInfo->audioBuiltinDigital)
				hdaGfx = "onboard-1";
			updateDeviceProperties(devInfo->audioBuiltinAnalog, devInfo, hdaGfx, true);
		}

		// Thirdly, update IGPU device in case we have digital audio
		if (hasBuiltinDigitalAudio && validateInjection(devInfo->videoBuiltin)) {
			devInfo->videoBuiltin->setProperty("hda-gfx", const_cast<char *>("onboard-1"), sizeof("onboard-1"));
			if (!devInfo->audioBuiltinDigital) {
				uint32_t dev = 0, rev = 0;
				if (WIOKit::getOSDataValue(devInfo->videoBuiltin, "device-id", dev) &&
					WIOKit::getOSDataValue(devInfo->videoBuiltin, "revision-id", rev))
					insertController(WIOKit::VendorID::Intel, dev, rev, nullptr != devInfo->videoBuiltin->getProperty("no-controller-patch"), devInfo->reportedFramebufferId);
			}
		}

		uint32_t hdaGfxCounter = hasBuiltinDigitalAudio ? 2 : 1;

		// Fourthly, update all the GPU devices if any
		for (size_t gpu = 0; gpu < devInfo->videoExternal.size(); gpu++) {
			auto hdaService = devInfo->videoExternal[gpu].audio;
			auto gpuService = devInfo->videoExternal[gpu].video;

			if (!hdaService || !validateInjection(hdaService))
				continue;

			uint32_t ven = devInfo->videoExternal[gpu].vendor;
			uint32_t dev = 0, rev = 0;
			if (WIOKit::getOSDataValue(hdaService, "device-id", dev) &&
				WIOKit::getOSDataValue(hdaService, "revision-id", rev)) {
				// Register the controller
				insertController(ven, dev, rev, nullptr != hdaService->getProperty("no-controller-patch"));
				// Disable the id in the list if any
				if (ven == WIOKit::VendorID::NVIDIA) {
					uint32_t device = (dev << 16) | WIOKit::VendorID::NVIDIA;
					for (size_t i = 0; i < MaxNvidiaDeviceIds; i++)
						if (nvidiaDeviceIdList[i] == device)
							nvidiaDeviceIdUsage[i] = true;
				}
			}

			// Refresh the main properties including hda-gfx.
			char hdaGfx[16];
			snprintf(hdaGfx, sizeof(hdaGfx), "onboard-%u", hdaGfxCounter++);
			updateDeviceProperties(hdaService, devInfo, hdaGfx, false);
			gpuService->setProperty("hda-gfx", hdaGfx, static_cast<uint32_t>(strlen(hdaGfx)+1));

			// Refresh connector types on NVIDIA, since they are required for HDMI audio to function.
			// Abort if preexisting connector-types or no-audio-fixconn property is found.
			if (ven == WIOKit::VendorID::NVIDIA && !gpuService->getProperty("no-audio-fixconn")) {
				uint8_t builtBytes[] { 0x00, 0x08, 0x00, 0x00 };
				char connector_type[] { "@0,connector-type" };
				for (size_t i = 0; i < MaxConnectorCount; i++) {
					connector_type[1] = '0' + i;
					if (!gpuService->getProperty(connector_type)) {
						DBGLOG("alc", "fixing %s in gpu", connector_type);
						gpuService->setProperty(connector_type, builtBytes, sizeof(builtBytes));
					} else {
						DBGLOG("alc", "found existing %s in gpu", connector_type);
						break;
					}
				}
			}
		}

		DeviceInfo::deleter(devInfo);
	}
}

void AlcEnabler::updateDeviceProperties(IORegistryEntry *hdaService, DeviceInfo *info, const char *hdaGfx, bool isAnalog) {
	auto hdaPlaneName = hdaService->getName();

	// AppleHDAController only recognises HDEF and HDAU.
	if (isAnalog && (!hdaPlaneName || strcmp(hdaPlaneName, "HDEF") != 0)) {
		DBGLOG("alc", "fixing audio plane name to HDEF");
		WIOKit::renameDevice(hdaService, "HDEF");
	} else if (!isAnalog && (!hdaPlaneName || strcmp(hdaPlaneName, "HDAU") != 0)) {
		DBGLOG("alc", "fixing audio plane name to HDAU");
		WIOKit::renameDevice(hdaService, "HDAU");
	}

	if (isAnalog) {
		// Refresh our own layout-id named alc-layout-id as follows:
		// alcid=X has highest priority and overrides any other value.
		// alc-layout-id has normal priority and is expected to be used.
		// layout-id will be used if both alcid and alc-layout-id are not set on non-Apple platforms.
		uint32_t layout = 0;
		if (PE_parse_boot_argn("alcid", &layout, sizeof(layout))) {
			DBGLOG("alc", "found alc-layout-id override %u", layout);
			hdaService->setProperty("alc-layout-id", &layout, sizeof(layout));
		} else {
			uint32_t alcId;
			if (WIOKit::getOSDataValue(hdaService, "alc-layout-id", alcId)) {
				DBGLOG("alc", "found normal alc-layout-id %u", alcId);
			} else if (info->firmwareVendor != DeviceInfo::FirmwareVendor::Apple &&
					   WIOKit::getOSDataValue(hdaService, "layout-id", alcId)) {
				DBGLOG("audio", "found legacy alc-layout-id (from layout-id) %u", alcId);
				hdaService->setProperty("alc-layout-id", &alcId, sizeof(alcId));
			}<commit_msg>Print explicit warning when `layout-id` is not injected  (#475)<commit_after>//
//  kern_alc.cpp
//  AppleALC
//
//  Copyright © 2016-2017 vit9696. All rights reserved.
//

#include <Headers/kern_api.hpp>
#include <Headers/kern_devinfo.hpp>
#include <Headers/plugin_start.hpp>
#include <Library/LegacyIOService.h>
#include <mach/vm_map.h>

#include "kern_alc.hpp"
#include "kern_resources.hpp"

// Only used in apple-driven callbacks
static AlcEnabler *callbackAlc;

void AlcEnabler::init() {
	callbackAlc = this;

	lilu.onPatcherLoadForce(
	[](void *user, KernelPatcher &pathcer) {
		static_cast<AlcEnabler *>(user)->updateProperties();
	}, this);

	if (getKernelVersion() < KernelVersion::Mojave)
		ADDPR(kextList)[KextIdAppleGFXHDA].switchOff();

	lilu.onKextLoadForce(ADDPR(kextList), ADDPR(kextListSize),
	[](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
		static_cast<AlcEnabler *>(user)->processKext(patcher, index, address, size);
	}, this);

	if (getKernelVersion() >= KernelVersion::Sierra) {
		// Unlock custom audio engines by disabling Apple private entitlement verification
		// Recent macOS versions (e.g. 10.13.6) support legacy_hda_tools_support=1 boot argument, which works similarly.
		if (checkKernelArgument("-alcdhost")) {
			if (getKernelVersion() >= KernelVersion::HighSierra)
				SYSLOG("alc", "consider replacing -alcdhost with legacy_hda_tools_support=1 boot-arg!");
			lilu.onEntitlementRequestForce([](void *user, task_t task, const char *entitlement, OSObject *&original) {
				static_cast<AlcEnabler *>(user)->handleAudioClientEntitlement(task, entitlement, original);
			}, this);
		}
	}
}

void AlcEnabler::deinit() {
	controllers.deinit();
	codecs.deinit();
}

void AlcEnabler::updateProperties() {
	auto devInfo = DeviceInfo::create();
	if (devInfo) {
		// Assume that IGPU with connections means built-in digital audio.
		bool hasBuiltinDigitalAudio = !devInfo->reportedFramebufferIsConnectorLess && devInfo->videoBuiltin;

		// Respect desire to disable digital audio. This may be particularly useful for configurations
		// with broken digital audio, resulting in kernel panics. Ref: https://github.com/acidanthera/bugtracker/issues/513
		if (hasBuiltinDigitalAudio && devInfo->audioBuiltinAnalog && devInfo->audioBuiltinAnalog->getProperty("No-hda-gfx"))
			hasBuiltinDigitalAudio = false;

		// Firstly, update Haswell or Broadwell HDAU device for built-in digital audio.
		if (devInfo->audioBuiltinDigital && validateInjection(devInfo->audioBuiltinDigital)) {
			if (hasBuiltinDigitalAudio) {
				// This is a normal HDAU device for an IGPU with connectors.
				updateDeviceProperties(devInfo->audioBuiltinDigital, devInfo, "onboard-1", false);
				uint32_t dev = 0, rev = 0;
				if (WIOKit::getOSDataValue(devInfo->audioBuiltinDigital, "device-id", dev) &&
					WIOKit::getOSDataValue(devInfo->audioBuiltinDigital, "revision-id", rev))
					insertController(WIOKit::VendorID::Intel, dev, rev, nullptr != devInfo->audioBuiltinDigital->getProperty("no-controller-patch"), devInfo->reportedFramebufferId);
			} else {
				// Terminate built-in HDAU audio, as we are using no connectors!
				auto hda = OSDynamicCast(IOService, devInfo->audioBuiltinDigital);
				auto pci = OSDynamicCast(IOService, devInfo->audioBuiltinDigital->getParentEntry(gIOServicePlane));
				if (hda && pci) {
					if (hda->requestTerminate(pci, 0) && hda->terminate())
						hda->stop(pci);
					else
						SYSLOG("alc", "failed to terminate built-in digital audio");
				} else {
					SYSLOG("alc", "incompatible built-in hdau discovered");
				}
			}
		}

		// Secondly, update HDEF device and make it support digital audio
		if (devInfo->audioBuiltinAnalog && validateInjection(devInfo->audioBuiltinAnalog)) {
			const char *hdaGfx = nullptr;
			if (hasBuiltinDigitalAudio && !devInfo->audioBuiltinDigital)
				hdaGfx = "onboard-1";
			updateDeviceProperties(devInfo->audioBuiltinAnalog, devInfo, hdaGfx, true);
		}

		// Thirdly, update IGPU device in case we have digital audio
		if (hasBuiltinDigitalAudio && validateInjection(devInfo->videoBuiltin)) {
			devInfo->videoBuiltin->setProperty("hda-gfx", const_cast<char *>("onboard-1"), sizeof("onboard-1"));
			if (!devInfo->audioBuiltinDigital) {
				uint32_t dev = 0, rev = 0;
				if (WIOKit::getOSDataValue(devInfo->videoBuiltin, "device-id", dev) &&
					WIOKit::getOSDataValue(devInfo->videoBuiltin, "revision-id", rev))
					insertController(WIOKit::VendorID::Intel, dev, rev, nullptr != devInfo->videoBuiltin->getProperty("no-controller-patch"), devInfo->reportedFramebufferId);
			}
		}

		uint32_t hdaGfxCounter = hasBuiltinDigitalAudio ? 2 : 1;

		// Fourthly, update all the GPU devices if any
		for (size_t gpu = 0; gpu < devInfo->videoExternal.size(); gpu++) {
			auto hdaService = devInfo->videoExternal[gpu].audio;
			auto gpuService = devInfo->videoExternal[gpu].video;

			if (!hdaService || !validateInjection(hdaService))
				continue;

			uint32_t ven = devInfo->videoExternal[gpu].vendor;
			uint32_t dev = 0, rev = 0;
			if (WIOKit::getOSDataValue(hdaService, "device-id", dev) &&
				WIOKit::getOSDataValue(hdaService, "revision-id", rev)) {
				// Register the controller
				insertController(ven, dev, rev, nullptr != hdaService->getProperty("no-controller-patch"));
				// Disable the id in the list if any
				if (ven == WIOKit::VendorID::NVIDIA) {
					uint32_t device = (dev << 16) | WIOKit::VendorID::NVIDIA;
					for (size_t i = 0; i < MaxNvidiaDeviceIds; i++)
						if (nvidiaDeviceIdList[i] == device)
							nvidiaDeviceIdUsage[i] = true;
				}
			}

			// Refresh the main properties including hda-gfx.
			char hdaGfx[16];
			snprintf(hdaGfx, sizeof(hdaGfx), "onboard-%u", hdaGfxCounter++);
			updateDeviceProperties(hdaService, devInfo, hdaGfx, false);
			gpuService->setProperty("hda-gfx", hdaGfx, static_cast<uint32_t>(strlen(hdaGfx)+1));

			// Refresh connector types on NVIDIA, since they are required for HDMI audio to function.
			// Abort if preexisting connector-types or no-audio-fixconn property is found.
			if (ven == WIOKit::VendorID::NVIDIA && !gpuService->getProperty("no-audio-fixconn")) {
				uint8_t builtBytes[] { 0x00, 0x08, 0x00, 0x00 };
				char connector_type[] { "@0,connector-type" };
				for (size_t i = 0; i < MaxConnectorCount; i++) {
					connector_type[1] = '0' + i;
					if (!gpuService->getProperty(connector_type)) {
						DBGLOG("alc", "fixing %s in gpu", connector_type);
						gpuService->setProperty(connector_type, builtBytes, sizeof(builtBytes));
					} else {
						DBGLOG("alc", "found existing %s in gpu", connector_type);
						break;
					}
				}
			}
		}

		DeviceInfo::deleter(devInfo);
	}
}

void AlcEnabler::updateDeviceProperties(IORegistryEntry *hdaService, DeviceInfo *info, const char *hdaGfx, bool isAnalog) {
	auto hdaPlaneName = hdaService->getName();

	// AppleHDAController only recognises HDEF and HDAU.
	if (isAnalog && (!hdaPlaneName || strcmp(hdaPlaneName, "HDEF") != 0)) {
		DBGLOG("alc", "fixing audio plane name to HDEF");
		WIOKit::renameDevice(hdaService, "HDEF");
	} else if (!isAnalog && (!hdaPlaneName || strcmp(hdaPlaneName, "HDAU") != 0)) {
		DBGLOG("alc", "fixing audio plane name to HDAU");
		WIOKit::renameDevice(hdaService, "HDAU");
	}

	if (isAnalog) {
		// Refresh our own layout-id named alc-layout-id as follows:
		// alcid=X has highest priority and overrides any other value.
		// alc-layout-id has normal priority and is expected to be used.
		// layout-id will be used if both alcid and alc-layout-id are not set on non-Apple platforms.
		uint32_t layout = 0;
		if (PE_parse_boot_argn("alcid", &layout, sizeof(layout))) {
			DBGLOG("alc", "found alc-layout-id override %u", layout);
			hdaService->setProperty("alc-layout-id", &layout, sizeof(layout));
		} else {
			uint32_t alcId;
			if (WIOKit::getOSDataValue(hdaService, "alc-layout-id", alcId)) {
				DBGLOG("alc", "found normal alc-layout-id %u", alcId);
			} else if (info->firmwareVendor != DeviceInfo::FirmwareVendor::Apple &&
					   WIOKit::getOSDataValue(hdaService, "layout-id", alcId)) {
				DBGLOG("audio", "found legacy alc-layout-id (from layout-id) %u", alcId);
				hdaService->setProperty("alc-layout-id", &alcId, sizeof(alcId));
			} else {
				SYSLOG("audio", "ERROR: Neither alc-layout-id nor layout-id is found in configuration");
			}
{'fraction_non_alphanumeric': 0.1378017058859113, 'fraction_numerical': 0.0098602625370516, 'mean_word_length': 4.573836817262306, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 123, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6678568', 'n_tokens_mistral': 6373, 'n_tokens_neox': 5573, 'n_words': 1281}