Extend the autodetach behavior

Detach interfaces before trying to change the config, as libusb doesn't handle that automatically.
This commit is contained in:
Nico MT
2017-07-21 21:15:49 +02:00
committed by zagrodzki
parent 9829f2fcba
commit bc91dd3f2c
6 changed files with 79 additions and 6 deletions

View File

@@ -12,3 +12,4 @@ Jirawat I. <nodtem66@gmail.com>
Thordur Bjornsson <thorduri@secnorth.net>
Vincent Serpoul <vincent@serpoul.com>
Josef Filzmaier <josef.filzmaier@gmail.com>
Nico MT <nicovell3@gmail.com>

View File

@@ -68,6 +68,9 @@ type Device struct {
// Claimed config
mu sync.Mutex
claimed *Config
// Handle AutoDetach in this library
autodetach bool
}
func (d *DeviceDesc) sortedConfigIds() []int {
@@ -129,6 +132,14 @@ func (d *Device) Config(cfgNum int) (*Config, error) {
claimed: make(map[int]bool),
}
if d.autodetach {
for _, iface := range cfg.Desc.Interfaces {
if err := libusb.detachKernelDriver(d.handle, uint8(iface.Number)); err != nil {
return nil, fmt.Errorf("Can't detach kernel driver of the device %s and interface %d: %v", d, iface.Number, err)
}
}
}
if activeCfgNum, err := d.ActiveConfigNum(); err != nil {
return nil, fmt.Errorf("failed to query active config of the device %s: %v", d, err)
} else if cfgNum != activeCfgNum {
@@ -182,7 +193,7 @@ func (d *Device) Close() error {
d.mu.Lock()
defer d.mu.Unlock()
if d.claimed != nil {
return fmt.Errorf("can't release the device %s, it has an open config %s", d, d.claimed.Desc.Number)
return fmt.Errorf("can't release the device %s, it has an open config %d", d, d.claimed.Desc.Number)
}
libusb.close(d.handle)
d.handle = nil
@@ -208,12 +219,10 @@ func (d *Device) SetAutoDetach(autodetach bool) error {
if d.handle == nil {
return fmt.Errorf("SetAutoDetach(%v) called on %s after Close", autodetach, d)
}
d.autodetach = autodetach
var autodetachInt int
switch autodetach {
case true:
if autodetach {
autodetachInt = 1
case false:
autodetachInt = 0
}
return libusb.setAutoDetach(d.handle, autodetachInt)
}

View File

@@ -15,6 +15,7 @@
package gousb
import (
"errors"
"reflect"
"testing"
)
@@ -42,6 +43,10 @@ func TestClaimAndRelease(t *testing.T) {
if err != nil {
t.Fatalf("OpenDeviceWithVIDPID(0x8888, 0x0002): %v", err)
}
if err = dev.SetAutoDetach(true); err != nil {
t.Fatalf("%s.SetAutoDetach(true): %v", dev, err)
}
cfg, err := dev.Config(cfgNum)
if err != nil {
t.Fatalf("%s.Config(1): %v", dev, err)
@@ -111,4 +116,49 @@ func TestClaimAndRelease(t *testing.T) {
if err := dev.Close(); err != nil {
t.Fatalf("%s.Close(): got error %v, want nil", dev, err)
}
if _, err := dev.Config(cfgNum); err == nil {
t.Fatalf("%s.Config(1): got error nil, want no nil because it is closed", dev)
}
if err := dev.Reset(); err == nil {
t.Fatalf("%s.Reset(): got error nil, want no nil because it is closed", dev)
}
if err := dev.SetAutoDetach(false); err == nil {
t.Fatalf("%s.SetAutoDetach(false): got error nil, want no nil because it is closed", dev)
}
}
type failDetachLib struct {
*fakeLibusb
}
func (*failDetachLib) detachKernelDriver(h *libusbDevHandle, i uint8) error {
if i == 1 {
return errors.New("test detach fail")
}
return nil
}
func TestAutoDetachFailure(t *testing.T) {
fake, done := newFakeLibusb()
defer done()
libusb = &failDetachLib{fake}
c := NewContext()
defer c.Close()
dev, err := c.OpenDeviceWithVIDPID(0x8888, 0x0002)
if dev == nil {
t.Fatal("OpenDeviceWithVIDPID(0x8888, 0x0002): got nil device, need non-nil")
}
defer dev.Close()
if err != nil {
t.Fatalf("OpenDeviceWithVIDPID(0x8888, 0x0002): %v", err)
}
dev.SetAutoDetach(true)
_, err = dev.Config(1)
if err == nil {
t.Fatalf("%s.Config(1) got nil, but want no nil because interface fails to detach", dev)
}
}

View File

@@ -76,6 +76,6 @@ func TestEndpointReadStream(t *testing.T) {
got += num
}
if got != want {
t.Errorf("%s.Read(): read %d bytes, want %d")
t.Errorf("stream.Read(): read %d bytes, want %d", got, want)
}
}

View File

@@ -114,6 +114,8 @@ func (f *fakeLibusb) getStringDesc(*libusbDevHandle, int) (string, error) {
}
func (f *fakeLibusb) setAutoDetach(*libusbDevHandle, int) error { return nil }
func (f *fakeLibusb) detachKernelDriver(*libusbDevHandle, uint8) error { return nil }
func (f *fakeLibusb) claim(d *libusbDevHandle, intf uint8) error {
debug.Printf("claim(%p, %d)\n", d, intf)
f.mu.Lock()

View File

@@ -148,6 +148,7 @@ type libusbIntf interface {
setConfig(*libusbDevHandle, uint8) error
getStringDesc(*libusbDevHandle, int) (string, error)
setAutoDetach(*libusbDevHandle, int) error
detachKernelDriver(*libusbDevHandle, uint8) error
// interface
claim(*libusbDevHandle, uint8) error
@@ -388,6 +389,16 @@ func (libusbImpl) setAutoDetach(d *libusbDevHandle, val int) error {
return nil
}
func (libusbImpl) detachKernelDriver(d *libusbDevHandle, iface uint8) error {
err := fromErrNo(C.libusb_detach_kernel_driver((*C.libusb_device_handle)(d), C.int(iface)))
if err != nil && err != ErrorNotSupported && err != ErrorNotFound {
// ErrorNotSupported is returned in non linux systems
// ErrorNotFound is returned if libusb's driver is already attached to the device
return err
}
return nil
}
func (libusbImpl) claim(d *libusbDevHandle, iface uint8) error {
return fromErrNo(C.libusb_claim_interface((*C.libusb_device_handle)(d), C.int(iface)))
}