FreeBSD doesn't have Wi-Fi driver for my old MacBook. AI build one for me
Source: Hacker News
Repurposing a 2016 MacBook Pro for FreeBSD
My old 2016 MacBook Pro has been collecting dust in a cabinet for some time now. The laptop suffers from a “flexgate” problem, and I don’t have any practical use for it.
For quite a while I’ve been thinking about repurposing it as a guinea pig to play with FreeBSD—an OS I’ve long wanted to try but never had a real reason to install.
During the recent holiday season, right after the FreeBSD 15 release, I finally found the time to set the laptop up. I didn’t plan for—or even imagine—that this would turn into a story about AI‑assisted coding.
Background
The 2016 MacBook Pro models use the Broadcom BCM4350 Wi‑Fi chip. FreeBSD does not have native support for this chip. A common workaround suggested on FreeBSD forums is to run wifibox – a tiny Linux VM with the PCI Wi‑Fi device passed through – allowing Linux to manage the device via its brcmfmac driver.
The brcmfmac driver
- License: ISC
- Target: FullMAC Broadcom chips
- Operation:
- Offloads low‑level tasks (e.g., 802.11 frame handling, WPA encryption/decryption) to the chip’s internal firmware.
- Performs high‑level management in the driver/OS.
For more details, see the Linux Wireless documentation:
Broadcom brcmfmac (PCIe) in Linux Wireless documentation.
Toward a native FreeBSD driver
If we wanted to build a native FreeBSD kernel module for the BCM4350, the division of labor between firmware and driver looks promising. FreeBSD already handles the “management” side for other supported Wi‑Fi devices; we would mainly need to port the glue code that adapts the Linux‑specific parts to FreeBSD.
In theory, ignoring many low‑level details, the task does not seem overly complex. The challenge lies in correctly translating the Linux‑specific interfaces and ensuring proper interaction with FreeBSD’s networking stack.
Act 1
A “level‑zero” idea for porting a large code base from A to B in 2026 is, of course, to use AI. That’s what I tried.
- I cloned the brcmfmac subtree.
- I asked Claude Code to make it work on FreeBSD.
FreeBSD already runs many drivers through LinuxKPI, a compatibility layer for Linux kernel drivers. I therefore pointed Claude at the iwlwifi driver (a soft‑MAC driver for Intel wireless cards) and said, “do as they did it.” At first it even looked like it could work—Claude told me so.
The module compiled, but it did nothing. The VM used for testing didn’t have the hardware, so the driver had nothing to drive. After I passed the PCI device through to the VM and tried to load the driver against the chip, problems appeared immediately:
- The kernel panicked.
- After Claude fixed the panics, the module still did nothing.
Claude started sprinkling #ifdef __FreeBSD__ wrappers throughout the code, complaining about missing LinuxKPI features. The module kept causing panics, and the AI kept adding FreeBSD‑specific shims and callbacks, warning me that the project would be very complicated and messy.
Act 2
After a number of sessions, the diff produced by the agent started to look significantly larger than I had hoped. Even worse, the driver didn’t even come close to working. This was around the time Armin Ronacher posted his experience building a game from scratch with Claude Opus and the Pi agent.
Besides the fact that working in the Pi coding agent feels more productive than in Claude Code, the video made me realize that my approach to the task was too straightforward. The brcmfmac driver is moderately large; it supports several generations of Wi‑Fi adapters, different capabilities, etc. My immediate task, however, was very narrow: one chip, PCI only, Wi‑Fi client only.
Instead of continuing to wrestle with the code, I started a fresh Pi session and asked the agent to write a detailed specification of how the brcmfmac driver works, focusing on the BCM4350 Wi‑Fi chip. I explicitly set the audience to be readers who would implement the specification in a clean‑room environment, and I asked the agent to explain everything “to the bits”. After providing a few high‑level layout guidelines, I let the agent go to work.
After a couple of rounds, the agent produced a “book of 11 chapters” that honestly looked like a solid specification:
% ls --tree spec/
spec
├── 00-overview.md
├── 01-data-structures.md
├── 02-bus-layer.md
├── 03-protocol-layer.md
├── 04-firmware-interface.md
├── 05-event-handling.md
├── 06-cfg80211-operations.md
├── 07-initialization.md
├── 08-data-path.md
├── 09-firmware-commands.md
└── 10-structures-reference.md
Of course, you can’t just trust what AI has written.
Proofreading the spec
-
First pass – I spawned a clean Pi session and, for fun, asked the Codex model to read the specification and flag any places where the text didn’t align with the driver’s code.
Prompt: “Source code is the ground truth. The spec needs to be verified and updated with any missing or wrong details.”
The agent identified several discrepancies and suggested multiple improvements. -
Second pass – To double‑check the fixes, I started another clean Pi session and asked the Opus model to verify whether the proposed changes were truly consistent with the driver’s implementation.
I repeated this loop with several coding models: Opus 4.5, Opus 4.6, Codex 5.2, and Gemini 3 Pro (preview). So far, Gemini hallucinated the most—a disappointment, given that the model performs reasonably well on simple coding tasks and is free for limited use.
Having a written specification should, in theory, make it clear how the driver’s code interacts with the firmware. The iterative AI‑assisted review process helped bring the spec much closer to that ideal.
Act 3 – Building a FreeBSD Driver for the BCM4350
1. Project kickoff
- Started a fresh repository containing only the specification for the BCM4350 Wi‑Fi chip.
- Prompted the Pi agent: “We are building a brand‑new FreeBSD driver for the BCM4350. Ask me about any important decisions we must make before writing code.”
The agent returned a list of decision points, for example:
| Decision | Question |
|---|---|
| Source location | Will the driver live in the kernel source‑tree? |
| Language | Will we write the driver in C? |
| Abstractions | Will we rely on LinuxKPI (or linuxkpi_wlan)? |
| Milestones | What are the high‑level milestones? |
| Documentation | Where should we record these decisions? |
I instructed the agent to document every decision in docs/decisions.md and to reference that file from AGENTS.md.
2. Evolving decisions
Not all initial choices survived the development process:
- LinuxKPI – At first I asked the agent to build the driver on top of
linuxkpiandlinuxkpi_wlan. After a few sessions it became clear that this added unnecessary complexity. - The agent removed the LinuxKPI dependency in a single commit and updated the decision document accordingly.
3. Development workflow
With the specification, documentation, and a concrete plan in place, the work turned into a repeatable routine:
- Environment – The agent had SSH access to both a build host and a testing VM (the VM had the PCI Wi‑Fi device passed through).
- Milestone execution – The agent iterated through the backlog, writing code, building the kernel module, and running functional tests.
- Progress tracking – After each completed milestone the agent logged the outcome in the documentation.
- Failure handling – When a build crashed or the VM hung, I opened a forked Pi session, asked the agent to summarize, investigate, and record the issue for future reference before fixing it.
4. Result
After many low‑involvement sessions the agent produced a working FreeBSD kernel module that:
- Scans Wi‑Fi networks.
- Provides 2.4 GHz and 5 GHz connectivity.
- Supports WPA/WPA2 authentication.

Original post on Bluesky:
Source code:
I did not write any of the driver code myself. Several known issues remain; I will task the agent with fixing them later. Until then, the driver should be used only for learning purposes.
5. Tags
Ai • Apple • Arduino • Arm64 • Askme • Aws • Berlin • Bookmarks • Brcmfmac • Buildkit • Cgo • Coffee • Continuous Profiling • COVID‑19 • Design • Docker • Dynamodb • E‑Paper • English • Enum • Esp8266 • Firefox • Freebsd • Github Actions • Go • Google • GraphQL • Homelab • IPv6 • K3s • Kubernetes • Linux • macOS • Material Design • MDNS • Music • Ndppd • NeonDatabase • Objective‑C • Passkeys • PostgreSQL • Pprof • Profefe • Random • Raspberry Pi • Rust • Travis CI • VS Code • Waveshare • Μ‑Benchmarks
End of Act 3.
