Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bin/omarchy-hw-acer-aspire-go-15
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

# omarchy:summary=Detect Acer Aspire Go 15 series laptops.

dmi_vendor="${OMARCHY_DMI_SYS_VENDOR:-/sys/class/dmi/id/sys_vendor}"

grep -qi "Acer" "$dmi_vendor" 2>/dev/null && {
omarchy-hw-match "Aspire AG15-42P" || omarchy-hw-match "Aspire Go 15"
}
16 changes: 16 additions & 0 deletions install/hardware/acer/fix-aspire-keyboard.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Keyboard fix for Acer Aspire Go 15 laptops.
#
# The internal keyboard drops out ~5 seconds post-boot on Linux kernels
# due to an i8042 / atkbd ACPI conflict with acer-wmi. Adding i8042.reset,
# atkbd.reset, and acpi_osi=Linux to the kernel cmdline keeps the controller
# responsive.

limine_dropin="${OMARCHY_ACER_ASPIRE_LIMINE_CONF:-/etc/limine-entry-tool.d/acer-aspire-keyboard.conf}"

if omarchy-hw-acer-aspire-go-15; then
sudo mkdir -p "$(dirname "$limine_dropin")"
sudo tee "$limine_dropin" >/dev/null <<'EOF'
# Acer Aspire Go 15 internal keyboard fix
KERNEL_CMDLINE[default]+=" i8042.reset atkbd.reset acpi_osi=Linux"
EOF
fi
2 changes: 2 additions & 0 deletions install/hardware/all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ run_logged "$OMARCHY_INSTALL/hardware/asus/fix-asus-ptl-b9406-display.sh"
run_logged "$OMARCHY_INSTALL/hardware/asus/fix-asus-ptl-b9406-touchpad.sh"
run_logged "$OMARCHY_INSTALL/hardware/asus/fix-z13-touchpad.sh"

run_logged "$OMARCHY_INSTALL/hardware/acer/fix-aspire-keyboard.sh"

run_logged "$OMARCHY_INSTALL/hardware/framework/qmk-hid.sh"

run_logged "$OMARCHY_INSTALL/hardware/apple/fix-spi-keyboard.sh"
Expand Down
24 changes: 24 additions & 0 deletions migrations/1788707260.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
echo "Apply internal keyboard fix for Acer Aspire Go 15 laptops"

drop_in="${OMARCHY_ACER_ASPIRE_LIMINE_CONF:-/etc/limine-entry-tool.d/acer-aspire-keyboard.conf}"
running_cmdline="${OMARCHY_RUNNING_CMDLINE:-/proc/cmdline}"

if omarchy-hw-acer-aspire-go-15; then
needs_rebuild=0
if [[ ! -f $drop_in ]] || ! grep -q 'i8042\.reset' "$drop_in"; then
source "$OMARCHY_PATH/install/hardware/acer/fix-aspire-keyboard.sh"
needs_rebuild=1
fi

if (( needs_rebuild )); then
if omarchy-cmd-present limine-update; then
sudo limine-update
elif omarchy-cmd-present limine-mkinitcpio; then
sudo limine-mkinitcpio
fi

if [[ ! -r $running_cmdline ]] || ! grep -q 'i8042\.reset' "$running_cmdline"; then
omarchy-state set reboot-required
fi
fi
fi
184 changes: 184 additions & 0 deletions test/shell.d/acer-aspire-keyboard-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

detector="$ROOT/bin/omarchy-hw-acer-aspire-go-15"
leaf="$ROOT/install/hardware/acer/fix-aspire-keyboard.sh"
all="$ROOT/install/hardware/all.sh"
migration=$(grep -l "fix-aspire-keyboard.sh" "$ROOT"/migrations/*.sh | head -1)

grep -q 'run_logged .*hardware/acer/fix-aspire-keyboard.sh' "$all" ||
fail "the Acer keyboard workaround runs during hardware setup"
pass "the Acer keyboard workaround runs during hardware setup"

[[ -n $migration ]] || fail "a migration enables the workaround on existing installs"
pass "a migration enables the workaround on existing installs"

test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
mkdir -p "$test_tmp/bin"

cat >"$test_tmp/bin/omarchy-hw-match" <<'SH'
#!/bin/bash
[[ ${TEST_PRODUCT_NAME:-} == *"$1"* ]]
SH

cat >"$test_tmp/bin/sudo" <<'SH'
#!/bin/bash
exec "$@"
SH

cat >"$test_tmp/bin/omarchy-cmd-present" <<'SH'
#!/bin/bash
if [[ $1 == "${TEST_CMD_MISSING:-}" ]]; then
exit 1
fi
command -v "$1" >/dev/null 2>&1
SH

cat >"$test_tmp/bin/limine-update" <<'SH'
#!/bin/bash
printf 'limine-update\n' >>"$CALL_LOG"
exit "${TEST_UPDATE_STATUS:-0}"
SH

cat >"$test_tmp/bin/limine-mkinitcpio" <<'SH'
#!/bin/bash
printf 'limine-mkinitcpio\n' >>"$CALL_LOG"
exit "${TEST_MKINITCPIO_STATUS:-0}"
SH

cat >"$test_tmp/bin/omarchy-state" <<'SH'
#!/bin/bash
printf 'state %s\n' "$*" >>"$CALL_LOG"
SH

chmod +x "$test_tmp/bin"/*

vendor_file="$test_tmp/sys_vendor"
call_log="$test_tmp/calls.log"

run_detector() {
printf '%s\n' "${2-Acer}" >"$vendor_file"
PATH="$test_tmp/bin:$PATH" \
TEST_PRODUCT_NAME="${1-Aspire AG15-42P}" \
OMARCHY_DMI_SYS_VENDOR="$vendor_file" \
bash "$detector"
}

run_detector || fail "the detector matches Acer Aspire AG15-42P"
pass "the detector matches Acer Aspire AG15-42P"

run_detector "Aspire Go 15" || fail "the detector matches Acer Aspire Go 15"
pass "the detector matches Acer Aspire Go 15"

run_detector "Aspire AG15-42P" "Dell" && fail "the detector rejects non-Acer vendor"
pass "the detector rejects non-Acer vendor"

run_detector "Swift SF314" "Acer" && fail "the detector rejects other Acer models"
pass "the detector rejects other Acer models"

run_detector "Aspire AG15-42P" "ACER" || fail "the detector matches case-insensitively"
pass "the detector matches case-insensitively"

PATH="$test_tmp/bin:$PATH" \
TEST_PRODUCT_NAME="Aspire AG15-42P" \
OMARCHY_DMI_SYS_VENDOR="$test_tmp/nonexistent" \
bash "$detector" && fail "the detector fails closed when vendor attribute is missing"
pass "the detector fails closed when vendor attribute is missing"

# Leaf execution test
drop_in_file="$test_tmp/etc/limine-entry-tool.d/acer-aspire-keyboard.conf"

run_leaf() {
: >"$call_log"
printf '%s\n' "${2-Acer}" >"$vendor_file"
PATH="$test_tmp/bin:$ROOT/bin:$PATH" \
CALL_LOG="$call_log" \
TEST_PRODUCT_NAME="${1-Aspire AG15-42P}" \
OMARCHY_DMI_SYS_VENDOR="$vendor_file" \
OMARCHY_ACER_ASPIRE_LIMINE_CONF="$drop_in_file" \
bash -c 'source "$1"' bash "$leaf"
}

run_leaf || fail "the leaf executes on matching hardware"
[[ -f $drop_in_file ]] || fail "the leaf creates the limine drop-in file"
grep -q 'i8042\.reset' "$drop_in_file" || fail "the drop-in contains i8042.reset"
grep -q 'atkbd\.reset' "$drop_in_file" || fail "the drop-in contains atkbd.reset"
grep -q 'acpi_osi=Linux' "$drop_in_file" || fail "the drop-in contains acpi_osi=Linux"
pass "the leaf creates the limine drop-in configuration"

# Leaf idempotency
run_leaf || fail "the leaf executes again idempotently"
(( $(grep -c 'i8042\.reset' "$drop_in_file") == 1 )) || fail "leaf does not duplicate cmdline lines"
pass "the leaf is idempotent and does not duplicate configuration"

# Leaf on non-matching hardware
rm -f "$drop_in_file"
run_leaf "ThinkPad X1" "Lenovo" || fail "the leaf no-ops on other hardware"
[[ -f $drop_in_file ]] && fail "the leaf does not create drop-in on other hardware"
pass "the leaf no-ops on other hardware"

# Migration execution test
running_cmdline_file="$test_tmp/proc_cmdline"

run_migration() {
: >"$call_log"
printf '%s\n' "${2-Acer}" >"$vendor_file"
PATH="$test_tmp/bin:$ROOT/bin:$PATH" \
CALL_LOG="$call_log" \
OMARCHY_PATH="$ROOT" \
TEST_PRODUCT_NAME="${1-Aspire AG15-42P}" \
TEST_CMD_MISSING="${3:-}" \
TEST_UPDATE_STATUS="${4:-0}" \
TEST_MKINITCPIO_STATUS="${5:-0}" \
OMARCHY_DMI_SYS_VENDOR="$vendor_file" \
OMARCHY_ACER_ASPIRE_LIMINE_CONF="$drop_in_file" \
OMARCHY_RUNNING_CMDLINE="$running_cmdline_file" \
bash -euo pipefail "$migration" >/dev/null
}

# 1. Migration on unconfigured machine: drop-in created, limine-update run, reboot-required set
rm -f "$drop_in_file"
printf 'BOOT_IMAGE=/vmlinuz-linux root=/dev/sda1 rw\n' >"$running_cmdline_file"
run_migration || fail "the migration executes on matching hardware"
[[ -f $drop_in_file ]] || fail "migration created drop-in"
grep -q '^limine-update$' "$call_log" || fail "migration executed limine-update"
grep -q 'state set reboot-required' "$call_log" || fail "migration requested reboot"
pass "the migration creates drop-in, rebuilds boot config, and requests reboot"

# 2. Migration on already-running quirk machine: rebuilds drop-in but does not need reboot
rm -f "$drop_in_file"
printf 'BOOT_IMAGE=/vmlinuz-linux root=/dev/sda1 i8042.reset atkbd.reset acpi_osi=Linux rw\n' >"$running_cmdline_file"
run_migration || fail "the migration executes when quirks already running"
grep -q '^limine-update$' "$call_log" || fail "migration executed limine-update"
grep -q 'state set reboot-required' "$call_log" && fail "migration skipped reboot request when quirks already active"
pass "the migration skips reboot request when quirks are already active in cmdline"

# 3. Migration fallback to limine-mkinitcpio when limine-update is not present
rm -f "$drop_in_file"
printf 'BOOT_IMAGE=/vmlinuz-linux root=/dev/sda1 rw\n' >"$running_cmdline_file"
run_migration "Aspire AG15-42P" "Acer" "limine-update" || fail "the migration falls back to limine-mkinitcpio"
grep -q '^limine-mkinitcpio$' "$call_log" || fail "migration executed limine-mkinitcpio fallback"
pass "the migration falls back to limine-mkinitcpio when limine-update is absent"

# 4. Migration fails and avoids marking reboot-required if bootloader rebuild fails
rm -f "$drop_in_file"
run_migration "Aspire AG15-42P" "Acer" "" "1" && fail "the migration must fail when limine-update fails"
grep -q 'state set reboot-required' "$call_log" && fail "failing rebuild must not mark reboot-required"
pass "the migration fails and avoids marking reboot-required when bootloader rebuild fails"

# 5. Migration idempotent: drop-in already present -> no rebuild needed
printf 'KERNEL_CMDLINE[default]+=" i8042.reset atkbd.reset acpi_osi=Linux"\n' >"$drop_in_file"
: >"$call_log"
run_migration || fail "the migration succeeds on already configured machine"
grep -q '^limine-update$' "$call_log" && fail "migration skipped rebuild when drop-in was already up to date"
pass "the migration is idempotent and skips rebuild when drop-in is already present"

# 6. Migration on other hardware
: >"$call_log"
run_migration "ThinkPad X1" "Lenovo" || fail "the migration runs cleanly on other hardware"
[[ -s $call_log ]] && fail "the migration does nothing on other hardware"
pass "the migration no-ops on other hardware"