accounts/usbwallet: support webusb for Trezor wallets
This commit is contained in:
parent
7a22da98b9
commit
4799b5abd4
@ -89,6 +89,12 @@ func NewTrezorHub() (*Hub, error) {
|
|||||||
return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver)
|
return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor 1 */}, 0xff00, 0, newTrezorDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWebUSBTrezorHub creates a new hardware wallet manager for Trezor devices with
|
||||||
|
// firmware version > 1.8.0
|
||||||
|
func NewWebUSBTrezorHub() (*Hub, error) {
|
||||||
|
return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor 1 WebUSB */}, 0, 0, newTrezorDriver)
|
||||||
|
}
|
||||||
|
|
||||||
// newHub creates a new hardware wallet manager for generic USB devices.
|
// newHub creates a new hardware wallet manager for generic USB devices.
|
||||||
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
||||||
if !hid.Supported() {
|
if !hid.Supported() {
|
||||||
@ -148,9 +154,19 @@ func (hub *Hub) refreshWallets() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, info := range hid.Enumerate(hub.vendorID, 0) {
|
infos, err := hid.Enumerate(hub.vendorID, 0)
|
||||||
|
if err != nil {
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
// See rationale before the enumeration why this is needed and only on Linux.
|
||||||
|
hub.commsLock.Unlock()
|
||||||
|
}
|
||||||
|
log.Error("error enumerating USB enumeration: ", "code", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, info := range infos {
|
||||||
for _, id := range hub.productIDs {
|
for _, id := range hub.productIDs {
|
||||||
if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) {
|
_, pid, endpoint, _ /* FIXME usageID */ := info.IDs()
|
||||||
|
if pid == id && ( /* FIXME usageID == hub.usageID || */ endpoint == hub.endpointID) {
|
||||||
devices = append(devices, info)
|
devices = append(devices, info)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -169,7 +185,7 @@ func (hub *Hub) refreshWallets() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
for _, device := range devices {
|
for _, device := range devices {
|
||||||
url := accounts.URL{Scheme: hub.scheme, Path: device.Path}
|
url := accounts.URL{Scheme: hub.scheme, Path: device.GetPath()}
|
||||||
|
|
||||||
// Drop wallets in front of the next device or those that failed for some reason
|
// Drop wallets in front of the next device or those that failed for some reason
|
||||||
for len(hub.wallets) > 0 {
|
for len(hub.wallets) > 0 {
|
||||||
|
@ -36,6 +36,8 @@ import (
|
|||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrInvalidDeviceType = errors.New("trezor: invalid device type")
|
||||||
|
|
||||||
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
||||||
// this case, the calling application should display a pinpad and send back the
|
// this case, the calling application should display a pinpad and send back the
|
||||||
// encoded passphrase.
|
// encoded passphrase.
|
||||||
|
@ -78,7 +78,7 @@ type wallet struct {
|
|||||||
url *accounts.URL // Textual URL uniquely identifying this wallet
|
url *accounts.URL // Textual URL uniquely identifying this wallet
|
||||||
|
|
||||||
info hid.DeviceInfo // Known USB device infos about the wallet
|
info hid.DeviceInfo // Known USB device infos about the wallet
|
||||||
device *hid.Device // USB device advertising itself as a hardware wallet
|
device hid.Device // USB device advertising itself as a hardware wallet
|
||||||
|
|
||||||
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
||||||
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
||||||
|
@ -507,6 +507,12 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
|
|||||||
} else {
|
} else {
|
||||||
backends = append(backends, trezorhub)
|
backends = append(backends, trezorhub)
|
||||||
}
|
}
|
||||||
|
// Start a USB hub for Trezor hardware wallets (WebUSB version)
|
||||||
|
if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil {
|
||||||
|
log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err))
|
||||||
|
} else {
|
||||||
|
backends = append(backends, trezorhub)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(conf.SmartCardDaemonPath) > 0 {
|
if len(conf.SmartCardDaemonPath) > 0 {
|
||||||
// Start a smart card hub
|
// Start a smart card hub
|
||||||
|
@ -151,6 +151,13 @@ func StartClefAccountManager(ksLocation string, nousb, lightKDF bool) *accounts.
|
|||||||
backends = append(backends, trezorhub)
|
backends = append(backends, trezorhub)
|
||||||
log.Debug("Trezor support enabled")
|
log.Debug("Trezor support enabled")
|
||||||
}
|
}
|
||||||
|
// Start a USB hub for Trezor hardware wallets (WebUSB version)
|
||||||
|
if trezorhub, err := usbwallet.NewWebUSBTrezorHub(); err != nil {
|
||||||
|
log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err))
|
||||||
|
} else {
|
||||||
|
backends = append(backends, trezorhub)
|
||||||
|
log.Debug("Trezor support enabled")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Clef doesn't allow insecure http account unlock.
|
// Clef doesn't allow insecure http account unlock.
|
||||||
return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, backends...)
|
return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, backends...)
|
||||||
|
54
vendor/github.com/karalabe/hid/generic.go
generated
vendored
Normal file
54
vendor/github.com/karalabe/hid/generic.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// hid - Gopher Interface Devices (USB HID)
|
||||||
|
// Copyright (c) 2019 Péter Szilágyi, Guillaume Ballet. All rights reserved.
|
||||||
|
|
||||||
|
package hid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GenericEndpointDirection uint8
|
||||||
|
|
||||||
|
// List of endpoint direction types
|
||||||
|
const (
|
||||||
|
GenericEndpointDirectionOut = 0x00
|
||||||
|
GenericEndpointDirectionIn = 0x80
|
||||||
|
)
|
||||||
|
|
||||||
|
// List of endpoint attributes
|
||||||
|
const (
|
||||||
|
GenericEndpointAttributeInterrupt = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenericEndpoint represents a USB endpoint
|
||||||
|
type GenericEndpoint struct {
|
||||||
|
Address uint8
|
||||||
|
Direction GenericEndpointDirection
|
||||||
|
Attributes uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type GenericDeviceInfo struct {
|
||||||
|
Path string // Platform-specific device path
|
||||||
|
VendorID uint16 // Device Vendor ID
|
||||||
|
ProductID uint16 // Device Product ID
|
||||||
|
|
||||||
|
device *GenericDevice
|
||||||
|
|
||||||
|
Interface int
|
||||||
|
|
||||||
|
Endpoints []GenericEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gdi *GenericDeviceInfo) Type() DeviceType {
|
||||||
|
return DeviceTypeGeneric
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform-specific device path
|
||||||
|
func (gdi *GenericDeviceInfo) GetPath() string {
|
||||||
|
return gdi.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDs returns the vendor and product IDs for the device
|
||||||
|
func (gdi *GenericDeviceInfo) IDs() (uint16, uint16, int, uint16) {
|
||||||
|
return gdi.VendorID, gdi.ProductID, gdi.Interface, 0
|
||||||
|
}
|
19
vendor/github.com/karalabe/hid/hid.go
generated
vendored
19
vendor/github.com/karalabe/hid/hid.go
generated
vendored
@ -17,8 +17,8 @@ var ErrDeviceClosed = errors.New("hid: device closed")
|
|||||||
// operating system is not supported by the library.
|
// operating system is not supported by the library.
|
||||||
var ErrUnsupportedPlatform = errors.New("hid: unsupported platform")
|
var ErrUnsupportedPlatform = errors.New("hid: unsupported platform")
|
||||||
|
|
||||||
// DeviceInfo is a hidapi info structure.
|
// HidDeviceInfo is a hidapi info structure.
|
||||||
type DeviceInfo struct {
|
type HidDeviceInfo struct {
|
||||||
Path string // Platform-specific device path
|
Path string // Platform-specific device path
|
||||||
VendorID uint16 // Device Vendor ID
|
VendorID uint16 // Device Vendor ID
|
||||||
ProductID uint16 // Device Product ID
|
ProductID uint16 // Device Product ID
|
||||||
@ -35,3 +35,18 @@ type DeviceInfo struct {
|
|||||||
// only if the device contains more than one interface.
|
// only if the device contains more than one interface.
|
||||||
Interface int
|
Interface int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPath returns the system-dependent path to the device
|
||||||
|
func (hdi *HidDeviceInfo) GetPath() string {
|
||||||
|
return hdi.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDs returns the vendor and product id of the device
|
||||||
|
func (hdi *HidDeviceInfo) IDs() (uint16, uint16, int, uint16) {
|
||||||
|
return hdi.VendorID, hdi.ProductID, hdi.Interface, hdi.UsagePage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns the type of the device (HID or generic)
|
||||||
|
func (hdi *HidDeviceInfo) Type() DeviceType {
|
||||||
|
return DeviceTypeHID
|
||||||
|
}
|
||||||
|
41
vendor/github.com/karalabe/hid/hid_disabled.go
generated
vendored
41
vendor/github.com/karalabe/hid/hid_disabled.go
generated
vendored
@ -4,7 +4,7 @@
|
|||||||
// This file is released under the 3-clause BSD license. Note however that Linux
|
// This file is released under the 3-clause BSD license. Note however that Linux
|
||||||
// support depends on libusb, released under GNU LGPL 2.1 or later.
|
// support depends on libusb, released under GNU LGPL 2.1 or later.
|
||||||
|
|
||||||
// +build !linux,!darwin,!windows ios !cgo
|
// +build !freebsd,!linux,!darwin,!windows ios !cgo
|
||||||
|
|
||||||
package hid
|
package hid
|
||||||
|
|
||||||
@ -22,30 +22,55 @@ func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device is a live HID USB connected device handle. On platforms that this file
|
// HidDevice is a live HID USB connected device handle. On platforms that this file
|
||||||
// implements the type lacks the actual HID device and all methods are noop.
|
// implements the type lacks the actual HID device and all methods are noop.
|
||||||
type Device struct {
|
type HidDevice struct {
|
||||||
DeviceInfo // Embed the infos for easier access
|
HidDeviceInfo // Embed the infos for easier access
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open connects to an HID device by its path name. On platforms that this file
|
// Open connects to an HID device by its path name. On platforms that this file
|
||||||
// implements the method just returns an error.
|
// implements the method just returns an error.
|
||||||
func (info DeviceInfo) Open() (*Device, error) {
|
func (info HidDeviceInfo) Open() (*Device, error) {
|
||||||
return nil, ErrUnsupportedPlatform
|
return nil, ErrUnsupportedPlatform
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close releases the HID USB device handle. On platforms that this file implements
|
// Close releases the HID USB device handle. On platforms that this file implements
|
||||||
// the method is just a noop.
|
// the method is just a noop.
|
||||||
func (dev *Device) Close() error { return nil }
|
func (dev *HidDevice) Close() error { return ErrUnsupportedPlatform }
|
||||||
|
|
||||||
// Write sends an output report to a HID device. On platforms that this file
|
// Write sends an output report to a HID device. On platforms that this file
|
||||||
// implements the method just returns an error.
|
// implements the method just returns an error.
|
||||||
func (dev *Device) Write(b []byte) (int, error) {
|
func (dev *HidDevice) Write(b []byte) (int, error) {
|
||||||
return 0, ErrUnsupportedPlatform
|
return 0, ErrUnsupportedPlatform
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read retrieves an input report from a HID device. On platforms that this file
|
// Read retrieves an input report from a HID device. On platforms that this file
|
||||||
// implements the method just returns an error.
|
// implements the method just returns an error.
|
||||||
func (dev *Device) Read(b []byte) (int, error) {
|
func (dev *HidDevice) Read(b []byte) (int, error) {
|
||||||
return 0, ErrUnsupportedPlatform
|
return 0, ErrUnsupportedPlatform
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open tries to open the USB device represented by the current DeviceInfo
|
||||||
|
func (gdi *GenericDeviceInfo) Open() (Device, error) {
|
||||||
|
return nil, ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericDevice represents a generic USB device
|
||||||
|
type GenericDevice struct {
|
||||||
|
*GenericDeviceInfo // Embed the infos for easier access
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements io.ReaderWriter
|
||||||
|
func (gd *GenericDevice) Write(b []byte) (int, error) {
|
||||||
|
return 0, ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements io.ReaderWriter
|
||||||
|
func (gd *GenericDevice) Read(b []byte) (int, error) {
|
||||||
|
return 0, ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close a previously opened generic USB device
|
||||||
|
func (gd *GenericDevice) Close() error {
|
||||||
|
return ErrUnsupportedPlatform
|
||||||
|
}
|
||||||
|
263
vendor/github.com/karalabe/hid/hid_enabled.go
generated
vendored
263
vendor/github.com/karalabe/hid/hid_enabled.go
generated
vendored
@ -4,7 +4,7 @@
|
|||||||
// This file is released under the 3-clause BSD license. Note however that Linux
|
// This file is released under the 3-clause BSD license. Note however that Linux
|
||||||
// support depends on libusb, released under LGNU GPL 2.1 or later.
|
// support depends on libusb, released under LGNU GPL 2.1 or later.
|
||||||
|
|
||||||
// +build linux,cgo darwin,!ios,cgo windows,cgo
|
// +build freebsd,cgo linux,cgo darwin,!ios,cgo windows,cgo
|
||||||
|
|
||||||
package hid
|
package hid
|
||||||
|
|
||||||
@ -13,13 +13,15 @@ package hid
|
|||||||
|
|
||||||
#cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int
|
#cgo linux CFLAGS: -I./libusb/libusb -DDEFAULT_VISIBILITY="" -DOS_LINUX -D_GNU_SOURCE -DPOLL_NFDS_TYPE=int
|
||||||
#cgo linux,!android LDFLAGS: -lrt
|
#cgo linux,!android LDFLAGS: -lrt
|
||||||
#cgo darwin CFLAGS: -DOS_DARWIN
|
#cgo darwin CFLAGS: -DOS_DARWIN -I./libusb/libusb
|
||||||
#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit
|
#cgo darwin LDFLAGS: -framework CoreFoundation -framework IOKit -lusb-1.0.0
|
||||||
#cgo windows CFLAGS: -DOS_WINDOWS
|
#cgo windows CFLAGS: -DOS_WINDOWS
|
||||||
#cgo windows LDFLAGS: -lsetupapi
|
#cgo windows LDFLAGS: -lsetupapi
|
||||||
|
#cgo freebsd CFLAGS: -DOS_FREEBSD
|
||||||
|
#cgo freebsd LDFLAGS: -lusb
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#ifdef OS_LINUX
|
||||||
#include <sys/poll.h>
|
#include <poll.h>
|
||||||
#include "os/threads_posix.c"
|
#include "os/threads_posix.c"
|
||||||
#include "os/poll_posix.c"
|
#include "os/poll_posix.c"
|
||||||
|
|
||||||
@ -35,15 +37,50 @@ package hid
|
|||||||
|
|
||||||
#include "hidapi/libusb/hid.c"
|
#include "hidapi/libusb/hid.c"
|
||||||
#elif OS_DARWIN
|
#elif OS_DARWIN
|
||||||
|
#include <libusb.h>
|
||||||
#include "hidapi/mac/hid.c"
|
#include "hidapi/mac/hid.c"
|
||||||
#elif OS_WINDOWS
|
#elif OS_WINDOWS
|
||||||
#include "hidapi/windows/hid.c"
|
#include "hidapi/windows/hid.c"
|
||||||
|
#elif OS_FREEBSD
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <libusb.h>
|
||||||
|
#include "hidapi/libusb/hid.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(OS_LINUX) || defined(OS_WINDOWS)
|
||||||
|
void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct libusb_device *current = *list;
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
data[i] = current;
|
||||||
|
current = list_entry(current->list.next, struct libusb_device, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(OS_DARWIN) || defined(OS_FREEBSD)
|
||||||
|
void copy_device_list_to_slice(struct libusb_device **data, struct libusb_device **list, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// No memcopy because the struct size isn't available for a sizeof()
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
data[i] = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *usb_strerror(int err)
|
||||||
|
{
|
||||||
|
return libusb_strerror(err);
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -65,26 +102,132 @@ func Supported() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// genericEnumerate performs generic USB device enumeration
|
||||||
|
func genericEnumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
|
||||||
|
var infos []DeviceInfo
|
||||||
|
var ctx *C.struct_libusb_context
|
||||||
|
errCode := int(C.libusb_init((**C.struct_libusb_context)(&ctx)))
|
||||||
|
if errCode < 0 {
|
||||||
|
return nil, fmt.Errorf("Error while initializing libusb: %d", errCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceListPtr **C.struct_libusb_device
|
||||||
|
count := C.libusb_get_device_list(ctx, (***C.struct_libusb_device)(&deviceListPtr))
|
||||||
|
if count < 0 {
|
||||||
|
return nil, fmt.Errorf("Error code listing devices: %d", count)
|
||||||
|
}
|
||||||
|
defer C.libusb_free_device_list(deviceListPtr, C.int(count))
|
||||||
|
|
||||||
|
deviceList := make([]*C.struct_libusb_device, count)
|
||||||
|
dlhdr := (*reflect.SliceHeader)(unsafe.Pointer(&deviceList))
|
||||||
|
C.copy_device_list_to_slice((**C.struct_libusb_device)(unsafe.Pointer(dlhdr.Data)), deviceListPtr, C.int(count))
|
||||||
|
|
||||||
|
for devnum, dev := range deviceList {
|
||||||
|
var desc C.struct_libusb_device_descriptor
|
||||||
|
errCode := int(C.libusb_get_device_descriptor(dev, &desc))
|
||||||
|
if errCode < 0 {
|
||||||
|
return nil, fmt.Errorf("Error getting device descriptor for generic device %d: %d", devnum, errCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start by checking the vendor id and the product id if necessary
|
||||||
|
if uint16(desc.idVendor) != vendorID || !(productID == 0 || uint16(desc.idProduct) == productID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip HID devices, they will be handled later
|
||||||
|
switch desc.bDeviceClass {
|
||||||
|
case 0:
|
||||||
|
/* Device class is specified at interface level */
|
||||||
|
for cfgnum := 0; cfgnum < int(desc.bNumConfigurations); cfgnum++ {
|
||||||
|
var cfgdesc *C.struct_libusb_config_descriptor
|
||||||
|
errCode = int(C.libusb_get_config_descriptor(dev, C.uint8_t(cfgnum), &cfgdesc))
|
||||||
|
if errCode != 0 {
|
||||||
|
return nil, fmt.Errorf("Error getting device configuration #%d for generic device %d: %d", cfgnum, devnum, errCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ifs []C.struct_libusb_interface
|
||||||
|
ifshdr := (*reflect.SliceHeader)(unsafe.Pointer(&ifs))
|
||||||
|
ifshdr.Cap = int(cfgdesc.bNumInterfaces)
|
||||||
|
ifshdr.Len = int(cfgdesc.bNumInterfaces)
|
||||||
|
ifshdr.Data = uintptr(unsafe.Pointer(cfgdesc._interface))
|
||||||
|
|
||||||
|
for ifnum, ifc := range ifs {
|
||||||
|
var ifdescs []C.struct_libusb_interface_descriptor
|
||||||
|
ifdshdr := (*reflect.SliceHeader)(unsafe.Pointer(&ifdescs))
|
||||||
|
ifdshdr.Cap = int(ifc.num_altsetting)
|
||||||
|
ifdshdr.Len = int(ifc.num_altsetting)
|
||||||
|
ifdshdr.Data = uintptr(unsafe.Pointer(ifc.altsetting))
|
||||||
|
|
||||||
|
for _, alt := range ifdescs {
|
||||||
|
if alt.bInterfaceClass != 3 {
|
||||||
|
// Device isn't a HID interface, add them to the device list.
|
||||||
|
|
||||||
|
var endps []C.struct_libusb_endpoint_descriptor
|
||||||
|
endpshdr := (*reflect.SliceHeader)(unsafe.Pointer(&endps))
|
||||||
|
endpshdr.Cap = int(alt.bNumEndpoints)
|
||||||
|
endpshdr.Len = int(alt.bNumEndpoints)
|
||||||
|
endpshdr.Data = uintptr(unsafe.Pointer(alt.endpoint))
|
||||||
|
|
||||||
|
endpoints := make([]GenericEndpoint, alt.bNumEndpoints)
|
||||||
|
|
||||||
|
for ne, endpoint := range endps {
|
||||||
|
endpoints[ne] = GenericEndpoint{
|
||||||
|
Direction: GenericEndpointDirection(endpoint.bEndpointAddress) & GenericEndpointDirectionIn,
|
||||||
|
Address: uint8(endpoint.bEndpointAddress),
|
||||||
|
Attributes: uint8(endpoint.bmAttributes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &GenericDeviceInfo{
|
||||||
|
Path: fmt.Sprintf("%x:%x:%d", vendorID, uint16(desc.idProduct), uint8(C.libusb_get_port_number(dev))),
|
||||||
|
VendorID: uint16(desc.idVendor),
|
||||||
|
ProductID: uint16(desc.idProduct),
|
||||||
|
device: &GenericDevice{
|
||||||
|
device: dev,
|
||||||
|
},
|
||||||
|
Endpoints: endpoints,
|
||||||
|
Interface: ifnum,
|
||||||
|
}
|
||||||
|
info.device.GenericDeviceInfo = info
|
||||||
|
infos = append(infos, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
// Device class is HID, skip it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return infos, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Enumerate returns a list of all the HID devices attached to the system which
|
// Enumerate returns a list of all the HID devices attached to the system which
|
||||||
// match the vendor and product id:
|
// match the vendor and product id:
|
||||||
// - If the vendor id is set to 0 then any vendor matches.
|
// - If the vendor id is set to 0 then any vendor matches.
|
||||||
// - If the product id is set to 0 then any product matches.
|
// - If the product id is set to 0 then any product matches.
|
||||||
// - If the vendor and product id are both 0, all HID devices are returned.
|
// - If the vendor and product id are both 0, all HID devices are returned.
|
||||||
func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
|
func Enumerate(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
|
||||||
enumerateLock.Lock()
|
enumerateLock.Lock()
|
||||||
defer enumerateLock.Unlock()
|
defer enumerateLock.Unlock()
|
||||||
|
|
||||||
|
infos, err := genericEnumerate(vendorID, productID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Gather all device infos and ensure they are freed before returning
|
// Gather all device infos and ensure they are freed before returning
|
||||||
head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID))
|
head := C.hid_enumerate(C.ushort(vendorID), C.ushort(productID))
|
||||||
if head == nil {
|
if head == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
defer C.hid_free_enumeration(head)
|
defer C.hid_free_enumeration(head)
|
||||||
|
|
||||||
// Iterate the list and retrieve the device details
|
// Iterate the list and retrieve the device details
|
||||||
var infos []DeviceInfo
|
|
||||||
for ; head != nil; head = head.next {
|
for ; head != nil; head = head.next {
|
||||||
info := DeviceInfo{
|
info := &HidDeviceInfo{
|
||||||
Path: C.GoString(head.path),
|
Path: C.GoString(head.path),
|
||||||
VendorID: uint16(head.vendor_id),
|
VendorID: uint16(head.vendor_id),
|
||||||
ProductID: uint16(head.product_id),
|
ProductID: uint16(head.product_id),
|
||||||
@ -104,11 +247,11 @@ func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
|
|||||||
}
|
}
|
||||||
infos = append(infos, info)
|
infos = append(infos, info)
|
||||||
}
|
}
|
||||||
return infos
|
return infos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open connects to an HID device by its path name.
|
// Open connects to an HID device by its path name.
|
||||||
func (info DeviceInfo) Open() (*Device, error) {
|
func (info *HidDeviceInfo) Open() (Device, error) {
|
||||||
enumerateLock.Lock()
|
enumerateLock.Lock()
|
||||||
defer enumerateLock.Unlock()
|
defer enumerateLock.Unlock()
|
||||||
|
|
||||||
@ -119,14 +262,14 @@ func (info DeviceInfo) Open() (*Device, error) {
|
|||||||
if device == nil {
|
if device == nil {
|
||||||
return nil, errors.New("hidapi: failed to open device")
|
return nil, errors.New("hidapi: failed to open device")
|
||||||
}
|
}
|
||||||
return &Device{
|
return &HidDevice{
|
||||||
DeviceInfo: info,
|
DeviceInfo: info,
|
||||||
device: device,
|
device: device,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device is a live HID USB connected device handle.
|
// HidDevice is a live HID USB connected device handle.
|
||||||
type Device struct {
|
type HidDevice struct {
|
||||||
DeviceInfo // Embed the infos for easier access
|
DeviceInfo // Embed the infos for easier access
|
||||||
|
|
||||||
device *C.hid_device // Low level HID device to communicate through
|
device *C.hid_device // Low level HID device to communicate through
|
||||||
@ -134,7 +277,7 @@ type Device struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close releases the HID USB device handle.
|
// Close releases the HID USB device handle.
|
||||||
func (dev *Device) Close() error {
|
func (dev *HidDevice) Close() error {
|
||||||
dev.lock.Lock()
|
dev.lock.Lock()
|
||||||
defer dev.lock.Unlock()
|
defer dev.lock.Unlock()
|
||||||
|
|
||||||
@ -149,7 +292,7 @@ func (dev *Device) Close() error {
|
|||||||
//
|
//
|
||||||
// Write will send the data on the first OUT endpoint, if one exists. If it does
|
// Write will send the data on the first OUT endpoint, if one exists. If it does
|
||||||
// not, it will send the data through the Control Endpoint (Endpoint 0).
|
// not, it will send the data through the Control Endpoint (Endpoint 0).
|
||||||
func (dev *Device) Write(b []byte) (int, error) {
|
func (dev *HidDevice) Write(b []byte) (int, error) {
|
||||||
// Abort if nothing to write
|
// Abort if nothing to write
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
@ -192,7 +335,7 @@ func (dev *Device) Write(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read retrieves an input report from a HID device.
|
// Read retrieves an input report from a HID device.
|
||||||
func (dev *Device) Read(b []byte) (int, error) {
|
func (dev *HidDevice) Read(b []byte) (int, error) {
|
||||||
// Aborth if nothing to read
|
// Aborth if nothing to read
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
@ -226,3 +369,91 @@ func (dev *Device) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
return read, nil
|
return read, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type identify the device as a HID device
|
||||||
|
func (dev *HidDevice) Type() DeviceType {
|
||||||
|
return dev.DeviceInfo.Type()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open tries to open the USB device represented by the current DeviceInfo
|
||||||
|
func (gdi *GenericDeviceInfo) Open() (Device, error) {
|
||||||
|
var handle *C.struct_libusb_device_handle
|
||||||
|
errCode := int(C.libusb_open(gdi.device.device, (**C.struct_libusb_device_handle)(&handle)))
|
||||||
|
if errCode < 0 {
|
||||||
|
return nil, fmt.Errorf("Error opening generic USB device %v, code %d", gdi.device.handle, errCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
gdi.device.handle = handle
|
||||||
|
// QUESTION: ai-je deja initialie le GDI ?
|
||||||
|
// GenericDeviceInfo: gdi,
|
||||||
|
// handle: handle,
|
||||||
|
// }
|
||||||
|
|
||||||
|
for _, endpoint := range gdi.Endpoints {
|
||||||
|
switch {
|
||||||
|
case endpoint.Direction == GenericEndpointDirectionOut && endpoint.Attributes == GenericEndpointAttributeInterrupt:
|
||||||
|
gdi.device.WEndpoint = endpoint.Address
|
||||||
|
case endpoint.Direction == GenericEndpointDirectionIn && endpoint.Attributes == GenericEndpointAttributeInterrupt:
|
||||||
|
gdi.device.REndpoint = endpoint.Address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if gdi.device.REndpoint == 0 || gdi.device.WEndpoint == 0 {
|
||||||
|
return nil, fmt.Errorf("Missing endpoint in device %#x:%#x:%d", gdi.VendorID, gdi.ProductID, gdi.Interface)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gdi.device, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericDevice represents a generic USB device
|
||||||
|
type GenericDevice struct {
|
||||||
|
*GenericDeviceInfo // Embed the infos for easier access
|
||||||
|
|
||||||
|
REndpoint uint8
|
||||||
|
WEndpoint uint8
|
||||||
|
|
||||||
|
device *C.struct_libusb_device
|
||||||
|
handle *C.struct_libusb_device_handle
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements io.ReaderWriter
|
||||||
|
func (gd *GenericDevice) Write(b []byte) (int, error) {
|
||||||
|
gd.lock.Lock()
|
||||||
|
defer gd.lock.Unlock()
|
||||||
|
|
||||||
|
out, err := interruptTransfer(gd.handle, gd.WEndpoint, b)
|
||||||
|
return len(out), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements io.ReaderWriter
|
||||||
|
func (gd *GenericDevice) Read(b []byte) (int, error) {
|
||||||
|
gd.lock.Lock()
|
||||||
|
defer gd.lock.Unlock()
|
||||||
|
|
||||||
|
out, err := interruptTransfer(gd.handle, gd.REndpoint, b)
|
||||||
|
return len(out), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close a previously opened generic USB device
|
||||||
|
func (gd *GenericDevice) Close() error {
|
||||||
|
gd.lock.Lock()
|
||||||
|
defer gd.lock.Unlock()
|
||||||
|
|
||||||
|
if gd.handle != nil {
|
||||||
|
C.libusb_close(gd.handle)
|
||||||
|
gd.handle = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// interruptTransfer is a helpler function for libusb's interrupt transfer function
|
||||||
|
func interruptTransfer(handle *C.struct_libusb_device_handle, endpoint uint8, data []byte) ([]byte, error) {
|
||||||
|
var transferred C.int
|
||||||
|
errCode := int(C.libusb_interrupt_transfer(handle, (C.uchar)(endpoint), (*C.uchar)(&data[0]), (C.int)(len(data)), &transferred, (C.uint)(0)))
|
||||||
|
if errCode != 0 {
|
||||||
|
return nil, fmt.Errorf("Interrupt transfer error: %s", C.GoString(C.usb_strerror(C.int(errCode))))
|
||||||
|
}
|
||||||
|
return data[:int(transferred)], nil
|
||||||
|
}
|
||||||
|
53
vendor/github.com/karalabe/hid/usb.go
generated
vendored
Normal file
53
vendor/github.com/karalabe/hid/usb.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// hid - Gopher Interface Devices (USB HID)
|
||||||
|
// Copyright (c) 2019 Péter Szilágyi, Guillaume Ballet. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is released under the 3-clause BSD license. Note however that Linux
|
||||||
|
// support depends on libusb, released under GNU LGPL 2.1 or later.
|
||||||
|
|
||||||
|
// Package usb provide interfaces for generic USB devices.
|
||||||
|
package hid
|
||||||
|
|
||||||
|
// DeviceType represents the type of a USB device (generic or HID)
|
||||||
|
type DeviceType int
|
||||||
|
|
||||||
|
// List of supported device types
|
||||||
|
const (
|
||||||
|
DeviceTypeGeneric DeviceType = 0
|
||||||
|
DeviceTypeHID DeviceType = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enumerate returns a list of all the HID devices attached to the system which
|
||||||
|
// match the vendor and product id:
|
||||||
|
// - If the vendor id is set to 0 then any vendor matches.
|
||||||
|
// - If the product id is set to 0 then any product matches.
|
||||||
|
// - If the vendor and product id are both 0, all HID devices are returned.
|
||||||
|
// func Enumerate(vendorID uint16, productID uint16) []DeviceInfo {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// DeviceInfo is a generic libusb info interface
|
||||||
|
type DeviceInfo interface {
|
||||||
|
// Type returns the type of the device (generic or HID)
|
||||||
|
Type() DeviceType
|
||||||
|
|
||||||
|
// Platform-specific device path
|
||||||
|
GetPath() string
|
||||||
|
|
||||||
|
// IDs returns the vendor and product IDs for the device,
|
||||||
|
// as well as the endpoint id and the usage page.
|
||||||
|
IDs() (uint16, uint16, int, uint16)
|
||||||
|
|
||||||
|
// Open tries to open the USB device represented by the current DeviceInfo
|
||||||
|
Open() (Device, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device is a generic libusb device interface
|
||||||
|
type Device interface {
|
||||||
|
Close() error
|
||||||
|
|
||||||
|
Write(b []byte) (int, error)
|
||||||
|
|
||||||
|
Read(b []byte) (int, error)
|
||||||
|
|
||||||
|
// Type returns the type of the device (generic or HID)
|
||||||
|
Type() DeviceType
|
||||||
|
}
|
2
vendor/github.com/karalabe/hid/wchar.go
generated
vendored
2
vendor/github.com/karalabe/hid/wchar.go
generated
vendored
@ -7,7 +7,7 @@
|
|||||||
// https://github.com/orofarne/gowchar/blob/master/LICENSE
|
// https://github.com/orofarne/gowchar/blob/master/LICENSE
|
||||||
|
|
||||||
// +build !ios
|
// +build !ios
|
||||||
// +build linux darwin windows
|
// +build freebsd linux darwin windows
|
||||||
|
|
||||||
package hid
|
package hid
|
||||||
|
|
||||||
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -267,10 +267,10 @@
|
|||||||
"revisionTime": "2017-04-30T22:20:11Z"
|
"revisionTime": "2017-04-30T22:20:11Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "6XsjAARQFvlW6dS15al0ibTFPOQ=",
|
"checksumSHA1": "p6UjFsx/1ACWAhsdEOWrXAHptGY=",
|
||||||
"path": "github.com/karalabe/hid",
|
"path": "github.com/karalabe/hid",
|
||||||
"revision": "d815e0c1a2e2082a287a2806bc90bc8fc7b276a9",
|
"revision": "e40407cce1c217644c09da5415bbfb07d330ea5e",
|
||||||
"revisionTime": "2018-11-28T19:21:57Z",
|
"revisionTime": "2019-05-28T15:16:06Z",
|
||||||
"tree": true
|
"tree": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user