diff --git a/lsusb/main.go b/lsusb/main.go index c7c3b28..dc30939 100644 --- a/lsusb/main.go +++ b/lsusb/main.go @@ -38,7 +38,7 @@ func main() { fmt.Printf(" %s:\n", cfg) for _, alt := range cfg.Interfaces { fmt.Printf(" --------------\n") - for _, iface := range alt { + for _, iface := range alt.Setups { fmt.Printf(" %s\n", iface) fmt.Printf(" %s\n", usbid.Classify(iface)) for _, end := range iface.Endpoints { diff --git a/usb/config.go b/usb/config.go index 80d5eb3..e0e37d4 100644 --- a/usb/config.go +++ b/usb/config.go @@ -11,7 +11,6 @@ import ( ) type EndpointInfo struct { - Type DescriptorType Address uint8 Attributes uint8 MaxPacketSize uint16 @@ -38,7 +37,15 @@ func (e EndpointInfo) String() string { } type InterfaceInfo struct { - Type DescriptorType + Number uint8 + Setups []InterfaceSetup +} + +func (i InterfaceInfo) String() string { + return fmt.Sprintf("Interface %02x (%d setups)", i.Number, len(i.Setups)) +} + +type InterfaceSetup struct { Number uint8 Alternate uint8 IfClass uint8 @@ -47,16 +54,15 @@ type InterfaceInfo struct { Endpoints []EndpointInfo } -func (i InterfaceInfo) String() string { - return fmt.Sprintf("Interface %02x (config %02x)", i.Number, i.Alternate) +func (a InterfaceSetup) String() string { + return fmt.Sprintf("Interface %02x Setup %02x", a.Number, a.Alternate) } type ConfigInfo struct { - Type DescriptorType Config uint8 Attributes uint8 MaxPower uint8 - Interfaces [][]InterfaceInfo + Interfaces []InterfaceInfo } func (c ConfigInfo) String() string { @@ -65,7 +71,6 @@ func (c ConfigInfo) String() string { func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo { c := ConfigInfo{ - Type: DescriptorType(cfg.bDescriptorType), Config: uint8(cfg.bConfigurationValue), Attributes: uint8(cfg.bmAttributes), MaxPower: uint8(cfg.MaxPower), @@ -77,18 +82,21 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo { Len: int(cfg.bNumInterfaces), Cap: int(cfg.bNumInterfaces), } - c.Interfaces = make([][]InterfaceInfo, 0, len(ifaces)) + c.Interfaces = make([]InterfaceInfo, 0, len(ifaces)) for _, iface := range ifaces { + if iface.num_altsetting == 0 { + continue + } + var alts []C.struct_libusb_interface_descriptor *(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(iface.altsetting)), Len: int(iface.num_altsetting), Cap: int(iface.num_altsetting), } - descs := make([]InterfaceInfo, 0, len(alts)) + descs := make([]InterfaceSetup, 0, len(alts)) for _, alt := range alts { - i := InterfaceInfo{ - Type: DescriptorType(alt.bDescriptorType), + i := InterfaceSetup{ Number: uint8(alt.bInterfaceNumber), Alternate: uint8(alt.bAlternateSetting), IfClass: uint8(alt.bInterfaceClass), @@ -104,7 +112,6 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo { i.Endpoints = make([]EndpointInfo, 0, len(ends)) for _, end := range ends { i.Endpoints = append(i.Endpoints, EndpointInfo{ - Type: DescriptorType(end.bDescriptorType), Address: uint8(end.bEndpointAddress), Attributes: uint8(end.bmAttributes), MaxPacketSize: uint16(end.wMaxPacketSize), @@ -115,7 +122,10 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo { } descs = append(descs, i) } - c.Interfaces = append(c.Interfaces, descs) + c.Interfaces = append(c.Interfaces, InterfaceInfo{ + Number: descs[0].Number, + Setups: descs, + }) } return c } diff --git a/usb/device.go b/usb/device.go index b182d38..65259a8 100644 --- a/usb/device.go +++ b/usb/device.go @@ -8,6 +8,7 @@ import ( "fmt" "reflect" "runtime" + "sync" "time" "unsafe" ) @@ -22,13 +23,20 @@ type Device struct { // Timeouts ControlTimeout time.Duration + + // Claimed interfaces + lock *sync.Mutex + claimed map[uint8]int } func newDevice(handle *C.libusb_device_handle, desc *Descriptor) *Device { + ifaces := 0 d := &Device{ handle: handle, Descriptor: desc, ControlTimeout: DefaultControlTimeout, + lock: new(sync.Mutex), + claimed: make(map[uint8]int, ifaces), } // This doesn't seem to actually get called @@ -86,7 +94,20 @@ func (d *Device) Close() error { if d.handle == nil { return fmt.Errorf("usb: double close on device") } + for iface := range d.claimed { + C.libusb_release_interface(d.handle, C.int(iface)) + } C.libusb_close(d.handle) d.handle = nil return nil } + +type Interface struct { +} + +func (d *Device) OpenInterface(id uint8) (*Interface, error) { + if errno := C.libusb_claim_interface(d.handle, C.int(id)); errno < 0 { + return nil, usbError(errno) + } + return &Interface{}, nil +} diff --git a/usb/usb_test.go b/usb/usb_test.go index f139b86..aedd0ef 100644 --- a/usb/usb_test.go +++ b/usb/usb_test.go @@ -26,7 +26,7 @@ func TestEnum(t *testing.T) { t.Logf("- %s:", cfg) for _, alt := range cfg.Interfaces { t.Logf(" --------------") - for _, iface := range alt { + for _, iface := range alt.Setups { t.Logf(" - %s", iface) t.Logf(" - %s", usbid.Classify(iface)) for _, end := range iface.Endpoints { diff --git a/usbid/describe.go b/usbid/describe.go index ed813a3..1bb20e6 100644 --- a/usbid/describe.go +++ b/usbid/describe.go @@ -39,13 +39,13 @@ func Describe(val interface{}) string { // // The given val must be one of the following: // - *usb.Descriptor "Class (SubClass) Protocol" -// - *usb.InterfaceInfo "IfClass (IfSubClass) IfProtocol" +// - *usb.InterfaceSetup "IfClass (IfSubClass) IfProtocol" func Classify(val interface{}) string { var class, sub, proto uint8 switch val := val.(type) { case *usb.Descriptor: class, sub, proto = val.Class, val.SubClass, val.Protocol - case *usb.InterfaceInfo: + case *usb.InterfaceSetup: class, sub, proto = val.IfClass, val.IfSubClass, val.IfProtocol default: return fmt.Sprintf("Unknown (%T)", val)