Complete hardware support guide and drivers for MacBook Pro 13" 2017 (MacBookPro14,1) running Ubuntu 26.04 (GNOME) or Xubuntu 26.04 (Xfce 4.20).
Covers: Audio · GPU · Bluetooth · WiFi · Camera · Thunderbolt · Battery · Fan · Touchpad · Suspend · Color Calibration
| Component | Chip | Status | Fixed by |
|---|---|---|---|
| Audio (speakers + headphones) | Cirrus CS8409 / CS42L83 | ✅ Works | macbook_hardware_fixer.sh step 0 |
| Audio (microphone) | Cirrus CS8409 | ✅ Works | PipeWire filter-chain DSP (noise gate + autogain) — macbook_hardware_fixer.sh step 0 |
| Intel GPU | Iris Plus 640 (Kaby Lake GT3) | ✅ Works + VA-API | macbook_hardware_fixer.sh step 1 |
| WiFi | Broadcom BCM4350 | ✅ Works | macbook_hardware_fixer.sh step 3 |
| Bluetooth | Broadcom BCM4350C0 (UART) | macbook_hardware_fixer.sh step 2 · bluetooth/bluetooth.sh |
|
| FaceTime HD Camera | Broadcom 720p PCIe 14e4:1570 | macbook_hardware_fixer.sh step 4 |
|
| Thunderbolt 3 | Intel Alpine Ridge 4C (JHL6540) | ✅ Works | macbook_hardware_fixer.sh step 5 |
| Battery & Thermal | Intel i5-7360U + applesmc | ✅ Works | macbook_hardware_fixer.sh step 6 |
| Fan control | applesmc + mbpfan | ✅ Works (max cooling profile: 4500 RPM min, 30°C trigger) | macbook_hardware_fixer.sh step 7 |
| Keyboard backlight | Apple SPI LED | ✅ Works | macbook_hardware_fixer.sh step 7 |
| Touchpad | Apple SPI Touchpad | ✅ Works | macbook_hardware_fixer.sh step 8 |
| Apple SPI Keyboard | Apple SPI Keyboard | ✅ Works | macbook_hardware_fixer.sh step 8 |
| Screen brightness | Intel i915 backlight | ✅ Works | macbook_hardware_fixer.sh step 9 |
| Suspend/Sleep | Intel S0ix / s2idle | ✅ Works (s2idle + NVMe d3cold fix) | macbook_hardware_fixer.sh step 9 |
| NVMe Storage | Apple SSD AP0256J | ✅ Works natively | — |
| USB 3.0 | Intel xHCI | ✅ Works natively | — |
| Display color calibration | Apple factory ICC profile | ✅ Works | macbook_hardware_fixer.sh step 11 |
- Battery life: expect under 4 hours. Panel Self-Refresh (PSR), NVMe APST, and Thunderbolt power management are not fully working — these components consume more power than on macOS.
- Audio microphone input: raw level is very low (CS8409/CS42L83 outputs the signal
without hardware amplification). Fixed automatically by the PipeWire filter-chain DSP
installed by
macbook_hardware_fixer.shstep 0 — the virtual source "MacBook Pro Mic (DSP)" applies noise gate + auto-gain and is set as default capture device. - Bluetooth A2DP audio: choppy A2DP is usually the baud rate, fixed by the one-time
SMC Reset (see Bluetooth section below). Basic scan and pairing work without firmware,
and the firmware patch has no measured effect on A2DP — see
firmware/README.md. - Suspend/resume: works with s2idle + NVMe d3cold fix (both applied by
macbook_hardware_fixer.shstep 9). Even so, resume may be slow in some cases. - Auto-boot on lid open: the MacBook Pro 2016/2017 powers on automatically when the
lid is opened. To disable this from Linux:
If you get "No space left on device", first clean up stale EFI dump variables:
sudo sh -c 'printf "\x07\x00\x00\x00\x00" > /sys/firmware/efi/efivars/AutoBoot-7c436110-ab2a-4bbb-a880-fe41995c9f82'for i in $(find /sys/firmware/efi/efivars/ -name 'dump-type0*'); do sudo chattr -i "$i" && sudo rm "$i"; done
On a brand new Ubuntu 26.04 installation on a MacBook Pro 13" 2017, run in order:
Step 1 — Install build dependencies:
sudo apt-get update && sudo apt-get install -y \
build-essential linux-headers-$(uname -r) make patch wget git dwarves
dwarvesprovidespahole, required for BTF generation when building the kernel module. Without it the build still succeeds but emits a "pahole version differs" warning.macbook_hardware_fixer.shinstalls it automatically if missing.
Step 2 — Clone this repository:
git clone https://github.com/vrilutza/MacBookPro14.1.git
cd MacBookPro14.1Step 3 — Install all hardware drivers (Audio, GPU, Bluetooth, WiFi, Camera, Thunderbolt, Battery, Fan, Keyboard backlight, Touchpad, Suspend, Display color calibration):
sudo ./macbook_hardware_fixer.shStep 4 — Reboot:
sudo rebootStep 5 — Verify everything was applied correctly:
# Full hardware check (all 12 steps including audio + color calibration):
./tests/verify-hardware.sh
sudo ./tests/verify-hardware.sh # for complete Bluetooth config check
# Audio-only check:
./tests/verify-installation.shIf verification reports a missing CS8409 module, generate a full diagnostics file with:
sudo ./tests/collect-logs.sh /tmp/macbook-diag-$(date +%Y%m%d-%H%M%S).txtThat file includes the CS8409 module layout and a suggested fix when the driver is present only in updates/dkms.
Script: macbook_hardware_fixer.sh step 1
Installs VA-API drivers for hardware-accelerated video decoding (H.264, HEVC):
sudo apt-get install -y intel-media-va-driver i965-va-driver vainfoVerify:
vainfo # should list VAProfileH264*, VAProfileHEVC* entriesScript: macbook_hardware_fixer.sh step 2 · standalone: bluetooth/bluetooth.sh
The chip self-identifies as BCM4350C0 (macOS marketing name: BCM2E7C). It is a UART
chip (not USB) — connected via serial0/ttyS4, and it works from internal ROM.
No firmware patch is installed, by this script or any other in the repo. Across three
cold boots the controller's HCI fingerprint was byte-identical with and without it, and a
build with the wrong launch address takes the controller off the UART entirely. The blob
and its converter stay in firmware/bluetooth/ for anyone who wants to experiment;
firmware/README.md has the numbers and the manual steps.
If you do install one by hand, note that a mainline kernel requests
/lib/firmware/brcm/BCM.hcd and no other name on this machine — a file called
BCM4350C0.hcd is never read.
The BCM4350C0 chip retains the baud rate set by macOS (3 Mbaud). Linux uses 115200
baud → the driver times out → hci0 never appears. This is the most common cause of "no
Bluetooth after Ubuntu install".
Fix (done once — never needed again):
- Shut down completely (not restart)
- Hold simultaneously for 10 seconds:
Shift(left)+Ctrl(left)+Option(left)+Power - Release all keys, press
Powernormally to start
After SMC Reset the chip resets to factory baud rate and hci0 will appear.
Important: Never apply USB firmware (files with
0a5cin the name) to this chip. USB firmware corrupts the UART baud rate and makes BT non-functional until another SMC Reset.macbook_hardware_fixer.shautomatically removes any such wrong symlinks.
What the script fixes:
- Removes wrong USB firmware symlinks (BCM4350C5-0a5c-*.hcd) that break the UART chip
- bluez 5.65+ config bug:
AutoEnablemoved from[General]to[Policy] - Creates
/etc/udev/rules.d/60-bluetooth-macbook.rulesto bringhci0up automatically - WirePlumber: disables A2DP → HFP/HSP auto-switch (prevents AirPods Pro dropouts)
Firmware patch — not installed, opt-in only. No measured effect on this chip, and a
wrong build costs you the controller. See firmware/README.md before trying it.
Verify:
hciconfig hci0 # should show: UP RUNNING
rfkill list bluetooth # Soft blocked: no
journalctl -b -k | grep "hci0.*BCM" # should NOT show "firmware Patch file not found"Script: macbook_hardware_fixer.sh step 3
Works out of the box with the brcmfmac kernel driver. The script applies optimisations:
-
Disables WiFi power save (causes latency spikes) via NetworkManager:
/etc/NetworkManager/conf.d/99-wifi-powersave-off.conf -
Sets
roamoff=1via/etc/modprobe.d/brcmfmac-macbook.conf(power_save removed in kernel 6.x) -
Installs macOS NVRAM (board-specific RF calibration) from
firmware/wifi/:brcmfmac4350-pcie.Apple Inc.-MacBookPro14,1.txt(model-specific, kernel prefers this)brcmfmac4350-pcie.txt(generic fallback)- Symlinks for kernel 6.6+ which reports the chip as
brcmfmac4350c2-pcie(BCM4350 rev C2):brcmfmac4350c2-pcie.Apple Inc.-MacBookPro14,1.txt→ model-specific NVRAMbrcmfmac4350c2-pcie.txt→ generic fallback
The macOS NVRAM is calibrated for
boardid=0x170(hawaii platform) and improves WiFi range, 5 GHz stability, and regulatory compliance vs the generic Linux NVRAM. -
5 GHz band preference: set per-connection (the
wifi.band=akey is invalid in NetworkManager conf.d files — NM ignores it and logs a warning):nmcli connection modify "YourWiFiName" 802-11-wireless.band a
Set regulatory domain (if channels are limited):
sudo iw reg set RO # replace RO with your country codeVerify:
lsmod | grep brcmfmac
ip link show # should show wlp* interface UPScript: macbook_hardware_fixer.sh step 4
The camera (PCIe 14e4:1570) requires the third-party facetimehd driver:
- Firmware downloaded from Apple CDN via patjak/facetimehd-firmware
- Kernel module compiled from patjak/facetimehd
If the module fails to compile (kernel too new), check https://github.com/patjak/facetimehd for kernel compatibility.
Verify:
lsmod | grep facetimehd # module loaded
ls /dev/video* # /dev/video0 should existScript: macbook_hardware_fixer.sh step 5
Works out of the box. The bolt daemon handles device authorisation:
boltctl list # list connected TB3 devices
boltctl enroll <device-uuid> # authorise a device permanentlyOr use GNOME Settings → Privacy → Thunderbolt.
Note: Thunderbolt power management is incomplete — TB ports consume power even with no devices attached, contributing to reduced battery life.
Script: macbook_hardware_fixer.sh step 6
The i5-7360U has a 15W TDP. macOS Ventura enforces PL1=15W / PL2=25W (Intel spec). Linux BIOS defaults leave PL1=100W / PL2=125W — the CPU can sustain turbo boost (3.5 GHz) indefinitely, generating much more heat than on macOS.
The script fixes this with two mechanisms:
| Fix | What it does |
|---|---|
macbook-rapl-limits.service |
Sets PL1=20W, PL2=40W on every boot, runs after thermald |
/etc/tlp.d/50-macbook-pro14-1.conf |
Disables turbo on battery, sets HWP to balance_power on battery / performance on AC |
Note — thermald interaction:
thermalddynamically adjusts RAPL limits via DPTF. The service is orderedAfter=thermald.serviceso it always applies last and its values are not overridden at boot. If you later runsystemctl restart thermald, re-runsystemctl restart macbook-rapl-limitsto restore the correct limits.
Why PL1=20W and not the stock 15W or cTDP-up 28W:
- 15W: leaves performance on the table — CPU throttles to 2.3 GHz under load
- 28W: exceeds heatsink capacity (thermal resistance ~2.0°C/W at max fan → 81°C sustained → thermal throttle)
- 20W sweet-spot: sustains 2.8–3.0 GHz continuously at ~65°C with aggressive fan — no throttle, no overheating
Expected result after reboot: 10–20°C lower at sustained load vs BIOS defaults (100W).
# Check current RAPL limits:
cat /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw # should be 20000000 (20W)
cat /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_power_limit_uw # should be 40000000 (40W)
# Check RAPL time windows (Intel Kaby Lake U spec):
cat /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_time_window_us # should be 976563 (~1s)
cat /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_time_window_us # should be 27343000 (~28s)
# Check RAPL service:
systemctl status macbook-rapl-limits
# Check TLP config applied:
sudo tlp-stat -p | grep -E "HWP|BOOST|PERF"
# Check CPU temperature:
sensors | grep "Package\|Core"
# Per-process power usage:
sudo powertopTLP configuration (/etc/tlp.d/50-macbook-pro14-1.conf):
| Setting | AC | Battery |
|---|---|---|
| CPU governor | powersave | powersave |
| HWP policy | performance | balance_power |
| HWP dynamic boost | ON | OFF |
| Platform profile | performance | low-power |
| Turbo boost | ON | OFF (−10–15°C) |
| PCIe ASPM | default | powersupersave |
| Runtime PM | on | auto |
Configure battery charging thresholds (extend long-term battery health):
sudo nano /etc/tlp.conf
# Add:
BAT0_CHARGE_THRESH_START=20
BAT0_CHARGE_THRESH_STOP=80
sudo tlp startNote: power-profiles-daemon (GNOME default) conflicts with TLP.
The script removes it automatically.
Script: macbook_hardware_fixer.sh step 7
Read temperatures and fan speed:
sensors # CPU temp, chassis temp, fan RPM (after reboot)Fan control: mbpfan is installed with an aggressive cooling profile tuned for the
i5-7360U. The profile (tested on Ubuntu 26.04) keeps the Mac cooler than the default:
| Setting | Value | Reason |
|---|---|---|
min_fan1_speed |
4500 RPM | Always spinning fast — maximum baseline cooling |
low_temp |
30°C | Fan ramps at even minor load — catches any workload early |
high_temp |
40°C | Ramps up quickly |
max_temp |
48°C | Full speed above this — CPU rarely exceeds 70°C |
polling_interval |
1 s | Fast response to temperature spikes |
Config at /etc/mbpfan.conf. Combined with the RAPL 20W limit (step 6), this keeps
the Mac at ~65°C sustained under full load. Fan noise is constant (~4500–6000 RPM) —
by design: cooling priority over silence.
Live monitor (run manually in any terminal):
macbook-monitor # colour-coded fan RPM + CPU temps, Ctrl+C to quitKeyboard backlight:
# Read current / max brightness:
cat /sys/class/leds/spi::kbd_backlight/brightness
cat /sys/class/leds/spi::kbd_backlight/max_brightness
# Set brightness (0–255):
echo 255 | sudo tee /sys/class/leds/spi::kbd_backlight/brightnessThe script sets maximum brightness on every boot via systemd-tmpfiles
(/etc/tmpfiles.d/macbook-kbd-backlight.conf).
Script: macbook_hardware_fixer.sh step 8
Configured automatically for both Wayland (via gsettings) and X11 (via
/usr/share/X11/xorg.conf.d/40-macbook-libinput.conf):
- Tap-to-click
- Natural scroll
- Two-finger scroll
- Clickfinger (1-finger = left, 2-finger = right, 3-finger = middle)
- Disable-while-typing
- PalmDetection — prevents cursor jumps when palms touch the trackpad while typing
- TappingButtonMap = lrm — 1-finger tap = left, 2-finger = right, 3-finger = middle
Fn key behaviour (set via hid_apple fnmode):
# Current mode:
cat /sys/module/hid_apple/parameters/fnmode
# F1-F12 as function keys (default after script): fnmode=1
# F1-F12 as media keys (Apple default): fnmode=0
# Change persistently: edit /etc/modprobe.d/hid-apple-macbook.confScript: macbook_hardware_fixer.sh step 9
Screen brightness (no root needed after adding user to video group):
brightnessctl set 50%
brightnessctl set +10%
brightnessctl set 10%-Lid-open auto-boot (step 9): macOS sets an EFI variable that causes the MacBook Pro to power on automatically when the lid is opened. The script disables this:
printf '\x07\x00\x00\x00\x00' | sudo tee /sys/firmware/efi/efivars/AutoBoot-7c436110-ab2a-4bbb-a880-fe41995c9f82Applied once at install time. If you see "No space left on device", clear stale EFI dump variables first (see Known Limitations).
Suspend: MacBook Pro 14,1 requires two fixes for reliable suspend/resume:
| Fix | What it does | Applied by |
|---|---|---|
mem_sleep_default=s2idle in GRUB |
Uses Intel S0ix instead of broken S3 | script + update-grub |
NVMe d3cold disabled (macbook-nvme-d3cold.service) |
Prevents NVMe from entering D3cold, which breaks resume | systemd service |
# Check current sleep mode (should show [s2idle]):
cat /sys/power/mem_sleep
# Check NVMe d3cold status (should be 0):
cat /sys/bus/pci/devices/0000:01:00.0/d3cold_allowed
# Check service:
systemctl status macbook-nvme-d3coldReference: https://github.com/Dunedan/mbp-2016-linux#suspend--hibernation
Hibernate / SuspendThenHibernate (optional — not configured by the script):
macOS uses hibernatemode=3 (hybrid sleep): RAM stays powered AND is saved to disk.
After ~3 hours on battery (standbydelaylow=10800) the machine enters full hibernate.
On Linux this is not configured because:
- Hibernate requires a swap partition or swap file ≥ RAM size (16 GB for this Mac)
- The Apple SSD NVMe controller's behaviour under hibernation is not well tested
- s2idle (
mem_sleep_default=s2idle) works reliably and is sufficient for daily use
If you want to enable SuspendThenHibernate manually on Ubuntu 26.04:
# 1. Create a swap file >= your RAM size (e.g., 16 GB)
sudo fallocate -l 16G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# 2. Get swap file offset (needed for hibernation resume)
sudo filefrag -v /swapfile | awk 'NR==4{print $4}' | tr -d '.'
# 3. Add to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub:
# resume=/dev/nvme0n1p2 resume_offset=<offset_from_step_2>
# 4. Enable SuspendThenHibernate
sudo systemctl enable systemd-hibernate-resume@$(findmnt -n -o SOURCE /)
echo 'HandleLidSwitch=suspend-then-hibernate' | sudo tee /etc/systemd/logind.conf.d/hibernate.conf
sudo mkdir -p /etc/systemd/logind.conf.d
sudo tee /etc/systemd/sleep.conf.d/hibernate.conf << 'EOF'
[Sleep]
HibernateDelaySec=10800
EOFNote: On MacBook Pro 14,1 the NVMe controller is Apple-proprietary (not standard NVMe). Hibernate has not been tested on this specific hardware. Proceed at your own risk.
Script: macbook_hardware_fixer.sh step 0 (calls install.cirrus.driver.sh internally)
The internal speakers and headphone jack use a Cirrus Logic CS8409 HDA codec with CS42L83 / MAX98706 / SSM3515 / TAS5764L amplifiers. This requires a custom out-of-tree kernel module.
Install:
sudo ./install.cirrus.driver.shDKMS (auto-rebuilds module on kernel upgrades — recommended):
sudo ./install.cirrus.driver.sh -i # install with DKMS
sudo ./install.cirrus.driver.sh -r # remove DKMS registrationThe installer now ensures the built module is present in /lib/modules/$(uname -r)/updates/codecs/cirrus/ even when DKMS stores the active module under updates/dkms.
Remove driver:
sudo rm /lib/modules/$(uname -r)/updates/codecs/cirrus/snd-hda-codec-cs8409.ko
sudo depmod -aGNOME sound settings:
- Output: set to Analogue Stereo Output
- Input: set to Analogue Stereo Duplex
Microphone: the recorded level is low (same as macOS raw level — CS8409/CS42L83 outputs the raw signal; Apple applies DSP in CoreAudio, not in hardware). The script installs a system-level PipeWire filter-chain (no GUI required) with:
- Noise gate (LADSPA
gate_1408, threshold −26 dB — removes fan noise between speech) - Auto-gain compressor (LADSPA
sc4_1882, makeup +18 dB — normalises input level)
The virtual source "MacBook Pro Mic (DSP)" is set as the default capture device via WirePlumber — transparent to all applications (video calls, recording software, etc.). To bypass DSP and use the raw mic, select the original source in your audio settings.
NOTA BENE: The direct hardware device hw:0,0 and plughw:0,0 have
NO volume control and will be VERY loud.
Test audio:
aplay tests/StereoTest32.wav # normal (respects volume)
aplay -D hw:0,0 tests/StereoTest32_reduced_m24dB.wav # direct hardware (-24 dB)Supported kernels: Ubuntu 26.04 kernel 6.17+ and 7.0+. The install script handles the 6.17 source directory reorganisation automatically.
Technical notes (audio hardware internals): see NOTES.md.
Script: macbook_hardware_fixer.sh step 10
Applied automatically — no extra tools needed. All settings are persistent across reboots.
| Optimization | Config file | Impact |
|---|---|---|
| ZRAM (lz4, 50% RAM) | /etc/systemd/zram-generator.conf |
No more freezes during cargo build / docker pull |
| vm.swappiness = 10 | /etc/sysctl.d/60-macbook-dev.conf |
Keeps data in RAM 6× longer before swapping |
| inotify = 524288 | same | VSCode / IntelliJ / webpack HMR work without error |
| BBR TCP | same | 30-50% faster git clone, npm install, docker pull over WiFi |
| TCP buffers | same | Better throughput for large transfers |
| NVMe I/O scheduler: none | /etc/udev/rules.d/61-nvme-scheduler.rules |
Lowest possible disk latency |
| fstab noatime | /etc/fstab |
Reduces NVMe write amplification on every file read |
| earlyoom | /etc/default/earlyoom |
Kills hungry processes at 10% free RAM → no freeze |
| ulimits (nofile=65536) | /etc/security/limits.d/60-macbook-dev.conf |
Node.js / Docker / JVM open many file descriptors |
| i915 FBC + PSR | /etc/modprobe.d/i915-macbook.conf |
Saves 1-2W GPU power → cooler, longer battery |
| HiDPI 2× scaling | gsettings (GNOME) / xfconf-query (Xfce) | 2560×1600 Retina display — without this text is microscopic |
| Fractional scaling | gsettings mutter (GNOME/Wayland only); MACBOOK_XFCE_FRACTIONAL_SCALE=1 for Xfce/X11 |
Enables 150%/175% options in GNOME Display Settings; Xfce/X11 fractional xrandr scaling is optional and may be slightly blurry |
| Power settings | gsettings (GNOME) / xfconf-query (Xfce) | Power button=suspend, lid=suspend, AC=never-sleep, screen-blank=5min |
| intel-microcode | apt package | CPU security patches + errata fixes for i5-7360U (Kaby Lake) |
Xfce fractional scaling: Run MACBOOK_XFCE_FRACTIONAL_SCALE=1 sudo bash macbook_hardware_fixer.sh to enable 1.75× scaling on Xfce/X11. This uses an xrandr autostart script plus DPI 170 so the Retina display offers more usable space than the default 2× mode.
| fstrim.timer | systemd timer | Weekly NVMe TRIM — sustained write speed + SSD longevity |
| journald limit | /etc/systemd/journald.conf.d/ | Caps logs at 1GB / 2 weeks — prevents disk fill during dev |
| coredump limit | /etc/systemd/coredump.conf.d/ | 512MB cap per dump — JVM/Chromium crashes won't fill NVMe |
| git fsmonitor | ~/.gitconfig | git status 10× faster in large repos (React, monorepo, Django) |
Verify:
sysctl fs.inotify.max_user_watches # 524288
sysctl vm.swappiness # 10
sysctl net.ipv4.tcp_congestion_control # bbr
zramctl # /dev/zram0 present
cat /sys/block/nvme0n1/queue/scheduler # [none]
systemctl is-active earlyoom # active
systemctl is-enabled fstrim.timer # enabled
dpkg -l intel-microcode | grep ^ii # installed
gsettings get org.gnome.desktop.interface scaling-factor # uint32 2
git config --global core.fsmonitor # trueLive monitor (fan + temps):
macbook-monitor # colour-coded RPM + CPU temps, Ctrl+C to quitScript: macbook_hardware_fixer.sh step 11
The MacBook Pro 13" 2017 display is factory-calibrated by Apple at the unit level. macOS ships a per-display ICC profile that encodes:
| Data | What it does |
|---|---|
| RGB primaries (rXYZ, gXYZ, bXYZ) | Describes the panel's actual gamut — wider than sRGB |
| Tone response curves (rTRC/gTRC/bTRC) | 1024-point factory gamma curves per channel |
| White point (D65) | Ensures neutral whites match the calibrated D65 standard |
| Apple vcgt/vcgp | Video card gamma table metadata |
Without this profile, Ubuntu uses a generic sRGB assumption: colors appear oversaturated (especially reds and greens) and the white point is wrong.
The profile is included in this repo at firmware/display/Color-LCD-MacBookPro14-1.icc (3.3 kB),
extracted from macOS Ventura at:
/Library/ColorSync/Profiles/Displays/Color LCD-<UUID>.icc
What the script does:
- Installs
colord(Linux color management daemon) - Copies the profile to
/usr/share/color/icc/macbook/(system-wide) - Copies to
~/.local/share/icc/(per-user — GNOME Color Manager lists it here) - Installs
/usr/local/bin/macbook-color-profile.sh— assigns the profile to the built-in eDP display viacolormgron each login - Creates
~/.config/autostart/macbook-color-profile.desktop— runs the script automatically on every GNOME session start
Verify:
# Check profile files are installed
ls /usr/share/color/icc/macbook/
ls ~/.local/share/icc/
# Check colord knows about the profile (after login)
colormgr get-profiles | grep Color-LCD
# Check the built-in display device
colormgr get-devices
# Manually assign (if autostart didn't fire yet):
/usr/local/bin/macbook-color-profile.sh
# GNOME GUI: Settings → Color → built-in display → select 'Color-LCD-MacBookPro14-1'Notes:
- The autostart script runs after every login — colord resets profile assignments between sessions, so it must be re-applied each time.
- If you use a display manager other than GDM, add
macbook-color-profile.shto your session startup manually. - For dual-boot: the profile is already on the macOS partition at
/Library/ColorSync/Profiles/Displays/Color LCD-*.iccif you ever need to re-extract it.
Before running on real hardware you can catch most errors in Docker or a VM. The three layers cover progressively more of the script:
| Layer | What it catches | Time | Command |
|---|---|---|---|
| Syntax | bash errors, typos | 5s | make test-syntax |
| Docker | missing packages, config logic, file writing | 3-5 min | make test-docker |
| Multipass VM | systemd services, GRUB, sysctl, fstab | 5-10 min | make test-vm |
| Real hardware | applesmc, Bluetooth, RAPL, NVMe | — | sudo ./macbook_hardware_fixer.sh |
make test-syntax
# or directly:
bash tests/test-docker.sh --syntaxChecks bash syntax on all scripts. Runs in seconds, no dependencies.
# Install Docker if not present:
sudo apt-get install docker.io
sudo usermod -aG docker $USER # log out and back in after this
# Run:
make test-docker
# Run and remove image afterwards:
make test-docker-cleanWhat Docker tests: package availability (apt-get install), all config files
written correctly, script logic, Python sections, sysctl syntax.
What Docker cannot test: systemd services (mocked), kernel modules,
hardware paths (/sys/devices/platform/applesmc, /sys/class/powercap/...),
GNOME gsettings — all mocked with stubs that log and return 0.
# Install Multipass:
sudo snap install multipass
# Run (creates a fresh Ubuntu 26.04 VM, runs the full script):
make test-vmWhat Multipass tests: everything Docker tests, plus: real systemctl enable/start,
real sysctl -p, real GRUB file modification, real fstab editing, real journald config.
# After test-vm completes, run the verifier inside the VM:
multipass exec macbook-test -- sudo bash /project/tests/verify-hardware.sh
# Destroy VM when done:
multipass delete macbook-test && multipass purgeEvery push and pull request automatically runs:
- Bash syntax check on all scripts
- Docker integration test (Ubuntu 26.04)
- Generated config file validation
./tests/verify-hardware.sh # run as normal user
sudo ./tests/verify-hardware.sh # run as root for complete check
# or via make:
make verifyChecks all 10 steps: GPU · Bluetooth · WiFi · Camera · Thunderbolt · Battery/Thermal · applesmc · Touchpad/Keyboard · Suspend/Sleep · Dev optimizations · Audio
./tests/verify-installation.shChecks: driver .ko binary · module loaded · dmesg probe · ALSA playback · ALSA capture