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 <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-03-09 21:58:45 +08:00
parent 49bdef68c7
commit f744e8ca26
6 changed files with 146 additions and 29 deletions

View File

@ -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: |

View File

@ -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: |

View File

@ -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

View File

@ -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 {

View File

@ -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 ""

View File

@ -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