Cleanup
This commit is contained in:
@@ -24,54 +24,17 @@ func main() {
|
||||
ctx.Debug(*debug)
|
||||
|
||||
// ListDevices is used to find the devices to open.
|
||||
devs, err := ctx.ListDevices(func(bus, addr int, desc *usb.Descriptor) bool {
|
||||
// After inspecting the descriptor, return true or false depending on whether
|
||||
// the device is "interesting" or not. Any descriptor for which true is returned
|
||||
// generates a DeviceInfo which is retuned in a slice.
|
||||
return true
|
||||
})
|
||||
|
||||
// All DeviceInfo returned from ListDevices must be closed.
|
||||
defer func() {
|
||||
for _, d := range devs {
|
||||
d.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// ListDevices can occaionally fail, so be sure to check its return value.
|
||||
if err != nil {
|
||||
log.Fatalf("list: %s", err)
|
||||
}
|
||||
|
||||
for _, dev := range devs {
|
||||
// The descriptor (which contains useful information) can always be obtained again
|
||||
// from a DeviceInfo.
|
||||
desc, err := dev.Descriptor()
|
||||
if err != nil {
|
||||
log.Printf("desc: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// The DeviceInfo contains the bus number and bus address of the device.
|
||||
bus := dev.BusNumber()
|
||||
addr := dev.Address()
|
||||
|
||||
devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
|
||||
// The usbid package can be used to print out human readable information.
|
||||
fmt.Printf("%03d:%03d %s\n", bus, addr, usbid.Describe(desc))
|
||||
fmt.Printf("%03d.%03d %s\n", desc.Bus, desc.Address, usbid.Describe(desc))
|
||||
fmt.Printf(" Protocol: %s\n", usbid.Classify(desc))
|
||||
|
||||
// The configurations can be examined from the DeviceInfo, though they can only
|
||||
// The configurations can be examined from the Descriptor, though they can only
|
||||
// be set once the device is opened. All configuration references must be closed,
|
||||
// to free up the memory in libusb.
|
||||
cfgs, err := dev.Configurations()
|
||||
if err != nil {
|
||||
log.Printf(" - configs: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// This loop just uses more of the built-in and usbid pretty printing to list
|
||||
// the USB devices.
|
||||
for _, cfg := range cfgs {
|
||||
for _, cfg := range desc.Configs {
|
||||
// This loop just uses more of the built-in and usbid pretty printing to list
|
||||
// the USB devices.
|
||||
fmt.Printf(" %s:\n", cfg)
|
||||
for _, alt := range cfg.Interfaces {
|
||||
fmt.Printf(" --------------\n")
|
||||
@@ -86,7 +49,27 @@ func main() {
|
||||
fmt.Printf(" --------------\n")
|
||||
}
|
||||
|
||||
// To actually interact with a device, DevInfo.Open() returns a device handle
|
||||
// which can be used to do more I/O with the device and its endpoints.
|
||||
// After inspecting the descriptor, return true or false depending on whether
|
||||
// the device is "interesting" or not. Any descriptor for which true is returned
|
||||
// opens a Device which is retuned in a slice (and must be subsequently closed).
|
||||
return false
|
||||
})
|
||||
|
||||
// All Devices returned from ListDevices must be closed.
|
||||
defer func() {
|
||||
for _, d := range devs {
|
||||
d.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// ListDevices can occaionally fail, so be sure to check its return value.
|
||||
if err != nil {
|
||||
log.Fatalf("list: %s", err)
|
||||
}
|
||||
|
||||
for _, dev := range devs {
|
||||
// Once the device has been selected from ListDevices, it is opened
|
||||
// and can be interacted with.
|
||||
_ = dev
|
||||
}
|
||||
}
|
||||
|
@@ -44,27 +44,27 @@ type InterfaceInfo struct {
|
||||
IfClass uint8
|
||||
IfSubClass uint8
|
||||
IfProtocol uint8
|
||||
Endpoints []*EndpointInfo
|
||||
Endpoints []EndpointInfo
|
||||
}
|
||||
|
||||
func (i InterfaceInfo) String() string {
|
||||
return fmt.Sprintf("Interface %02x (config %02x)", i.Number, i.Alternate)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
type ConfigInfo struct {
|
||||
Type DescriptorType
|
||||
Config uint8
|
||||
Attributes uint8
|
||||
MaxPower uint8
|
||||
Interfaces [][]*InterfaceInfo
|
||||
Interfaces [][]InterfaceInfo
|
||||
}
|
||||
|
||||
func (c Config) String() string {
|
||||
func (c ConfigInfo) String() string {
|
||||
return fmt.Sprintf("Config %02x", c.Config)
|
||||
}
|
||||
|
||||
func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||
c := &Config{
|
||||
func newConfig(cfg *C.struct_libusb_config_descriptor) ConfigInfo {
|
||||
c := ConfigInfo{
|
||||
Type: DescriptorType(cfg.bDescriptorType),
|
||||
Config: uint8(cfg.bConfigurationValue),
|
||||
Attributes: uint8(cfg.bmAttributes),
|
||||
@@ -77,7 +77,7 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||
Len: int(cfg.bNumInterfaces),
|
||||
Cap: int(cfg.bNumInterfaces),
|
||||
}
|
||||
c.Interfaces = make([][]*InterfaceInfo, 0, len(ifaces))
|
||||
c.Interfaces = make([][]InterfaceInfo, 0, len(ifaces))
|
||||
for _, iface := range ifaces {
|
||||
var alts []C.struct_libusb_interface_descriptor
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{
|
||||
@@ -85,9 +85,9 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||
Len: int(iface.num_altsetting),
|
||||
Cap: int(iface.num_altsetting),
|
||||
}
|
||||
descs := make([]*InterfaceInfo, 0, len(alts))
|
||||
descs := make([]InterfaceInfo, 0, len(alts))
|
||||
for _, alt := range alts {
|
||||
i := &InterfaceInfo{
|
||||
i := InterfaceInfo{
|
||||
Type: DescriptorType(alt.bDescriptorType),
|
||||
Number: uint8(alt.bInterfaceNumber),
|
||||
Alternate: uint8(alt.bAlternateSetting),
|
||||
@@ -101,9 +101,9 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||
Len: int(alt.bNumEndpoints),
|
||||
Cap: int(alt.bNumEndpoints),
|
||||
}
|
||||
i.Endpoints = make([]*EndpointInfo, 0, len(ends))
|
||||
i.Endpoints = make([]EndpointInfo, 0, len(ends))
|
||||
for _, end := range ends {
|
||||
i.Endpoints = append(i.Endpoints, &EndpointInfo{
|
||||
i.Endpoints = append(i.Endpoints, EndpointInfo{
|
||||
Type: DescriptorType(end.bDescriptorType),
|
||||
Address: uint8(end.bEndpointAddress),
|
||||
Attributes: uint8(end.bmAttributes),
|
||||
|
150
usb/constants.go
Normal file
150
usb/constants.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package usb
|
||||
|
||||
// #cgo LDFLAGS: -lusb-1.0
|
||||
// #include <libusb-1.0/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 = 0x03
|
||||
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]
|
||||
}
|
@@ -5,16 +5,25 @@ package usb
|
||||
import "C"
|
||||
|
||||
type Descriptor struct {
|
||||
desc *C.struct_libusb_device_descriptor
|
||||
// Bus information
|
||||
Bus uint8 // The bus on which the device was detected
|
||||
Address uint8 // The address of the device on the bus
|
||||
|
||||
Type DescriptorType // The type of this descriptor
|
||||
Spec BCD // USB Specification Release Number
|
||||
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
|
||||
Vendor ID // The 8-bit Vendor identifer
|
||||
Product ID // The 8-bit Product identifier
|
||||
Device BCD // The device version
|
||||
// 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
|
||||
}
|
||||
|
||||
func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
||||
@@ -22,196 +31,28 @@ func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
||||
if errno := C.libusb_get_device_descriptor(dev, &desc); errno < 0 {
|
||||
return nil, usbError(errno)
|
||||
}
|
||||
return &Descriptor{
|
||||
desc: &desc,
|
||||
Type: DescriptorType(desc.bDescriptorType),
|
||||
Spec: BCD(desc.bcdUSB),
|
||||
Class: uint8(desc.bDeviceClass),
|
||||
SubClass: uint8(desc.bDeviceSubClass),
|
||||
Protocol: uint8(desc.bDeviceProtocol),
|
||||
Vendor: ID(desc.idVendor),
|
||||
Product: ID(desc.idProduct),
|
||||
Device: BCD(desc.bcdDevice),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Configurations returns a list of configurations configured on this
|
||||
// device. Each config must be Closed.
|
||||
func (d *DeviceInfo) Configurations() ([]*Config, error) {
|
||||
var desc C.struct_libusb_device_descriptor
|
||||
if errno := C.libusb_get_device_descriptor(d.dev, &desc); errno < 0 {
|
||||
return nil, usbError(errno)
|
||||
}
|
||||
|
||||
var cfgs []*Config
|
||||
// Enumerate configurations
|
||||
var cfgs []ConfigInfo
|
||||
for i := 0; i < int(desc.bNumConfigurations); i++ {
|
||||
var cfg *C.struct_libusb_config_descriptor
|
||||
if errno := C.libusb_get_config_descriptor(d.dev, C.uint8_t(i), &cfg); errno < 0 {
|
||||
if errno := C.libusb_get_config_descriptor(dev, C.uint8_t(i), &cfg); errno < 0 {
|
||||
return nil, usbError(errno)
|
||||
}
|
||||
cfgs = append(cfgs, newConfig(cfg))
|
||||
C.libusb_free_config_descriptor(cfg)
|
||||
}
|
||||
return cfgs, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (d Descriptor) str(idx int) (string, error) {
|
||||
str := [64]byte{}
|
||||
n := C.libusb_get_string_descriptor_ascii(
|
||||
d.dev.handle,
|
||||
C.uint8_t(idx),
|
||||
(*C.uchar)(unsafe.Pointer(&str)),
|
||||
64,
|
||||
)
|
||||
if n < 0 {
|
||||
return "", usbError(n)
|
||||
}
|
||||
return string(str[:n]), nil
|
||||
}
|
||||
*/
|
||||
|
||||
type Class int
|
||||
|
||||
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 int
|
||||
|
||||
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 int
|
||||
|
||||
const (
|
||||
ENDPOINT_NUM_MASK = 0x03
|
||||
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 int
|
||||
|
||||
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 int
|
||||
|
||||
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 int
|
||||
|
||||
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]
|
||||
|
||||
return &Descriptor{
|
||||
Bus: uint8(C.libusb_get_bus_number(dev)),
|
||||
Address: uint8(C.libusb_get_device_address(dev)),
|
||||
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
|
||||
}
|
||||
|
@@ -5,80 +5,35 @@ package usb
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DeviceInfo struct {
|
||||
dev *C.libusb_device
|
||||
}
|
||||
|
||||
func newDeviceInfo(dev *C.libusb_device) *DeviceInfo {
|
||||
d := &DeviceInfo{
|
||||
dev: dev,
|
||||
}
|
||||
|
||||
// Reference this device
|
||||
C.libusb_ref_device(dev)
|
||||
|
||||
// I still can't get this to be called
|
||||
runtime.SetFinalizer(d, (*DeviceInfo).Close)
|
||||
|
||||
//log.Printf("deviceInfo %p initialized", d.dev)
|
||||
return d
|
||||
}
|
||||
|
||||
// Get the assigned Bus Number for this USB device.
|
||||
func (d *DeviceInfo) BusNumber() byte {
|
||||
return byte(C.libusb_get_bus_number(d.dev))
|
||||
}
|
||||
|
||||
// Get the assigned Bus Address for this USB device.
|
||||
func (d *DeviceInfo) Address() byte {
|
||||
return byte(C.libusb_get_device_address(d.dev))
|
||||
}
|
||||
|
||||
// Get a descriptor for the device.
|
||||
func (d *DeviceInfo) Descriptor() (*Descriptor, error) {
|
||||
return newDescriptor(d.dev)
|
||||
}
|
||||
|
||||
// Open the given device for I/O.
|
||||
func (d *DeviceInfo) Open() (*Device, error) {
|
||||
var handle *C.libusb_device_handle
|
||||
if errno := C.libusb_open(d.dev, &handle); errno != 0 {
|
||||
return nil, usbError(errno)
|
||||
}
|
||||
|
||||
return newDevice(handle), nil
|
||||
}
|
||||
|
||||
// Close decrements the reference count for the device in the libusb driver
|
||||
// code. It should be called exactly once!
|
||||
func (d *DeviceInfo) Close() error {
|
||||
if d.dev != nil {
|
||||
//log.Printf("deviceInfo %p closed", d.dev)
|
||||
C.libusb_unref_device(d.dev)
|
||||
}
|
||||
d.dev = nil
|
||||
return nil
|
||||
}
|
||||
var DefaultControlTimeout = 5 * time.Second
|
||||
|
||||
type Device struct {
|
||||
handle *C.libusb_device_handle
|
||||
|
||||
// Embed the device information for easy access
|
||||
*Descriptor
|
||||
|
||||
// Timeouts
|
||||
ControlTimeout time.Duration
|
||||
}
|
||||
|
||||
func newDevice(handle *C.libusb_device_handle) *Device {
|
||||
func newDevice(handle *C.libusb_device_handle, desc *Descriptor) *Device {
|
||||
d := &Device{
|
||||
handle: handle,
|
||||
handle: handle,
|
||||
Descriptor: desc,
|
||||
ControlTimeout: DefaultControlTimeout,
|
||||
}
|
||||
|
||||
// :(
|
||||
// This doesn't seem to actually get called
|
||||
runtime.SetFinalizer(d, (*Device).Close)
|
||||
|
||||
//log.Printf("device %p initialized", d.handle)
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -89,8 +44,6 @@ func (d *Device) Reset() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ControlTimeout = 5 * time.Second
|
||||
|
||||
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
||||
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||
n := C.libusb_control_transfer(
|
||||
@@ -101,33 +54,39 @@ func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (in
|
||||
C.uint16_t(idx),
|
||||
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
||||
C.uint16_t(len(data)),
|
||||
C.uint(ControlTimeout/time.Millisecond))
|
||||
C.uint(d.ControlTimeout/time.Millisecond))
|
||||
if n < 0 {
|
||||
return int(n), usbError(n)
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func (d *Device) ActiveConfig() (int, error) {
|
||||
// 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) {
|
||||
var cfg C.int
|
||||
if errno := C.libusb_get_configuration(d.handle, &cfg); errno < 0 {
|
||||
return 0, usbError(errno)
|
||||
}
|
||||
return int(cfg), nil
|
||||
return uint8(cfg), nil
|
||||
}
|
||||
|
||||
func (d *Device) SetConfig(cfg int) error {
|
||||
// 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 {
|
||||
if errno := C.libusb_set_configuration(d.handle, C.int(cfg)); errno < 0 {
|
||||
return usbError(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close the device.
|
||||
func (d *Device) Close() error {
|
||||
if d.handle != nil {
|
||||
//log.Printf("device %p closed", d.handle)
|
||||
C.libusb_unref_device(d.handle)
|
||||
if d.handle == nil {
|
||||
return fmt.Errorf("usb: double close on device")
|
||||
}
|
||||
C.libusb_close(d.handle)
|
||||
d.handle = nil
|
||||
return nil
|
||||
}
|
||||
|
32
usb/usb.go
32
usb/usb.go
@@ -21,7 +21,6 @@ func (c *Context) Debug(level int) {
|
||||
func NewContext() *Context {
|
||||
c := new(Context)
|
||||
|
||||
//log.Printf("gousb initialized")
|
||||
if errno := C.libusb_init(&c.ctx); errno != 0 {
|
||||
panic(usbError(errno))
|
||||
}
|
||||
@@ -32,10 +31,12 @@ func NewContext() *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// ListDevices calls each with each enumerated device. If the function returns
|
||||
// true, the device is added to the list of *DeviceInfo to return. All of
|
||||
// these must be Closed, even if an error is also returned.
|
||||
func (c *Context) ListDevices(each func(bus, addr int, desc *Descriptor) bool) ([]*DeviceInfo, error) {
|
||||
// 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) {
|
||||
var list **C.libusb_device
|
||||
cnt := C.libusb_get_device_list(c.ctx, &list)
|
||||
if cnt < 0 {
|
||||
@@ -50,25 +51,30 @@ func (c *Context) ListDevices(each func(bus, addr int, desc *Descriptor) bool) (
|
||||
Cap: int(cnt),
|
||||
}
|
||||
|
||||
ret := []*DeviceInfo{}
|
||||
var reterr error
|
||||
ret := []*Device{}
|
||||
for _, dev := range slice {
|
||||
bus := int(C.libusb_get_bus_number(dev))
|
||||
addr := int(C.libusb_get_device_address(dev))
|
||||
desc, err := newDescriptor(dev)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
reterr = err
|
||||
continue
|
||||
}
|
||||
if each(bus, addr, desc) {
|
||||
ret = append(ret, newDeviceInfo(dev))
|
||||
|
||||
if each(desc) {
|
||||
var handle *C.libusb_device_handle
|
||||
if errno := C.libusb_open(dev, &handle); errno != 0 {
|
||||
reterr = err
|
||||
continue
|
||||
}
|
||||
ret = append(ret, newDevice(handle, desc))
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
return ret, reterr
|
||||
}
|
||||
|
||||
func (c *Context) Close() error {
|
||||
if c.ctx != nil {
|
||||
C.libusb_exit(c.ctx)
|
||||
//log.Printf("gousb finished")
|
||||
}
|
||||
c.ctx = nil
|
||||
return nil
|
||||
|
@@ -18,9 +18,30 @@ func TestEnum(t *testing.T) {
|
||||
defer c.Close()
|
||||
c.Debug(0)
|
||||
|
||||
cnt := 0
|
||||
devs, err := c.ListDevices(func(bus, addr int, desc *Descriptor) bool {
|
||||
cnt++
|
||||
logDevice := func(t *testing.T, desc *Descriptor) {
|
||||
t.Logf("%03d.%03d %s", desc.Bus, desc.Address, usbid.Describe(desc))
|
||||
t.Logf("- Protocol: %s", usbid.Classify(desc))
|
||||
|
||||
for _, cfg := range desc.Configs {
|
||||
t.Logf("- %s:", cfg)
|
||||
for _, alt := range cfg.Interfaces {
|
||||
t.Logf(" --------------")
|
||||
for _, iface := range alt {
|
||||
t.Logf(" - %s", iface)
|
||||
t.Logf(" - %s", usbid.Classify(iface))
|
||||
for _, end := range iface.Endpoints {
|
||||
t.Logf(" - %s (packet size: %d bytes)", end, end.MaxPacketSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Logf(" --------------")
|
||||
}
|
||||
}
|
||||
|
||||
descs := []*Descriptor{}
|
||||
devs, err := c.ListDevices(func(desc *Descriptor) bool {
|
||||
logDevice(t, desc)
|
||||
descs = append(descs, desc)
|
||||
return true
|
||||
})
|
||||
defer func() {
|
||||
@@ -32,41 +53,13 @@ func TestEnum(t *testing.T) {
|
||||
t.Fatalf("list: %s", err)
|
||||
}
|
||||
|
||||
if got, want := len(devs), cnt; got != want {
|
||||
t.Errorf("len(devs) = %d, want %d", got, want)
|
||||
if got, want := len(devs), len(descs); got != want {
|
||||
t.Fatalf("len(devs) = %d, want %d", got, want)
|
||||
}
|
||||
|
||||
for _, dev := range devs {
|
||||
desc, err := dev.Descriptor()
|
||||
if err != nil {
|
||||
t.Errorf("desc: %s", err)
|
||||
continue
|
||||
}
|
||||
bus := dev.BusNumber()
|
||||
addr := dev.Address()
|
||||
|
||||
t.Logf("%03d:%03d %s", bus, addr, usbid.Describe(desc))
|
||||
t.Logf("- Protocol: %s", usbid.Classify(desc))
|
||||
|
||||
cfgs, err := dev.Configurations()
|
||||
if err != nil {
|
||||
t.Errorf(" - configs: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
t.Logf("- %s:", cfg)
|
||||
for _, alt := range cfg.Interfaces {
|
||||
t.Logf(" --------------")
|
||||
for _, iface := range alt {
|
||||
t.Logf(" - %s", iface)
|
||||
t.Logf(" - %s", usbid.Classify(iface))
|
||||
for _, end := range iface.Endpoints {
|
||||
t.Logf(" - %s", end)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Logf(" --------------")
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user