Config and interface description (#16)
* Add APIs for config and interface descriptors. Split out the common parts of selecting a config descriptor from device desc and selecting a setting descriptor from a config desc. * Parallelize the few tests that actually can be parallelized safely. Add comments where they can't. Note to self: it would be beneficial to restructure the fakelibusb to index all properties of the lib with the used context. That way a libusb implementation wouldn't need to be referred via a shared variable.
This commit is contained in:
25
config.go
25
config.go
@@ -40,6 +40,8 @@ type ConfigDesc struct {
|
|||||||
MaxPower Milliamperes
|
MaxPower Milliamperes
|
||||||
// Interfaces has a list of USB interfaces available in this configuration.
|
// Interfaces has a list of USB interfaces available in this configuration.
|
||||||
Interfaces []InterfaceDesc
|
Interfaces []InterfaceDesc
|
||||||
|
|
||||||
|
iConfiguration int // index of a string descriptor describing this configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the human-readable description of the configuration descriptor.
|
// String returns the human-readable description of the configuration descriptor.
|
||||||
@@ -47,6 +49,17 @@ func (c ConfigDesc) String() string {
|
|||||||
return fmt.Sprintf("Configuration %d", c.Number)
|
return fmt.Sprintf("Configuration %d", c.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c ConfigDesc) intfDesc(num, alt int) (*InterfaceSetting, error) {
|
||||||
|
if num < 0 || num >= len(c.Interfaces) {
|
||||||
|
return nil, fmt.Errorf("interface %d not found, available interfaces 0..%d", num, len(c.Interfaces)-1)
|
||||||
|
}
|
||||||
|
ifInfo := c.Interfaces[num]
|
||||||
|
if alt < 0 || alt >= len(ifInfo.AltSettings) {
|
||||||
|
return nil, fmt.Errorf("alternate setting %d not found for %s, available alt settings 0..%d", alt, ifInfo, len(ifInfo.AltSettings)-1)
|
||||||
|
}
|
||||||
|
return &ifInfo.AltSettings[alt], nil
|
||||||
|
}
|
||||||
|
|
||||||
// Config represents a USB device set to use a particular configuration.
|
// Config represents a USB device set to use a particular configuration.
|
||||||
// Only one Config of a particular device can be used at any one time.
|
// Only one Config of a particular device can be used at any one time.
|
||||||
// To access device endpoints, claim an interface and it's alternate
|
// To access device endpoints, claim an interface and it's alternate
|
||||||
@@ -94,12 +107,10 @@ func (c *Config) Interface(num, alt int) (*Interface, error) {
|
|||||||
if c.dev == nil {
|
if c.dev == nil {
|
||||||
return nil, fmt.Errorf("Interface(%d, %d) called on %s after Close", num, alt, c)
|
return nil, fmt.Errorf("Interface(%d, %d) called on %s after Close", num, alt, c)
|
||||||
}
|
}
|
||||||
if num < 0 || num >= len(c.Desc.Interfaces) {
|
|
||||||
return nil, fmt.Errorf("interface %d not found in %s, available interfaces 0..%d", num, c, len(c.Desc.Interfaces)-1)
|
altInfo, err := c.Desc.intfDesc(num, alt)
|
||||||
}
|
if err != nil {
|
||||||
ifInfo := c.Desc.Interfaces[num]
|
return nil, fmt.Errorf("in %s: %v", err)
|
||||||
if alt < 0 || alt >= len(ifInfo.AltSettings) {
|
|
||||||
return nil, fmt.Errorf("alternate setting %d not found for %s in %s, available alt settings 0..%d", alt, ifInfo, c, len(ifInfo.AltSettings)-1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
@@ -120,7 +131,7 @@ func (c *Config) Interface(num, alt int) (*Interface, error) {
|
|||||||
|
|
||||||
c.claimed[num] = true
|
c.claimed[num] = true
|
||||||
return &Interface{
|
return &Interface{
|
||||||
Setting: ifInfo.AltSettings[alt],
|
Setting: *altInfo,
|
||||||
config: c,
|
config: c,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
63
device.go
63
device.go
@@ -56,6 +56,23 @@ func (d *DeviceDesc) String() string {
|
|||||||
return fmt.Sprintf("%d.%d: %s:%s (available configs: %v)", d.Bus, d.Address, d.Vendor, d.Product, d.sortedConfigIds())
|
return fmt.Sprintf("%d.%d: %s:%s (available configs: %v)", d.Bus, d.Address, d.Vendor, d.Product, d.sortedConfigIds())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DeviceDesc) sortedConfigIds() []int {
|
||||||
|
var cfgs []int
|
||||||
|
for c := range d.Configs {
|
||||||
|
cfgs = append(cfgs, c)
|
||||||
|
}
|
||||||
|
sort.Ints(cfgs)
|
||||||
|
return cfgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeviceDesc) cfgDesc(cfgNum int) (*ConfigDesc, error) {
|
||||||
|
desc, ok := d.Configs[cfgNum]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("configuration id %d not found in the descriptor of the device. Available config ids: %v", cfgNum, d.sortedConfigIds())
|
||||||
|
}
|
||||||
|
return &desc, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Device represents an opened USB device.
|
// Device represents an opened USB device.
|
||||||
// Device allows sending USB control commands through the Command() method.
|
// Device allows sending USB control commands through the Command() method.
|
||||||
// For data transfers select a device configuration through a call to
|
// For data transfers select a device configuration through a call to
|
||||||
@@ -77,15 +94,6 @@ type Device struct {
|
|||||||
autodetach bool
|
autodetach bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DeviceDesc) sortedConfigIds() []int {
|
|
||||||
var cfgs []int
|
|
||||||
for c := range d.Configs {
|
|
||||||
cfgs = append(cfgs, c)
|
|
||||||
}
|
|
||||||
sort.Ints(cfgs)
|
|
||||||
return cfgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// String represents a human readable representation of the device.
|
// String represents a human readable representation of the device.
|
||||||
func (d *Device) String() string {
|
func (d *Device) String() string {
|
||||||
return fmt.Sprintf("vid=%s,pid=%s,bus=%d,addr=%d", d.Desc.Vendor, d.Desc.Product, d.Desc.Bus, d.Desc.Address)
|
return fmt.Sprintf("vid=%s,pid=%s,bus=%d,addr=%d", d.Desc.Vendor, d.Desc.Product, d.Desc.Bus, d.Desc.Address)
|
||||||
@@ -126,12 +134,12 @@ func (d *Device) Config(cfgNum int) (*Config, error) {
|
|||||||
if d.handle == nil {
|
if d.handle == nil {
|
||||||
return nil, fmt.Errorf("Config(%d) called on %s after Close", cfgNum, d)
|
return nil, fmt.Errorf("Config(%d) called on %s after Close", cfgNum, d)
|
||||||
}
|
}
|
||||||
desc, ok := d.Desc.Configs[cfgNum]
|
desc, err := d.Desc.cfgDesc(cfgNum)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("configuration id %d not found in the descriptor of the device %s. Available config ids: %v", cfgNum, d, d.Desc.sortedConfigIds())
|
return nil, fmt.Errorf("device %s: %v", d, err)
|
||||||
}
|
}
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Desc: desc,
|
Desc: *desc,
|
||||||
dev: d,
|
dev: d,
|
||||||
claimed: make(map[int]bool),
|
claimed: make(map[int]bool),
|
||||||
}
|
}
|
||||||
@@ -212,6 +220,10 @@ func (d *Device) GetStringDescriptor(descIndex int) (string, error) {
|
|||||||
if d.handle == nil {
|
if d.handle == nil {
|
||||||
return "", fmt.Errorf("GetStringDescriptor(%d) called on %s after Close", descIndex, d)
|
return "", fmt.Errorf("GetStringDescriptor(%d) called on %s after Close", descIndex, d)
|
||||||
}
|
}
|
||||||
|
// string descriptor index value of 0 indicates no string descriptor.
|
||||||
|
if descIndex == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
return libusb.getStringDesc(d.handle, descIndex)
|
return libusb.getStringDesc(d.handle, descIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +245,31 @@ func (d *Device) SerialNumber() (string, error) {
|
|||||||
return d.GetStringDescriptor(d.Desc.iSerialNumber)
|
return d.GetStringDescriptor(d.Desc.iSerialNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigDescription returns the description of the selected device
|
||||||
|
// configuration. GetStringDescriptor's string conversion rules apply.
|
||||||
|
func (d *Device) ConfigDescription(cfg int) (string, error) {
|
||||||
|
c, err := d.Desc.cfgDesc(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("%s: %v", d, err)
|
||||||
|
}
|
||||||
|
return d.GetStringDescriptor(c.iConfiguration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceDescription returns the description of the selected interface and
|
||||||
|
// its alternate setting in a selected configuration. GetStringDescriptor's
|
||||||
|
// string conversion rules apply.
|
||||||
|
func (d *Device) InterfaceDescription(cfgNum, intfNum, altNum int) (string, error) {
|
||||||
|
cfg, err := d.Desc.cfgDesc(cfgNum)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("%s: %v", d, err)
|
||||||
|
}
|
||||||
|
alt, err := cfg.intfDesc(intfNum, altNum)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("%s, configuration %d: %v", d, cfgNum, err)
|
||||||
|
}
|
||||||
|
return d.GetStringDescriptor(alt.iInterface)
|
||||||
|
}
|
||||||
|
|
||||||
// SetAutoDetach enables/disables automatic kernel driver detachment.
|
// SetAutoDetach enables/disables automatic kernel driver detachment.
|
||||||
// When autodetach is enabled gousb will automatically detach the kernel driver
|
// When autodetach is enabled gousb will automatically detach the kernel driver
|
||||||
// on the interface and reattach it when releasing the interface.
|
// on the interface and reattach it when releasing the interface.
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestClaimAndRelease(t *testing.T) {
|
func TestClaimAndRelease(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
_, done := newFakeLibusb()
|
_, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
@@ -44,26 +45,45 @@ func TestClaimAndRelease(t *testing.T) {
|
|||||||
t.Fatalf("OpenDeviceWithVIDPID(0x8888, 0x0002): %v", err)
|
t.Fatalf("OpenDeviceWithVIDPID(0x8888, 0x0002): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mfg, err := dev.Manufacturer()
|
if mfg, err := dev.Manufacturer(); err != nil {
|
||||||
if err != nil {
|
t.Errorf("%s.Manufacturer(): error %v", dev, err)
|
||||||
t.Errorf("%s.Manufacturer(): %v", dev, err)
|
} else if want := "ACME Industries"; mfg != want {
|
||||||
|
t.Errorf("%s.Manufacturer(): %q, want %q", dev, mfg, want)
|
||||||
}
|
}
|
||||||
if mfg != "ACME Industries" {
|
if prod, err := dev.Product(); err != nil {
|
||||||
t.Errorf("%s.Manufacturer(): %q", dev, mfg)
|
t.Errorf("%s.Product(): error %v", dev, err)
|
||||||
|
} else if want := "Fidgety Gadget"; prod != want {
|
||||||
|
t.Errorf("%s.Product(): %q, want %q", dev, prod, want)
|
||||||
}
|
}
|
||||||
prod, err := dev.Product()
|
if sn, err := dev.SerialNumber(); err != nil {
|
||||||
if err != nil {
|
t.Errorf("%s.SerialNumber(): error %v", dev, err)
|
||||||
t.Errorf("%s.Product(): %v", dev, err)
|
} else if want := "01234567"; sn != want {
|
||||||
|
t.Errorf("%s.SerialNumber(): %q, want %q", dev, sn, want)
|
||||||
}
|
}
|
||||||
if prod != "Fidgety Gadget" {
|
|
||||||
t.Errorf("%s.Product(): %q", dev, prod)
|
if got, err := dev.ConfigDescription(1); err != nil {
|
||||||
|
t.Errorf("%s.ConfigDescription(1): %v", dev, err)
|
||||||
|
} else if want := "Weird configuration"; got != want {
|
||||||
|
t.Errorf("%s.ConfigDescription(1): %q, want %q", dev, got, want)
|
||||||
}
|
}
|
||||||
sn, err := dev.SerialNumber()
|
if got, err := dev.ConfigDescription(2); err == nil {
|
||||||
if err != nil {
|
t.Errorf("%s.ConfigDescription(2): %q, want error", dev, got)
|
||||||
t.Errorf("%s.SerialNumber(): %v", dev, err)
|
|
||||||
}
|
}
|
||||||
if sn != "01234567" {
|
|
||||||
t.Errorf("%s.SerialNumber(): %q", dev, sn)
|
for _, tc := range []struct {
|
||||||
|
intf, alt int
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{0, 0, "Boring setting"},
|
||||||
|
{1, 0, "Fast streaming"},
|
||||||
|
{1, 1, "Slower streaming"},
|
||||||
|
{1, 2, ""},
|
||||||
|
} {
|
||||||
|
if got, err := dev.InterfaceDescription(1, tc.intf, tc.alt); err != nil {
|
||||||
|
t.Errorf("%s.InterfaceDescription(1, %d, %d): %v", dev, tc.intf, tc.alt, err)
|
||||||
|
} else if got != tc.want {
|
||||||
|
t.Errorf("%s.InterfaceDescription(1, %d, %d): %q, want %q", dev, tc.intf, tc.alt, got, tc.want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = dev.SetAutoDetach(true); err != nil {
|
if err = dev.SetAutoDetach(true); err != nil {
|
||||||
@@ -156,6 +176,38 @@ func TestClaimAndRelease(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInterfaceDescriptionError(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
|
_, done := newFakeLibusb()
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
cfg, intf, alt int
|
||||||
|
}{
|
||||||
|
{"no config", 2, 1, 1},
|
||||||
|
{"no interface", 1, 3, 1},
|
||||||
|
{"no alt setting", 1, 1, 5},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// Can't be parallelized, depends on the shared global state set before the loop.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if desc, err := dev.InterfaceDescription(tc.cfg, tc.intf, tc.alt); err == nil {
|
||||||
|
t.Errorf("%s.InterfaceDescriptor(%d, %d, %d): %q, want error", dev, tc.cfg, tc.intf, tc.alt, desc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type failDetachLib struct {
|
type failDetachLib struct {
|
||||||
*fakeLibusb
|
*fakeLibusb
|
||||||
}
|
}
|
||||||
@@ -168,6 +220,7 @@ func (*failDetachLib) detachKernelDriver(h *libusbDevHandle, i uint8) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoDetachFailure(t *testing.T) {
|
func TestAutoDetachFailure(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
fake, done := newFakeLibusb()
|
fake, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
libusb = &failDetachLib{fake}
|
libusb = &failDetachLib{fake}
|
||||||
|
@@ -17,6 +17,7 @@ package gousb
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestEndpointReadStream(t *testing.T) {
|
func TestEndpointReadStream(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
lib, done := newFakeLibusb()
|
lib, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestEndpoint(t *testing.T) {
|
func TestEndpoint(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
lib, done := newFakeLibusb()
|
lib, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
@@ -116,6 +117,7 @@ func TestEndpoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEndpointInfo(t *testing.T) {
|
func TestEndpointInfo(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
ep EndpointDesc
|
ep EndpointDesc
|
||||||
want string
|
want string
|
||||||
@@ -161,8 +163,7 @@ func TestEndpointInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEndpointInOut(t *testing.T) {
|
func TestEndpointInOut(t *testing.T) {
|
||||||
defer func(i libusbIntf) { libusb = i }(libusb)
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
|
|
||||||
lib, done := newFakeLibusb()
|
lib, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
@@ -242,8 +243,7 @@ func TestEndpointInOut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSameEndpointNumberInOut(t *testing.T) {
|
func TestSameEndpointNumberInOut(t *testing.T) {
|
||||||
defer func(i libusbIntf) { libusb = i }(libusb)
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
|
|
||||||
_, done := newFakeLibusb()
|
_, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
|
@@ -78,14 +78,16 @@ var fakeDevices = []fakeDevice{
|
|||||||
Product: ID(0x0002),
|
Product: ID(0x0002),
|
||||||
Protocol: 255,
|
Protocol: 255,
|
||||||
Configs: map[int]ConfigDesc{1: {
|
Configs: map[int]ConfigDesc{1: {
|
||||||
Number: 1,
|
Number: 1,
|
||||||
MaxPower: Milliamperes(100),
|
MaxPower: Milliamperes(100),
|
||||||
|
iConfiguration: 5,
|
||||||
Interfaces: []InterfaceDesc{{
|
Interfaces: []InterfaceDesc{{
|
||||||
Number: 0,
|
Number: 0,
|
||||||
AltSettings: []InterfaceSetting{{
|
AltSettings: []InterfaceSetting{{
|
||||||
Number: 0,
|
Number: 0,
|
||||||
Alternate: 0,
|
Alternate: 0,
|
||||||
Class: ClassVendorSpec,
|
Class: ClassVendorSpec,
|
||||||
|
iInterface: 6,
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
Number: 1,
|
Number: 1,
|
||||||
@@ -111,6 +113,7 @@ var fakeDevices = []fakeDevice{
|
|||||||
UsageType: IsoUsageTypeData,
|
UsageType: IsoUsageTypeData,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
iInterface: 7,
|
||||||
}, {
|
}, {
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Alternate: 1,
|
Alternate: 1,
|
||||||
@@ -131,6 +134,7 @@ var fakeDevices = []fakeDevice{
|
|||||||
TransferType: TransferTypeIsochronous,
|
TransferType: TransferTypeIsochronous,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
iInterface: 8,
|
||||||
}, {
|
}, {
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Alternate: 2,
|
Alternate: 2,
|
||||||
@@ -162,6 +166,10 @@ var fakeDevices = []fakeDevice{
|
|||||||
1: "ACME Industries",
|
1: "ACME Industries",
|
||||||
2: "Fidgety Gadget",
|
2: "Fidgety Gadget",
|
||||||
3: "01234567",
|
3: "01234567",
|
||||||
|
5: "Weird configuration",
|
||||||
|
6: "Boring setting",
|
||||||
|
7: "Fast streaming",
|
||||||
|
8: "Slower streaming",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Bus 001 Device 003: ID 9999:0002
|
// Bus 001 Device 003: ID 9999:0002
|
||||||
|
@@ -52,6 +52,8 @@ type InterfaceSetting struct {
|
|||||||
// Endpoints enumerates the endpoints available on this interface with
|
// Endpoints enumerates the endpoints available on this interface with
|
||||||
// this alternate setting.
|
// this alternate setting.
|
||||||
Endpoints map[EndpointAddress]EndpointDesc
|
Endpoints map[EndpointAddress]EndpointDesc
|
||||||
|
|
||||||
|
iInterface int // index of a string descriptor describing this interface.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a InterfaceSetting) sortedEndpointIds() []string {
|
func (a InterfaceSetting) sortedEndpointIds() []string {
|
||||||
|
20
libusb.go
20
libusb.go
@@ -250,10 +250,11 @@ func (libusbImpl) getDeviceDesc(d *libusbDevice) (*DeviceDesc, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c := ConfigDesc{
|
c := ConfigDesc{
|
||||||
Number: int(cfg.bConfigurationValue),
|
Number: int(cfg.bConfigurationValue),
|
||||||
SelfPowered: (cfg.bmAttributes & selfPoweredMask) != 0,
|
SelfPowered: (cfg.bmAttributes & selfPoweredMask) != 0,
|
||||||
RemoteWakeup: (cfg.bmAttributes & remoteWakeupMask) != 0,
|
RemoteWakeup: (cfg.bmAttributes & remoteWakeupMask) != 0,
|
||||||
MaxPower: 2 * Milliamperes(cfg.MaxPower),
|
MaxPower: 2 * Milliamperes(cfg.MaxPower),
|
||||||
|
iConfiguration: int(cfg.iConfiguration),
|
||||||
}
|
}
|
||||||
// at GenX speeds MaxPower is expressed in units of 8mA, not 2mA.
|
// at GenX speeds MaxPower is expressed in units of 8mA, not 2mA.
|
||||||
if dev.Speed == SpeedSuper {
|
if dev.Speed == SpeedSuper {
|
||||||
@@ -281,11 +282,12 @@ func (libusbImpl) getDeviceDesc(d *libusbDevice) (*DeviceDesc, error) {
|
|||||||
descs := make([]InterfaceSetting, 0, len(alts))
|
descs := make([]InterfaceSetting, 0, len(alts))
|
||||||
for altNum, alt := range alts {
|
for altNum, alt := range alts {
|
||||||
i := InterfaceSetting{
|
i := InterfaceSetting{
|
||||||
Number: int(alt.bInterfaceNumber),
|
Number: int(alt.bInterfaceNumber),
|
||||||
Alternate: int(alt.bAlternateSetting),
|
Alternate: int(alt.bAlternateSetting),
|
||||||
Class: Class(alt.bInterfaceClass),
|
Class: Class(alt.bInterfaceClass),
|
||||||
SubClass: Class(alt.bInterfaceSubClass),
|
SubClass: Class(alt.bInterfaceSubClass),
|
||||||
Protocol: Protocol(alt.bInterfaceProtocol),
|
Protocol: Protocol(alt.bInterfaceProtocol),
|
||||||
|
iInterface: int(alt.iInterface),
|
||||||
}
|
}
|
||||||
if ifNum != i.Number {
|
if ifNum != i.Number {
|
||||||
return nil, fmt.Errorf("config %d interface at index %d has number %d, USB standard states they should be identical", c.Number, ifNum, i.Number)
|
return nil, fmt.Errorf("config %d interface at index %d has number %d, USB standard states they should be identical", c.Number, ifNum, i.Number)
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBCD(t *testing.T) {
|
func TestBCD(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
major, minor uint8
|
major, minor uint8
|
||||||
bcd BCD
|
bcd BCD
|
||||||
|
@@ -106,6 +106,7 @@ func (r readRes) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTransferReadStream(t *testing.T) {
|
func TestTransferReadStream(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for tcNum, tc := range []struct {
|
for tcNum, tc := range []struct {
|
||||||
desc string
|
desc string
|
||||||
closeBefore int
|
closeBefore int
|
||||||
@@ -211,7 +212,9 @@ func TestTransferReadStream(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
tcNum, tc := tcNum, tc // t.Parallel will delay the execution of the test, save the iteration values.
|
||||||
t.Run(strconv.Itoa(tcNum), func(t *testing.T) {
|
t.Run(strconv.Itoa(tcNum), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
t.Logf("Case %d: %s", tcNum, tc.desc)
|
t.Logf("Case %d: %s", tcNum, tc.desc)
|
||||||
ftt := make([]*fakeStreamTransfer, len(tc.transfers))
|
ftt := make([]*fakeStreamTransfer, len(tc.transfers))
|
||||||
tt := make([]transferIntf, len(tc.transfers))
|
tt := make([]transferIntf, len(tc.transfers))
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTransfer(t *testing.T) {
|
func TestNewTransfer(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
_, done := newFakeLibusb()
|
_, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ func TestNewTransfer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTransferProtocol(t *testing.T) {
|
func TestTransferProtocol(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
f, done := newFakeLibusb()
|
f, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ package gousb
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestOPenDevices(t *testing.T) {
|
func TestOPenDevices(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
_, done := newFakeLibusb()
|
_, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ func TestOPenDevices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenDeviceWithVIDPID(t *testing.T) {
|
func TestOpenDeviceWithVIDPID(t *testing.T) {
|
||||||
|
// Can't be parallelized, newFakeLibusb modifies a shared global state.
|
||||||
_, done := newFakeLibusb()
|
_, done := newFakeLibusb()
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user