aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/kylelemons/gousb/usb
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/kylelemons/gousb/usb')
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/config.go84
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/config_test.go32
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/constants.go184
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/debug.go37
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/descriptor.go38
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/device.go196
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/endpoint.go89
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/endpoint_info_test.go46
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/endpoint_test.go134
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/error.go101
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/fakelibusb_test.go312
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/libusb.go368
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/libusb_cgo_benchmark_test.go46
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/misc.go48
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/misc_test.go39
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/transfer.c80
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/transfer.go147
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/transfer_test.go145
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/usb.go110
-rw-r--r--vendor/github.com/kylelemons/gousb/usb/usb_test.go87
20 files changed, 2323 insertions, 0 deletions
diff --git a/vendor/github.com/kylelemons/gousb/usb/config.go b/vendor/github.com/kylelemons/gousb/usb/config.go
new file mode 100644
index 0000000..f967595
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/config.go
@@ -0,0 +1,84 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+)
+
+type EndpointInfo struct {
+ Address uint8
+ Attributes uint8
+ MaxPacketSize uint16
+ MaxIsoPacket uint32
+ PollInterval uint8
+ RefreshRate uint8
+ SynchAddress uint8
+}
+
+func (e EndpointInfo) Number() int {
+ return int(e.Address) & ENDPOINT_NUM_MASK
+}
+
+func (e EndpointInfo) TransferType() TransferType {
+ return TransferType(e.Attributes) & TRANSFER_TYPE_MASK
+}
+
+func (e EndpointInfo) Direction() EndpointDirection {
+ return EndpointDirection(e.Address) & ENDPOINT_DIR_MASK
+}
+
+func (e EndpointInfo) String() string {
+ return fmt.Sprintf("Endpoint #%d %-3s %s - %s %s [%d %d]",
+ e.Number(), e.Direction(), e.TransferType(),
+ IsoSyncType(e.Attributes)&ISO_SYNC_TYPE_MASK,
+ IsoUsageType(e.Attributes)&ISO_USAGE_TYPE_MASK,
+ e.MaxPacketSize, e.MaxIsoPacket,
+ )
+}
+
+type InterfaceInfo struct {
+ 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
+ IfSubClass uint8
+ IfProtocol uint8
+ Endpoints []EndpointInfo
+}
+
+func (a InterfaceSetup) String() string {
+ return fmt.Sprintf("Interface %02x Setup %02x", a.Number, a.Alternate)
+}
+
+type ConfigInfo struct {
+ Config uint8
+ Attributes uint8
+ MaxPower uint8
+ Interfaces []InterfaceInfo
+}
+
+func (c ConfigInfo) String() string {
+ return fmt.Sprintf("Config %02x", c.Config)
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/config_test.go b/vendor/github.com/kylelemons/gousb/usb/config_test.go
new file mode 100644
index 0000000..f4cbbcf
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/config_test.go
@@ -0,0 +1,32 @@
+package usb
+
+import "testing"
+
+func TestEndpointInfo(t *testing.T) {
+ for _, tc := range []struct {
+ ep EndpointInfo
+ want string
+ }{
+ {
+ ep: EndpointInfo{
+ Address: 0x86,
+ Attributes: 0x02,
+ MaxPacketSize: 512,
+ },
+ want: "Endpoint #6 IN bulk - unsynchronized data [512 0]",
+ },
+ {
+ ep: EndpointInfo{
+ Address: 0x02,
+ Attributes: 0x05,
+ MaxPacketSize: 512,
+ MaxIsoPacket: 512,
+ },
+ want: "Endpoint #2 OUT isochronous - asynchronous data [512 512]",
+ },
+ } {
+ if got := tc.ep.String(); got != tc.want {
+ t.Errorf("%#v.String(): got %q, want %q", tc.ep, got, tc.want)
+ }
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/constants.go b/vendor/github.com/kylelemons/gousb/usb/constants.go
new file mode 100644
index 0000000..67c41ce
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/constants.go
@@ -0,0 +1,184 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+// #include <libusb.h>
+import "C"
+
+type Class uint8
+
+const (
+ CLASS_PER_INTERFACE Class = C.LIBUSB_CLASS_PER_INTERFACE
+ CLASS_AUDIO Class = C.LIBUSB_CLASS_AUDIO
+ CLASS_COMM Class = C.LIBUSB_CLASS_COMM
+ CLASS_HID Class = C.LIBUSB_CLASS_HID
+ CLASS_PRINTER Class = C.LIBUSB_CLASS_PRINTER
+ CLASS_PTP Class = C.LIBUSB_CLASS_PTP
+ CLASS_MASS_STORAGE Class = C.LIBUSB_CLASS_MASS_STORAGE
+ CLASS_HUB Class = C.LIBUSB_CLASS_HUB
+ CLASS_DATA Class = C.LIBUSB_CLASS_DATA
+ CLASS_WIRELESS Class = C.LIBUSB_CLASS_WIRELESS
+ CLASS_APPLICATION Class = C.LIBUSB_CLASS_APPLICATION
+ CLASS_VENDOR_SPEC Class = C.LIBUSB_CLASS_VENDOR_SPEC
+)
+
+var classDescription = map[Class]string{
+ CLASS_PER_INTERFACE: "per-interface",
+ CLASS_AUDIO: "audio",
+ CLASS_COMM: "communications",
+ CLASS_HID: "human interface device",
+ CLASS_PRINTER: "printer dclass",
+ CLASS_PTP: "picture transfer protocol",
+ CLASS_MASS_STORAGE: "mass storage",
+ CLASS_HUB: "hub",
+ CLASS_DATA: "data",
+ CLASS_WIRELESS: "wireless",
+ CLASS_APPLICATION: "application",
+ CLASS_VENDOR_SPEC: "vendor-specific",
+}
+
+func (c Class) String() string {
+ return classDescription[c]
+}
+
+type DescriptorType uint8
+
+const (
+ DT_DEVICE DescriptorType = C.LIBUSB_DT_DEVICE
+ DT_CONFIG DescriptorType = C.LIBUSB_DT_CONFIG
+ DT_STRING DescriptorType = C.LIBUSB_DT_STRING
+ DT_INTERFACE DescriptorType = C.LIBUSB_DT_INTERFACE
+ DT_ENDPOINT DescriptorType = C.LIBUSB_DT_ENDPOINT
+ DT_HID DescriptorType = C.LIBUSB_DT_HID
+ DT_REPORT DescriptorType = C.LIBUSB_DT_REPORT
+ DT_PHYSICAL DescriptorType = C.LIBUSB_DT_PHYSICAL
+ DT_HUB DescriptorType = C.LIBUSB_DT_HUB
+)
+
+var descriptorTypeDescription = map[DescriptorType]string{
+ DT_DEVICE: "device",
+ DT_CONFIG: "configuration",
+ DT_STRING: "string",
+ DT_INTERFACE: "interface",
+ DT_ENDPOINT: "endpoint",
+ DT_HID: "HID",
+ DT_REPORT: "HID report",
+ DT_PHYSICAL: "physical",
+ DT_HUB: "hub",
+}
+
+func (dt DescriptorType) String() string {
+ return descriptorTypeDescription[dt]
+}
+
+type EndpointDirection uint8
+
+const (
+ ENDPOINT_NUM_MASK = 0x0f
+ ENDPOINT_DIR_IN EndpointDirection = C.LIBUSB_ENDPOINT_IN
+ ENDPOINT_DIR_OUT EndpointDirection = C.LIBUSB_ENDPOINT_OUT
+ ENDPOINT_DIR_MASK EndpointDirection = 0x80
+)
+
+var endpointDirectionDescription = map[EndpointDirection]string{
+ ENDPOINT_DIR_IN: "IN",
+ ENDPOINT_DIR_OUT: "OUT",
+}
+
+func (ed EndpointDirection) String() string {
+ return endpointDirectionDescription[ed]
+}
+
+type TransferType uint8
+
+const (
+ TRANSFER_TYPE_CONTROL TransferType = C.LIBUSB_TRANSFER_TYPE_CONTROL
+ TRANSFER_TYPE_ISOCHRONOUS TransferType = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
+ TRANSFER_TYPE_BULK TransferType = C.LIBUSB_TRANSFER_TYPE_BULK
+ TRANSFER_TYPE_INTERRUPT TransferType = C.LIBUSB_TRANSFER_TYPE_INTERRUPT
+ TRANSFER_TYPE_MASK TransferType = 0x03
+)
+
+var transferTypeDescription = map[TransferType]string{
+ TRANSFER_TYPE_CONTROL: "control",
+ TRANSFER_TYPE_ISOCHRONOUS: "isochronous",
+ TRANSFER_TYPE_BULK: "bulk",
+ TRANSFER_TYPE_INTERRUPT: "interrupt",
+}
+
+func (tt TransferType) String() string {
+ return transferTypeDescription[tt]
+}
+
+type IsoSyncType uint8
+
+const (
+ ISO_SYNC_TYPE_NONE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_NONE << 2
+ ISO_SYNC_TYPE_ASYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ASYNC << 2
+ ISO_SYNC_TYPE_ADAPTIVE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ADAPTIVE << 2
+ ISO_SYNC_TYPE_SYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_SYNC << 2
+ ISO_SYNC_TYPE_MASK IsoSyncType = 0x0C
+)
+
+var isoSyncTypeDescription = map[IsoSyncType]string{
+ ISO_SYNC_TYPE_NONE: "unsynchronized",
+ ISO_SYNC_TYPE_ASYNC: "asynchronous",
+ ISO_SYNC_TYPE_ADAPTIVE: "adaptive",
+ ISO_SYNC_TYPE_SYNC: "synchronous",
+}
+
+func (ist IsoSyncType) String() string {
+ return isoSyncTypeDescription[ist]
+}
+
+type IsoUsageType uint8
+
+const (
+ ISO_USAGE_TYPE_DATA IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_DATA << 4
+ ISO_USAGE_TYPE_FEEDBACK IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_FEEDBACK << 4
+ ISO_USAGE_TYPE_IMPLICIT IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_IMPLICIT << 4
+ ISO_USAGE_TYPE_MASK IsoUsageType = 0x30
+)
+
+var isoUsageTypeDescription = map[IsoUsageType]string{
+ ISO_USAGE_TYPE_DATA: "data",
+ ISO_USAGE_TYPE_FEEDBACK: "feedback",
+ ISO_USAGE_TYPE_IMPLICIT: "implicit data",
+}
+
+func (iut IsoUsageType) String() string {
+ return isoUsageTypeDescription[iut]
+}
+
+type RequestType uint8
+
+const (
+ REQUEST_TYPE_STANDARD = C.LIBUSB_REQUEST_TYPE_STANDARD
+ REQUEST_TYPE_CLASS = C.LIBUSB_REQUEST_TYPE_CLASS
+ REQUEST_TYPE_VENDOR = C.LIBUSB_REQUEST_TYPE_VENDOR
+ REQUEST_TYPE_RESERVED = C.LIBUSB_REQUEST_TYPE_RESERVED
+)
+
+var requestTypeDescription = map[RequestType]string{
+ REQUEST_TYPE_STANDARD: "standard",
+ REQUEST_TYPE_CLASS: "class",
+ REQUEST_TYPE_VENDOR: "vendor",
+ REQUEST_TYPE_RESERVED: "reserved",
+}
+
+func (rt RequestType) String() string {
+ return requestTypeDescription[rt]
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/debug.go b/vendor/github.com/kylelemons/gousb/usb/debug.go
new file mode 100644
index 0000000..c3e061d
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/debug.go
@@ -0,0 +1,37 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+// To enable internal debugging:
+// -ldflags "-X github.com/kylelemons/gousb/usb.debugInternal true"
+
+import (
+ "io"
+ "io/ioutil"
+ "log" // TODO(kevlar): make a logger
+ "os"
+)
+
+var debug *log.Logger
+var debugInternal string
+
+func init() {
+ var out io.Writer = ioutil.Discard
+ if debugInternal != "" {
+ out = os.Stderr
+ }
+ debug = log.New(out, "usb", log.LstdFlags|log.Lshortfile)
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/descriptor.go b/vendor/github.com/kylelemons/gousb/usb/descriptor.go
new file mode 100644
index 0000000..76a9b77
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/descriptor.go
@@ -0,0 +1,38 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+type Descriptor struct {
+ // Bus information
+ Bus uint8 // The bus on which the device was detected
+ Address uint8 // The address of the device on the bus
+
+ // Version information
+ Spec BCD // USB Specification Release Number
+ Device BCD // The device version
+
+ // Product information
+ Vendor ID // The Vendor identifer
+ Product ID // The Product identifier
+
+ // Protocol information
+ Class uint8 // The class of this device
+ SubClass uint8 // The sub-class (within the class) of this device
+ Protocol uint8 // The protocol (within the sub-class) of this device
+
+ // Configuration information
+ Configs []ConfigInfo
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/device.go b/vendor/github.com/kylelemons/gousb/usb/device.go
new file mode 100644
index 0000000..bc22287
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/device.go
@@ -0,0 +1,196 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+ "sync"
+ "time"
+)
+
+var DefaultReadTimeout = 1 * time.Second
+var DefaultWriteTimeout = 1 * time.Second
+var DefaultControlTimeout = 250 * time.Millisecond //5 * time.Second
+
+type Device struct {
+ handle *libusbDevHandle
+
+ // Embed the device information for easy access
+ *Descriptor
+
+ // Timeouts
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+ ControlTimeout time.Duration
+
+ // Claimed interfaces
+ lock *sync.Mutex
+ claimed map[uint8]int
+}
+
+func newDevice(handle *libusbDevHandle, desc *Descriptor) *Device {
+ ifaces := 0
+ d := &Device{
+ handle: handle,
+ Descriptor: desc,
+ ReadTimeout: DefaultReadTimeout,
+ WriteTimeout: DefaultWriteTimeout,
+ ControlTimeout: DefaultControlTimeout,
+ lock: new(sync.Mutex),
+ claimed: make(map[uint8]int, ifaces),
+ }
+
+ return d
+}
+
+func (d *Device) Reset() error {
+ return libusb.reset(d.handle)
+}
+
+func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
+ return libusb.control(d.handle, d.ControlTimeout, rType, request, val, idx, data)
+}
+
+// ActiveConfig returns the config id (not the index) of the active configuration.
+// This corresponds to the ConfigInfo.Config field.
+func (d *Device) ActiveConfig() (uint8, error) {
+ return libusb.getConfig(d.handle)
+}
+
+// SetConfig attempts to change the active configuration.
+// The cfg provided is the config id (not the index) of the configuration to set,
+// which corresponds to the ConfigInfo.Config field.
+func (d *Device) SetConfig(cfg uint8) error {
+ return libusb.setConfig(d.handle, cfg)
+}
+
+// Close the device.
+func (d *Device) Close() error {
+ if d.handle == nil {
+ return fmt.Errorf("usb: double close on device")
+ }
+ d.lock.Lock()
+ defer d.lock.Unlock()
+ for iface := range d.claimed {
+ libusb.release(d.handle, iface)
+ }
+ libusb.close(d.handle)
+ d.handle = nil
+ return nil
+}
+
+func (d *Device) OpenEndpoint(cfgNum, ifNum, setNum, epNum uint8) (Endpoint, error) {
+ var cfg *ConfigInfo
+ for _, c := range d.Configs {
+ if c.Config == cfgNum {
+ debug.Printf("found conf: %#v\n", c)
+ cfg = &c
+ break
+ }
+ }
+ if cfg == nil {
+ return nil, fmt.Errorf("usb: unknown configuration %02x", cfgNum)
+ }
+
+ var intf *InterfaceInfo
+ for _, i := range cfg.Interfaces {
+ if i.Number == ifNum {
+ debug.Printf("found iface: %#v\n", i)
+ intf = &i
+ break
+ }
+ }
+ if intf == nil {
+ return nil, fmt.Errorf("usb: unknown interface %02x", ifNum)
+ }
+
+ var setAlternate bool
+ var ifs *InterfaceSetup
+ for i, s := range intf.Setups {
+ if s.Alternate == setNum {
+ setAlternate = i != 0
+ debug.Printf("found setup: %#v [default: %v]\n", s, !setAlternate)
+ ifs = &s
+ break
+ }
+ }
+ if ifs == nil {
+ return nil, fmt.Errorf("usb: unknown setup %02x", setNum)
+ }
+
+ var ep *EndpointInfo
+ for _, e := range ifs.Endpoints {
+ if e.Address == epNum {
+ debug.Printf("found ep %02x in %#v\n", epNum, *ifs)
+ ep = &e
+ break
+ }
+ }
+ if ep == nil {
+ return nil, fmt.Errorf("usb: unknown endpoint %02x", epNum)
+ }
+
+ end := newEndpoint(d.handle, *ifs, *ep, d.ReadTimeout, d.WriteTimeout)
+
+ // Set the configuration
+ activeConf, err := libusb.getConfig(d.handle)
+ if err != nil {
+ return nil, fmt.Errorf("usb: getcfg: %s", err)
+ }
+ if activeConf != cfgNum {
+ if err := libusb.setConfig(d.handle, cfgNum); err != nil {
+ return nil, fmt.Errorf("usb: setcfg: %s", err)
+ }
+ }
+
+ // Claim the interface
+ if err := libusb.claim(d.handle, ifNum); err != nil {
+ return nil, fmt.Errorf("usb: claim: %s", err)
+ }
+
+ // Increment the claim count
+ d.lock.Lock()
+ d.claimed[ifNum]++
+ d.lock.Unlock() // unlock immediately because the next calls may block
+
+ // Choose the alternate
+ if setAlternate {
+ if err := libusb.setAlt(d.handle, ifNum, setNum); err != nil {
+ return nil, fmt.Errorf("usb: setalt: %s", err)
+ }
+ }
+
+ return end, nil
+}
+
+func (d *Device) GetStringDescriptor(desc_index int) (string, error) {
+ return libusb.getStringDesc(d.handle, desc_index)
+}
+
+// SetAutoDetach enables/disables libusb's automatic kernel driver detachment.
+// When autodetach is enabled libusb will automatically detach the kernel driver
+// 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 {
+ var autodetachInt int
+ switch autodetach {
+ case true:
+ autodetachInt = 1
+ case false:
+ autodetachInt = 0
+ }
+ return libusb.setAutoDetach(d.handle, autodetachInt)
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/endpoint.go b/vendor/github.com/kylelemons/gousb/usb/endpoint.go
new file mode 100644
index 0000000..067fa63
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/endpoint.go
@@ -0,0 +1,89 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+ "time"
+)
+
+type Endpoint interface {
+ Read(b []byte) (int, error)
+ Write(b []byte) (int, error)
+ Interface() InterfaceSetup
+ Info() EndpointInfo
+}
+
+type endpoint struct {
+ h *libusbDevHandle
+
+ InterfaceSetup
+ EndpointInfo
+
+ readTimeout time.Duration
+ writeTimeout time.Duration
+}
+
+func (e *endpoint) Read(buf []byte) (int, error) {
+ if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_IN {
+ return 0, fmt.Errorf("usb: read: not an IN endpoint")
+ }
+
+ return e.transfer(buf, e.readTimeout)
+}
+
+func (e *endpoint) Write(buf []byte) (int, error) {
+ if EndpointDirection(e.Address)&ENDPOINT_DIR_MASK != ENDPOINT_DIR_OUT {
+ return 0, fmt.Errorf("usb: write: not an OUT endpoint")
+ }
+
+ return e.transfer(buf, e.writeTimeout)
+}
+
+func (e *endpoint) Interface() InterfaceSetup { return e.InterfaceSetup }
+func (e *endpoint) Info() EndpointInfo { return e.EndpointInfo }
+
+func (e *endpoint) transfer(buf []byte, timeout time.Duration) (int, error) {
+ if len(buf) == 0 {
+ return 0, nil
+ }
+
+ t, err := newUSBTransfer(e.h, e.EndpointInfo, buf, timeout)
+ if err != nil {
+ return 0, err
+ }
+ defer t.free()
+
+ if err := t.submit(); err != nil {
+ return 0, err
+ }
+
+ n, err := t.wait()
+ if err != nil {
+ return n, err
+ }
+ return n, nil
+}
+
+func newEndpoint(h *libusbDevHandle, s InterfaceSetup, e EndpointInfo, rt, wt time.Duration) *endpoint {
+ return &endpoint{
+ InterfaceSetup: s,
+ EndpointInfo: e,
+ h: h,
+ readTimeout: rt,
+ writeTimeout: wt,
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/endpoint_info_test.go b/vendor/github.com/kylelemons/gousb/usb/endpoint_info_test.go
new file mode 100644
index 0000000..d19a323
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/endpoint_info_test.go
@@ -0,0 +1,46 @@
+// Copyright 2017 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+// IN bulk endpoint
+var testBulkInEP = EndpointInfo{
+ Address: 0x82,
+ Attributes: uint8(TRANSFER_TYPE_BULK),
+ MaxPacketSize: 512,
+ PollInterval: 1,
+}
+
+var testBulkInSetup = InterfaceSetup{
+ Number: 0,
+ Alternate: 0,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{testBulkInEP},
+}
+
+// OUT iso endpoint
+var testIsoOutEP = EndpointInfo{
+ Address: 0x06,
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 3<<11 + 1024,
+ MaxIsoPacket: 3 * 1024,
+ PollInterval: 1,
+}
+
+var testIsoOutSetup = InterfaceSetup{
+ Number: 0,
+ Alternate: 0,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{testIsoOutEP},
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/endpoint_test.go b/vendor/github.com/kylelemons/gousb/usb/endpoint_test.go
new file mode 100644
index 0000000..8f31099
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/endpoint_test.go
@@ -0,0 +1,134 @@
+// Copyright 2017 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestEndpoint(t *testing.T) {
+ defer func(i libusbIntf) { libusb = i }(libusb)
+ for _, epCfg := range []struct {
+ method string
+ InterfaceSetup
+ EndpointInfo
+ }{
+ {"Read", testBulkInSetup, testBulkInEP},
+ {"Write", testIsoOutSetup, testIsoOutEP},
+ } {
+ t.Run(epCfg.method, func(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ buf []byte
+ ret int
+ status TransferStatus
+ want int
+ wantErr bool
+ }{
+ {
+ desc: "empty buffer",
+ buf: nil,
+ ret: 10,
+ want: 0,
+ },
+ {
+ desc: "128B buffer, 60 transferred",
+ buf: make([]byte, 128),
+ ret: 60,
+ want: 60,
+ },
+ {
+ desc: "128B buffer, 10 transferred and then error",
+ buf: make([]byte, 128),
+ ret: 10,
+ status: LIBUSB_TRANSFER_ERROR,
+ want: 10,
+ wantErr: true,
+ },
+ } {
+ lib := newFakeLibusb()
+ libusb = lib
+ ep := newEndpoint(nil, epCfg.InterfaceSetup, epCfg.EndpointInfo, time.Second, time.Second)
+ op, ok := reflect.TypeOf(ep).MethodByName(epCfg.method)
+ if !ok {
+ t.Fatalf("method %s not found in endpoint struct", epCfg.method)
+ }
+ go func() {
+ fakeT := lib.waitForSubmitted()
+ fakeT.length = tc.ret
+ fakeT.status = tc.status
+ close(fakeT.done)
+ }()
+ opv := op.Func.Interface().(func(*endpoint, []byte) (int, error))
+ got, err := opv(ep, tc.buf)
+ if (err != nil) != tc.wantErr {
+ t.Errorf("%s: bulkInEP.Read(): got err: %v, err != nil is %v, want %v", tc.desc, err, err != nil, tc.wantErr)
+ continue
+ }
+ if got != tc.want {
+ t.Errorf("%s: bulkInEP.Read(): got %d bytes, want %d", tc.desc, got, tc.want)
+ }
+ }
+ })
+ }
+}
+
+func TestEndpointWrongDirection(t *testing.T) {
+ ep := &endpoint{
+ InterfaceSetup: testBulkInSetup,
+ EndpointInfo: testBulkInEP,
+ }
+ _, err := ep.Write([]byte{1, 2, 3})
+ if err == nil {
+ t.Error("bulkInEP.Write(): got nil error, want non-nil")
+ }
+ ep = &endpoint{
+ InterfaceSetup: testIsoOutSetup,
+ EndpointInfo: testIsoOutEP,
+ }
+ _, err = ep.Read(make([]byte, 64))
+ if err == nil {
+ t.Error("isoOutEP.Read(): got nil error, want non-nil")
+ }
+}
+
+func TestOpenEndpoint(t *testing.T) {
+ origLib := libusb
+ defer func() { libusb = origLib }()
+ libusb = newFakeLibusb()
+
+ c := NewContext()
+ 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): got error %v, want nil", err)
+ }
+ ep, err := dev.OpenEndpoint(1, 1, 1, 0x86)
+ if err != nil {
+ t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): got error %v, want nil", err)
+ }
+ i := ep.Info()
+ if got, want := i.Address, uint8(0x86); got != want {
+ t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): ep.Info.Address = %x, want %x", got, want)
+ }
+ if got, want := i.MaxIsoPacket, uint32(2*1024); got != want {
+ t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): ep.Info.MaxIsoPacket = %d, want %d", got, want)
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/error.go b/vendor/github.com/kylelemons/gousb/usb/error.go
new file mode 100644
index 0000000..892c54d
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/error.go
@@ -0,0 +1,101 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+)
+
+// #include <libusb.h>
+import "C"
+
+type usbError C.int
+
+func (e usbError) Error() string {
+ return fmt.Sprintf("libusb: %s [code %d]", usbErrorString[e], int(e))
+}
+
+func fromUSBError(errno C.int) error {
+ err := usbError(errno)
+ if err == SUCCESS {
+ return nil
+ }
+ return err
+}
+
+const (
+ SUCCESS usbError = C.LIBUSB_SUCCESS
+ ERROR_IO usbError = C.LIBUSB_ERROR_IO
+ ERROR_INVALID_PARAM usbError = C.LIBUSB_ERROR_INVALID_PARAM
+ ERROR_ACCESS usbError = C.LIBUSB_ERROR_ACCESS
+ ERROR_NO_DEVICE usbError = C.LIBUSB_ERROR_NO_DEVICE
+ ERROR_NOT_FOUND usbError = C.LIBUSB_ERROR_NOT_FOUND
+ ERROR_BUSY usbError = C.LIBUSB_ERROR_BUSY
+ ERROR_TIMEOUT usbError = C.LIBUSB_ERROR_TIMEOUT
+ ERROR_OVERFLOW usbError = C.LIBUSB_ERROR_OVERFLOW
+ ERROR_PIPE usbError = C.LIBUSB_ERROR_PIPE
+ ERROR_INTERRUPTED usbError = C.LIBUSB_ERROR_INTERRUPTED
+ ERROR_NO_MEM usbError = C.LIBUSB_ERROR_NO_MEM
+ ERROR_NOT_SUPPORTED usbError = C.LIBUSB_ERROR_NOT_SUPPORTED
+ ERROR_OTHER usbError = C.LIBUSB_ERROR_OTHER
+)
+
+var usbErrorString = map[usbError]string{
+ C.LIBUSB_SUCCESS: "success",
+ C.LIBUSB_ERROR_IO: "i/o error",
+ C.LIBUSB_ERROR_INVALID_PARAM: "invalid param",
+ C.LIBUSB_ERROR_ACCESS: "bad access",
+ C.LIBUSB_ERROR_NO_DEVICE: "no device",
+ C.LIBUSB_ERROR_NOT_FOUND: "not found",
+ C.LIBUSB_ERROR_BUSY: "device or resource busy",
+ C.LIBUSB_ERROR_TIMEOUT: "timeout",
+ C.LIBUSB_ERROR_OVERFLOW: "overflow",
+ C.LIBUSB_ERROR_PIPE: "pipe error",
+ C.LIBUSB_ERROR_INTERRUPTED: "interrupted",
+ C.LIBUSB_ERROR_NO_MEM: "out of memory",
+ C.LIBUSB_ERROR_NOT_SUPPORTED: "not supported",
+ C.LIBUSB_ERROR_OTHER: "unknown error",
+}
+
+type TransferStatus uint8
+
+const (
+ LIBUSB_TRANSFER_COMPLETED TransferStatus = C.LIBUSB_TRANSFER_COMPLETED
+ LIBUSB_TRANSFER_ERROR TransferStatus = C.LIBUSB_TRANSFER_ERROR
+ LIBUSB_TRANSFER_TIMED_OUT TransferStatus = C.LIBUSB_TRANSFER_TIMED_OUT
+ LIBUSB_TRANSFER_CANCELLED TransferStatus = C.LIBUSB_TRANSFER_CANCELLED
+ LIBUSB_TRANSFER_STALL TransferStatus = C.LIBUSB_TRANSFER_STALL
+ LIBUSB_TRANSFER_NO_DEVICE TransferStatus = C.LIBUSB_TRANSFER_NO_DEVICE
+ LIBUSB_TRANSFER_OVERFLOW TransferStatus = C.LIBUSB_TRANSFER_OVERFLOW
+)
+
+var transferStatusDescription = map[TransferStatus]string{
+ LIBUSB_TRANSFER_COMPLETED: "transfer completed without error",
+ LIBUSB_TRANSFER_ERROR: "transfer failed",
+ LIBUSB_TRANSFER_TIMED_OUT: "transfer timed out",
+ LIBUSB_TRANSFER_CANCELLED: "transfer was cancelled",
+ LIBUSB_TRANSFER_STALL: "halt condition detected (endpoint stalled) or control request not supported",
+ LIBUSB_TRANSFER_NO_DEVICE: "device was disconnected",
+ LIBUSB_TRANSFER_OVERFLOW: "device sent more data than requested",
+}
+
+func (ts TransferStatus) String() string {
+ return transferStatusDescription[ts]
+}
+
+func (ts TransferStatus) Error() string {
+ return "libusb: " + ts.String()
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/fakelibusb_test.go b/vendor/github.com/kylelemons/gousb/usb/fakelibusb_test.go
new file mode 100644
index 0000000..c658d2e
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/fakelibusb_test.go
@@ -0,0 +1,312 @@
+// Copyright 2017 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+ "unsafe"
+)
+
+var (
+ // fake devices connected through the fakeLibusb stack.
+ fakeDevices = []*Descriptor{
+ // Bus 001 Device 001: ID 9999:0001
+ // One config, one interface, one setup,
+ // two endpoints: 0x01 OUT, 0x82 IN.
+ &Descriptor{
+ Bus: 1,
+ Address: 1,
+ Spec: USB_2_0,
+ Device: BCD(0x0100), // 1.00
+ Vendor: ID(0x9999),
+ Product: ID(0x0001),
+ Protocol: 255,
+ Configs: []ConfigInfo{{
+ Config: 1,
+ MaxPower: 50, // * 2mA
+ Interfaces: []InterfaceInfo{{
+ Number: 0,
+ Setups: []InterfaceSetup{{
+ Number: 0,
+ Alternate: 0,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{{
+ Address: uint8(0x01 | ENDPOINT_DIR_OUT),
+ Attributes: uint8(TRANSFER_TYPE_BULK),
+ MaxPacketSize: 512,
+ }, {
+ Address: uint8(0x02 | ENDPOINT_DIR_IN),
+ Attributes: uint8(TRANSFER_TYPE_BULK),
+ MaxPacketSize: 512,
+ }},
+ }},
+ }},
+ }},
+ },
+ // Bus 001 Device 002: ID 8888:0002
+ // One config, two interfaces. interface #0 with no endpoints,
+ // interface #1 with two alt setups with different packet sizes for
+ // endpoints. Two isochronous endpoints, 0x05 OUT and 0x86 OUT.
+ &Descriptor{
+ Bus: 1,
+ Address: 2,
+ Spec: USB_2_0,
+ Device: BCD(0x0103), // 1.03
+ Vendor: ID(0x8888),
+ Product: ID(0x0002),
+ Protocol: 255,
+ Configs: []ConfigInfo{{
+ Config: 1,
+ MaxPower: 50, // * 2mA
+ Interfaces: []InterfaceInfo{{
+ Number: 0,
+ Setups: []InterfaceSetup{{
+ Number: 0,
+ Alternate: 0,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ }},
+ }, {
+ Number: 1,
+ Setups: []InterfaceSetup{{
+ Number: 1,
+ Alternate: 0,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{{
+ Address: uint8(0x05 | ENDPOINT_DIR_OUT),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 2<<11 | 1024,
+ MaxIsoPacket: 3 * 1024,
+ }, {
+ Address: uint8(0x06 | ENDPOINT_DIR_IN),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 2<<11 | 1024,
+ MaxIsoPacket: 3 * 1024,
+ }},
+ }, {
+ Number: 1,
+ Alternate: 1,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{{
+ Address: uint8(0x05 | ENDPOINT_DIR_OUT),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 1<<11 | 1024,
+ MaxIsoPacket: 2 * 1024,
+ }, {
+ Address: uint8(0x06 | ENDPOINT_DIR_IN),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 1<<11 | 1024,
+ MaxIsoPacket: 2 * 1024,
+ }},
+ }, {
+ Number: 1,
+ Alternate: 2,
+ IfClass: uint8(CLASS_VENDOR_SPEC),
+ Endpoints: []EndpointInfo{{
+ Address: uint8(0x05 | ENDPOINT_DIR_OUT),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 1024,
+ MaxIsoPacket: 1024,
+ }, {
+ Address: uint8(0x06 | ENDPOINT_DIR_IN),
+ Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
+ MaxPacketSize: 1024,
+ MaxIsoPacket: 1024,
+ }},
+ }},
+ }},
+ }},
+ },
+ }
+)
+
+type fakeDevice struct {
+ desc *Descriptor
+ alt uint8
+}
+
+type fakeTransfer struct {
+ // done is the channel that needs to be closed when the transfer has finished.
+ done chan struct{}
+ // buf is the slice for reading/writing data between the submit() and wait() returning.
+ buf []byte
+ // status will be returned by wait() on this transfer
+ status TransferStatus
+ // length is the number of bytes used from the buffer (write) or available
+ // in the buffer (read).
+ length int
+}
+
+// fakeLibusb implements a fake libusb stack that pretends to have a number of
+// devices connected to it (see fakeDevices variable for a list of devices).
+// fakeLibusb is expected to implement all the functions related to device
+// enumeration, configuration etc. according to fakeDevices descriptors.
+// The fake devices endpoints don't have any particular behavior implemented,
+// instead fakeLibusb provides additional functions, like waitForSubmitted,
+// that allows the test to explicitly control individual transfer behavior.
+type fakeLibusb struct {
+ mu sync.Mutex
+ // fakeDevices has a map of devices and their descriptors.
+ fakeDevices map[*libusbDevice]*fakeDevice
+ // ts has a map of all allocated transfers, indexed by the pointer of
+ // underlying libusbTransfer.
+ ts map[*libusbTransfer]*fakeTransfer
+ // submitted receives a fakeTransfers when submit() is called.
+ submitted chan *fakeTransfer
+ // handles is a map of device handles pointing at opened devices.
+ handles map[*libusbDevHandle]*libusbDevice
+ // claims is a map of devices to a set of claimed interfaces
+ claims map[*libusbDevice]map[uint8]bool
+}
+
+func (f *fakeLibusb) init() (*libusbContext, error) { return new(libusbContext), nil }
+func (f *fakeLibusb) handleEvents(c *libusbContext, done <-chan struct{}) { <-done }
+func (f *fakeLibusb) getDevices(*libusbContext) ([]*libusbDevice, error) {
+ ret := make([]*libusbDevice, 0, len(fakeDevices))
+ for d := range f.fakeDevices {
+ ret = append(ret, d)
+ }
+ return ret, nil
+}
+func (f *fakeLibusb) exit(*libusbContext) {}
+func (f *fakeLibusb) setDebug(*libusbContext, int) {}
+
+func (f *fakeLibusb) dereference(d *libusbDevice) {}
+func (f *fakeLibusb) getDeviceDesc(d *libusbDevice) (*Descriptor, error) {
+ if dev, ok := f.fakeDevices[d]; ok {
+ return dev.desc, nil
+ }
+ return nil, fmt.Errorf("invalid USB device %p", d)
+}
+func (f *fakeLibusb) open(d *libusbDevice) (*libusbDevHandle, error) {
+ h := new(libusbDevHandle)
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ f.handles[h] = d
+ return h, nil
+}
+
+func (f *fakeLibusb) close(h *libusbDevHandle) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ delete(f.handles, h)
+}
+func (f *fakeLibusb) reset(*libusbDevHandle) error { return nil }
+func (f *fakeLibusb) control(*libusbDevHandle, time.Duration, uint8, uint8, uint16, uint16, []byte) (int, error) {
+ return 0, errors.New("not implemented")
+}
+func (f *fakeLibusb) getConfig(*libusbDevHandle) (uint8, error) { return 1, nil }
+func (f *fakeLibusb) setConfig(d *libusbDevHandle, cfg uint8) error {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ if len(f.claims[f.handles[d]]) != 0 {
+ return fmt.Errorf("can't set device config while interfaces are claimed: %v", f.claims[f.handles[d]])
+ }
+ if cfg != 1 {
+ return fmt.Errorf("device doesn't have config number %d", cfg)
+ }
+ return nil
+}
+func (f *fakeLibusb) getStringDesc(*libusbDevHandle, int) (string, error) {
+ return "", errors.New("not implemented")
+}
+func (f *fakeLibusb) setAutoDetach(*libusbDevHandle, int) error { return nil }
+
+func (f *fakeLibusb) claim(d *libusbDevHandle, intf uint8) error {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ c := f.claims[f.handles[d]]
+ if c == nil {
+ c = make(map[uint8]bool)
+ f.claims[f.handles[d]] = c
+ }
+ c[intf] = true
+ return nil
+}
+func (f *fakeLibusb) release(d *libusbDevHandle, intf uint8) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ c := f.claims[f.handles[d]]
+ if c == nil {
+ return
+ }
+ c[intf] = false
+}
+func (f *fakeLibusb) setAlt(d *libusbDevHandle, intf, alt uint8) error {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ if !f.claims[f.handles[d]][intf] {
+ return fmt.Errorf("interface %d must be claimed before alt setup can be set", intf)
+ }
+ f.fakeDevices[f.handles[d]].alt = alt
+ return nil
+}
+
+func (f *fakeLibusb) alloc(_ *libusbDevHandle, _ uint8, _ TransferType, _ time.Duration, _ int, buf []byte) (*libusbTransfer, error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ t := new(libusbTransfer)
+ f.ts[t] = &fakeTransfer{buf: buf}
+ return t, nil
+}
+func (f *fakeLibusb) cancel(t *libusbTransfer) error { return errors.New("not implemented") }
+func (f *fakeLibusb) submit(t *libusbTransfer, done chan struct{}) error {
+ f.mu.Lock()
+ ft := f.ts[t]
+ f.mu.Unlock()
+ ft.done = done
+ f.submitted <- ft
+ return nil
+}
+func (f *fakeLibusb) data(t *libusbTransfer) (int, TransferStatus) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return f.ts[t].length, f.ts[t].status
+}
+func (f *fakeLibusb) free(t *libusbTransfer) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ delete(f.ts, t)
+}
+func (f *fakeLibusb) setIsoPacketLengths(*libusbTransfer, uint32) {}
+
+// waitForSubmitted can be used by tests to define custom behavior of the transfers submitted on the USB bus.
+// TODO(sebek): add fields in fakeTransfer to differentiate between different devices/endpoints used concurrently.
+func (f *fakeLibusb) waitForSubmitted() *fakeTransfer {
+ return <-f.submitted
+}
+
+func newFakeLibusb() *fakeLibusb {
+ fl := &fakeLibusb{
+ fakeDevices: make(map[*libusbDevice]*fakeDevice),
+ ts: make(map[*libusbTransfer]*fakeTransfer),
+ submitted: make(chan *fakeTransfer, 10),
+ handles: make(map[*libusbDevHandle]*libusbDevice),
+ claims: make(map[*libusbDevice]map[uint8]bool),
+ }
+ for i, d := range fakeDevices {
+ // libusb does not export a way to allocate a new libusb_device struct
+ // without using the full USB stack. Since the fake library uses the
+ // libusbDevice only as an identifier, use arbitrary numbers pretending
+ // to be pointers. The contents of these pointers is never accessed.
+ fl.fakeDevices[(*libusbDevice)(unsafe.Pointer(uintptr(i)))] = &fakeDevice{
+ desc: d,
+ alt: 0,
+ }
+ }
+ return fl
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/libusb.go b/vendor/github.com/kylelemons/gousb/usb/libusb.go
new file mode 100644
index 0000000..22856e4
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/libusb.go
@@ -0,0 +1,368 @@
+// Copyright 2017 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+ "log"
+ "reflect"
+ "time"
+ "unsafe"
+)
+
+/*
+#cgo pkg-config: libusb-1.0
+#include <libusb.h>
+
+int compact_iso_data(struct libusb_transfer *xfer, unsigned char *status);
+int submit(struct libusb_transfer *xfer);
+*/
+import "C"
+
+type libusbContext C.libusb_context
+type libusbDevice C.libusb_device
+type libusbDevHandle C.libusb_device_handle
+type libusbTransfer C.struct_libusb_transfer
+
+// libusbIntf is a set of trivial idiomatic Go wrappers around libusb C functions.
+// The underlying code is generally not testable or difficult to test,
+// since libusb interacts directly with the host USB stack.
+//
+// All functions here should operate on types defined on C.libusb* data types,
+// and occasionally on convenience data types (like TransferType or Descriptor).
+type libusbIntf interface {
+ // context
+ init() (*libusbContext, error)
+ handleEvents(*libusbContext, <-chan struct{})
+ getDevices(*libusbContext) ([]*libusbDevice, error)
+ exit(*libusbContext)
+ setDebug(*libusbContext, int)
+
+ // device
+ dereference(*libusbDevice)
+ getDeviceDesc(*libusbDevice) (*Descriptor, error)
+ open(*libusbDevice) (*libusbDevHandle, error)
+
+ close(*libusbDevHandle)
+ reset(*libusbDevHandle) error
+ control(*libusbDevHandle, time.Duration, uint8, uint8, uint16, uint16, []byte) (int, error)
+ getConfig(*libusbDevHandle) (uint8, error)
+ setConfig(*libusbDevHandle, uint8) error
+ getStringDesc(*libusbDevHandle, int) (string, error)
+ setAutoDetach(*libusbDevHandle, int) error
+
+ // interface
+ claim(*libusbDevHandle, uint8) error
+ release(*libusbDevHandle, uint8)
+ setAlt(*libusbDevHandle, uint8, uint8) error
+
+ // transfer
+ alloc(*libusbDevHandle, uint8, TransferType, time.Duration, int, []byte) (*libusbTransfer, error)
+ cancel(*libusbTransfer) error
+ submit(*libusbTransfer, chan struct{}) error
+ data(*libusbTransfer) (int, TransferStatus)
+ free(*libusbTransfer)
+ setIsoPacketLengths(*libusbTransfer, uint32)
+}
+
+// libusbImpl is an implementation of libusbIntf using real CGo-wrapped libusb.
+type libusbImpl struct{}
+
+func (libusbImpl) init() (*libusbContext, error) {
+ var ctx *C.libusb_context
+ if err := fromUSBError(C.libusb_init(&ctx)); err != nil {
+ return nil, err
+ }
+ return (*libusbContext)(ctx), nil
+}
+
+func (libusbImpl) handleEvents(c *libusbContext, done <-chan struct{}) {
+ tv := C.struct_timeval{tv_usec: 100e3}
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ }
+ if errno := C.libusb_handle_events_timeout_completed((*C.libusb_context)(c), &tv, nil); errno < 0 {
+ log.Printf("handle_events: error: %s", usbError(errno))
+ }
+ }
+}
+
+func (libusbImpl) getDevices(ctx *libusbContext) ([]*libusbDevice, error) {
+ var list **C.libusb_device
+ cnt := C.libusb_get_device_list((*C.libusb_context)(ctx), &list)
+ if cnt < 0 {
+ return nil, fromUSBError(C.int(cnt))
+ }
+ var devs []*C.libusb_device
+ *(*reflect.SliceHeader)(unsafe.Pointer(&devs)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(list)),
+ Len: int(cnt),
+ Cap: int(cnt),
+ }
+ var ret []*libusbDevice
+ for _, d := range devs {
+ ret = append(ret, (*libusbDevice)(d))
+ }
+ // devices will be dereferenced later, during close.
+ C.libusb_free_device_list(list, 0)
+ return ret, nil
+}
+
+func (libusbImpl) exit(c *libusbContext) {
+ C.libusb_exit((*C.libusb_context)(c))
+}
+
+func (libusbImpl) setDebug(c *libusbContext, lvl int) {
+ C.libusb_set_debug((*C.libusb_context)(c), C.int(lvl))
+}
+
+func (libusbImpl) getDeviceDesc(d *libusbDevice) (*Descriptor, error) {
+ var desc C.struct_libusb_device_descriptor
+ if err := fromUSBError(C.libusb_get_device_descriptor((*C.libusb_device)(d), &desc)); err != nil {
+ return nil, err
+ }
+ // Enumerate configurations
+ var cfgs []ConfigInfo
+ for i := 0; i < int(desc.bNumConfigurations); i++ {
+ var cfg *C.struct_libusb_config_descriptor
+ if err := fromUSBError(C.libusb_get_config_descriptor((*C.libusb_device)(d), C.uint8_t(i), &cfg)); err != nil {
+ return nil, err
+ }
+ c := ConfigInfo{
+ Config: uint8(cfg.bConfigurationValue),
+ Attributes: uint8(cfg.bmAttributes),
+ MaxPower: uint8(cfg.MaxPower),
+ }
+
+ var ifaces []C.struct_libusb_interface
+ *(*reflect.SliceHeader)(unsafe.Pointer(&ifaces)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(cfg._interface)),
+ Len: int(cfg.bNumInterfaces),
+ Cap: int(cfg.bNumInterfaces),
+ }
+ 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([]InterfaceSetup, 0, len(alts))
+ for _, alt := range alts {
+ i := InterfaceSetup{
+ Number: uint8(alt.bInterfaceNumber),
+ Alternate: uint8(alt.bAlternateSetting),
+ IfClass: uint8(alt.bInterfaceClass),
+ IfSubClass: uint8(alt.bInterfaceSubClass),
+ IfProtocol: uint8(alt.bInterfaceProtocol),
+ }
+ var ends []C.struct_libusb_endpoint_descriptor
+ *(*reflect.SliceHeader)(unsafe.Pointer(&ends)) = reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(alt.endpoint)),
+ Len: int(alt.bNumEndpoints),
+ Cap: int(alt.bNumEndpoints),
+ }
+ i.Endpoints = make([]EndpointInfo, 0, len(ends))
+ for _, end := range ends {
+ ei := EndpointInfo{
+ Address: uint8(end.bEndpointAddress),
+ Attributes: uint8(end.bmAttributes),
+ MaxPacketSize: uint16(end.wMaxPacketSize),
+ PollInterval: uint8(end.bInterval),
+ RefreshRate: uint8(end.bRefresh),
+ SynchAddress: uint8(end.bSynchAddress),
+ }
+ if ei.TransferType() == TRANSFER_TYPE_ISOCHRONOUS {
+ // bits 0-10 identify the packet size, bits 11-12 are the number of additional transactions per microframe.
+ // Don't use libusb_get_max_iso_packet_size, as it has a bug where it returns the same value
+ // regardless of alternative setting used, where different alternative settings might define different
+ // max packet sizes.
+ // See http://libusb.org/ticket/77 for more background.
+ ei.MaxIsoPacket = uint32(end.wMaxPacketSize) & 0x07ff * (uint32(end.wMaxPacketSize)>>11&3 + 1)
+ }
+ i.Endpoints = append(i.Endpoints, ei)
+ }
+ descs = append(descs, i)
+ }
+ c.Interfaces = append(c.Interfaces, InterfaceInfo{
+ Number: descs[0].Number,
+ Setups: descs,
+ })
+ }
+ C.libusb_free_config_descriptor(cfg)
+ cfgs = append(cfgs, c)
+ }
+
+ return &Descriptor{
+ Bus: uint8(C.libusb_get_bus_number((*C.libusb_device)(d))),
+ Address: uint8(C.libusb_get_device_address((*C.libusb_device)(d))),
+ Spec: BCD(desc.bcdUSB),
+ Device: BCD(desc.bcdDevice),
+ Vendor: ID(desc.idVendor),
+ Product: ID(desc.idProduct),
+ Class: uint8(desc.bDeviceClass),
+ SubClass: uint8(desc.bDeviceSubClass),
+ Protocol: uint8(desc.bDeviceProtocol),
+ Configs: cfgs,
+ }, nil
+}
+
+func (libusbImpl) dereference(d *libusbDevice) {
+ C.libusb_unref_device((*C.libusb_device)(d))
+}
+
+func (libusbImpl) open(d *libusbDevice) (*libusbDevHandle, error) {
+ var handle *C.libusb_device_handle
+ if err := fromUSBError(C.libusb_open((*C.libusb_device)(d), &handle)); err != nil {
+ return nil, err
+ }
+ return (*libusbDevHandle)(handle), nil
+}
+
+func (libusbImpl) close(d *libusbDevHandle) {
+ C.libusb_close((*C.libusb_device_handle)(d))
+}
+
+func (libusbImpl) reset(d *libusbDevHandle) error {
+ return fromUSBError(C.libusb_reset_device((*C.libusb_device_handle)(d)))
+}
+
+func (libusbImpl) control(d *libusbDevHandle, timeout time.Duration, rType, request uint8, val, idx uint16, data []byte) (int, error) {
+ dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ n := C.libusb_control_transfer(
+ (*C.libusb_device_handle)(d),
+ C.uint8_t(rType),
+ C.uint8_t(request),
+ C.uint16_t(val),
+ C.uint16_t(idx),
+ (*C.uchar)(unsafe.Pointer(dataSlice.Data)),
+ C.uint16_t(len(data)),
+ C.uint(timeout/time.Millisecond))
+ if n < 0 {
+ return int(n), fromUSBError(n)
+ }
+ return int(n), nil
+}
+
+func (libusbImpl) getConfig(d *libusbDevHandle) (uint8, error) {
+ var cfg C.int
+ if errno := C.libusb_get_configuration((*C.libusb_device_handle)(d), &cfg); errno < 0 {
+ return 0, fromUSBError(errno)
+ }
+ return uint8(cfg), nil
+}
+
+func (libusbImpl) setConfig(d *libusbDevHandle, cfg uint8) error {
+ return fromUSBError(C.libusb_set_configuration((*C.libusb_device_handle)(d), C.int(cfg)))
+}
+
+func (libusbImpl) getStringDesc(d *libusbDevHandle, index int) (string, error) {
+ // allocate 200-byte array limited the length of string descriptor
+ buf := make([]byte, 200)
+ // get string descriptor from libusb. if errno < 0 then there are any errors.
+ // if errno >= 0; it is a length of result string descriptor
+ errno := C.libusb_get_string_descriptor_ascii(
+ (*C.libusb_device_handle)(d),
+ C.uint8_t(index),
+ (*C.uchar)(unsafe.Pointer(&buf[0])),
+ 200)
+ if errno < 0 {
+ return "", fmt.Errorf("usb: getstr: %s", fromUSBError(errno))
+ }
+ return string(buf[:errno]), nil
+}
+
+func (libusbImpl) setAutoDetach(d *libusbDevHandle, val int) error {
+ err := fromUSBError(C.libusb_set_auto_detach_kernel_driver((*C.libusb_device_handle)(d), C.int(val)))
+ if err != nil && err != ERROR_NOT_SUPPORTED {
+ return err
+ }
+ return nil
+}
+
+func (libusbImpl) claim(d *libusbDevHandle, iface uint8) error {
+ return fromUSBError(C.libusb_claim_interface((*C.libusb_device_handle)(d), C.int(iface)))
+}
+
+func (libusbImpl) release(d *libusbDevHandle, iface uint8) {
+ C.libusb_release_interface((*C.libusb_device_handle)(d), C.int(iface))
+}
+
+func (libusbImpl) setAlt(d *libusbDevHandle, iface, setup uint8) error {
+ return fromUSBError(C.libusb_set_interface_alt_setting((*C.libusb_device_handle)(d), C.int(iface), C.int(setup)))
+}
+
+func (libusbImpl) alloc(d *libusbDevHandle, addr uint8, tt TransferType, timeout time.Duration, isoPackets int, buf []byte) (*libusbTransfer, error) {
+ xfer := C.libusb_alloc_transfer(C.int(isoPackets))
+ if xfer == nil {
+ return nil, fmt.Errorf("libusb_alloc_transfer(%d) failed", isoPackets)
+ }
+ xfer.dev_handle = (*C.libusb_device_handle)(d)
+ xfer.endpoint = C.uchar(addr)
+ xfer.timeout = C.uint(timeout / time.Millisecond)
+ xfer._type = C.uchar(tt)
+ xfer.num_iso_packets = C.int(isoPackets)
+ xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
+ xfer.length = C.int(len(buf))
+ return (*libusbTransfer)(xfer), nil
+}
+
+func (libusbImpl) cancel(t *libusbTransfer) error {
+ return fromUSBError(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t)))
+}
+
+func (libusbImpl) submit(t *libusbTransfer, done chan struct{}) error {
+ t.user_data = (unsafe.Pointer)(&done)
+ return fromUSBError(C.submit((*C.struct_libusb_transfer)(t)))
+}
+
+func (libusbImpl) data(t *libusbTransfer) (int, TransferStatus) {
+ if TransferType(t._type) == TRANSFER_TYPE_ISOCHRONOUS {
+ var status TransferStatus
+ n := int(C.compact_iso_data((*C.struct_libusb_transfer)(t), (*C.uchar)(unsafe.Pointer(&status))))
+ return n, status
+ }
+ return int(t.actual_length), TransferStatus(t.status)
+}
+
+func (libusbImpl) free(t *libusbTransfer) {
+ C.libusb_free_transfer((*C.struct_libusb_transfer)(t))
+}
+
+func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) {
+ C.libusb_set_iso_packet_lengths((*C.struct_libusb_transfer)(t), C.uint(length))
+}
+
+// libusb is an injection point for tests
+var libusb libusbIntf = libusbImpl{}
+
+//export xfer_callback
+func xfer_callback(cptr unsafe.Pointer) {
+ ch := *(*chan struct{})(cptr)
+ close(ch)
+}
+
+// for benchmarking
+func libusbSetDebug(c *libusbContext, lvl int) {
+ C.libusb_set_debug((*C.libusb_context)(c), C.int(lvl))
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/libusb_cgo_benchmark_test.go b/vendor/github.com/kylelemons/gousb/usb/libusb_cgo_benchmark_test.go
new file mode 100644
index 0000000..da8acc9
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/libusb_cgo_benchmark_test.go
@@ -0,0 +1,46 @@
+package usb
+
+import "testing"
+
+func BenchmarkCGo(b *testing.B) {
+ for _, bc := range []struct {
+ name string
+ bfunc func(*libusbContext, int)
+ }{
+ {
+ name: "simple function",
+ bfunc: func(ctx *libusbContext, N int) {
+ for i := 0; i < N; i++ {
+ libusbSetDebug(ctx, i&1)
+ }
+ },
+ },
+ {
+ name: "method",
+ bfunc: func(ctx *libusbContext, N int) {
+ impl := libusbImpl{}
+ for i := 0; i < N; i++ {
+ impl.setDebug(ctx, i&1)
+ }
+ },
+ },
+ {
+ name: "interface",
+ bfunc: func(ctx *libusbContext, N int) {
+ var intf libusbIntf = libusbImpl{}
+ for i := 0; i < N; i++ {
+ intf.setDebug(ctx, i&1)
+ }
+ },
+ },
+ } {
+ b.Run(bc.name, func(b *testing.B) {
+ ctx, err := libusbImpl{}.init()
+ if err != nil {
+ b.Fatalf("libusb_init() failed: %v", err)
+ }
+ b.ResetTimer()
+ bc.bfunc(ctx, b.N)
+ })
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/misc.go b/vendor/github.com/kylelemons/gousb/usb/misc.go
new file mode 100644
index 0000000..1650e10
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/misc.go
@@ -0,0 +1,48 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "fmt"
+)
+
+type BCD uint16
+
+const (
+ USB_2_0 BCD = 0x0200
+ USB_1_1 BCD = 0x0110
+ USB_1_0 BCD = 0x0100
+)
+
+func (d BCD) Int() (i int) {
+ ten := 1
+ for o := uint(0); o < 4; o++ {
+ n := ((0xF << (o * 4)) & d) >> (o * 4)
+ i += int(n) * ten
+ ten *= 10
+ }
+ return
+}
+
+func (d BCD) String() string {
+ return fmt.Sprintf("%02x.%02x", int(d>>8), int(d&0xFF))
+}
+
+type ID uint16
+
+func (id ID) String() string {
+ return fmt.Sprintf("%04x", int(id))
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/misc_test.go b/vendor/github.com/kylelemons/gousb/usb/misc_test.go
new file mode 100644
index 0000000..106e5d5
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/misc_test.go
@@ -0,0 +1,39 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "testing"
+)
+
+func TestBCD(t *testing.T) {
+ tests := []struct {
+ BCD
+ Int int
+ Str string
+ }{
+ {0x1234, 1234, "12.34"},
+ }
+
+ for _, test := range tests {
+ if got, want := test.BCD.Int(), test.Int; got != want {
+ t.Errorf("Int(%x) = %d, want %d", test.BCD, got, want)
+ }
+ if got, want := test.BCD.String(), test.Str; got != want {
+ t.Errorf("String(%x) = %q, want %q", test.BCD, got, want)
+ }
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/transfer.c b/vendor/github.com/kylelemons/gousb/usb/transfer.c
new file mode 100644
index 0000000..9965019
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/transfer.c
@@ -0,0 +1,80 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <libusb.h>
+#include <stdio.h>
+#include <string.h>
+
+void print_xfer(struct libusb_transfer *xfer);
+void xfer_callback(void *);
+
+void callback(struct libusb_transfer *xfer) {
+ xfer_callback(xfer->user_data);
+}
+
+int submit(struct libusb_transfer *xfer) {
+ xfer->callback = (libusb_transfer_cb_fn)(&callback);
+ xfer->status = -1;
+ return libusb_submit_transfer(xfer);
+}
+
+void print_xfer(struct libusb_transfer *xfer) {
+ int i;
+
+ printf("Transfer:\n");
+ printf(" dev_handle: %p\n", xfer->dev_handle);
+ printf(" flags: %08x\n", xfer->flags);
+ printf(" endpoint: %x\n", xfer->endpoint);
+ printf(" type: %x\n", xfer->type);
+ printf(" timeout: %dms\n", xfer->timeout);
+ printf(" status: %x\n", xfer->status);
+ printf(" length: %d (act: %d)\n", xfer->length, xfer->actual_length);
+ printf(" callback: %p\n", xfer->callback);
+ printf(" user_data: %p\n", xfer->user_data);
+ printf(" buffer: %p\n", xfer->buffer);
+ printf(" num_iso_pkts: %d\n", xfer->num_iso_packets);
+ printf(" packets:\n");
+ for (i = 0; i < xfer->num_iso_packets; i++) {
+ printf(" [%04d] %d (act: %d) %x\n", i,
+ xfer->iso_packet_desc[i].length,
+ xfer->iso_packet_desc[i].actual_length,
+ xfer->iso_packet_desc[i].status);
+ }
+}
+
+// compact the data in an isochronous transfer. The contents of individual
+// iso packets are shifted left, so that no gaps are left between them.
+// Status is set to the first non-zero status of an iso packet.
+int compact_iso_data(struct libusb_transfer *xfer, unsigned char *status) {
+ int i;
+ int sum = 0;
+ unsigned char *in = xfer->buffer;
+ unsigned char *out = xfer->buffer;
+ for (i = 0; i < xfer->num_iso_packets; i++) {
+ struct libusb_iso_packet_descriptor pkt = xfer->iso_packet_desc[i];
+ if (pkt.status != 0) {
+ *status = pkt.status;
+ break;
+ }
+ // Copy the data
+ int len = pkt.actual_length;
+ memmove(out, in, len);
+ // Increment offsets
+ sum += len;
+ in += pkt.length;
+ out += len;
+ }
+ return sum;
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/transfer.go b/vendor/github.com/kylelemons/gousb/usb/transfer.go
new file mode 100644
index 0000000..e41713a
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/transfer.go
@@ -0,0 +1,147 @@
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "errors"
+ "fmt"
+ "runtime"
+ "sync"
+ "time"
+)
+
+type usbTransfer struct {
+ // mu protects the transfer state.
+ mu sync.Mutex
+ // xfer is the allocated libusb_transfer.
+ xfer *libusbTransfer
+ // buf is the buffer allocated for the transfer. Both buf and xfer.buffer
+ // point to the same piece of memory.
+ buf []byte
+ // done is blocking until the transfer is complete and data and transfer
+ // status are available.
+ done chan struct{}
+ // submitted is true if this transfer was passed to libusb through submit()
+ submitted bool
+}
+
+// submits the transfer. After submit() the transfer is in flight and is owned by libusb.
+// It's not safe to access the contents of the transfer until wait() returns.
+// Once wait() returns, it's ok to re-use the same transfer structure by calling submit() again.
+func (t *usbTransfer) submit() error {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ if t.submitted {
+ return errors.New("transfer was already submitted and is not finished yet.")
+ }
+ t.done = make(chan struct{})
+ if err := libusb.submit(t.xfer, t.done); err != nil {
+ return err
+ }
+ t.submitted = true
+ return nil
+}
+
+// wait waits for libusb to signal the release of transfer data.
+// After wait returns, the transfer contents are safe to access
+// via t.buf. The number returned by wait indicates how many bytes
+// of the buffer were read or written by libusb, and it can be
+// smaller than the length of t.buf.
+func (t *usbTransfer) wait() (n int, err error) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ if !t.submitted {
+ return 0, nil
+ }
+ select {
+ case <-time.After(10 * time.Second):
+ return 0, fmt.Errorf("wait timed out after 10s")
+ case <-t.done:
+ }
+ t.submitted = false
+ n, status := libusb.data(t.xfer)
+ if status != LIBUSB_TRANSFER_COMPLETED {
+ return n, status
+ }
+ return n, err
+}
+
+// cancel aborts a submitted transfer. The transfer is cancelled
+// asynchronously and the user still needs to wait() to return.
+func (t *usbTransfer) cancel() error {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ if !t.submitted {
+ return nil
+ }
+ err := libusb.cancel(t.xfer)
+ if err == ERROR_NOT_FOUND {
+ // transfer already completed
+ return nil
+ }
+ return err
+}
+
+// free releases the memory allocated for the transfer.
+// free should be called only if the transfer is not used by libusb,
+// i.e. it should not be called after submit() and before wait() returns.
+func (t *usbTransfer) free() error {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ if t.submitted {
+ return errors.New("free() cannot be called on a submitted transfer until wait() returns")
+ }
+ libusb.free(t.xfer)
+ t.xfer = nil
+ t.buf = nil
+ t.done = nil
+ return nil
+}
+
+// newUSBTransfer allocates a new transfer structure for communication with a
+// given device/endpoint, with buf as the underlying transfer buffer.
+func newUSBTransfer(dev *libusbDevHandle, ei EndpointInfo, buf []byte, timeout time.Duration) (*usbTransfer, error) {
+ var isoPackets int
+ var isoPktSize uint32
+ tt := ei.TransferType()
+ if tt == TRANSFER_TYPE_ISOCHRONOUS {
+ isoPktSize = ei.MaxIsoPacket
+ if len(buf) < int(isoPktSize) {
+ isoPktSize = uint32(len(buf))
+ }
+ isoPackets = len(buf) / int(isoPktSize)
+ debug.Printf("New isochronous transfer - buffer length %d, using %d packets of %d bytes each", len(buf), isoPackets, isoPktSize)
+ }
+
+ xfer, err := libusb.alloc(dev, ei.Address, tt, timeout, isoPackets, buf)
+ if err != nil {
+ return nil, err
+ }
+
+ if tt == TRANSFER_TYPE_ISOCHRONOUS {
+ libusb.setIsoPacketLengths(xfer, isoPktSize)
+ }
+
+ t := &usbTransfer{
+ xfer: xfer,
+ buf: buf,
+ }
+ runtime.SetFinalizer(t, func(t *usbTransfer) {
+ t.cancel()
+ t.wait()
+ t.free()
+ })
+ return t, nil
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/transfer_test.go b/vendor/github.com/kylelemons/gousb/usb/transfer_test.go
new file mode 100644
index 0000000..4e4fcea
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/transfer_test.go
@@ -0,0 +1,145 @@
+// Copyright 2017 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import (
+ "testing"
+ "time"
+)
+
+func TestNewTransfer(t *testing.T) {
+ defer func(i libusbIntf) { libusb = i }(libusb)
+ libusb = newFakeLibusb()
+
+ for _, tc := range []struct {
+ desc string
+ dir EndpointDirection
+ tt TransferType
+ maxPkt uint16
+ maxIso uint32
+ buf int
+ timeout time.Duration
+ wantIso int
+ wantLength int
+ wantTimeout int
+ }{
+ {
+ desc: "bulk in transfer, 512B packets",
+ dir: ENDPOINT_DIR_IN,
+ tt: TRANSFER_TYPE_BULK,
+ maxPkt: 512,
+ buf: 1024,
+ timeout: time.Second,
+ wantLength: 1024,
+ },
+ {
+ desc: "iso out transfer, 3 * 1024B packets",
+ dir: ENDPOINT_DIR_OUT,
+ tt: TRANSFER_TYPE_ISOCHRONOUS,
+ maxPkt: 2<<11 + 1024,
+ maxIso: 3 * 1024,
+ buf: 10000,
+ wantLength: 10000,
+ },
+ } {
+ xfer, err := newUSBTransfer(nil, EndpointInfo{
+ Address: uint8(tc.dir) | 0x02,
+ Attributes: uint8(tc.tt),
+ MaxPacketSize: tc.maxPkt,
+ MaxIsoPacket: tc.maxIso,
+ PollInterval: 1,
+ }, make([]byte, tc.buf), tc.timeout)
+
+ if err != nil {
+ t.Fatalf("newUSBTransfer(): %v", err)
+ }
+ if got, want := len(xfer.buf), tc.wantLength; got != want {
+ t.Errorf("xfer.buf: got %d bytes, want %d", got, want)
+ }
+ }
+}
+
+func TestTransferProtocol(t *testing.T) {
+ defer func(i libusbIntf) { libusb = i }(libusb)
+
+ f := newFakeLibusb()
+ libusb = f
+
+ xfers := make([]*usbTransfer, 2)
+ var err error
+ for i := 0; i < 2; i++ {
+ xfers[i], err = newUSBTransfer(nil, EndpointInfo{
+ Address: 0x86,
+ Attributes: uint8(TRANSFER_TYPE_BULK),
+ MaxPacketSize: 512,
+ PollInterval: 1,
+ }, make([]byte, 10240), time.Second)
+ if err != nil {
+ t.Fatalf("newUSBTransfer: %v", err)
+ }
+ }
+
+ go func() {
+ ft := f.waitForSubmitted()
+ ft.length = 5
+ ft.status = LIBUSB_TRANSFER_COMPLETED
+ copy(ft.buf, []byte{1, 2, 3, 4, 5})
+ close(ft.done)
+
+ ft = f.waitForSubmitted()
+ ft.length = 99
+ ft.status = LIBUSB_TRANSFER_COMPLETED
+ copy(ft.buf, []byte{12, 12, 12, 12, 12})
+ close(ft.done)
+
+ ft = f.waitForSubmitted()
+ ft.length = 123
+ ft.status = LIBUSB_TRANSFER_CANCELLED
+ close(ft.done)
+ }()
+
+ xfers[0].submit()
+ xfers[1].submit()
+ got, err := xfers[0].wait()
+ if err != nil {
+ t.Errorf("xfer#0.wait returned error %v, want nil", err)
+ }
+ if want := 5; got != want {
+ t.Errorf("xfer#0.wait returned %d bytes, want %d", got, want)
+ }
+ got, err = xfers[1].wait()
+ if err != nil {
+ t.Errorf("xfer#0.wait returned error %v, want nil", err)
+ }
+ if want := 99; got != want {
+ t.Errorf("xfer#0.wait returned %d bytes, want %d", got, want)
+ }
+
+ xfers[1].submit()
+ xfers[1].cancel()
+ got, err = xfers[1].wait()
+ if err == nil {
+ t.Error("xfer#1(resubmitted).wait returned error nil, want non-nil")
+ }
+ if want := 123; got != want {
+ t.Errorf("xfer#1(resubmitted).wait returned %d bytes, want %d", got, want)
+ }
+
+ for _, x := range xfers {
+ x.cancel()
+ x.wait()
+ x.free()
+ }
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/usb.go b/vendor/github.com/kylelemons/gousb/usb/usb.go
new file mode 100644
index 0000000..b4bb258
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/usb.go
@@ -0,0 +1,110 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package usb provides a wrapper around libusb-1.0.
+//
+// Deprecated: this package was deprecated in favor of github.com/google/gousb.
+// Please use the new package when starting new projects.
+package usb
+
+type Context struct {
+ ctx *libusbContext
+ done chan struct{}
+}
+
+func (c *Context) Debug(level int) {
+ libusb.setDebug(c.ctx, level)
+}
+
+func NewContext() *Context {
+ c, err := libusb.init()
+ if err != nil {
+ panic(err)
+ }
+ ctx := &Context{
+ ctx: c,
+ done: make(chan struct{}),
+ }
+ go libusb.handleEvents(ctx.ctx, ctx.done)
+ return ctx
+}
+
+// ListDevices calls each with each enumerated device.
+// If the function returns true, the device is opened and a Device is returned if the operation succeeds.
+// Every Device returned (whether an error is also returned or not) must be closed.
+// If there are any errors enumerating the devices,
+// the final one is returned along with any successfully opened devices.
+func (c *Context) ListDevices(each func(desc *Descriptor) bool) ([]*Device, error) {
+ list, err := libusb.getDevices(c.ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ var reterr error
+ var ret []*Device
+ for _, dev := range list {
+ desc, err := libusb.getDeviceDesc(dev)
+ if err != nil {
+ libusb.dereference(dev)
+ reterr = err
+ continue
+ }
+
+ if each(desc) {
+ handle, err := libusb.open(dev)
+ if err != nil {
+ reterr = err
+ continue
+ }
+ ret = append(ret, newDevice(handle, desc))
+ } else {
+ libusb.dereference(dev)
+ }
+ }
+ return ret, reterr
+}
+
+// OpenDeviceWithVidPid opens Device from specific VendorId and ProductId.
+// If none is found, it returns nil and nil error. If there are multiple devices
+// with the same VID/PID, it will return one of them, picked arbitrarily.
+// If there were any errors during device list traversal, it is possible
+// it will return a non-nil device and non-nil error. A Device.Close() must
+// be called to release the device if the returned device wasn't nil.
+func (c *Context) OpenDeviceWithVidPid(vid, pid int) (*Device, error) {
+ var found bool
+ devs, err := c.ListDevices(func(desc *Descriptor) bool {
+ if found {
+ return false
+ }
+ if desc.Vendor == ID(vid) && desc.Product == ID(pid) {
+ found = true
+ return true
+ }
+ return false
+ })
+ if len(devs) == 0 {
+ return nil, err
+ }
+ return devs[0], nil
+}
+
+func (c *Context) Close() error {
+ c.done <- struct{}{}
+ if c.ctx != nil {
+ libusb.exit(c.ctx)
+ }
+ c.ctx = nil
+ return nil
+}
diff --git a/vendor/github.com/kylelemons/gousb/usb/usb_test.go b/vendor/github.com/kylelemons/gousb/usb/usb_test.go
new file mode 100644
index 0000000..cad8646
--- /dev/null
+++ b/vendor/github.com/kylelemons/gousb/usb/usb_test.go
@@ -0,0 +1,87 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2016 the gousb Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package usb
+
+import "testing"
+
+func TestListDevices(t *testing.T) {
+ orig := libusb
+ defer func() { libusb = orig }()
+ libusb = newFakeLibusb()
+
+ c := NewContext()
+ defer c.Close()
+ c.Debug(0)
+
+ descs := []*Descriptor{}
+ devs, err := c.ListDevices(func(desc *Descriptor) bool {
+ descs = append(descs, desc)
+ return true
+ })
+ defer func() {
+ for _, d := range devs {
+ d.Close()
+ }
+ }()
+ if err != nil {
+ t.Fatalf("ListDevices(): %s", err)
+ }
+
+ if got, want := len(devs), len(fakeDevices); got != want {
+ t.Fatalf("len(devs) = %d, want %d (based on num fake devs)", got, want)
+ }
+ if got, want := len(devs), len(descs); got != want {
+ t.Fatalf("len(devs) = %d, want %d (based on num opened devices)", got, want)
+ }
+
+ for i := range devs {
+ if got, want := devs[i].Descriptor, descs[i]; got != want {
+ t.Errorf("dev[%d].Descriptor = %p, want %p", i, got, want)
+ }
+ }
+}
+
+func TestOpenDeviceWithVidPid(t *testing.T) {
+ orig := libusb
+ defer func() { libusb = orig }()
+ libusb = newFakeLibusb()
+
+ for _, d := range []struct {
+ vid, pid int
+ exists bool
+ }{
+ {0x7777, 0x0003, false},
+ {0x8888, 0x0001, false},
+ {0x8888, 0x0002, true},
+ {0x9999, 0x0001, true},
+ {0x9999, 0x0002, false},
+ } {
+ c := NewContext()
+ dev, err := c.OpenDeviceWithVidPid(d.vid, d.pid)
+ if (dev != nil) != d.exists {
+ t.Errorf("OpenDeviceWithVidPid(%s/%s): device != nil is %v, want %v", ID(d.vid), ID(d.pid), dev != nil, d.exists)
+ }
+ if err != nil {
+ t.Errorf("OpenDeviceWithVidPid(%s/%s): got error %v, want nil", ID(d.vid), ID(d.pid), err)
+ }
+ if dev != nil {
+ if dev.Descriptor.Vendor != ID(d.vid) || dev.Descriptor.Product != ID(d.pid) {
+ t.Errorf("OpenDeviceWithVidPid(%s/%s): the device returned has VID/PID %s/%s, different from specified in the arguments", ID(d.vid), ID(d.pid), dev.Descriptor.Vendor, dev.Descriptor.Product)
+ }
+ dev.Close()
+ }
+ }
+}