diff --git a/edge-ai-platform/tools/test_driver_install/main.go b/edge-ai-platform/tools/test_driver_install/main.go index 6b788d8..f81e3c5 100644 --- a/edge-ai-platform/tools/test_driver_install/main.go +++ b/edge-ai-platform/tools/test_driver_install/main.go @@ -8,6 +8,7 @@ package main import ( "fmt" "os" + "strings" "syscall" "unsafe" ) @@ -19,7 +20,6 @@ var ( procSetupDiGetClassDevsW = setupapi.MustFindProc("SetupDiGetClassDevsW") procSetupDiEnumDeviceInfo = setupapi.MustFindProc("SetupDiEnumDeviceInfo") procSetupDiGetDeviceRegistryPropW = setupapi.MustFindProc("SetupDiGetDeviceRegistryPropertyW") - procSetupDiSetDeviceRegistryPropW = setupapi.MustFindProc("SetupDiSetDeviceRegistryPropertyW") procSetupDiSetDevInstallParamsW = setupapi.MustFindProc("SetupDiSetDeviceInstallParamsW") procSetupDiGetDevInstallParamsW = setupapi.MustFindProc("SetupDiGetDeviceInstallParamsW") procSetupDiCallClassInstaller = setupapi.MustFindProc("SetupDiCallClassInstaller") @@ -34,23 +34,23 @@ const ( DIGCF_PRESENT = 0x00000002 DIGCF_ALLCLASSES = 0x00000004 - SPDRP_HARDWAREID = 0x00000001 + SPDRP_HARDWAREID = 0x00000001 + SPDRP_COMPATIBLEIDS = 0x00000002 + SPDRP_DEVICEDESC = 0x00000000 DIF_SELECTBESTCOMPATDRV = 0x00000017 - DIF_INSTALLDEVICE = 0x00000002 + DIF_INSTALLDEVICE = 0x00000002 DI_FLAGSEX_ALLOWEXCLUDEDDRVS = 0x00000800 DI_ENUMSINGLEINF = 0x00010000 - DI_DONOTCALLCONFIGMG = 0x00000002 - INSTALLFLAG_FORCE = 0x00000001 - DIIRFLAG_FORCE_INF = 0x00000002 - SPDIT_COMPATDRIVER = 0x00000002 + INSTALLFLAG_FORCE = 0x00000001 + DIIRFLAG_FORCE_INF = 0x00000002 + SPDIT_COMPATDRIVER = 0x00000002 INVALID_HANDLE_VALUE = ^uintptr(0) ) -// SP_DEVINFO_DATA type SP_DEVINFO_DATA struct { cbSize uint32 ClassGuid [16]byte @@ -58,26 +58,52 @@ type SP_DEVINFO_DATA struct { Reserved uintptr } -// SP_DEVINSTALL_PARAMS_W (size depends on arch: 584 bytes on amd64) type SP_DEVINSTALL_PARAMS_W struct { - cbSize uint32 - Flags uint32 - FlagsEx uint32 - hwndParent uintptr - InstallMsgHandler uintptr - InstallMsgHandlerContext uintptr - FileQueue uintptr - ClassInstallReserved uintptr - Reserved uint32 - DriverPath [260]uint16 + cbSize uint32 + Flags uint32 + FlagsEx uint32 + hwndParent uintptr + InstallMsgHandler uintptr + InstallMsgHandlerContext uintptr + FileQueue uintptr + ClassInstallReserved uintptr + Reserved uint32 + DriverPath [260]uint16 +} + +// multiSzToStrings parses a REG_MULTI_SZ buffer into individual strings +func multiSzToStrings(buf []uint16, size uint32) []string { + var result []string + count := size / 2 // byte count to uint16 count + if count == 0 { + return result + } + start := 0 + for i := 0; i < int(count); i++ { + if buf[i] == 0 { + if i > start { + result = append(result, syscall.UTF16ToString(buf[start:i])) + } + start = i + 1 + } + } + return result } func main() { if len(os.Args) < 2 { fmt.Println("Usage: test_driver_install.exe ") + fmt.Println(" test_driver_install.exe --list") os.Exit(1) } + targetHWID := "USB\\VID_3231&PID_0100" + + if os.Args[1] == "--list" { + listAllDevices(targetHWID) + return + } + infPath := os.Args[1] fmt.Printf("INF path: %s\n", infPath) @@ -86,25 +112,116 @@ func main() { os.Exit(1) } - hardwareID := "USB\\VID_3231&PID_0100" + fmt.Println("") + fmt.Println("=== Step 1: List USB devices matching VID_3231 ===") + listAllDevices(targetHWID) fmt.Println("") - fmt.Println("=== Method 1: UpdateDriverForPlugAndPlayDevicesW ===") - tryUpdateDriver(infPath, hardwareID) + fmt.Println("=== Step 2: UpdateDriverForPlugAndPlayDevicesW ===") + tryUpdateDriver(infPath, targetHWID) fmt.Println("") - fmt.Println("=== Method 2: DiInstallDriverW ===") + fmt.Println("=== Step 3: DiInstallDriverW ===") tryDiInstallDriver(infPath) fmt.Println("") - fmt.Println("=== Method 3: SetupAPI direct device node install ===") - trySetupAPIInstall(infPath, hardwareID) + fmt.Println("=== Step 4: SetupAPI direct device node install ===") + trySetupAPIInstall(infPath, targetHWID) +} + +func listAllDevices(targetHWID string) { + hDevInfo, _, err := procSetupDiGetClassDevsW.Call( + 0, 0, 0, + DIGCF_PRESENT|DIGCF_ALLCLASSES, + ) + if hDevInfo == INVALID_HANDLE_VALUE { + fmt.Printf("ERROR: SetupDiGetClassDevsW: %v\n", err) + return + } + defer procSetupDiDestroyDevInfoList.Call(hDevInfo) + + var devInfoData SP_DEVINFO_DATA + devInfoData.cbSize = uint32(unsafe.Sizeof(devInfoData)) + + total := 0 + matched := 0 + for i := uint32(0); ; i++ { + ret, _, _ := procSetupDiEnumDeviceInfo.Call( + hDevInfo, uintptr(i), + uintptr(unsafe.Pointer(&devInfoData)), + ) + if ret == 0 { + break + } + total++ + + // Get hardware IDs (REG_MULTI_SZ) + var buf [2048]uint16 + var dataType, reqSize uint32 + ret, _, _ = procSetupDiGetDeviceRegistryPropW.Call( + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + SPDRP_HARDWAREID, + uintptr(unsafe.Pointer(&dataType)), + uintptr(unsafe.Pointer(&buf[0])), + uintptr(len(buf)*2), + uintptr(unsafe.Pointer(&reqSize)), + ) + if ret == 0 { + continue + } + + hwids := multiSzToStrings(buf[:], reqSize) + + // Check if any HWID contains "VID_3231" or matches target + isKneron := false + for _, id := range hwids { + upper := strings.ToUpper(id) + if strings.Contains(upper, "VID_3231") { + isKneron = true + break + } + } + if !isKneron { + continue + } + + matched++ + + // Get device description + var descBuf [512]uint16 + ret, _, _ = procSetupDiGetDeviceRegistryPropW.Call( + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + SPDRP_DEVICEDESC, + uintptr(unsafe.Pointer(&dataType)), + uintptr(unsafe.Pointer(&descBuf[0])), + uintptr(len(descBuf)*2), + uintptr(unsafe.Pointer(&reqSize)), + ) + desc := "(no description)" + if ret != 0 { + desc = syscall.UTF16ToString(descBuf[:]) + } + + fmt.Printf("\n Device #%d (DevInst: %d)\n", matched, devInfoData.DevInst) + fmt.Printf(" Description: %s\n", desc) + fmt.Printf(" Hardware IDs:\n") + for _, id := range hwids { + match := "" + if strings.EqualFold(id, targetHWID) { + match = " <== MATCH" + } + fmt.Printf(" - %s%s\n", id, match) + } + } + + fmt.Printf("\nTotal devices enumerated: %d, Kneron devices found: %d\n", total, matched) } func tryUpdateDriver(infPath, hardwareID string) { infUTF16, _ := syscall.UTF16PtrFromString(infPath) hwIDUTF16, _ := syscall.UTF16PtrFromString(hardwareID) - var needReboot int32 fmt.Printf("Hardware ID: %s\n", hardwareID) @@ -132,7 +249,6 @@ func tryDiInstallDriver(infPath string) { var needReboot int32 fmt.Println("Calling DiInstallDriverW...") - ret, _, lastErr := procDiInstallDriverW.Call( 0, uintptr(unsafe.Pointer(infUTF16)), @@ -150,17 +266,14 @@ func tryDiInstallDriver(infPath string) { } func trySetupAPIInstall(infPath, targetHWID string) { - fmt.Println("Enumerating all present USB devices...") + fmt.Println("Enumerating present USB devices...") - // Get all present devices hDevInfo, _, err := procSetupDiGetClassDevsW.Call( - 0, // NULL = all classes - 0, // no enumerator - 0, // no hwnd + 0, 0, 0, DIGCF_PRESENT|DIGCF_ALLCLASSES, ) if hDevInfo == INVALID_HANDLE_VALUE { - fmt.Printf("ERROR: SetupDiGetClassDevsW failed: %v\n", err) + fmt.Printf("ERROR: SetupDiGetClassDevsW: %v\n", err) return } defer procSetupDiDestroyDevInfoList.Call(hDevInfo) @@ -171,16 +284,14 @@ func trySetupAPIInstall(infPath, targetHWID string) { found := false for i := uint32(0); ; i++ { ret, _, _ := procSetupDiEnumDeviceInfo.Call( - hDevInfo, - uintptr(i), + hDevInfo, uintptr(i), uintptr(unsafe.Pointer(&devInfoData)), ) if ret == 0 { break } - // Get hardware ID - var buf [1024]uint16 + var buf [2048]uint16 var dataType, reqSize uint32 ret, _, _ = procSetupDiGetDeviceRegistryPropW.Call( hDevInfo, @@ -195,100 +306,99 @@ func trySetupAPIInstall(infPath, targetHWID string) { continue } - // MULTI_SZ: check each string - hwid := syscall.UTF16ToString(buf[:]) - if hwid == targetHWID { - fmt.Printf("FOUND device: %s (DevInst: %d)\n", hwid, devInfoData.DevInst) - found = true - - // Now try to install driver on this specific device - installOnDevice(hDevInfo, &devInfoData, infPath) - break + hwids := multiSzToStrings(buf[:], reqSize) + matchFound := false + for _, id := range hwids { + if strings.EqualFold(id, targetHWID) { + matchFound = true + break + } } + if !matchFound { + continue + } + + fmt.Printf("FOUND target device (DevInst: %d)\n", devInfoData.DevInst) + found = true + + // Set install params: use our specific INF + var installParams SP_DEVINSTALL_PARAMS_W + installParams.cbSize = uint32(unsafe.Sizeof(installParams)) + + ret, _, err = procSetupDiGetDevInstallParamsW.Call( + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + uintptr(unsafe.Pointer(&installParams)), + ) + if ret == 0 { + fmt.Printf("ERROR: GetDeviceInstallParams: %v\n", err) + return + } + + fmt.Printf("Current Flags: 0x%08X, FlagsEx: 0x%08X\n", installParams.Flags, installParams.FlagsEx) + + infUTF16, _ := syscall.UTF16FromString(infPath) + copy(installParams.DriverPath[:], infUTF16) + installParams.Flags |= DI_ENUMSINGLEINF + installParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS + + ret, _, err = procSetupDiSetDevInstallParamsW.Call( + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + uintptr(unsafe.Pointer(&installParams)), + ) + if ret == 0 { + fmt.Printf("ERROR: SetDeviceInstallParams: %v\n", err) + return + } + fmt.Println("Install params set OK") + + // Build compatible driver list + fmt.Println("Building driver info list...") + ret, _, err = procSetupDiBuildDriverInfoList.Call( + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + SPDIT_COMPATDRIVER, + ) + if ret == 0 { + errno := err.(syscall.Errno) + fmt.Printf("ERROR: BuildDriverInfoList: %v (0x%08X)\n", err, uint32(errno)) + return + } + fmt.Println("Driver info list built OK") + + // Select best compatible driver + fmt.Println("Selecting best compatible driver...") + ret, _, err = procSetupDiCallClassInstaller.Call( + DIF_SELECTBESTCOMPATDRV, + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + ) + if ret == 0 { + errno := err.(syscall.Errno) + fmt.Printf("ERROR: DIF_SELECTBESTCOMPATDRV: %v (0x%08X)\n", err, uint32(errno)) + return + } + fmt.Println("Best driver selected OK") + + // Install device + fmt.Println("Installing driver on device...") + fmt.Println("(Windows Security dialog may appear)") + ret, _, err = procSetupDiCallClassInstaller.Call( + DIF_INSTALLDEVICE, + hDevInfo, + uintptr(unsafe.Pointer(&devInfoData)), + ) + if ret == 0 { + errno := err.(syscall.Errno) + fmt.Printf("ERROR: DIF_INSTALLDEVICE: %v (0x%08X)\n", err, uint32(errno)) + } else { + fmt.Println("SUCCESS - driver installed!") + } + break } if !found { - fmt.Printf("Device with Hardware ID '%s' not found among present devices.\n", targetHWID) - } -} - -func installOnDevice(hDevInfo uintptr, devInfoData *SP_DEVINFO_DATA, infPath string) { - fmt.Println("Setting up driver install params...") - - // Get current install params - var installParams SP_DEVINSTALL_PARAMS_W - installParams.cbSize = uint32(unsafe.Sizeof(installParams)) - - ret, _, err := procSetupDiGetDevInstallParamsW.Call( - hDevInfo, - uintptr(unsafe.Pointer(devInfoData)), - uintptr(unsafe.Pointer(&installParams)), - ) - if ret == 0 { - fmt.Printf("ERROR: GetDeviceInstallParams failed: %v\n", err) - return - } - - fmt.Printf("Current Flags: 0x%08X, FlagsEx: 0x%08X\n", installParams.Flags, installParams.FlagsEx) - - // Set DriverPath to our INF and enable DI_ENUMSINGLEINF - infUTF16, _ := syscall.UTF16FromString(infPath) - copy(installParams.DriverPath[:], infUTF16) - installParams.Flags |= DI_ENUMSINGLEINF - installParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS - - ret, _, err = procSetupDiSetDevInstallParamsW.Call( - hDevInfo, - uintptr(unsafe.Pointer(devInfoData)), - uintptr(unsafe.Pointer(&installParams)), - ) - if ret == 0 { - fmt.Printf("ERROR: SetDeviceInstallParams failed: %v\n", err) - return - } - fmt.Println("Install params set (DI_ENUMSINGLEINF, DriverPath set)") - - // Build driver info list from our specific INF - fmt.Println("Building driver info list from INF...") - ret, _, err = procSetupDiBuildDriverInfoList.Call( - hDevInfo, - uintptr(unsafe.Pointer(devInfoData)), - SPDIT_COMPATDRIVER, - ) - if ret == 0 { - errno := err.(syscall.Errno) - fmt.Printf("ERROR: BuildDriverInfoList failed: %v (code: 0x%08X)\n", err, uint32(errno)) - return - } - fmt.Println("Driver info list built.") - - // Select best compatible driver - fmt.Println("Selecting best compatible driver...") - ret, _, err = procSetupDiCallClassInstaller.Call( - DIF_SELECTBESTCOMPATDRV, - hDevInfo, - uintptr(unsafe.Pointer(devInfoData)), - ) - if ret == 0 { - errno := err.(syscall.Errno) - fmt.Printf("ERROR: DIF_SELECTBESTCOMPATDRV failed: %v (code: 0x%08X)\n", err, uint32(errno)) - fmt.Println(" (This might mean the INF is not compatible or catalog issue)") - return - } - fmt.Println("Best compatible driver selected.") - - // Install the device - fmt.Println("Installing device with selected driver...") - fmt.Println("(If a Windows Security dialog appears, click 'Install this driver software anyway')") - ret, _, err = procSetupDiCallClassInstaller.Call( - DIF_INSTALLDEVICE, - hDevInfo, - uintptr(unsafe.Pointer(devInfoData)), - ) - if ret == 0 { - errno := err.(syscall.Errno) - fmt.Printf("ERROR: DIF_INSTALLDEVICE failed: %v (code: 0x%08X)\n", err, uint32(errno)) - } else { - fmt.Println("SUCCESS - driver installed on device!") + fmt.Println("Target device NOT found among present devices") } } diff --git a/edge-ai-platform/tools/test_driver_install/test_driver_install.exe b/edge-ai-platform/tools/test_driver_install/test_driver_install.exe index e513ed3..af002f5 100755 Binary files a/edge-ai-platform/tools/test_driver_install/test_driver_install.exe and b/edge-ai-platform/tools/test_driver_install/test_driver_install.exe differ