package device import ( "context" "fmt" "github.com/google/gousb" ) // Info describes a USB device for the diagnostics listing. type Info struct { VendorID int ProductID int Manufacturer string Product string Serial string Bus int Address int IsLCD bool } // ListDevices enumerates all USB devices visible to libusb. Descriptor // strings are best-effort: reading them requires device access, which is // why failures are ignored. func ListDevices(ctx context.Context) ([]Info, error) { gctx := gousb.NewContext() defer gctx.Close() devs, err := gctx.OpenDevices(func(*gousb.DeviceDesc) bool { return true }) if err != nil && len(devs) == 0 { return nil, fmt.Errorf("enumerate USB devices (run as root or install the udev rule): %w", err) } defer func() { for _, d := range devs { _ = d.Close() } }() infos := make([]Info, 0, len(devs)) for _, d := range devs { info := Info{ VendorID: int(d.Desc.Vendor), ProductID: int(d.Desc.Product), Bus: d.Desc.Bus, Address: d.Desc.Address, IsLCD: d.Desc.Vendor == gousb.ID(0x0416) && d.Desc.Product == gousb.ID(0x7395), } if info.IsLCD { // Only read strings for the device we care about. info.Manufacturer, _ = d.Manufacturer() info.Product, _ = d.Product() info.Serial, _ = d.SerialNumber() } infos = append(infos, info) } return infos, err }