diff --git a/edge-ai-platform/tools/test_driver_install/main.go b/edge-ai-platform/tools/test_driver_install/main.go index 79bb6d5..6b788d8 100644 --- a/edge-ai-platform/tools/test_driver_install/main.go +++ b/edge-ai-platform/tools/test_driver_install/main.go @@ -12,6 +12,66 @@ import ( "unsafe" ) +var ( + setupapi = syscall.MustLoadDLL("setupapi.dll") + newdev = syscall.MustLoadDLL("newdev.dll") + + 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") + procSetupDiDestroyDevInfoList = setupapi.MustFindProc("SetupDiDestroyDeviceInfoList") + procSetupDiBuildDriverInfoList = setupapi.MustFindProc("SetupDiBuildDriverInfoList") + + procUpdateDriverForPlugAndPlayDevicesW = newdev.MustFindProc("UpdateDriverForPlugAndPlayDevicesW") + procDiInstallDriverW = newdev.MustFindProc("DiInstallDriverW") +) + +const ( + DIGCF_PRESENT = 0x00000002 + DIGCF_ALLCLASSES = 0x00000004 + + SPDRP_HARDWAREID = 0x00000001 + + DIF_SELECTBESTCOMPATDRV = 0x00000017 + DIF_INSTALLDEVICE = 0x00000002 + + DI_FLAGSEX_ALLOWEXCLUDEDDRVS = 0x00000800 + DI_ENUMSINGLEINF = 0x00010000 + DI_DONOTCALLCONFIGMG = 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 + DevInst uint32 + 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 +} + func main() { if len(os.Args) < 2 { fmt.Println("Usage: test_driver_install.exe ") @@ -26,7 +86,6 @@ func main() { os.Exit(1) } - // Hardware ID for Kneron KL520 hardwareID := "USB\\VID_3231&PID_0100" fmt.Println("") @@ -36,34 +95,23 @@ func main() { fmt.Println("") fmt.Println("=== Method 2: DiInstallDriverW ===") tryDiInstallDriver(infPath) + + fmt.Println("") + fmt.Println("=== Method 3: SetupAPI direct device node install ===") + trySetupAPIInstall(infPath, hardwareID) } func tryUpdateDriver(infPath, hardwareID string) { - newdev, err := syscall.LoadDLL("newdev.dll") - if err != nil { - fmt.Printf("ERROR: LoadDLL: %v\n", err) - return - } - defer newdev.Release() - - proc, err := newdev.FindProc("UpdateDriverForPlugAndPlayDevicesW") - if err != nil { - fmt.Printf("ERROR: FindProc: %v\n", err) - return - } - infUTF16, _ := syscall.UTF16PtrFromString(infPath) hwIDUTF16, _ := syscall.UTF16PtrFromString(hardwareID) - const INSTALLFLAG_FORCE = 0x00000001 var needReboot int32 fmt.Printf("Hardware ID: %s\n", hardwareID) fmt.Println("Calling UpdateDriverForPlugAndPlayDevicesW...") - fmt.Println("(If a Windows Security dialog appears, click 'Install this driver software anyway')") - ret, _, lastErr := proc.Call( - 0, // hwndParent = NULL + ret, _, lastErr := procUpdateDriverForPlugAndPlayDevicesW.Call( + 0, uintptr(unsafe.Pointer(hwIDUTF16)), uintptr(unsafe.Pointer(infUTF16)), INSTALLFLAG_FORCE, @@ -71,51 +119,176 @@ func tryUpdateDriver(infPath, hardwareID string) { ) fmt.Printf("Return value: %d\n", ret) - fmt.Printf("NeedReboot: %d\n", needReboot) - if ret == 0 { errno := lastErr.(syscall.Errno) fmt.Printf("FAILED - error: %v (code: %d / 0x%08X)\n", lastErr, uint32(errno), uint32(errno)) } else { - fmt.Println("SUCCESS - driver installed!") + fmt.Println("SUCCESS!") } } func tryDiInstallDriver(infPath string) { - newdev, err := syscall.LoadDLL("newdev.dll") - if err != nil { - fmt.Printf("ERROR: LoadDLL: %v\n", err) - return - } - defer newdev.Release() - - proc, err := newdev.FindProc("DiInstallDriverW") - if err != nil { - fmt.Printf("ERROR: FindProc: %v\n", err) - return - } - infUTF16, _ := syscall.UTF16PtrFromString(infPath) - - const DIIRFLAG_FORCE_INF = 0x00000002 var needReboot int32 - fmt.Println("Calling DiInstallDriverW (DIIRFLAG_FORCE_INF)...") + fmt.Println("Calling DiInstallDriverW...") - ret, _, lastErr := proc.Call( - 0, // hwndParent = NULL + ret, _, lastErr := procDiInstallDriverW.Call( + 0, uintptr(unsafe.Pointer(infUTF16)), DIIRFLAG_FORCE_INF, uintptr(unsafe.Pointer(&needReboot)), ) fmt.Printf("Return value: %d\n", ret) - fmt.Printf("NeedReboot: %d\n", needReboot) - if ret == 0 { errno := lastErr.(syscall.Errno) fmt.Printf("FAILED - error: %v (code: %d / 0x%08X)\n", lastErr, uint32(errno), uint32(errno)) } else { - fmt.Println("SUCCESS - driver installed!") + fmt.Println("SUCCESS!") + } +} + +func trySetupAPIInstall(infPath, targetHWID string) { + fmt.Println("Enumerating all present USB devices...") + + // Get all present devices + hDevInfo, _, err := procSetupDiGetClassDevsW.Call( + 0, // NULL = all classes + 0, // no enumerator + 0, // no hwnd + DIGCF_PRESENT|DIGCF_ALLCLASSES, + ) + if hDevInfo == INVALID_HANDLE_VALUE { + fmt.Printf("ERROR: SetupDiGetClassDevsW failed: %v\n", err) + return + } + defer procSetupDiDestroyDevInfoList.Call(hDevInfo) + + var devInfoData SP_DEVINFO_DATA + devInfoData.cbSize = uint32(unsafe.Sizeof(devInfoData)) + + found := false + for i := uint32(0); ; i++ { + ret, _, _ := procSetupDiEnumDeviceInfo.Call( + hDevInfo, + uintptr(i), + uintptr(unsafe.Pointer(&devInfoData)), + ) + if ret == 0 { + break + } + + // Get hardware ID + var buf [1024]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 + } + + // 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 + } + } + + 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!") } } 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 3c3af70..e513ed3 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