fix: improve dependency installation diagnostics

Install mode-switch dependencies, support a69c:572f, avoid redundant generic headers when a usable kernel build tree exists, and discover DKMS logs dynamically. Addresses installer portions of #28, #55, #65, #66, and #68.
This commit is contained in:
Shen Mintao
2026-07-14 17:23:53 +08:00
parent 0ed5afba03
commit 7dc7569312
3 changed files with 163 additions and 61 deletions
+2 -8
View File
@@ -7,12 +7,13 @@ KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5726", SYMLINK+="ten
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5727", SYMLINK+="tendaudiskv4", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5727", SYMLINK+="tendaudiskv4", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572a", SYMLINK+="tendaudiskv5", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572a", SYMLINK+="tendaudiskv5", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572c", SYMLINK+="cudydiskv2", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572c", SYMLINK+="cudydiskv2", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572f", SYMLINK+="aicudisk572f", RUN+="/usr/bin/eject /dev/%k"
# AIC8800D80 "Pandora" clone adapter - automatic mode switch & driver binding # AIC8800D80 "Pandora" clone adapter - automatic mode switch & driver binding
# Triggers usb_modeswitch when the device is plugged in as 1111:1111 # Triggers usb_modeswitch when the device is plugged in as 1111:1111
# --- Mode Switch --- # --- Mode Switch ---
ACTION=="add", ATTRS{idVendor}=="1111", ATTRS{idProduct}=="1111", RUN+="/usr/sbin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111" ACTION=="add", ATTRS{idVendor}=="1111", ATTRS{idProduct}=="1111", RUN+="/bin/sh -c 'if [ -x /usr/sbin/usb_modeswitch ]; then exec /usr/sbin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; elif [ -x /usr/bin/usb_modeswitch ]; then exec /usr/bin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; fi'"
# --- WiFi Driver Binding --- # --- WiFi Driver Binding ---
# After mode switch, the device re-enumerates as a69c:8d81 (Radxa fw) or a69c:8d83 (Brostrend fw). # After mode switch, the device re-enumerates as a69c:8d81 (Radxa fw) or a69c:8d83 (Brostrend fw).
@@ -21,13 +22,6 @@ ACTION=="add", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", RUN+="/bin/sh
ACTION=="add", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'echo a69c 8d83 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'" ACTION=="add", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'echo a69c 8d83 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'"
ACTION=="add", ATTRS{idVendor}=="368b", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'echo 368b 8d81 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'" ACTION=="add", ATTRS{idVendor}=="368b", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'echo 368b 8d81 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'"
# --- Bluetooth Driver Binding ---
# PID 8d81 (Radxa fw with BT enabled) exposes BT interfaces.
# If aic_btusb doesn't auto-bind, add the VID:PID dynamically.
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", ATTR{bInterfaceClass}=="e0", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="01", RUN+="/bin/sh -c 'echo a69c 8d81 > /sys/bus/usb/drivers/aic_btusb/new_id 2>/dev/null || true'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", ATTR{bInterfaceClass}=="e0", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="01", RUN+="/bin/sh -c 'echo a69c 8d83 > /sys/bus/usb/drivers/aic_btusb/new_id 2>/dev/null || true'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="368b", ATTRS{idProduct}=="8d81", ATTR{bInterfaceClass}=="e0", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="01", RUN+="/bin/sh -c 'echo 368b 8d81 > /sys/bus/usb/drivers/aic_btusb/new_id 2>/dev/null || true'"
# Unblock rfkill for Bluetooth # Unblock rfkill for Bluetooth
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'" ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'" ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'"
+77 -17
View File
@@ -17,6 +17,29 @@ YELLOW='\033[1;33m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
NC='\033[0m' NC='\033[0m'
DRV_NAME="aic8800"
DRV_VERSION="1.0.0"
INSTALL_LOG="/tmp/aic8800d80_install.log"
read_dkms_conf_value() {
local key="$1"
local file="$2"
grep -E "^[[:space:]]*${key}[[:space:]]*=" "$file" 2>/dev/null \
| head -1 \
| cut -d= -f2- \
| tr -d "\"'[:space:]"
}
if [ -f "./dkms.conf" ]; then
detected_name="$(read_dkms_conf_value PACKAGE_NAME ./dkms.conf)"
detected_version="$(read_dkms_conf_value PACKAGE_VERSION ./dkms.conf)"
[ -n "$detected_name" ] && DRV_NAME="$detected_name"
[ -n "$detected_version" ] && DRV_VERSION="$detected_version"
fi
mapfile -t DKMS_SOURCE_DIRS < <(find /usr/src -maxdepth 1 -type d -name "${DRV_NAME}-*" -print 2>/dev/null | sort)
print_section() { print_section() {
echo "" echo ""
echo -e "${BLUE}━━━ $1 ━━━${NC}" echo -e "${BLUE}━━━ $1 ━━━${NC}"
@@ -58,46 +81,73 @@ fi
print_section "2. Checking DKMS directory" print_section "2. Checking DKMS directory"
if [ -d "/usr/src/aic8800-1.0.0" ]; then echo "Detected package: ${DRV_NAME}/${DRV_VERSION}"
echo -e "${GREEN}✓${NC} /usr/src/aic8800-1.0.0 directory exists" if [ "${#DKMS_SOURCE_DIRS[@]}" -gt 0 ]; then
for source_dir in "${DKMS_SOURCE_DIRS[@]}"; do
echo -e "${GREEN}✓${NC} $source_dir directory exists"
echo "" echo ""
echo "Content:" echo "Content:"
ls -la /usr/src/aic8800-1.0.0/ ls -la "$source_dir/"
echo "" echo ""
echo "Checking drivers/aic8800 inside DKMS:" echo "Checking drivers/aic8800 inside DKMS:"
if [ -d "/usr/src/aic8800-1.0.0/drivers/aic8800" ]; then if [ -d "$source_dir/drivers/aic8800" ]; then
echo -e "${GREEN}✓${NC} drivers/aic8800 copied to DKMS" echo -e "${GREEN}✓${NC} drivers/aic8800 copied to DKMS"
ls -la /usr/src/aic8800-1.0.0/drivers/aic8800/ ls -la "$source_dir/drivers/aic8800/"
else else
echo -e "${RED}✗${NC} drivers/aic8800 NOT copied correctly!" echo -e "${RED}✗${NC} drivers/aic8800 NOT copied correctly!"
fi fi
echo ""
done
else else
echo -e "${RED}✗${NC} /usr/src/aic8800-1.0.0 directory NOT FOUND" echo -e "${RED}✗${NC} No /usr/src/${DRV_NAME}-* directory found"
fi fi
print_section "3. Checking DKMS build logs" print_section "3. Checking DKMS build logs"
if [ -f "/var/lib/dkms/aic8800/1.0.0/build/make.log" ]; then mapfile -t BUILD_LOGS < <(find "/var/lib/dkms/${DRV_NAME}" -type f -name make.log -print 2>/dev/null | sort)
echo -e "${GREEN}✓${NC} Build log found"
if [ "${#BUILD_LOGS[@]}" -gt 0 ]; then
for build_log in "${BUILD_LOGS[@]}"; do
echo -e "${GREEN}✓${NC} Build log found: $build_log"
echo "" echo ""
echo "Last 50 lines of make.log:" echo "Last 50 lines of make.log:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tail -50 /var/lib/dkms/aic8800/1.0.0/build/make.log tail -50 "$build_log"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
done
else
echo -e "${RED}✗${NC} No make.log found under /var/lib/dkms/${DRV_NAME}/"
echo "The module may not have reached the build step yet, or this DKMS version stores logs elsewhere."
fi
if [ -f "$INSTALL_LOG" ]; then
echo ""
echo -e "${GREEN}✓${NC} Installer log found: $INSTALL_LOG"
echo "Last 50 lines of installer log:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tail -50 "$INSTALL_LOG"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
else else
echo -e "${RED}✗${NC} Build log not found in /var/lib/dkms/aic8800/1.0.0/build/make.log" echo -e "${YELLOW}!${NC} Installer log not found: $INSTALL_LOG"
fi fi
print_section "4. Checking dkms.conf" print_section "4. Checking dkms.conf"
if [ -f "/usr/src/aic8800-1.0.0/dkms.conf" ]; then if [ "${#DKMS_SOURCE_DIRS[@]}" -gt 0 ]; then
echo -e "${GREEN}✓${NC} dkms.conf found" for source_dir in "${DKMS_SOURCE_DIRS[@]}"; do
if [ -f "$source_dir/dkms.conf" ]; then
echo -e "${GREEN}✓${NC} dkms.conf found: $source_dir/dkms.conf"
echo ""
cat "$source_dir/dkms.conf"
echo "" echo ""
echo "dkms.conf content:"
cat /usr/src/aic8800-1.0.0/dkms.conf
else else
echo -e "${RED}✗${NC} dkms.conf NOT FOUND!" echo -e "${RED}✗${NC} dkms.conf NOT FOUND in $source_dir"
fi
done
else
echo -e "${RED}✗${NC} No DKMS source directory available to inspect"
fi fi
if [ -f "./dkms.conf" ]; then if [ -f "./dkms.conf" ]; then
@@ -120,13 +170,23 @@ print_section "6. System information"
echo "Kernel: $(uname -r)" echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)" echo "Architecture: $(uname -m)"
echo "" echo ""
echo "GCC version:" echo "Compiler version:"
if command -v gcc >/dev/null 2>&1; then
gcc --version | head -1 gcc --version | head -1
elif command -v clang >/dev/null 2>&1; then
clang --version | head -1
else
echo "No gcc or clang found"
fi
echo "" echo ""
echo "Installed kernel headers:" echo "Installed kernel headers:"
ls -d /lib/modules/$(uname -r)/build 2>/dev/null && echo "✓ Headers found" || echo "✗ Headers NOT found" ls -d "/lib/modules/$(uname -r)/build" 2>/dev/null && echo "✓ Headers found" || echo "✗ Headers NOT found"
print_section "7. DKMS status" print_section "7. DKMS status"
echo "DKMS modules registered:" echo "DKMS modules registered:"
if command -v dkms >/dev/null 2>&1; then
dkms status dkms status
else
echo -e "${RED}✗${NC} dkms command not found"
fi
+70 -22
View File
@@ -70,13 +70,29 @@ print_step() {
log_message "STEP" "$1" log_message "STEP" "$1"
} }
run_logged() {
local description="$1"
shift
local command_status=0
"$@" 2>&1 | tee -a "$LOG_FILE"
command_status="${PIPESTATUS[0]}"
if [ "$command_status" -ne 0 ]; then
print_error "$description failed (exit code $command_status)."
fi
return "$command_status"
}
############################################################################# #############################################################################
# Error Handling # Error Handling
############################################################################# #############################################################################
cleanup_on_error() { cleanup_on_error() {
print_error "Installation failed. Check $LOG_FILE for details." local exit_code=$?
exit 1 trap - ERR
print_error "Installation failed (exit code $exit_code). Check $LOG_FILE for details."
exit "$exit_code"
} }
trap cleanup_on_error ERR trap cleanup_on_error ERR
@@ -180,6 +196,8 @@ detect_package_manager() {
echo " - build-essential / base-devel / development tools" echo " - build-essential / base-devel / development tools"
echo " - linux-headers for your kernel version" echo " - linux-headers for your kernel version"
echo " - mokutil (optional, for Secure Boot detection)" echo " - mokutil (optional, for Secure Boot detection)"
echo " - eject"
echo " - usb_modeswitch / usb-modeswitch"
echo "" echo ""
exit 1 exit 1
fi fi
@@ -196,48 +214,78 @@ is_volumio() {
return 1 return 1
} }
kernel_build_tree_available() {
local kernel_build_dir="/lib/modules/$(uname -r)/build"
[ -d "$kernel_build_dir" ] && [ -r "$kernel_build_dir/Makefile" ]
}
install_dependencies() { install_dependencies() {
local pkg_manager="$1" local pkg_manager="$1"
local install_kernel_headers=true
print_step "Installing dependencies..." print_step "Installing dependencies..."
if kernel_build_tree_available; then
install_kernel_headers=false
print_info "Kernel build tree already exists; skipping generic kernel headers package."
elif is_volumio; then
install_kernel_headers=false
print_info "Volumio detected; skipping generic kernel headers package."
fi
case "$pkg_manager" in case "$pkg_manager" in
apt) apt)
print_info "Updating package database..." print_info "Updating package database..."
apt-get update -qq >> "$LOG_FILE" 2>&1 run_logged "Package database update" apt-get update
if is_volumio; then local -a packages=(dkms build-essential mokutil eject usb-modeswitch)
print_info "Volumio detected; skipping generic linux-headers package." if [ "$install_kernel_headers" = true ]; then
print_info "Installing: dkms, build-essential, mokutil..." packages+=("linux-headers-$(uname -r)")
apt-get install -y dkms build-essential mokutil >> "$LOG_FILE" 2>&1
else
print_info "Installing: dkms, build-essential, linux-headers, mokutil..."
apt-get install -y dkms build-essential linux-headers-$(uname -r) mokutil >> "$LOG_FILE" 2>&1
fi fi
print_info "Installing: ${packages[*]}..."
run_logged "Dependency installation" env DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
;; ;;
dnf) dnf)
print_info "Installing: dkms, gcc, make, kernel-devel, kernel-headers, mokutil..." local -a packages=(dkms make gcc mokutil util-linux usb_modeswitch)
dnf install -y dkms make gcc kernel-devel kernel-headers mokutil >> "$LOG_FILE" 2>&1 if [ "$install_kernel_headers" = true ]; then
packages+=(kernel-devel kernel-headers)
fi
print_info "Installing: ${packages[*]}..."
run_logged "Dependency installation" dnf install -y "${packages[@]}"
;; ;;
yum) yum)
print_info "Installing: dkms, gcc, make, kernel-devel, mokutil..." local -a packages=(dkms make gcc mokutil util-linux usb_modeswitch)
yum install -y epel-release >> "$LOG_FILE" 2>&1 if [ "$install_kernel_headers" = true ]; then
yum install -y dkms make gcc kernel-devel mokutil >> "$LOG_FILE" 2>&1 packages+=(kernel-devel)
fi
print_info "Enabling EPEL repository..."
run_logged "EPEL repository installation" yum install -y epel-release
print_info "Installing: ${packages[*]}..."
run_logged "Dependency installation" yum install -y "${packages[@]}"
;; ;;
pacman) pacman)
print_info "Syncing package database..." print_info "Syncing package database..."
pacman -Sy --noconfirm >> "$LOG_FILE" 2>&1 run_logged "Package database sync" pacman -Sy --noconfirm
print_info "Installing: dkms, base-devel, linux-headers, mokutil..." local -a packages=(dkms base-devel mokutil util-linux usb_modeswitch)
pacman -S --noconfirm dkms base-devel linux-headers mokutil >> "$LOG_FILE" 2>&1 if [ "$install_kernel_headers" = true ]; then
packages+=(linux-headers)
fi
print_info "Installing: ${packages[*]}..."
run_logged "Dependency installation" pacman -S --needed --noconfirm "${packages[@]}"
;; ;;
zypper) zypper)
print_info "Installing: dkms, gcc, make, kernel-devel, mokutil..." local -a packages=(dkms make gcc mokutil util-linux usb_modeswitch)
zypper install -y dkms make gcc kernel-devel mokutil >> "$LOG_FILE" 2>&1 if [ "$install_kernel_headers" = true ]; then
packages+=(kernel-devel)
fi
print_info "Installing: ${packages[*]}..."
run_logged "Dependency installation" zypper --non-interactive install "${packages[@]}"
;; ;;
*) *)
@@ -252,11 +300,11 @@ install_dependencies() {
check_kernel_build_tree() { check_kernel_build_tree() {
local kernel_build_dir="/lib/modules/$(uname -r)/build" local kernel_build_dir="/lib/modules/$(uname -r)/build"
if [ -e "$kernel_build_dir" ]; then if kernel_build_tree_available; then
return 0 return 0
fi fi
print_error "Kernel build directory not found: $kernel_build_dir" print_error "Kernel build directory is missing or incomplete: $kernel_build_dir"
echo "" echo ""
if is_volumio; then if is_volumio; then
echo "Volumio does not use the normal linux-headers package flow." echo "Volumio does not use the normal linux-headers package flow."