# DF-5092 — ar5416GpioCfgInput drives the pin instead of tristating it

File: `sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c:136-155`
Class: hardware-correctness / insecure pin initialization (Info)
Pass 2 (GLM 5.3 re-audit) of `ar5416_gpio.c`. Known findings DF-2098 (unvalidated
gpio index in 4/5 exports) and DF-2099 (AR9287 wrong input bit) were *not*
re-reported.

## What the code does

`ar5416GpioCfgInput()` is documented (by its own comment, line 146) to
tristate the pin when configuring it as an input:

```c
/* TODO: configure input mux for AR5416 */
/* If configured as input, set output to tristate */
gpio_shift = gpio << 1;

reg = OS_REG_READ(ah, AR_GPIO_OE_OUT);
reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift);
reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift;      /* <-- BUG */
OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg);
```

`AR_GPIO_OE_OUT_DRV_ALL == 0x3` is "drive always" (ar5416reg.h:574), the
exact opposite of the intended `AR_GPIO_OE_OUT_DRV_NO == 0x0` ("tristate",
ar5416reg.h:571). Clearing the field and *not* setting anything would
tristate the pin — that is precisely what the AR5210/5211/5212 twins do:

- `ar5212GpioCfgInput()` — `sys/dev/netif/ath/ath_hal/ar5212/ar5212_gpio.c:57-66`
  ORs in `AR_GPIOCR_CR_N(gpio)` (no-drive/tristate).
- `ar5211GpioCfgInput()` — `sys/dev/netif/ath/ath_hal/ar5211/ar5211_misc.c:213-225`
  ORs in `AR_GPIOCR_0_CR_N << (gpio * CR_SHIFT)`.

The function is byte-identical in FreeBSD CURRENT
(`sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c`, verified 2026-09-27 against
cgit.freebsd.org) — this is an upstream-inherited defect, not a DragonFly
regression. Fix owner: upstream FreeBSD ath HAL, portable to DF as below.

## Why it matters

Real consumers configure *externally driven* sense pins through this entry
point:

- `ar5416_btcoex.c:355-356` — BT ACTIVE / BT PRIORITY inputs
  (`ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect)` etc., 3-wire btcoex)
- `ar5416_btcoex.c:388` — BT ACTIVE input (2-wire btcoex)
- `ar5416_btcoex.c:237` — WLAN ACTIVE pin switched back to "input" on disable

After this call the WLAN MAC actively drives a pin that the Bluetooth module
(or another chip) also drives. Two push-pull drivers at opposite levels =
electrical contention (crowbar current), mis-read inputs, and degraded BT
coexistence — the "input" pin can never reliably sample the external signal.

Security impact: **none at the kernel-memory level**. Reachability is
root-gated (driver/HAL-internal configuration, EEPROM-derived pin selects);
there is no unprivileged path to these functions. Filed as Info for
hardware-correctness and defense-in-depth (input must not drive).

## Reproduction

Not runnable in the QEMU guest: the standard snapshot has no Atheros WLAN
device (`dfbsd-qemu/boot.log` contains zero ath(4) probes; the code is
compiled in via `sys/config/X86_64_GENERIC:263-266` but only executes
against real AR5416-family silicon). To reproduce on hardware with a
btcoex-capable Atheros NIC (AR9285/AR9287 + BT combo):

1. `sysctl hw.ath.0.btcoex=...` per if_ath docs to enable 2/3-wire btcoex.
2. Probe `dev.ath.0.%parent` registers: read AR_GPIO_OE_OUT (0x404c) after
   attach — bits for the btcoex input pins read 0b11 (drive) instead of 0b00
   (tristate).

`./verify_static.sh` (host-side) prints the decisive source lines and the
twin implementations for contrast.
