Install the HDMI CEC and HDMI connection APEX packages plus the
android.hardware.hdmi.cec.xml feature file, set the playback-device
CEC properties, and give system ownership of /dev/cec0 in ueventd.
The connection HAL now reports a single HDMI output port and monitors
/sys/class/drm/card0-HDMI-A-1/status with poll(), reporting hotplug
transitions through the AIDL callback and shutting the monitor thread
down through an eventfd.
The CEC HAL now polls POLLPRI for CEC_DQEVENT and POLLIN for
CEC_RECEIVE, guards the ioctl paths against an uninitialised adapter,
and bounds message length by CEC_MAX_MSG_SIZE.
The config_maxUiWidth=0 override never took effect from /vendor/overlay:
static RRO precedence is decided by partition order before priority, so
the product-partition TvFrameworkOverlay (1920) always won and silently
re-capped the UI to 1920x1080 on 4K displays. Moving our overlay to the
product partition lets its priority 10 beat TvFrameworkOverlay's 0, so
the cap is disabled and the UI renders at the display's native
resolution. Users can select a lower mode in Settings if needed.
On this mac80211/mt7921u stack, Android's WifiCountryCode path issues
the private DRIVER COUNTRY command (a Broadcom-era AIDL path), which
is a silent no-op. The kernel never receives NL80211_CMD_REQ_SET_REG,
so scanning runs in world regdom (00) with 5GHz passive-only.
Ship country=US in wpa_supplicant_overlay.conf, loaded by the supplicant
AIDL service (addStaInterfaceInternal -> confanother) at every interface
init. This goes through wpa_drv_set_country() -> nl80211's set_country,
issuing a genuine user regulatory hint to the kernel.
ro.boot.wificountrycode was set in two places: androidboot.wificountrycode=US
on the kernel cmdline (mkimg.sh extlinux heredoc) and ro.boot.wificountrycode=00
in vendor.prop. Because ro.* properties are set-once and init processes the
cmdline first, the cmdline always won and the vendor.prop value silently lost
(init logs 'Read-only property was already set' every boot). Worse, the
vendor.prop value was 00 (world regulatory domain), a landmine that would
activate if the cmdline param were ever dropped.
Remove the cmdline param and set vendor.prop to US so the country code lives
in exactly one place, delivered via vendor.img instead of a hand-maintained
boot heredoc. Note this only feeds the Android framework (WifiCountryCode);
the kernel side additionally needs regulatory.db to actually apply it (fixed
separately by embedding it via CONFIG_EXTRA_FIRMWARE in the kernel).
The ro.boot.wificountrycode property is a ro.boot.* namespace property
that can ONLY be populated from the kernel cmdline (androidboot.xxx).
Setting it in vendor.prop had no effect — the value stayed '00'.
This caused the WiFi regulatory domain to default to 'country 00'
(world), which forced passive scanning on all 5GHz channels and
capped TX power at 3 dBm. On a DFS channel this meant 60s CAC
delays, failed scans, and crippled TX power causing SAE handshake
failures.
This is the actual fix — adding the boot parameter that the WiFi
framework reads to set the regulatory domain via nl80211.
Users in other regulatory domains should edit this line.
The world regulatory domain (00) forces passive scanning on all 5GHz
channels and limits TX power to 3 dBm. For a device whose AP is on
channel 144 (5720 MHz, DFS), this means:
- Scans must wait for beacons instead of actively probing
- DFS channel availability check adds up to 60s delay
- Transmit power is crippled to 3 dBm
Setting to US enables active scanning, proper TX power, and standard
DFS handling, which eliminates the 2-3 minute connection delay.
Users in other regulatory domains should override this via their own
vendor.prop or the build system.
Without BOARD_WLAN_DEVICE, libwifi-hal's fallback returns
WIFI_ERROR_NOT_SUPPORTED from init_wifi_vendor_hal_func_table, which
causes the AIDL wifi HAL (com.android.hardware.wifi) to fail at startup:
E android.hardware.wifi-service: Can not initialize the vendor
function pointer table
E android.hardware.wifi-service: Wifi HAL start failed
The bcmdhd implementation of init_wifi_vendor_hal_func_table uses
purely generic nl80211 — it scans /sys/class/net/ for phy80211
interfaces, creates netlink sockets, and resolves the nl80211 family
ID via genl_ctrl_resolve(). There are no bcmdhd-specific IOCTLs or
vendor commands in the core startup path (wifi_initialize, wifi_cleanup,
wifi_event_loop, wifi_get_ifaces, wifi_get_iface_name); the vendor
commands are only used for optional advanced features (RTT, NAN, etc.)
that this device does not use.
The glob pattern '$drvdir/*/' appended a trailing '/' to each
entry, which caused the shell to dereference symlinks before
the '[ -L ]' test could run. Since the only symlinks in a USB
driver directory ARE the bound device entries (e.g. 4-1:1.0),
'[ -L path/ ]' always returned false and the unbind+rebind
never fired for any driver.
Drop the trailing '/', iterate over all entries, and filter
with '[ -L ]' on the raw name. The module/uevent/new_id
name-skips still work correctly.
The old script only re-probed driverless USB interfaces. Some built-in
USB WiFi drivers (notably mt7921u) do NOT fail probe() when firmware is
missing — they bind 'successfully', then loop on the MCU handshake until
a timeout kills hardware init. The driverless-only reprobe never
touches them, so the adapter stays dead after the initial probe.
Fix: add phase 2 that force-unbinds and re-probes every USB interface
already bound to a known built-in WiFi driver, so their firmware request
runs again now that /vendor/firmware is available on the kernel's
fw_path[].
Also increase the driver list to match all built-in =y USB WiFi drivers
from tart_defconfig.
The display sizing fix now uses PRODUCT_AAPT_PREF_CONFIG=xhdpi, so the
device no longer resolves the tvdpi resource bucket. The values-tvdpi
override with config_maxUiWidth=0 is dead code. The values-xhdpi override
provides the same defense-in-depth in the currently-resolved bucket.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
The root cause of the oversized/clipped UI is TvFrameworkOverlay's
config_maxUiWidth=1280 in the values-tvdpi resource bucket. With
PRODUCT_AAPT_PREF_CONFIG=tvdpi, the device resolves this bucket and
the 1280px cap is enforced, limiting the logical display to 1280x720
(which SurfaceFlinger then upscales to 1920x1080).
The Raspberry Pi 5 ATV build (KonstaKANG) uses PRODUCT_AAPT_PREF_CONFIG=xhdpi
and has no display sizing issues, because values-xhdpi has
config_maxUiWidth=1920 (no effective cap on 1080p displays).
Also adds a values-xhdpi/config.xml overlay with config_maxUiWidth=0 as
defense-in-depth, matching the existing values-tvdpi override.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
The partitions are typically already unmounted when wrimg.sh runs, so
umount prints 'not mounted' to stderr. This is harmless but noisy.
Redirect stderr to /dev/null and use || true so the warning is silenced.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
check_device() was using lsblk -o LABEL (filesystem labels) to identify
partitions, but mkimg.sh sets the labels via e2label which can silently
fail if the partition image wasn't built with an ext4 filesystem label.
The system partition in particular often shows as '/' (the mkfs.ext4
default) instead of 'system'.
Switch to lsblk -o PARTLABEL (GPT partition names), which are always set
correctly by mkimg.sh via sfdisk's name= parameter, and are preserved
regardless of filesystem layer.
Also broaden find_device() to check sde and mmcblk[01] entries.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
The Android TV framework overlay (TvFrameworkOverlay) sets
config_maxUiWidth=1280 in its values-tvdpi resource bucket. This device
resolves the tvdpi bucket via PRODUCT_AAPT_PREF_CONFIG=tvdpi, so the
logical display gets capped to 1280x720@320dpi even though the physical
panel runs at 1920x1080. SurfaceFlinger then upscales 720p->1080p, making
the UI oversized/clipped, and makes the Settings Resolution picker a no-op.
The previous fix (commit ada397e) put config_maxUiWidth=0 in the unqualified
values/ bucket, which loses to values-tvdpi because Android prioritizes
config-qualified resources over RRO priority.
This new override lives in values-tvdpi/ — same config-qualifier bucket as
TvFrameworkOverlay's entry — so RRO priority decides. Our overlay priority
10 beats TvFrameworkOverlay's priority 0, and config_maxUiWidth=0 disables
the cap, letting the native 1920x1080 panel render at full resolution.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Create aosp_tart.mk as the AOSP base product config (like
aosp_oriole.mk), inherited by lineage_tart.mk (like
lineage_oriole.mk). This matches the standard LineageOS
device tree convention.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
- Rename product makefile: lineage_tart.mk (PRODUCT_NAME=lineage_tart)
- Update AndroidProducts.mk for lineage_tart lunch target
- Change androidboot.hardware and TARGET_BOOTLOADER_BOARD_NAME to tart
- Rename ramdisk files: fstab.tart, init.tart.rc, ueventd.tart.rc
- Update device.mk ramdisk copy targets for tart names
- Update vendor makefile reference to tart-vendor.mk
- Update extlinux.conf kernel cmdline with tart hardware ID
- Fix bluetooth device name in vendor.prop
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Without androidboot.boot_devices or androidboot.boot_part_uuid
set in the kernel cmdline, init can't identify the boot device
and won't create /dev/block/by-name/ symlinks. The boot.cmd
script sets boot_part_uuid via U-Boot's 'part uuid' command,
but extlinux.conf boots without running boot.cmd.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Use build/soong/bin/get_build_var LINEAGE_VERSION to query
the build system for the version string, producing filenames
like lineage-23.2-20260711-UNOFFICIAL-orangepi5ultra.img.
Removes fragile zip-parsing and hardcoded fallback. Fails
cleanly if LINEAGE_VERSION cannot be resolved.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
The extlinux.conf provides a standard U-Boot distro boot configuration
that allows boards with U-Boot already flashed to SPI NOR to boot
without needing the boot.scr script. U-Boot scans for this file at
/extlinux/extlinux.conf during its distro boot sequence.
This is the fallback when U-Boot is already on SPI and the boot
partition provides the kernel/DTB/ramdisk for Android TV.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Remove unused OPI_BOOT_OUT staging directory. Boot.img is now
just the U-Boot binary for build system packaging. The actual
FAT32 boot partition with kernel/DTB/ramdisk is created by
mkimg_gpt.sh, which runs outside the build system and has
access to mkfs.vfat and mcopy.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
- Make mkimg_gpt.sh executable (chmod +x)
- Fix boot partition creation: create FAT32 fs and copy kernel/boot
files instead of relying on boot.img (which was the u-boot binary)
- Add android-sdcard.dtbo to boot partition
- Parameterize DEVICE_PATH and KERNEL_PATH variables
- Use correct U-Boot path (new Ultra-specific bl32less binary)
The boot partition (p1) is now properly created as FAT32 with
kernel Image, DTB, boot.scr, ramdisk.img, and config.txt.
This matches what U-Boot expects to read from the boot media.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
mkfs.fat and mcopy are disallowed in Android 16 build system.
Use pre-built U-Boot binary as boot.img for packaging purposes.
The actual bootable image is created by mkimg_gpt.sh.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Without explicit definition, the variable is empty when
TARGET_NO_KERNEL was set. Define it to ensure boot.img
is created for the target-files packaging step.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
The kernel repo only has the Orange Pi 5 Ultra DTB. Remove
references to other OPI5 variant DTBs. Fix ramdisk dependency
to use built ramdisk.img directly.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
TARGET_NO_KERNEL prevented INSTALLED_BOOTIMAGE_TARGET from
being defined, breaking the target-files packaging step.
Use BOARD_KERNEL_IMAGE_NAME instead to satisfy kernel.mk.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Stock AOSP mesa3d doesn't build libgbm_mesa, so the
minigbm_gbm_mesa gralloc wrapper can't link. Remove
for now to get a booting PoC with software rendering.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>
Stock AOSP mesa3d doesn't build libEGL_mesa, libgallium_dri,
or com.android.hardware.vulkan.panfrost. Remove these references
until Panfrost support is added back.
Copyright (C) 2026 Brendan Szymanski <hello@bscubed.dev>