This commit is contained in:
Kyle Lemons
2012-03-27 19:40:22 -07:00
parent 25c01a9f60
commit e5a0531ed2
7 changed files with 297 additions and 365 deletions

View File

@@ -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
}
}

View File

@@ -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
View 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]
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)
}
}
}