fix: add udev rules for Kneron USB access on Linux

Without udev rules, only root can access Kneron USB devices, so the
web server running as a normal user cannot scan/connect to devices.

Adds /etc/udev/rules.d/99-kneron.rules granting MODE=0666 for
KL520 (PID 0x0100), KL720 KDP (PID 0x0200), KL720 KDP2 (PID 0x0720).

Applied in both GUI installer (platform_linux.go installLibusb) and
CLI installer (install.sh setup_libusb).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-03-25 15:44:25 +08:00
parent b7e6da4c05
commit 559d0fdb8a
2 changed files with 86 additions and 7 deletions

View File

@ -43,18 +43,51 @@ func removeSystemLink() {
}
func installLibusb(installDir string) error {
// Check if already installed
if _, err := exec.LookPath("lsusb"); err == nil {
return nil
// Install libusb if not present
if exec.Command("dpkg", "-s", "libusb-1.0-0-dev").Run() != nil {
cmd := exec.Command("pkexec", "apt-get", "install", "-y", "libusb-1.0-0-dev")
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("apt install libusb failed: %s — %w", string(out), err)
}
}
cmd := exec.Command("pkexec", "apt-get", "install", "-y", "libusb-1.0-0-dev")
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("apt install libusb failed: %s — %w", string(out), err)
}
// Install udev rules so non-root users can access Kneron USB devices
installKneronUdevRules()
return nil
}
// installKneronUdevRules writes a udev rule file granting non-root access
// to Kneron KL520/KL720 USB devices and reloads udev.
func installKneronUdevRules() {
const rulesPath = "/etc/udev/rules.d/99-kneron.rules"
// Skip if already installed
if _, err := os.Stat(rulesPath); err == nil {
return
}
rules := strings.Join([]string{
`# Kneron KL520`,
`SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0100", MODE="0666"`,
`# Kneron KL720 KDP (legacy)`,
`SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0200", MODE="0666"`,
`# Kneron KL720 KDP2`,
`SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0720", MODE="0666"`,
}, "\n") + "\n"
// Write to a temp file then move with pkexec (needs root)
tmpFile := filepath.Join(os.TempDir(), "99-kneron.rules")
if err := os.WriteFile(tmpFile, []byte(rules), 0644); err != nil {
return
}
defer os.Remove(tmpFile)
exec.Command("pkexec", "cp", tmpFile, rulesPath).Run()
exec.Command("pkexec", "udevadm", "control", "--reload-rules").Run()
exec.Command("pkexec", "udevadm", "trigger").Run()
}
func checkLibusbInstalled() bool {
return exec.Command("dpkg", "-s", "libusb-1.0-0-dev").Run() == nil
}

View File

@ -116,6 +116,30 @@ setup_python_venv() {
info "Installing pyusb ..."
"$VENV_DIR/bin/pip" install --quiet pyusb
# Install KneronPLUS SDK wheel if bundled
local scripts_dir="$INSTALL_DIR/scripts"
local os_type
os_type="$(uname -s)"
local kp_wheel=""
if [ "$os_type" = "Darwin" ]; then
# macOS wheels are stored in scripts/macos/ subdirectory
kp_wheel="$(ls "$scripts_dir"/macos/KneronPLUS*.whl 2>/dev/null | head -1)"
fi
if [ -z "$kp_wheel" ]; then
kp_wheel="$(ls "$scripts_dir"/KneronPLUS*.whl 2>/dev/null | head -1)"
fi
if [ -n "$kp_wheel" ]; then
info "Installing Kneron SDK: $(basename "$kp_wheel") ..."
"$VENV_DIR/bin/pip" install --quiet "$kp_wheel" || true
# On macOS, ad-hoc codesign bundled dylibs for Gatekeeper
if [ "$os_type" = "Darwin" ]; then
find "$VENV_DIR" -path "*/kp/lib/*.dylib" -exec codesign --force --sign - {} \; 2>/dev/null || true
fi
fi
info "Python environment ready"
}
@ -141,6 +165,22 @@ setup_libusb() {
info "Installing libusb ..."
sudo apt-get install -y libusb-1.0-0-dev
fi
# Install udev rules so non-root users can access Kneron USB devices
if [ ! -f /etc/udev/rules.d/99-kneron.rules ]; then
info "Installing Kneron USB udev rules ..."
cat <<'UDEV' | sudo tee /etc/udev/rules.d/99-kneron.rules >/dev/null
# Kneron KL520
SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0100", MODE="0666"
# Kneron KL720 KDP (legacy)
SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0200", MODE="0666"
# Kneron KL720 KDP2
SUBSYSTEM=="usb", ATTR{idVendor}=="3231", ATTR{idProduct}=="0720", MODE="0666"
UDEV
sudo udevadm control --reload-rules
sudo udevadm trigger
info "udev rules installed. Please re-plug Kneron USB devices."
fi
fi
}
@ -186,6 +226,12 @@ setup_launchd_service() {
<string>${INSTALL_DIR}/edge-ai-server</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>WorkingDirectory</key>
<string>${INSTALL_DIR}</string>