From f744e8ca261befcc5cdee3102c86536b4f760b41 Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Mon, 9 Mar 2026 21:58:45 +0800 Subject: [PATCH] feat: auto-install WinUSB driver for Kneron devices on Windows Bundle WinUSB driver INF + co-installer DLLs in installer payload. During USB driver setup step, extract driver files and run pnputil to install the WinUSB driver for all Kneron devices (KL520 VID_3231&PID_0100, KL720 VID_3231&PID_0200, KL720v2 VID_3231&PID_0720). This eliminates the need for manual Zadig installation, which was the root cause of KP_ERROR_CONNECT_FAILED_28 on Windows. Co-Authored-By: Claude Opus 4.6 --- .gitea/workflows/build-installer.yaml | 4 + .github/workflows/build-installer.yaml | 4 + edge-ai-platform/Makefile | 8 ++ .../installer/platform_windows.go | 65 ++++++++------- edge-ai-platform/scripts/build-installer.ps1 | 12 +++ .../server/scripts/drivers/kneron_winusb.inf | 82 +++++++++++++++++++ 6 files changed, 146 insertions(+), 29 deletions(-) create mode 100644 edge-ai-platform/server/scripts/drivers/kneron_winusb.inf diff --git a/.gitea/workflows/build-installer.yaml b/.gitea/workflows/build-installer.yaml index 97b9b19..2edbb56 100644 --- a/.gitea/workflows/build-installer.yaml +++ b/.gitea/workflows/build-installer.yaml @@ -117,6 +117,10 @@ jobs: Copy-Item "local_service_win\third_party\Kneron_DFUT\bin\libusb-1.0.dll" "$base\installer\payload\scripts\" $kpWheel = Get-ChildItem "local_service_win" -Filter "KneronPLUS*.whl" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($kpWheel) { Copy-Item $kpWheel.FullName "$base\installer\payload\scripts\" } + New-Item -ItemType Directory -Force -Path "$base\installer\payload\drivers\amd64" + Copy-Item "$base\server\scripts\drivers\kneron_winusb.inf" "$base\installer\payload\drivers\" + Copy-Item "local_service_win\LocalAPI\win_driver\amd64\WdfCoInstaller01011.dll" "$base\installer\payload\drivers\amd64\" + Copy-Item "local_service_win\LocalAPI\win_driver\amd64\winusbcoinstaller2.dll" "$base\installer\payload\drivers\amd64\" - name: Build Windows installer run: | diff --git a/.github/workflows/build-installer.yaml b/.github/workflows/build-installer.yaml index 97b9b19..2edbb56 100644 --- a/.github/workflows/build-installer.yaml +++ b/.github/workflows/build-installer.yaml @@ -117,6 +117,10 @@ jobs: Copy-Item "local_service_win\third_party\Kneron_DFUT\bin\libusb-1.0.dll" "$base\installer\payload\scripts\" $kpWheel = Get-ChildItem "local_service_win" -Filter "KneronPLUS*.whl" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($kpWheel) { Copy-Item $kpWheel.FullName "$base\installer\payload\scripts\" } + New-Item -ItemType Directory -Force -Path "$base\installer\payload\drivers\amd64" + Copy-Item "$base\server\scripts\drivers\kneron_winusb.inf" "$base\installer\payload\drivers\" + Copy-Item "local_service_win\LocalAPI\win_driver\amd64\WdfCoInstaller01011.dll" "$base\installer\payload\drivers\amd64\" + Copy-Item "local_service_win\LocalAPI\win_driver\amd64\winusbcoinstaller2.dll" "$base\installer\payload\drivers\amd64\" - name: Build Windows installer run: | diff --git a/edge-ai-platform/Makefile b/edge-ai-platform/Makefile index c2f60f6..9b8cde3 100644 --- a/edge-ai-platform/Makefile +++ b/edge-ai-platform/Makefile @@ -135,6 +135,14 @@ installer-payload: build-server-tray ## Stage payload files for GUI installer cp ../local_service_win/KneronPLUS*.whl installer/payload/scripts/; \ echo " KneronPLUS wheel bundled."; \ fi + @# Copy WinUSB driver files (for Windows installer) + @mkdir -p installer/payload/drivers/amd64 + cp server/scripts/drivers/kneron_winusb.inf installer/payload/drivers/ + @if [ -d "../local_service_win/LocalAPI/win_driver/amd64" ]; then \ + cp ../local_service_win/LocalAPI/win_driver/amd64/WdfCoInstaller01011.dll installer/payload/drivers/amd64/; \ + cp ../local_service_win/LocalAPI/win_driver/amd64/winusbcoinstaller2.dll installer/payload/drivers/amd64/; \ + echo " WinUSB driver files bundled."; \ + fi @echo "Payload staged in installer/payload/" installer: installer-payload ## Build GUI installer app diff --git a/edge-ai-platform/installer/platform_windows.go b/edge-ai-platform/installer/platform_windows.go index e59194b..7e16705 100644 --- a/edge-ai-platform/installer/platform_windows.go +++ b/edge-ai-platform/installer/platform_windows.go @@ -71,43 +71,50 @@ func removeSystemLink() { } func installLibusb(installDir string) error { - // Check if already present in system or install directory - checkPaths := []string{ - filepath.Join(os.Getenv("SystemRoot"), "System32", "libusb-1.0.dll"), - filepath.Join(os.Getenv("SystemRoot"), "SysWOW64", "libusb-1.0.dll"), - filepath.Join(installDir, "libusb-1.0.dll"), - } - for _, p := range checkPaths { - if _, err := os.Stat(p); err == nil { - return nil // already installed - } - } - - // Try to extract libusb-1.0.dll from payload to install directory - // The DLL is bundled at payload/scripts/libusb-1.0.dll + // 1. Extract libusb-1.0.dll from payload dllDest := filepath.Join(installDir, "libusb-1.0.dll") - data, err := payloadFS.ReadFile("payload/scripts/libusb-1.0.dll") - if err == nil { - if writeErr := os.WriteFile(dllDest, data, 0644); writeErr == nil { - return nil // successfully extracted + if _, err := os.Stat(dllDest); os.IsNotExist(err) { + data, readErr := payloadFS.ReadFile("payload/scripts/libusb-1.0.dll") + if readErr == nil { + os.WriteFile(dllDest, data, 0644) } } - // Fallback: try winget - if wingetPath, err := exec.LookPath("winget"); err == nil { - cmd := exec.Command(wingetPath, "install", "libusb", - "--accept-source-agreements", "--accept-package-agreements", "--silent") - cmd.Run() // best effort + // 2. Extract and install WinUSB driver for Kneron devices + installWinUSBDriver(installDir) - // Re-check - for _, p := range checkPaths { - if _, err := os.Stat(p); err == nil { - return nil - } + return nil +} + +// installWinUSBDriver extracts the WinUSB driver package from the payload +// and installs it via pnputil so libusb can access Kneron USB devices. +func installWinUSBDriver(installDir string) { + driverDir := filepath.Join(installDir, "drivers") + os.MkdirAll(filepath.Join(driverDir, "amd64"), 0755) + + // Extract driver files from embedded payload + driverFiles := map[string]string{ + "payload/drivers/kneron_winusb.inf": filepath.Join(driverDir, "kneron_winusb.inf"), + "payload/drivers/amd64/WdfCoInstaller01011.dll": filepath.Join(driverDir, "amd64", "WdfCoInstaller01011.dll"), + "payload/drivers/amd64/winusbcoinstaller2.dll": filepath.Join(driverDir, "amd64", "winusbcoinstaller2.dll"), + } + + for src, dst := range driverFiles { + data, err := payloadFS.ReadFile(src) + if err != nil { + return // driver files not bundled, skip silently + } + if err := os.WriteFile(dst, data, 0644); err != nil { + return } } - return fmt.Errorf("libusb not found. For Kneron USB device support, install the WinUSB driver via Zadig: https://zadig.akeo.ie") + infPath := filepath.Join(driverDir, "kneron_winusb.inf") + + // Use pnputil to add driver to the driver store and install on matching devices. + // This requires admin privileges; pnputil will trigger a UAC prompt if needed. + cmd := exec.Command("pnputil", "/add-driver", infPath, "/install") + cmd.CombinedOutput() // best effort — non-fatal if it fails } func checkLibusbInstalled() bool { diff --git a/edge-ai-platform/scripts/build-installer.ps1 b/edge-ai-platform/scripts/build-installer.ps1 index 0754910..418a024 100644 --- a/edge-ai-platform/scripts/build-installer.ps1 +++ b/edge-ai-platform/scripts/build-installer.ps1 @@ -94,6 +94,18 @@ if ($kpWheel) { Write-Host " KneronPLUS wheel not found, skipping." -ForegroundColor Yellow } +# Copy WinUSB driver files +New-Item -ItemType Directory -Force -Path installer\payload\drivers\amd64 | Out-Null +Copy-Item server\scripts\drivers\kneron_winusb.inf installer\payload\drivers\ +$winDriverDir = Join-Path $repoRoot "local_service_win\LocalAPI\win_driver\amd64" +if (Test-Path $winDriverDir) { + Copy-Item (Join-Path $winDriverDir "WdfCoInstaller01011.dll") installer\payload\drivers\amd64\ + Copy-Item (Join-Path $winDriverDir "winusbcoinstaller2.dll") installer\payload\drivers\amd64\ + Write-Host " WinUSB driver files bundled." -ForegroundColor Green +} else { + Write-Host " WinUSB co-installer DLLs not found, skipping." -ForegroundColor Yellow +} + $fileCount = (Get-ChildItem -Recurse installer\payload -File).Count Write-Host " Payload staged: $fileCount files." -ForegroundColor Green Write-Host "" diff --git a/edge-ai-platform/server/scripts/drivers/kneron_winusb.inf b/edge-ai-platform/server/scripts/drivers/kneron_winusb.inf new file mode 100644 index 0000000..17fd05a --- /dev/null +++ b/edge-ai-platform/server/scripts/drivers/kneron_winusb.inf @@ -0,0 +1,82 @@ +; kneron_winusb.inf +; WinUSB driver for Kneron KL520 and KL720 USB AI accelerators +; Supports: KL520 (PID 0x0100), KL720 KDP legacy (PID 0x0200), KL720 KDP2 (PID 0x0720) + +[Strings] +DeviceName520 = "Kneron KL520" +DeviceName720 = "Kneron KL720" +DeviceName720v2 = "Kneron KL720 v2" +VendorName = "Kneron Inc." +SourceName = "Kneron WinUSB Install Disk" +DeviceGUID = "{A897B340-F751-4FEE-8DAD-40EC8BC77200}" + +[Version] +Signature = "$Windows NT$" +Class = "USBDevice" +ClassGuid = {88bae032-5a81-49f0-bc3d-a4ff138216d6} +Provider = %VendorName% +CatalogFile = kneron_winusb.cat +DriverVer = 03/09/2026, 6.1.7600.16385 + +[ClassInstall32] +Addreg = WinUSBDeviceClassReg + +[WinUSBDeviceClassReg] +HKR,,,0,"Universal Serial Bus devices" +HKR,,Icon,,-20 + +[Manufacturer] +%VendorName% = KneronDevices,NTamd64 + +[KneronDevices.NTamd64] +%DeviceName520% = USB_Install, USB\VID_3231&PID_0100 +%DeviceName720% = USB_Install, USB\VID_3231&PID_0200 +%DeviceName720v2% = USB_Install, USB\VID_3231&PID_0720 + +[USB_Install] +Include = winusb.inf +Needs = WINUSB.NT + +[USB_Install.Services] +Include = winusb.inf +AddService = WinUSB,0x00000002,WinUSB_ServiceInstall + +[WinUSB_ServiceInstall] +DisplayName = "WinUSB - Kneron USB Device" +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WinUSB.sys + +[USB_Install.Wdf] +KmdfService = WINUSB, WinUsb_Install + +[WinUSB_Install] +KmdfLibraryVersion = 1.11 + +[USB_Install.HW] +AddReg = AddDeviceInterfaceGUID + +[AddDeviceInterfaceGUID] +HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID% + +[USB_Install.CoInstallers] +AddReg = CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUSBCoInstaller2.dll" + +[CoInstallers_CopyFiles] +WinUSBCoInstaller2.dll +WdfCoInstaller01011.dll + +[DestinationDirs] +CoInstallers_CopyFiles = 11 + +[SourceDisksNames] +1 = %SourceName% + +[SourceDisksFiles.amd64] +WinUSBCoInstaller2.dll = 1,amd64 +WdfCoInstaller01011.dll = 1,amd64