From 0cfaee351451459ff99f476d2c4f242b7b02b573 Mon Sep 17 00:00:00 2001 From: Sebastian Zagrodzki Date: Sat, 29 Apr 2017 00:18:26 +0200 Subject: [PATCH] Fail operations if Close was called before. --- usb/config.go | 7 +++++++ usb/device.go | 19 +++++++++++++++++-- usb/device_test.go | 8 ++++++++ usb/interface.go | 10 ++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/usb/config.go b/usb/config.go index 6c265dc..309a272 100644 --- a/usb/config.go +++ b/usb/config.go @@ -69,6 +69,7 @@ func (c *Config) Close() error { c.dev.mu.Lock() defer c.dev.mu.Unlock() c.dev.claimed = nil + c.dev = nil return nil } @@ -78,11 +79,17 @@ func (c *Config) String() string { // Control sends a control request to the device. func (c *Config) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) { + if c.dev == nil { + return 0, fmt.Errorf("Control() called on %s after Close", c) + } return libusb.control(c.dev.handle, c.ControlTimeout, rType, request, val, idx, data) } // Interface claims and returns an interface on a USB device. func (c *Config) Interface(intf, alt int) (*Interface, error) { + if c.dev == nil { + return nil, fmt.Errorf("Interface(%d, %d) called on %s after Close", intf, alt, c) + } if intf < 0 || intf >= len(c.Info.Interfaces) { return nil, fmt.Errorf("interface %d not found in %s. Interface number needs to be a 0-based index into the interface table, which has %d elements.", intf, c, len(c.Info.Interfaces)) } diff --git a/usb/device.go b/usb/device.go index 91c0b00..bce1544 100644 --- a/usb/device.go +++ b/usb/device.go @@ -34,10 +34,13 @@ type Device struct { // Reset performs a USB port reset to reinitialize a device. func (d *Device) Reset() error { + if d.handle == nil { + return fmt.Errorf("Reset() called on %s after Close", d) + } d.mu.Lock() defer d.mu.Unlock() if d.claimed != nil { - return fmt.Errorf("can't reset a device with an open configuration") + return fmt.Errorf("can't reset device %s while it has an active configuration %s", d, d.claimed) } return libusb.reset(d.handle) } @@ -45,6 +48,9 @@ func (d *Device) Reset() error { // ActiveConfig returns the config id (not the index) of the active configuration. // This corresponds to the ConfigInfo.Config field. func (d *Device) ActiveConfig() (int, error) { + if d.handle == nil { + return 0, fmt.Errorf("ActiveConfig() called on %s after Close", d) + } ret, err := libusb.getConfig(d.handle) return int(ret), err } @@ -55,6 +61,9 @@ func (d *Device) ActiveConfig() (int, error) { // USB supports only one active config per device at a time. Config claims the // device before setting the desired config and keeps it locked until Close is called. func (d *Device) Config(cfgNum int) (*Config, error) { + if d.handle == nil { + return nil, fmt.Errorf("Config(%d) called on %s after Close", cfgNum, d) + } cfg := &Config{ dev: d, claimed: make(map[int]bool), @@ -82,7 +91,7 @@ func (d *Device) Config(cfgNum int) (*Config, error) { // Close closes the device. func (d *Device) Close() error { if d.handle == nil { - return fmt.Errorf("double close on device %s", d) + return nil } d.mu.Lock() defer d.mu.Unlock() @@ -99,6 +108,9 @@ func (d *Device) Close() error { // descriptor string is converted to ASCII (non-ASCII characters are replaced // with "?"). func (d *Device) GetStringDescriptor(descIndex int) (string, error) { + if d.handle == nil { + return "", fmt.Errorf("GetStringDescriptor(%d) called on %s after Close", descIndex, d) + } return libusb.getStringDesc(d.handle, descIndex) } @@ -107,6 +119,9 @@ func (d *Device) GetStringDescriptor(descIndex int) (string, error) { // on the interface and reattach it when releasing the interface. // Automatic kernel driver detachment is disabled on newly opened device handles by default. func (d *Device) SetAutoDetach(autodetach bool) error { + if d.handle == nil { + return fmt.Errorf("SetAutoDetach(%v) called on %s after Close", autodetach, d) + } var autodetachInt int switch autodetach { case true: diff --git a/usb/device_test.go b/usb/device_test.go index c9367ec..c55a700 100644 --- a/usb/device_test.go +++ b/usb/device_test.go @@ -50,4 +50,12 @@ func TestOpenEndpoint(t *testing.T) { if want := fakeDevices[1].Configs[0].Interfaces[1].AltSettings[1].Endpoints[1]; !reflect.DeepEqual(got.Info, want) { t.Errorf("InEndpoint(cfg=1, if=1, alt=1, ep=6IN): got %+v, want %+v", got, want) } + + if err := cfg.Close(); err == nil { + t.Fatalf("cfg.Close(): returned nil, want non nil, because the Interface was not release.") + } + if err := dev.Close(); err == nil { + t.Fatalf("dev.Close(): returned nil, want non nil, because the Config was not released.") + } + intf.Close() } diff --git a/usb/interface.go b/usb/interface.go index 5d986ae..c956f60 100644 --- a/usb/interface.go +++ b/usb/interface.go @@ -71,10 +71,14 @@ func (i *Interface) String() string { // Close releases the interface. func (i *Interface) Close() { + if i.config == nil { + return + } libusb.release(i.config.dev.handle, uint8(i.Setting.Number)) i.config.mu.Lock() defer i.config.mu.Unlock() delete(i.config.claimed, i.Setting.Number) + i.config = nil } func (i *Interface) openEndpoint(epNum int) (*endpoint, error) { @@ -100,6 +104,9 @@ func (i *Interface) openEndpoint(epNum int) (*endpoint, error) { // InEndpoint prepares an IN endpoint for transfer. func (i *Interface) InEndpoint(epNum int) (*InEndpoint, error) { + if i.config == nil { + return nil, fmt.Errorf("InEndpoint(%d) called on %s after Close", epNum, i) + } ep, err := i.openEndpoint(epNum) if err != nil { return nil, err @@ -114,6 +121,9 @@ func (i *Interface) InEndpoint(epNum int) (*InEndpoint, error) { // OutEndpoint prepares an OUT endpoint for transfer. func (i *Interface) OutEndpoint(epNum int) (*OutEndpoint, error) { + if i.config == nil { + return nil, fmt.Errorf("OutEndpoint(%d) called on %s after Close", epNum, i) + } ep, err := i.openEndpoint(epNum) if err != nil { return nil, err