96 lines
3.5 KiB
Markdown
96 lines
3.5 KiB
Markdown
# NVbright: directly control NVIDIA-based LCD backlight brightness on Apple MacBook Air A1370
|
|||
|
|
|
||
|
|
NVbright is a lightweight utility for controlling LCD backlight brightness on NVIDIA-equipped Apple MacBooks running FreeBSD under EFI boot.
|
||
|
|
|
||
|
|
## About
|
||
|
|
|
||
|
|
On older NVIDIA-based Apple MacBooks (such as the MacBook Air A1370 with GeForce 320M, MCP89, or GT218 chipsets), LCD backlight level is modulated via a Pulse Width Modulation (PWM) signal generated by the GPU display engine (`PDISPLAY`).
|
||
|
|
|
||
|
|
Under macOS or BIOS compatibility mode, firmware dynamically alters backlight brightness through System Management Interrupts (SMI) triggered by legacy I/O port writes. However, when booting FreeBSD natively in EFI mode, this legacy SMI path is unavailable, leaving the screen backlight stuck or uncontrollable via standard ACPI methods.
|
||
|
|
|
||
|
|
`nvbright` addresses this by directly interacting with the GPU MMIO register BAR:
|
||
|
|
|
||
|
|
1. Identifies the NVIDIA VGA controller's physical MMIO BAR0 address dynamically using `/usr/sbin/pciconf`.
|
||
|
|
2. Maps the register space into memory via `/dev/mem` using `mmap(2)`.
|
||
|
|
3. Detects the active Serial Output Router (SOR) with an initialized PWM divisor (`PWM_DIV`).
|
||
|
|
4. Reads and computes current duty cycle or writes new values latching the display engine registers (`PWM_CTL`).
|
||
|
|
|
||
|
|
The register mapping and control logic mirror the Linux `nouveau` driver implementation for NV50 and NVA3 chip architectures:
|
||
|
|
|
||
|
|
- `NV50_PDISP_SOR_PWM_DIV(i) = 0x0061c080 + i * 0x800`
|
||
|
|
- `NV50_PDISP_SOR_PWM_CTL(i) = 0x0061c084 + i * 0x800`
|
||
|
|
- `CTL_NEW (0x80000000)`: Latch/apply updated brightness value
|
||
|
|
- `CTL_UNK (0x40000000)`: Required control flag on NVA3-class chipsets
|
||
|
|
|
||
|
|
## Build
|
||
|
|
|
||
|
|
`nvbright` is written in standard C and relies only on standard POSIX and FreeBSD system headers (`sys/mman.h`, `sys/types.h`, `fcntl.h`, `unistd.h`). No external dependencies or third-party libraries are required.
|
||
|
|
|
||
|
|
Compile using `make`:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
make
|
||
|
|
```
|
||
|
|
|
||
|
|
Or compile manually using `clang` / `cc`:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
cc -O2 -Wall -Wextra -o nvbright nvbright.c
|
||
|
|
```
|
||
|
|
|
||
|
|
To install the binary system-wide to `/usr/local/bin` (respects `PREFIX` and `DESTDIR`):
|
||
|
|
|
||
|
|
```sh
|
||
|
|
sudo make install
|
||
|
|
```
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
Because `nvbright` requires direct access to `/dev/mem` to map GPU MMIO registers and executes `/usr/sbin/pciconf`, it must be run as root (e.g., with `sudo` or `doas`).
|
||
|
|
|
||
|
|
### Command Syntax
|
||
|
|
|
||
|
|
```sh
|
||
|
|
nvbright <get|set|up|down> [value 0-100]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Commands
|
||
|
|
|
||
|
|
- **`get`**: Queries the hardware and prints the current brightness level (percentage from 0 to 100), active SOR index, and PWM divisor.
|
||
|
|
```sh
|
||
|
|
sudo nvbright get
|
||
|
|
```
|
||
|
|
*Example Output:*
|
||
|
|
```text
|
||
|
|
Brightness: 65 / 100 (SOR1, pwm_div=1024)
|
||
|
|
```
|
||
|
|
|
||
|
|
- **`set <0-100>`**: Sets the display backlight directly to the specified percentage value.
|
||
|
|
```sh
|
||
|
|
sudo nvbright set 75
|
||
|
|
```
|
||
|
|
*Example Output:*
|
||
|
|
```text
|
||
|
|
Set brightness: 75 / 100
|
||
|
|
```
|
||
|
|
|
||
|
|
- **`up`**: Increases brightness by 10% (clamped at 100%).
|
||
|
|
```sh
|
||
|
|
sudo nvbright up
|
||
|
|
```
|
||
|
|
|
||
|
|
- **`down`**: Decreases brightness by 10% (clamped at 0%).
|
||
|
|
```sh
|
||
|
|
sudo nvbright down
|
||
|
|
```
|
||
|
|
|
||
|
|
### Desktop and Window Manager Integration
|
||
|
|
|
||
|
|
You can bind `nvbright up` and `nvbright down` commands to the brightness keys (`XF86MonBrightnessUp` and `XF86MonBrightnessDown`) in window manager configurations (such as Sway, i3, or Openbox) or configure `sudoers` / `doas.conf` rules to allow execution without password prompts.
|
||
|
|
|
||
|
|
## Credits
|
||
|
|
|
||
|
|
Created by Luxferre in 2026, released into the public domain with no warranties.
|
||
|
|
|
||
|
|
Hardware register specifications and control flow inspired by the Linux `nouveau` DRM backlight driver (`nv50` / `nva3`).
|