Add compatibility information and improve multi hardware management

This commit is contained in:
Hoang Hong Quan
2025-03-20 20:15:01 +07:00
parent 6626e0cd88
commit 623bcbfbb8
4 changed files with 342 additions and 141 deletions
+106 -99
View File
@@ -1,4 +1,3 @@
from Scripts.datasets import chipset_data
from Scripts.datasets import gpu_data
from Scripts.datasets import os_data
from Scripts.datasets import pci_data
@@ -22,16 +21,16 @@ class CompatibilityChecker:
max_version = self.utils.parse_darwin_version(os_data.get_latest_darwin_version())[0]
min_version = self.utils.parse_darwin_version(os_data.get_lowest_darwin_version())[0]
if min_version < min_compatibility and max_compatibility < max_version:
return "\033[1;32m{} - {}\033[0m".format(
os_data.get_macos_name_by_darwin(device_compatibility[0]),
os_data.get_macos_name_by_darwin(device_compatibility[-1])
)
if max_compatibility == min_version:
return "\033[1;36mMaximum support up to {}\033[0m".format(
os_data.get_macos_name_by_darwin(device_compatibility[-1])
)
if min_version < min_compatibility or max_compatibility < max_version:
return "\033[1;32m{} to {}\033[0m".format(
os_data.get_macos_name_by_darwin(device_compatibility[-1]),
os_data.get_macos_name_by_darwin(device_compatibility[0])
)
return "\033[1;36mUp to {}\033[0m".format(
os_data.get_macos_name_by_darwin(device_compatibility[0])
@@ -53,19 +52,31 @@ class CompatibilityChecker:
max_version = "21.99.99"
self.hardware_report["CPU"]["Compatibility"] = (max_version, min_version)
print("{}- {}: {}".format(" "*3, self.hardware_report.get("CPU").get("Processor Name"), self.show_macos_compatibility(self.hardware_report["CPU"].get("Compatibility"))))
if max_version == min_version and max_version == None:
self.utils.request_input("\n\nThe CPU is not compatible with macOS!")
print("")
print("Missing required SSE4.x instruction set.")
print("Your CPU is not supported by macOS versions newer than Sierra (10.12).")
print("")
self.utils.request_input()
self.utils.exit_program()
self.max_native_macos_version = max_version
self.min_native_macos_version = min_version
def check_gpu_compatibility(self):
gpu_compatibility = []
if not self.hardware_report.get("GPU"):
print("")
print("No GPU found!")
print("Please make sure to export the hardware report with the GPU information")
print("and try again.")
print("")
self.utils.request_input()
self.utils.exit_program()
for gpu_name, gpu_props in self.hardware_report.get("GPU").items():
for gpu_name, gpu_props in self.hardware_report["GPU"].items():
gpu_manufacturer = gpu_props.get("Manufacturer")
gpu_codename = gpu_props.get("Codename")
device_id = gpu_props.get("Device ID")[5:]
@@ -84,14 +95,14 @@ class CompatibilityChecker:
max_version = "20.99.99"
elif device_id.startswith(("04", "0A", "0C", "0D", "0B", "16")):
max_version = "21.99.99"
elif device_id.startswith(("09", "19", "59", "59", "3E", "87", "9B")) and not device_id in ("3E90", "3E93", "3E99", "3E9C", "3EA1", "3EA4", "9B21", "9BA0", "9BA2", "9BA4", "9BA5", "9BA8", "9BAA", "9BAB", "9BAC"):
elif device_id.startswith(("09", "19", "59", "3E", "87", "9B")) and not device_id in ("3E90", "3E93", "3E99", "3E9C", "3EA1", "3EA4", "9B21", "9BA0", "9BA2", "9BA4", "9BA5", "9BA8", "9BAA", "9BAB", "9BAC"):
pass
elif device_id.startswith("8A"):
min_version = "19.4.0"
else:
max_version = min_version = None
if self.is_low_end_intel_cpu(self.hardware_report.get("CPU").get("Processor Name")) or self.hardware_report.get("Motherboard").get("Chipset") in chipset_data.IntelChipsets[127:141]:
if self.is_low_end_intel_cpu(self.hardware_report.get("CPU").get("Processor Name")):
max_version = min_version = None
elif "AMD" in gpu_manufacturer:
if "Navi 2" in gpu_codename:
@@ -144,15 +155,11 @@ class CompatibilityChecker:
if max_version != ocl_patched_max_version:
gpu_props["OCLP Compatibility"] = (ocl_patched_max_version, ocl_patched_min_version if self.utils.parse_darwin_version(ocl_patched_min_version) > self.utils.parse_darwin_version("{}.{}.{}".format(int(max_version[:2]) + 1, 0, 0)) else "{}.{}.{}".format(int(max_version[:2]) + 1, 0, 0))
print("{}- {}: {}{}".format(
" "*3,
gpu_name,
self.show_macos_compatibility(gpu_props.get("Compatibility")),
" \033[1;36m(requires monitor)\033[0m"
if max_version and \
not "Intel" in gpu_manufacturer and \
not any(monitor_info.get("Connected GPU", gpu_name) == gpu_name for monitor_name, monitor_info in self.hardware_report.get("Monitor", {}).items()) else ""
))
print("{}- {}: {}".format(" "*3, gpu_name, self.show_macos_compatibility(gpu_props.get("Compatibility"))))
if "OCLP Compatibility" in gpu_props:
print("{}- OCLP Compatibility: {}".format(" "*6, self.show_macos_compatibility(gpu_props.get("OCLP Compatibility"))))
connected_monitors = []
for monitor_name, monitor_info in self.hardware_report.get("Monitor", {}).items():
if monitor_info.get("Connected GPU") == gpu_name:
@@ -182,50 +189,46 @@ class CompatibilityChecker:
self.ocl_patched_macos_version = (gpu_props.get("OCLP Compatibility")[0], self.ocl_patched_macos_version[-1] if self.ocl_patched_macos_version and self.utils.parse_darwin_version(self.ocl_patched_macos_version[-1]) < self.utils.parse_darwin_version(gpu_props.get("OCLP Compatibility")[-1]) else gpu_props.get("OCLP Compatibility")[-1])
if max_supported_gpu_version == min_supported_gpu_version and max_supported_gpu_version == None:
self.utils.request_input("\n\nNo compatible GPU card for macOS was found!")
print("")
print("No compatible GPU for macOS was found!")
if self.hardware_report.get("Motherboard").get("Platform") == "Desktop":
print("Consider purchasing a compatible GPU for your system.")
print("")
self.utils.request_input()
self.utils.exit_program()
self.max_native_macos_version = max_supported_gpu_version if self.utils.parse_darwin_version(max_supported_gpu_version) < self.utils.parse_darwin_version(self.max_native_macos_version) else self.max_native_macos_version
self.min_native_macos_version = min_supported_gpu_version if self.utils.parse_darwin_version(min_supported_gpu_version) > self.utils.parse_darwin_version(self.min_native_macos_version) else self.min_native_macos_version
return gpu_compatibility
def check_sound_compatibility(self):
sound_info = {}
for audio_device, audio_props in self.hardware_report.get("Sound", {}).items():
codec_id = audio_props.get("Device ID")
max_version = min_version = None
if "USB" in audio_props.get("Bus Type") or \
codec_id.startswith("1002") or \
codec_id.startswith("8086") and not codec_id in pci_data.IntelSSTIDs or \
codec_id in codec_layouts.data:
audio_props["Compatibility"] = (os_data.get_latest_darwin_version(), os_data.get_lowest_darwin_version())
if codec_id in codec_layouts.data:
sound_info = {**{audio_device: audio_props}, **sound_info}
else:
sound_info[audio_device] = audio_props
else:
audio_props["Compatibility"] = (None, None)
sound_info[audio_device] = audio_props
max_version, min_version = os_data.get_latest_darwin_version(), os_data.get_lowest_darwin_version()
audio_props["Compatibility"] = (max_version, min_version)
print("{}- {}: {}".format(" "*3, audio_device, self.show_macos_compatibility(audio_props.get("Compatibility"))))
audio_endpoints = audio_props.get("Audio Endpoints")
if audio_endpoints:
print("{}- Audio Endpoint{}: {}".format(" "*6, "s" if len(audio_endpoints) > 1 else "", ", ".join(audio_endpoints)))
self.hardware_report["Sound"] = sound_info
def check_biometric_compatibility(self):
print(" \033[93mNote:\033[0m Biometric authentication in macOS requires Apple T2 Chip,")
print(" which is not available for Hackintosh systems.")
print("")
for biometric_device, biometric_props in self.hardware_report.get("Biometric", {}).items():
biometric_props["Compatibility"] = (None, None)
print("{}- {}: {}".format(" "*3, biometric_device, self.show_macos_compatibility(biometric_props.get("Compatibility"))))
def check_network_compatibility(self):
primary_wifi_device = next((device_props.get("Device ID") for device_name, device_props in self.hardware_report.get("Network", {}).items() if device_props.get("Device ID") in pci_data.BroadcomWiFiIDs), None)
if not primary_wifi_device:
primary_wifi_device = next((device_props.get("Device ID") for device_name, device_props in self.hardware_report.get("Network", {}).items() if device_props.get("Device ID") in pci_data.IntelWiFiIDs), None)
if not primary_wifi_device:
primary_wifi_device = next((device_props.get("Device ID") for device_name, device_props in self.hardware_report.get("Network", {}).items() if device_props.get("Device ID") in pci_data.AtherosWiFiIDs), None)
for device_name, device_props in self.hardware_report.get("Network", {}).items():
bus_type = device_props.get("Bus Type")
device_id = device_props.get("Device ID")
@@ -253,12 +256,10 @@ class CompatibilityChecker:
min_version = "21.0.0"
if device_id in pci_data.WirelessCardIDs:
if device_id == primary_wifi_device:
if not device_id in pci_data.IntelWiFiIDs and not device_id in pci_data.AtherosWiFiIDs[8:]:
device_props["OCLP Compatibility"] = (ocl_patched_max_version, ocl_patched_min_version)
self.ocl_patched_macos_version = (ocl_patched_max_version, self.ocl_patched_macos_version[-1] if self.ocl_patched_macos_version and self.utils.parse_darwin_version(self.ocl_patched_macos_version[-1]) < self.utils.parse_darwin_version(device_props.get("OCLP Compatibility")[-1]) else device_props.get("OCLP Compatibility")[-1])
device_props["Compatibility"] = (max_version, min_version)
primary_wifi_device = None
if not device_id in pci_data.IntelWiFiIDs and not device_id in pci_data.AtherosWiFiIDs[8:]:
device_props["OCLP Compatibility"] = (ocl_patched_max_version, ocl_patched_min_version)
self.ocl_patched_macos_version = (ocl_patched_max_version, self.ocl_patched_macos_version[-1] if self.ocl_patched_macos_version and self.utils.parse_darwin_version(self.ocl_patched_macos_version[-1]) < self.utils.parse_darwin_version(device_props.get("OCLP Compatibility")[-1]) else device_props.get("OCLP Compatibility")[-1])
device_props["Compatibility"] = (max_version, min_version)
elif device_id in pci_data.EthernetIDs + pci_data.WirelessUSBIDs:
device_props["Compatibility"] = (max_version, min_version)
@@ -267,9 +268,31 @@ class CompatibilityChecker:
print("{}- {}: {}".format(" "*3, device_name, self.show_macos_compatibility(device_props.get("Compatibility"))))
if device_id in pci_data.WirelessCardIDs:
if device_id in pci_data.BroadcomWiFiIDs:
print("{}- Continuity Support: \033[1;32mFull\033[0m (AirDrop, Handoff, Universal Clipboard, Instant Hotspot,...)".format(" "*6))
elif device_id in pci_data.IntelWiFiIDs:
print("{}- Continuity Support: \033[1;33mPartial\033[0m (Handoff and Universal Clipboard with AirportItlwm)".format(" "*6))
print("{}\033[93mNote:\033[0m AirDrop, Universal Clipboard, Instant Hotspot,... not available".format(" "*6))
elif device_id in pci_data.AtherosWiFiIDs:
print("{}- Continuity Support: \033[1;31mLimited\033[0m (No Continuity features available)".format(" "*6))
print("{}\033[93mNote:\033[0m Atheros cards are not recommended for macOS".format(" "*6))
if "OCLP Compatibility" in device_props:
print("{}- OCLP Compatibility: {}".format(" "*6, self.show_macos_compatibility(device_props.get("OCLP Compatibility"))))
def check_storage_compatibility(self):
for controller_name, controller_props in self.hardware_report.get("Storage Controllers", {}).items():
if "PCI" not in controller_props.get("Bus Type"):
if not self.hardware_report.get("Storage Controllers"):
print("")
print("No storage controller found!")
print("Please make sure to export the hardware report with the storage controller information")
print("and try again.")
print("")
self.utils.request_input()
self.utils.exit_program()
for controller_name, controller_props in self.hardware_report["Storage Controllers"].items():
if controller_props.get("Bus Type") != "PCI":
continue
device_id = controller_props.get("Device ID")
@@ -279,18 +302,27 @@ class CompatibilityChecker:
min_version = os_data.get_lowest_darwin_version()
if device_id in pci_data.IntelVMDIDs:
self.utils.request_input("\n\nDisable Intel RST VMD in the BIOS before exporting the hardware report and try again with the new report")
print("")
print("Intel VMD controllers are not supported in macOS.")
print("Please disable Intel VMD in the BIOS settings and try again with new hardware report.")
print("")
self.utils.request_input()
self.utils.exit_program()
controller_props["Compatibility"] = (max_version, min_version)
if next((device for device in pci_data.UnsupportedNVMeSSDIDs if device_id == device[0] and subsystem_id in device[1]), None):
controller_props["Compatibility"] = (None, None)
max_version = min_version = None
controller_props["Compatibility"] = (max_version, min_version)
print("{}- {}: {}".format(" "*3, controller_name, self.show_macos_compatibility(controller_props.get("Compatibility"))))
if all(controller_props.get("Compatibility") == (None, None) for controller_name, controller_props in self.hardware_report.get("Storage Controllers", {}).items()):
self.utils.request_input("\n\nNo compatible storage for macOS was found!")
if all(controller_props.get("Compatibility") == (None, None) for controller_name, controller_props in self.hardware_report["Storage Controllers"].items()):
print("")
print("No compatible storage controller for macOS was found!")
print("Consider purchasing a compatible SSD NVMe for your system.")
print("Western Digital NVMe SSDs are generally recommended for good macOS compatibility.")
print("")
self.utils.request_input()
self.utils.exit_program()
def check_bluetooth_compatibility(self):
@@ -308,59 +340,34 @@ class CompatibilityChecker:
max_version = min_version = None
bluetooth_props["Compatibility"] = (max_version, min_version)
print("{}- {}: {}".format(" "*3, bluetooth_name, self.show_macos_compatibility(bluetooth_props.get("Compatibility"))))
def check_sd_controller_compatibility(self):
for controller_name, controller_props in self.hardware_report.get("SD Controller", {}).items():
if controller_props.get("Device ID") not in pci_data.RealtekCardReaderIDs:
controller_props["Compatibility"] = (None, None)
device_id = controller_props.get("Device ID")
max_version = os_data.get_latest_darwin_version()
min_version = os_data.get_lowest_darwin_version()
if device_id in pci_data.RealtekCardReaderIDs:
if device_id in pci_data.RealtekCardReaderIDs[:5]:
max_version = "23.99.99"
else:
controller_props["Compatibility"] = (os_data.get_latest_darwin_version() if controller_props.get("Device ID") in pci_data.RealtekCardReaderIDs[5:] else "23.99.99", os_data.get_lowest_darwin_version())
max_version = min_version = None
controller_props["Compatibility"] = (max_version, min_version)
print("{}- {}: {}".format(" "*3, controller_name, self.show_macos_compatibility(controller_props.get("Compatibility"))))
def get_unsupported_devices(self, macos_verison):
new_hardware_report = {}
unsupported_device = {}
needs_oclp = False
for device_type, devices in self.hardware_report.items():
if device_type in ("Motherboard", "BIOS", "CPU", "USB Controllers", "Input", "System Devices"):
new_hardware_report[device_type] = devices
continue
new_hardware_report[device_type] = {}
for device_name in devices:
device_props = devices[device_name].copy()
if device_props.get("OCLP Compatibility") and self.utils.parse_darwin_version(device_props.get("OCLP Compatibility")[0]) >= self.utils.parse_darwin_version(macos_verison) >= self.utils.parse_darwin_version(device_props.get("OCLP Compatibility")[-1]):
new_hardware_report[device_type][device_name] = device_props
needs_oclp = True
continue
device_compatibility = device_props.get("Compatibility")
if device_compatibility:
if device_compatibility[0] is None or not self.utils.parse_darwin_version(device_compatibility[0]) >= self.utils.parse_darwin_version(macos_verison) >= self.utils.parse_darwin_version(device_compatibility[-1]):
unsupported_device["{}: {}{}".format(device_props.get("Device Type") or device_type, device_name, "" if not device_props.get("Audio Endpoints") else " ({})".format(", ".join(device_props.get("Audio Endpoints"))))] = device_props
else:
new_hardware_report[device_type][device_name] = device_props
else:
new_hardware_report[device_type][device_name] = device_props
if new_hardware_report[device_type].get(device_name) and new_hardware_report[device_type][device_name].get("OCLP Compatibility"):
del new_hardware_report[device_type][device_name]["OCLP Compatibility"]
if not new_hardware_report[device_type]:
del new_hardware_report[device_type]
return new_hardware_report, unsupported_device, needs_oclp
def check_compatibility(self, hardware_report):
self.hardware_report = hardware_report
self.ocl_patched_macos_version = None
self.utils.head("Compatibility Checker")
print()
print("")
print("Checking compatibility with macOS for the following devices:")
print("")
steps = [
('CPU', self.check_cpu_compatibility),
@@ -378,10 +385,10 @@ class CompatibilityChecker:
if self.hardware_report.get(device_type):
index += 1
print("{}. {}:".format(index, device_type))
time.sleep(0.5)
time.sleep(0.25)
function()
print("")
self.utils.request_input()
return (self.min_native_macos_version, self.max_native_macos_version), *self.get_unsupported_devices(self.max_native_macos_version), self.ocl_patched_macos_version
return hardware_report, (self.min_native_macos_version, self.max_native_macos_version), self.ocl_patched_macos_version