Add self-signed cert + catalog approach for driver installation
New flow: PowerShell New-SelfSignedCertificate → install to TrustedPublisher/Root stores → create .cat via inf2cat/makecat/ New-FileCatalog → sign with signtool/Set-AuthenticodeSignature → pnputil /install. Falls back to SetupAPI DIF_INSTALLDEVICE. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c9b0ae5b89
commit
9ec1926133
@ -1,13 +1,15 @@
|
||||
// Test tool for Windows USB driver installation.
|
||||
// Build: GOOS=windows GOARCH=amd64 go build -o test_driver_install.exe .
|
||||
// Run on Windows (as admin):
|
||||
// .\test_driver_install.exe "C:\Users\User\AppData\Local\EdgeAIPlatform\drivers\kneron_winusb.inf"
|
||||
// .\test_driver_install.exe "C:\Users\User\AppData\Local\EdgeAIPlatform\drivers"
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@ -15,7 +17,6 @@ import (
|
||||
|
||||
var (
|
||||
setupapi = syscall.MustLoadDLL("setupapi.dll")
|
||||
newdev = syscall.MustLoadDLL("newdev.dll")
|
||||
|
||||
procSetupDiGetClassDevsW = setupapi.MustFindProc("SetupDiGetClassDevsW")
|
||||
procSetupDiEnumDeviceInfo = setupapi.MustFindProc("SetupDiEnumDeviceInfo")
|
||||
@ -25,18 +26,14 @@ var (
|
||||
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
|
||||
SPDRP_COMPATIBLEIDS = 0x00000002
|
||||
SPDRP_DEVICEDESC = 0x00000000
|
||||
SPDRP_HARDWAREID = 0x00000001
|
||||
SPDRP_DEVICEDESC = 0x00000000
|
||||
|
||||
DIF_SELECTBESTCOMPATDRV = 0x00000017
|
||||
DIF_INSTALLDEVICE = 0x00000002
|
||||
@ -44,8 +41,6 @@ const (
|
||||
DI_FLAGSEX_ALLOWEXCLUDEDDRVS = 0x00000800
|
||||
DI_ENUMSINGLEINF = 0x00010000
|
||||
|
||||
INSTALLFLAG_FORCE = 0x00000001
|
||||
DIIRFLAG_FORCE_INF = 0x00000002
|
||||
SPDIT_COMPATDRIVER = 0x00000002
|
||||
|
||||
INVALID_HANDLE_VALUE = ^uintptr(0)
|
||||
@ -71,10 +66,9 @@ type SP_DEVINSTALL_PARAMS_W struct {
|
||||
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
|
||||
count := size / 2
|
||||
if count == 0 {
|
||||
return result
|
||||
}
|
||||
@ -92,50 +86,237 @@ func multiSzToStrings(buf []uint16, size uint32) []string {
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("Usage: test_driver_install.exe <path-to-inf>")
|
||||
fmt.Println(" test_driver_install.exe --list")
|
||||
fmt.Println("Usage: test_driver_install.exe <driver-directory>")
|
||||
fmt.Println(" The directory should contain kneron_winusb.inf and amd64\\ co-installers")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
driverDir := os.Args[1]
|
||||
infPath := filepath.Join(driverDir, "kneron_winusb.inf")
|
||||
fmt.Printf("Driver dir: %s\n", driverDir)
|
||||
fmt.Printf("INF path: %s\n", infPath)
|
||||
|
||||
if _, err := os.Stat(infPath); err != nil {
|
||||
fmt.Printf("ERROR: %s not found: %v\n", infPath, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
targetHWID := "USB\\VID_3231&PID_0100"
|
||||
|
||||
if os.Args[1] == "--list" {
|
||||
listAllDevices(targetHWID)
|
||||
return
|
||||
}
|
||||
// Step 1: List devices
|
||||
fmt.Println("\n=== Step 1: List Kneron USB devices ===")
|
||||
listKneronDevices(targetHWID)
|
||||
|
||||
infPath := os.Args[1]
|
||||
fmt.Printf("INF path: %s\n", infPath)
|
||||
// Step 2: Self-sign approach — create cert, create cat, sign, install
|
||||
fmt.Println("\n=== Step 2: Create self-signed cert + catalog, then install ===")
|
||||
certPath := filepath.Join(driverDir, "kneron_selfsign.cer")
|
||||
|
||||
if _, err := os.Stat(infPath); err != nil {
|
||||
fmt.Printf("ERROR: file not found: %v\n", err)
|
||||
// 2a: Create self-signed code signing cert via PowerShell
|
||||
fmt.Println("[2a] Creating self-signed code signing certificate...")
|
||||
thumbprint, err := createSelfSignedCert(certPath)
|
||||
if err != nil {
|
||||
fmt.Printf(" FAILED: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf(" Thumbprint: %s\n", thumbprint)
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Step 1: List USB devices matching VID_3231 ===")
|
||||
listAllDevices(targetHWID)
|
||||
// 2b: Install cert to TrustedPublisher store
|
||||
fmt.Println("[2b] Installing cert to TrustedPublisher + Root stores...")
|
||||
installCertToStore(certPath, "TrustedPublisher")
|
||||
installCertToStore(certPath, "Root")
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Step 2: UpdateDriverForPlugAndPlayDevicesW ===")
|
||||
tryUpdateDriver(infPath, targetHWID)
|
||||
// 2c: Create .cat file using makecat.exe (from system) or manual approach
|
||||
catPath := filepath.Join(driverDir, "kneron_winusb.cat")
|
||||
fmt.Println("[2c] Creating catalog file...")
|
||||
err = createCatalog(driverDir, infPath, catPath)
|
||||
if err != nil {
|
||||
fmt.Printf(" Catalog creation failed: %v\n", err)
|
||||
fmt.Println(" Trying alternative approach without catalog...")
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Step 3: DiInstallDriverW ===")
|
||||
tryDiInstallDriver(infPath)
|
||||
// 2d: Sign the catalog
|
||||
if _, err := os.Stat(catPath); err == nil {
|
||||
fmt.Println("[2d] Signing catalog file...")
|
||||
signCatalog(catPath, thumbprint)
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("=== Step 4: SetupAPI direct device node install ===")
|
||||
trySetupAPIInstall(infPath, targetHWID)
|
||||
// 2e: Try pnputil with signed catalog
|
||||
fmt.Println("[2e] Installing driver with pnputil...")
|
||||
cmd := exec.Command("pnputil", "/add-driver", infPath, "/install")
|
||||
out, err := cmd.CombinedOutput()
|
||||
fmt.Printf(" pnputil: %s\n", strings.TrimSpace(string(out)))
|
||||
if err != nil {
|
||||
fmt.Printf(" pnputil error: %v\n", err)
|
||||
// Fallback: try SetupAPI
|
||||
fmt.Println("\n[2f] Fallback: SetupAPI DIF_INSTALLDEVICE...")
|
||||
trySetupAPIInstall(infPath, targetHWID)
|
||||
} else {
|
||||
fmt.Println(" SUCCESS via pnputil!")
|
||||
}
|
||||
|
||||
fmt.Println("\n=== Done ===")
|
||||
}
|
||||
|
||||
func listAllDevices(targetHWID string) {
|
||||
hDevInfo, _, err := procSetupDiGetClassDevsW.Call(
|
||||
0, 0, 0,
|
||||
DIGCF_PRESENT|DIGCF_ALLCLASSES,
|
||||
)
|
||||
func createSelfSignedCert(certPath string) (string, error) {
|
||||
psScript := fmt.Sprintf(`
|
||||
$ErrorActionPreference = 'Stop'
|
||||
# Remove old cert if exists
|
||||
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -eq 'CN=Kneron Edge AI Platform' } | Remove-Item -Force -ErrorAction SilentlyContinue
|
||||
# Create new self-signed code signing cert
|
||||
$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Kneron Edge AI Platform" -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddYears(10) -FriendlyName "Kneron Edge AI Platform Driver Signing"
|
||||
# Export DER cert
|
||||
Export-Certificate -Cert $cert -FilePath '%s' -Force | Out-Null
|
||||
Write-Output $cert.Thumbprint
|
||||
`, certPath)
|
||||
|
||||
cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psScript)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("powershell: %v\nOutput: %s", err, string(out))
|
||||
}
|
||||
|
||||
thumbprint := strings.TrimSpace(string(out))
|
||||
// Extract just the thumbprint (last line)
|
||||
lines := strings.Split(thumbprint, "\n")
|
||||
for i := len(lines) - 1; i >= 0; i-- {
|
||||
line := strings.TrimSpace(lines[i])
|
||||
if len(line) == 40 { // SHA1 thumbprint length
|
||||
return line, nil
|
||||
}
|
||||
}
|
||||
return thumbprint, nil
|
||||
}
|
||||
|
||||
func installCertToStore(certPath, storeName string) {
|
||||
cmd := exec.Command("certutil", "-addstore", storeName, certPath)
|
||||
out, err := cmd.CombinedOutput()
|
||||
outStr := strings.TrimSpace(string(out))
|
||||
if err != nil {
|
||||
fmt.Printf(" certutil %s: FAILED - %v\n %s\n", storeName, err, outStr)
|
||||
} else {
|
||||
fmt.Printf(" certutil %s: OK\n", storeName)
|
||||
}
|
||||
}
|
||||
|
||||
func createCatalog(driverDir, infPath, catPath string) error {
|
||||
// Method 1: Try inf2cat from Windows SDK
|
||||
sdkBases := []string{
|
||||
`C:\Program Files (x86)\Windows Kits\10\bin`,
|
||||
}
|
||||
sdkVersions := []string{
|
||||
"10.0.26100.0", "10.0.22621.0", "10.0.22000.0", "10.0.19041.0", "10.0.18362.0",
|
||||
}
|
||||
|
||||
for _, base := range sdkBases {
|
||||
for _, ver := range sdkVersions {
|
||||
inf2cat := filepath.Join(base, ver, "x86", "inf2cat.exe")
|
||||
if _, err := os.Stat(inf2cat); err == nil {
|
||||
fmt.Printf(" Found inf2cat: %s\n", inf2cat)
|
||||
cmd := exec.Command(inf2cat, "/driver:"+driverDir, "/os:10_X64", "/verbose")
|
||||
out, err := cmd.CombinedOutput()
|
||||
outStr := strings.TrimSpace(string(out))
|
||||
fmt.Printf(" inf2cat output: %s\n", outStr)
|
||||
if err == nil {
|
||||
if _, err := os.Stat(catPath); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
fmt.Printf(" inf2cat error: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method 2: Create a minimal catalog using MakeCat.exe definition file
|
||||
fmt.Println(" inf2cat not found, trying MakeCat approach...")
|
||||
cdfPath := filepath.Join(driverDir, "kneron_winusb.cdf")
|
||||
cdfContent := fmt.Sprintf(`[CatalogHeader]
|
||||
Name=%s
|
||||
PublicVersion=0x0000001
|
||||
EncodingType=0x00010001
|
||||
CATATTR1=0x10010001:OSAttr:2:10.0
|
||||
|
||||
[CatalogFiles]
|
||||
kneron_winusb.inf=%s
|
||||
`, catPath, infPath)
|
||||
|
||||
if err := os.WriteFile(cdfPath, []byte(cdfContent), 0644); err != nil {
|
||||
return fmt.Errorf("write CDF: %w", err)
|
||||
}
|
||||
defer os.Remove(cdfPath)
|
||||
|
||||
cmd := exec.Command("makecat", "-v", cdfPath)
|
||||
out, err := cmd.CombinedOutput()
|
||||
outStr := strings.TrimSpace(string(out))
|
||||
fmt.Printf(" makecat output: %s\n", outStr)
|
||||
if err != nil {
|
||||
fmt.Printf(" makecat error: %v\n", err)
|
||||
|
||||
// Method 3: Use PowerShell to create catalog via .NET
|
||||
fmt.Println(" Trying PowerShell New-FileCatalog...")
|
||||
psCmd := fmt.Sprintf(`New-FileCatalog -Path '%s' -CatalogFilePath '%s' -CatalogVersion 2.0`, driverDir, catPath)
|
||||
cmd = exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psCmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
outStr = strings.TrimSpace(string(out))
|
||||
fmt.Printf(" New-FileCatalog: %s\n", outStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("all catalog creation methods failed")
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(catPath); err == nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("catalog file not created")
|
||||
}
|
||||
|
||||
func signCatalog(catPath, thumbprint string) {
|
||||
// Try signtool from Windows SDK
|
||||
sdkBases := []string{`C:\Program Files (x86)\Windows Kits\10\bin`}
|
||||
sdkVersions := []string{
|
||||
"10.0.26100.0", "10.0.22621.0", "10.0.22000.0", "10.0.19041.0", "10.0.18362.0",
|
||||
}
|
||||
|
||||
for _, base := range sdkBases {
|
||||
for _, ver := range sdkVersions {
|
||||
signtool := filepath.Join(base, ver, "x64", "signtool.exe")
|
||||
if _, err := os.Stat(signtool); err == nil {
|
||||
fmt.Printf(" Found signtool: %s\n", signtool)
|
||||
cmd := exec.Command(signtool, "sign", "/sha1", thumbprint, "/fd", "SHA256",
|
||||
"/s", "My", "/sm", "/v", catPath)
|
||||
out, err := cmd.CombinedOutput()
|
||||
outStr := strings.TrimSpace(string(out))
|
||||
fmt.Printf(" signtool: %s\n", outStr)
|
||||
if err != nil {
|
||||
fmt.Printf(" signtool error: %v\n", err)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: PowerShell Set-AuthenticodeSignature
|
||||
fmt.Println(" signtool not found, trying Set-AuthenticodeSignature...")
|
||||
psCmd := fmt.Sprintf(`
|
||||
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq '%s' }
|
||||
if ($cert) {
|
||||
Set-AuthenticodeSignature -FilePath '%s' -Certificate $cert -HashAlgorithm SHA256
|
||||
} else {
|
||||
Write-Error "Certificate not found"
|
||||
}
|
||||
`, thumbprint, catPath)
|
||||
cmd := exec.Command("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psCmd)
|
||||
out, err := cmd.CombinedOutput()
|
||||
fmt.Printf(" PowerShell sign: %s\n", strings.TrimSpace(string(out)))
|
||||
if err != nil {
|
||||
fmt.Printf(" PowerShell sign error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func listKneronDevices(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)
|
||||
fmt.Printf("ERROR: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer procSetupDiDestroyDevInfoList.Call(hDevInfo)
|
||||
@ -143,41 +324,28 @@ func listAllDevices(targetHWID string) {
|
||||
var devInfoData SP_DEVINFO_DATA
|
||||
devInfoData.cbSize = uint32(unsafe.Sizeof(devInfoData))
|
||||
|
||||
total := 0
|
||||
matched := 0
|
||||
total, matched := 0, 0
|
||||
for i := uint32(0); ; i++ {
|
||||
ret, _, _ := procSetupDiEnumDeviceInfo.Call(
|
||||
hDevInfo, uintptr(i),
|
||||
uintptr(unsafe.Pointer(&devInfoData)),
|
||||
)
|
||||
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)),
|
||||
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") {
|
||||
if strings.Contains(strings.ToUpper(id), "VID_3231") {
|
||||
isKneron = true
|
||||
break
|
||||
}
|
||||
@ -185,95 +353,34 @@ func listAllDevices(targetHWID string) {
|
||||
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)),
|
||||
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)"
|
||||
desc := "(unknown)"
|
||||
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")
|
||||
fmt.Printf(" #%d: %s (DevInst: %d)\n", matched, desc, devInfoData.DevInst)
|
||||
for _, id := range hwids {
|
||||
match := ""
|
||||
tag := ""
|
||||
if strings.EqualFold(id, targetHWID) {
|
||||
match = " <== MATCH"
|
||||
tag = " <== MATCH"
|
||||
}
|
||||
fmt.Printf(" - %s%s\n", id, match)
|
||||
fmt.Printf(" %s%s\n", id, tag)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
fmt.Println("Calling UpdateDriverForPlugAndPlayDevicesW...")
|
||||
|
||||
ret, _, lastErr := procUpdateDriverForPlugAndPlayDevicesW.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(hwIDUTF16)),
|
||||
uintptr(unsafe.Pointer(infUTF16)),
|
||||
INSTALLFLAG_FORCE,
|
||||
uintptr(unsafe.Pointer(&needReboot)),
|
||||
)
|
||||
|
||||
fmt.Printf("Return value: %d\n", ret)
|
||||
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!")
|
||||
}
|
||||
}
|
||||
|
||||
func tryDiInstallDriver(infPath string) {
|
||||
infUTF16, _ := syscall.UTF16PtrFromString(infPath)
|
||||
var needReboot int32
|
||||
|
||||
fmt.Println("Calling DiInstallDriverW...")
|
||||
ret, _, lastErr := procDiInstallDriverW.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(infUTF16)),
|
||||
DIIRFLAG_FORCE_INF,
|
||||
uintptr(unsafe.Pointer(&needReboot)),
|
||||
)
|
||||
|
||||
fmt.Printf("Return value: %d\n", ret)
|
||||
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!")
|
||||
}
|
||||
fmt.Printf(" Total: %d, Kneron: %d\n", total, matched)
|
||||
}
|
||||
|
||||
func trySetupAPIInstall(infPath, targetHWID string) {
|
||||
fmt.Println("Enumerating present USB devices...")
|
||||
|
||||
hDevInfo, _, err := procSetupDiGetClassDevsW.Call(
|
||||
0, 0, 0,
|
||||
DIGCF_PRESENT|DIGCF_ALLCLASSES,
|
||||
)
|
||||
hDevInfo, _, err := procSetupDiGetClassDevsW.Call(0, 0, 0, DIGCF_PRESENT|DIGCF_ALLCLASSES)
|
||||
if hDevInfo == INVALID_HANDLE_VALUE {
|
||||
fmt.Printf("ERROR: SetupDiGetClassDevsW: %v\n", err)
|
||||
fmt.Printf(" ERROR: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer procSetupDiDestroyDevInfoList.Call(hDevInfo)
|
||||
@ -281,124 +388,67 @@ func trySetupAPIInstall(infPath, targetHWID string) {
|
||||
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)),
|
||||
)
|
||||
ret, _, _ := procSetupDiEnumDeviceInfo.Call(hDevInfo, uintptr(i), uintptr(unsafe.Pointer(&devInfoData)))
|
||||
if ret == 0 {
|
||||
break
|
||||
fmt.Println(" Target device not found")
|
||||
return
|
||||
}
|
||||
|
||||
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)),
|
||||
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)
|
||||
matchFound := false
|
||||
match := false
|
||||
for _, id := range hwids {
|
||||
if strings.EqualFold(id, targetHWID) {
|
||||
matchFound = true
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matchFound {
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("FOUND target device (DevInst: %d)\n", devInfoData.DevInst)
|
||||
found = true
|
||||
fmt.Printf(" Found device (DevInst: %d)\n", devInfoData.DevInst)
|
||||
|
||||
// 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)
|
||||
procSetupDiGetDevInstallParamsW.Call(hDevInfo, uintptr(unsafe.Pointer(&devInfoData)), uintptr(unsafe.Pointer(&installParams)))
|
||||
|
||||
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)),
|
||||
)
|
||||
procSetupDiSetDevInstallParamsW.Call(hDevInfo, uintptr(unsafe.Pointer(&devInfoData)), uintptr(unsafe.Pointer(&installParams)))
|
||||
|
||||
ret, _, _ = procSetupDiBuildDriverInfoList.Call(hDevInfo, uintptr(unsafe.Pointer(&devInfoData)), SPDIT_COMPATDRIVER)
|
||||
if ret == 0 {
|
||||
fmt.Printf("ERROR: SetDeviceInstallParams: %v\n", err)
|
||||
fmt.Println(" BuildDriverInfoList failed")
|
||||
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,
|
||||
)
|
||||
ret, _, _ = procSetupDiCallClassInstaller.Call(DIF_SELECTBESTCOMPATDRV, hDevInfo, uintptr(unsafe.Pointer(&devInfoData)))
|
||||
if ret == 0 {
|
||||
errno := err.(syscall.Errno)
|
||||
fmt.Printf("ERROR: BuildDriverInfoList: %v (0x%08X)\n", err, uint32(errno))
|
||||
fmt.Println(" DIF_SELECTBESTCOMPATDRV failed")
|
||||
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)),
|
||||
)
|
||||
ret, _, err = procSetupDiCallClassInstaller.Call(DIF_INSTALLDEVICE, 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))
|
||||
fmt.Printf(" DIF_INSTALLDEVICE FAILED: %v (0x%08X)\n", err, uint32(errno))
|
||||
} else {
|
||||
fmt.Println("SUCCESS - driver installed!")
|
||||
fmt.Println(" SUCCESS - driver installed!")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Println("Target device NOT found among present devices")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user