mirror of
https://github.com/NixOS/nixos-hardware.git
synced 2025-11-03 08:47:13 +08:00
apple/t2: add Wi-Fi and Bluetooth firmware option
This commit is contained in:
@@ -63,6 +63,19 @@ in
|
||||
example = "latest";
|
||||
description = "The kernel release stream to use.";
|
||||
};
|
||||
firmware = {
|
||||
enable = lib.mkEnableOption "automatic and declarative Wi-Fi and Bluetooth firmware configuration";
|
||||
version = lib.mkOption {
|
||||
type = types.enum [
|
||||
"monterey"
|
||||
"ventura"
|
||||
"sonoma"
|
||||
];
|
||||
default = "sonoma";
|
||||
example = "ventura";
|
||||
description = "The macOS version to use.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
@@ -105,5 +118,11 @@ in
|
||||
options apple-gmux force_igd=y
|
||||
'';
|
||||
})
|
||||
(lib.mkIf t2Cfg.firmware.enable {
|
||||
# Configure Wi-Fi and Bluetooth firmware
|
||||
hardware.firmware = [
|
||||
(pkgs.callPackage ./pkgs/brcm-firmware { version = t2Cfg.firmware.version; })
|
||||
];
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
89
apple/t2/pkgs/brcm-firmware/default.nix
Normal file
89
apple/t2/pkgs/brcm-firmware/default.nix
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
callPackage,
|
||||
vmTools,
|
||||
util-linux,
|
||||
linux,
|
||||
kmod,
|
||||
version,
|
||||
}:
|
||||
|
||||
let
|
||||
get-firmware = callPackage ./get-firmware.nix { };
|
||||
fetchmacos = callPackage ./fetchmacos.nix { };
|
||||
|
||||
# See https://github.com/kholia/OSX-KVM/blob/master/fetch-macOS-v2.py#L534-L546.
|
||||
# Versions before macOS Monterey don't have Bluetooth firmware.
|
||||
# Whereas macOS Sequoia doesn't have firmware for MacBook Air 2018 and 2019.
|
||||
boards = {
|
||||
monterey = {
|
||||
boardId = "Mac-B809C3757DA9BB8D";
|
||||
mlb = "00000000000000000";
|
||||
osType = "latest";
|
||||
hash = "sha256-My8FLnqHZn+THfGPIhTSApW/kIWM0ZZhjBxWujhhWPM=";
|
||||
};
|
||||
ventura = {
|
||||
boardId = "Mac-4B682C642B45593E";
|
||||
mlb = "00000000000000000";
|
||||
osType = "latest";
|
||||
hash = "sha256-Qy9Whu8pqHo+m6wHnCIqURAR53LYQKc0r87g9eHgnS4=";
|
||||
};
|
||||
sonoma = {
|
||||
boardId = "Mac-827FAC58A8FDFA22";
|
||||
mlb = "00000000000000000";
|
||||
osType = "default";
|
||||
hash = "sha256-phlpwNTYhugqX2KGljqxpbfGtCFDgggQPzB7U29XSmM=";
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
vmTools.runInLinuxVM (
|
||||
stdenvNoCC.mkDerivation {
|
||||
pname = "brcm-firmware";
|
||||
inherit version;
|
||||
|
||||
src = fetchmacos {
|
||||
name = version;
|
||||
inherit (boards.${version})
|
||||
boardId
|
||||
mlb
|
||||
osType
|
||||
hash
|
||||
;
|
||||
};
|
||||
dontUnpack = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
util-linux
|
||||
get-firmware
|
||||
];
|
||||
buildPhase = ''
|
||||
ln -s ${linux}/lib /lib
|
||||
${kmod}/bin/modprobe loop
|
||||
${kmod}/bin/modprobe hfsplus
|
||||
|
||||
imgdir=$(mktemp -d)
|
||||
loopdev=$(losetup -f | cut -d "/" -f 3)
|
||||
losetup -P $loopdev $src
|
||||
loopdev_partition=/dev/$(lsblk -o KNAME,TYPE,MOUNTPOINT -n | grep $loopdev | tail -1 | awk '{print $1}')
|
||||
mount $loopdev_partition $imgdir
|
||||
|
||||
get-bluetooth $imgdir/usr/share/firmware/bluetooth bluetooth/
|
||||
get-wifi $imgdir/usr/share/firmware/wifi wifi/
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib/firmware/brcm
|
||||
cp bluetooth/brcm/* $out/lib/firmware/brcm/
|
||||
cp wifi/brcm/* $out/lib/firmware/brcm/
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Wi-Fi and Bluetooth firmware for T2 Macs";
|
||||
license = licenses.unfree;
|
||||
maintainers = with maintainers; [ mkorje ];
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
}
|
||||
)
|
||||
42
apple/t2/pkgs/brcm-firmware/fetchmacos.nix
Normal file
42
apple/t2/pkgs/brcm-firmware/fetchmacos.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
fetchFromGitHub,
|
||||
callPackage,
|
||||
dmg2img,
|
||||
}:
|
||||
|
||||
let
|
||||
macrecovery = callPackage ./macrecovery.nix { };
|
||||
in
|
||||
|
||||
{
|
||||
name,
|
||||
boardId,
|
||||
mlb,
|
||||
osType,
|
||||
hash,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = name;
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
macrecovery
|
||||
dmg2img
|
||||
];
|
||||
buildPhase = ''
|
||||
macrecovery download -o . -b ${boardId} -m ${mlb} -os ${osType}
|
||||
dmg2img -s BaseSystem.dmg fw.img
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
cp fw.img $out
|
||||
'';
|
||||
|
||||
outputHashMode = "recursive";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHash = hash;
|
||||
}
|
||||
133
apple/t2/pkgs/brcm-firmware/get-firmware-standalone.patch
Normal file
133
apple/t2/pkgs/brcm-firmware/get-firmware-standalone.patch
Normal file
@@ -0,0 +1,133 @@
|
||||
diff --git a/asahi_firmware/bluetooth.py b/asahi_firmware/bluetooth.py
|
||||
index 0934225..3eaa442 100644
|
||||
--- a/asahi_firmware/bluetooth.py
|
||||
+++ b/asahi_firmware/bluetooth.py
|
||||
@@ -1,8 +1,25 @@
|
||||
+#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
import logging, os, os.path, re, sys
|
||||
from collections import namedtuple, defaultdict
|
||||
+from hashlib import sha256
|
||||
|
||||
-from .core import FWFile
|
||||
+class FWFile(object):
|
||||
+ def __init__(self, name, data):
|
||||
+ self.name = name
|
||||
+ self.data = data
|
||||
+ self.sha = sha256(data).hexdigest()
|
||||
+
|
||||
+ def __repr__(self):
|
||||
+ return f"FWFile({self.name!r}, <{self.sha[:16]}>)"
|
||||
+
|
||||
+ def __eq__(self, other):
|
||||
+ if other is None:
|
||||
+ return False
|
||||
+ return self.sha == other.sha
|
||||
+
|
||||
+ def __hash__(self):
|
||||
+ return hash(self.sha)
|
||||
|
||||
log = logging.getLogger("asahi_firmware.bluetooth")
|
||||
|
||||
@@ -127,16 +144,16 @@ class BluetoothFWCollection(object):
|
||||
|
||||
if __name__ == "__main__":
|
||||
col = BluetoothFWCollection(sys.argv[1])
|
||||
-
|
||||
- if len(sys.argv) > 2:
|
||||
- from . import FWPackage
|
||||
-
|
||||
- pkg = FWPackage(sys.argv[2])
|
||||
- pkg.add_files(sorted(col.files()))
|
||||
- pkg.close()
|
||||
-
|
||||
- for i in pkg.manifest:
|
||||
- print(i)
|
||||
- else:
|
||||
- for name, fwfile in col.files():
|
||||
- print(name, f"{fwfile.name} ({len(fwfile.data)} bytes)")
|
||||
+
|
||||
+ dir = os.path.join(sys.argv[2], "brcm")
|
||||
+ os.makedirs(dir)
|
||||
+
|
||||
+ hashes = {}
|
||||
+ for name, data in sorted(col.files()):
|
||||
+ path = os.path.join(sys.argv[2], name)
|
||||
+ if data.sha in hashes:
|
||||
+ os.link(hashes[data.sha], path)
|
||||
+ else:
|
||||
+ with open(path, "wb") as f:
|
||||
+ f.write(data.data)
|
||||
+ hashes[data.sha] = path
|
||||
diff --git a/asahi_firmware/wifi.py b/asahi_firmware/wifi.py
|
||||
index 346965c..261aa32 100644
|
||||
--- a/asahi_firmware/wifi.py
|
||||
+++ b/asahi_firmware/wifi.py
|
||||
@@ -1,6 +1,24 @@
|
||||
+#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
import sys, os, os.path, pprint, statistics, logging
|
||||
-from .core import FWFile
|
||||
+from hashlib import sha256
|
||||
+
|
||||
+class FWFile(object):
|
||||
+ def __init__(self, name, data):
|
||||
+ self.name = name
|
||||
+ self.data = data
|
||||
+ self.sha = sha256(data).hexdigest()
|
||||
+
|
||||
+ def __repr__(self):
|
||||
+ return f"FWFile({self.name!r}, <{self.sha[:16]}>)"
|
||||
+
|
||||
+ def __eq__(self, other):
|
||||
+ if other is None:
|
||||
+ return False
|
||||
+ return self.sha == other.sha
|
||||
+
|
||||
+ def __hash__(self):
|
||||
+ return hash(self.sha)
|
||||
|
||||
log = logging.getLogger("asahi_firmware.wifi")
|
||||
|
||||
@@ -40,7 +58,9 @@ class WiFiFWCollection(object):
|
||||
self.prune()
|
||||
|
||||
def load(self, source_path):
|
||||
+ included_folders = ["C-4355__s-C1", "C-4364__s-B2", "C-4364__s-B3", "C-4377__s-B3"]
|
||||
for dirpath, dirnames, filenames in os.walk(source_path):
|
||||
+ dirnames[:] = [d for d in dirnames if d in included_folders]
|
||||
if "perf" in dirnames:
|
||||
dirnames.remove("perf")
|
||||
if "assert" in dirnames:
|
||||
@@ -141,18 +161,16 @@ class WiFiFWCollection(object):
|
||||
|
||||
if __name__ == "__main__":
|
||||
col = WiFiFWCollection(sys.argv[1])
|
||||
- if len(sys.argv) > 2:
|
||||
- from .core import FWPackage
|
||||
-
|
||||
- pkg = FWPackage(sys.argv[2])
|
||||
- pkg.add_files(sorted(col.files()))
|
||||
- pkg.close()
|
||||
-
|
||||
- for i in pkg.manifest:
|
||||
- print(i)
|
||||
- else:
|
||||
- for name, fwfile in col.files():
|
||||
- if isinstance(fwfile, str):
|
||||
- print(name, "->", fwfile)
|
||||
- else:
|
||||
- print(name, f"({len(fwfile.data)} bytes)")
|
||||
+
|
||||
+ dir = os.path.join(sys.argv[2], "brcm")
|
||||
+ os.makedirs(dir)
|
||||
+
|
||||
+ hashes = {}
|
||||
+ for name, data in sorted(col.files()):
|
||||
+ path = os.path.join(sys.argv[2], name)
|
||||
+ if data.sha in hashes:
|
||||
+ os.link(hashes[data.sha], path)
|
||||
+ else:
|
||||
+ with open(path, "wb") as f:
|
||||
+ f.write(data.data)
|
||||
+ hashes[data.sha] = path
|
||||
35
apple/t2/pkgs/brcm-firmware/get-firmware.nix
Normal file
35
apple/t2/pkgs/brcm-firmware/get-firmware.nix
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
fetchFromGitHub,
|
||||
python3,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "get-firmware";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "AsahiLinux";
|
||||
repo = "asahi-installer";
|
||||
rev = "v0.7.9";
|
||||
hash = "sha256-vbhepoZ52k5tW2Gd7tfQTZ5CLqzhV7dUcVh6+AYwECk=";
|
||||
};
|
||||
|
||||
patches = [ ./get-firmware-standalone.patch ];
|
||||
|
||||
buildInputs = [ python3 ];
|
||||
|
||||
installPhase = ''
|
||||
cd asahi_firmware
|
||||
install -Dm755 bluetooth.py $out/bin/get-bluetooth
|
||||
install -Dm755 wifi.py $out/bin/get-wifi
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Patched Asahi Linux Installer scripts to get brcm firmware";
|
||||
homepage = "https://github.com/AsahiLinux/asahi-installer";
|
||||
license = licenses.mit;
|
||||
maintainers = with maintainers; [ mkorje ];
|
||||
platforms = platforms.all;
|
||||
};
|
||||
}
|
||||
36
apple/t2/pkgs/brcm-firmware/macrecovery.nix
Normal file
36
apple/t2/pkgs/brcm-firmware/macrecovery.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
fetchFromGitHub,
|
||||
python3,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "macrecovery";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "acidanthera";
|
||||
repo = "OpenCorePkg";
|
||||
rev = "1.0.4";
|
||||
hash = "sha256-5Eypza9teSJSulHaK7Sxh562cTKedXKn3y+Z3+fC6sM=";
|
||||
};
|
||||
|
||||
buildInputs = [ python3 ];
|
||||
|
||||
installPhase = ''
|
||||
cd Utilities/macrecovery
|
||||
install -Dm755 macrecovery.py $out/opt/macrecovery
|
||||
cp boards.json $out/opt/boards.json
|
||||
mkdir $out/bin
|
||||
ln -s $out/opt/macrecovery $out/bin/macrecovery
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "A tool that helps to automate recovery interaction";
|
||||
homepage = "https://github.com/acidanthera/OpenCorePkg";
|
||||
license = licenses.bsd3;
|
||||
maintainers = with maintainers; [ mkorje ];
|
||||
mainProgram = "macrecovery";
|
||||
platforms = platforms.all;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user