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";
|
example = "latest";
|
||||||
description = "The kernel release stream to use.";
|
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 [
|
config = lib.mkMerge [
|
||||||
@@ -105,5 +118,11 @@ in
|
|||||||
options apple-gmux force_igd=y
|
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