Add config, interfaces, endpoints, etc
This commit is contained in:
114
usb/config.go
Normal file
114
usb/config.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package usb
|
||||
|
||||
// #cgo LDFLAGS: -lusb-1.0
|
||||
// #include <libusb-1.0/libusb.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Endpoint struct {
|
||||
Type DescriptorType
|
||||
Address ID
|
||||
MaxPacketSize uint16
|
||||
PollInterval uint8
|
||||
RefreshRate uint8
|
||||
SynchAddress ID
|
||||
}
|
||||
|
||||
type Interface struct {
|
||||
Type DescriptorType
|
||||
Number ID
|
||||
Alternate ID
|
||||
IfClass Class
|
||||
IfSubClass uint8
|
||||
IfProtocol uint8
|
||||
Endpoints []*Endpoint
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
cfg *C.struct_libusb_config_descriptor
|
||||
|
||||
Type DescriptorType
|
||||
Config ID
|
||||
Attributes uint8
|
||||
MaxPower uint8
|
||||
Interfaces [][]*Interface
|
||||
}
|
||||
|
||||
func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||
c := &Config{
|
||||
cfg: cfg,
|
||||
Type: DescriptorType(cfg.bDescriptorType),
|
||||
Config: ID(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([][]*Interface, 0, len(ifaces))
|
||||
for _, iface := range ifaces {
|
||||
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([]*Interface, 0, len(alts))
|
||||
for _, alt := range alts {
|
||||
i := &Interface{
|
||||
Type: DescriptorType(alt.bDescriptorType),
|
||||
Number: ID(alt.bInterfaceNumber),
|
||||
Alternate: ID(alt.bAlternateSetting),
|
||||
IfClass: Class(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([]*Endpoint, 0, len(ends))
|
||||
for _, end := range ends {
|
||||
i.Endpoints = append(i.Endpoints, &Endpoint{
|
||||
Type: DescriptorType(end.bDescriptorType),
|
||||
Address: ID(end.bEndpointAddress),
|
||||
MaxPacketSize: uint16(end.wMaxPacketSize),
|
||||
PollInterval: uint8(end.bInterval),
|
||||
RefreshRate: uint8(end.bRefresh),
|
||||
SynchAddress: ID(end.bSynchAddress),
|
||||
})
|
||||
}
|
||||
descs = append(descs, i)
|
||||
}
|
||||
c.Interfaces = append(c.Interfaces, descs)
|
||||
}
|
||||
|
||||
// *sigh*
|
||||
runtime.SetFinalizer(c, (*Config).Close)
|
||||
|
||||
log.Printf("config %p initialized", c.cfg)
|
||||
return c
|
||||
}
|
||||
|
||||
// Close decrements the reference count for the device in the libusb driver
|
||||
// code. It should be called exactly once!
|
||||
func (c *Config) Close() error {
|
||||
if c.cfg != nil {
|
||||
log.Printf("config %p closed", c.cfg)
|
||||
C.libusb_free_config_descriptor(c.cfg)
|
||||
}
|
||||
c.cfg = nil
|
||||
return nil
|
||||
}
|
@@ -15,7 +15,6 @@ type Descriptor struct {
|
||||
Vendor ID // The 8-bit Vendor identifer
|
||||
Product ID // The 8-bit Product identifier
|
||||
Device BCD // The device version
|
||||
Configs int // Number of configurations
|
||||
}
|
||||
|
||||
func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
||||
@@ -33,10 +32,36 @@ func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
||||
Vendor: ID(desc.idVendor),
|
||||
Product: ID(desc.idProduct),
|
||||
Device: BCD(desc.bcdDevice),
|
||||
Configs: int(desc.bNumConfigurations),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Configurations returns a list of configurations configured on this
|
||||
// device. Each config must be Closed.
|
||||
func (d *DeviceInfo) Configurations() (_c []*Config, _e 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
|
||||
defer func() {
|
||||
if _e != nil {
|
||||
for _, c := range cfgs {
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
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 {
|
||||
return nil, usbError(errno)
|
||||
}
|
||||
cfgs = append(cfgs, newConfig(cfg))
|
||||
}
|
||||
return cfgs, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (d Descriptor) str(idx int) (string, error) {
|
||||
str := [64]byte{}
|
||||
|
@@ -6,7 +6,9 @@ import "C"
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DeviceInfo struct {
|
||||
@@ -80,6 +82,30 @@ func newDevice(handle *C.libusb_device_handle) *Device {
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Device) Reset() error {
|
||||
if errno := C.libusb_reset_device(d.handle); errno != 0 {
|
||||
return usbError(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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(
|
||||
d.handle,
|
||||
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)),
|
||||
0)
|
||||
if n < 0 {
|
||||
return int(n), usbError(n)
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func (d *Device) Close() error {
|
||||
if d.handle != nil {
|
||||
log.Printf("device %p closed", d.handle)
|
||||
|
@@ -15,7 +15,7 @@ const (
|
||||
func (d BCD) Int() (i int) {
|
||||
ten := 1
|
||||
for o := uint(0); o < 4; o++ {
|
||||
n := ((0xF << (o*4)) & d) >> (o*4)
|
||||
n := ((0xF << (o * 4)) & d) >> (o * 4)
|
||||
i += int(n) * ten
|
||||
ten *= 10
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func (d BCD) Int() (i int) {
|
||||
}
|
||||
|
||||
func (d BCD) String() string {
|
||||
return fmt.Sprintf("%02x.%02x", int(d >> 8), int(d & 0xFF))
|
||||
return fmt.Sprintf("%02x.%02x", int(d>>8), int(d&0xFF))
|
||||
}
|
||||
|
||||
type ID uint16
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBCD(t *testing.T) {
|
||||
tests := []struct{
|
||||
tests := []struct {
|
||||
BCD
|
||||
Int int
|
||||
Str string
|
||||
|
@@ -10,24 +10,18 @@ import (
|
||||
func TestNoop(t *testing.T) {
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(3)
|
||||
c.Debug(0)
|
||||
}
|
||||
|
||||
func TestEnum(t *testing.T) {
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(3)
|
||||
c.Debug(0)
|
||||
|
||||
cnt := 0
|
||||
devs, err := c.ListDevices(func(bus, addr int, desc *Descriptor) bool {
|
||||
t.Logf("%03d:%03d %+v", bus, addr, desc)
|
||||
if v, ok := usbid.Vendors[desc.Vendor]; ok {
|
||||
if p, ok := v.Devices[desc.Product]; ok {
|
||||
t.Logf(" - %s (%s) %s (%s)", v, desc.Vendor, p, desc.Product)
|
||||
} else {
|
||||
t.Logf(" - %s (%s) Unknown", v, desc.Vendor)
|
||||
}
|
||||
}
|
||||
return false
|
||||
cnt++
|
||||
return true
|
||||
})
|
||||
defer func() {
|
||||
for _, d := range devs {
|
||||
@@ -37,4 +31,51 @@ func TestEnum(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("list: %s", err)
|
||||
}
|
||||
|
||||
if got, want := len(devs), cnt; got != want {
|
||||
t.Errorf("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 %+v", bus, addr, desc)
|
||||
if v, ok := usbid.Vendors[desc.Vendor]; ok {
|
||||
if p, ok := v.Devices[desc.Product]; ok {
|
||||
t.Logf(" - %s (%s) %s (%s)", v, desc.Vendor, p, desc.Product)
|
||||
} else {
|
||||
t.Logf(" - %s (%s) Unknown", v, desc.Vendor)
|
||||
}
|
||||
}
|
||||
|
||||
cfgs, err := dev.Configurations()
|
||||
defer func() {
|
||||
for _, cfg := range cfgs {
|
||||
cfg.Close()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
t.Errorf(" - configs: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
t.Logf(" - %#v", cfg)
|
||||
for _, alt := range cfg.Interfaces {
|
||||
for _, iface := range alt {
|
||||
t.Logf(" - %#v", iface)
|
||||
for _, end := range iface.Endpoints {
|
||||
t.Logf(" - %#v", end)
|
||||
}
|
||||
}
|
||||
t.Logf(" -----")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
package usbid
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"log"
|
||||
|
||||
"github.com/kylelemons/gousb/usb"
|
||||
)
|
||||
|
@@ -151,7 +151,8 @@ parseLines:
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case "": err = parseVendor(level, id, name)
|
||||
case "":
|
||||
err = parseVendor(level, id, name)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("line %d: %s", lineno, err)
|
||||
|
Reference in New Issue
Block a user