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
|
||||||
|
}
|
@@ -5,17 +5,16 @@ package usb
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type Descriptor struct {
|
type Descriptor struct {
|
||||||
desc *C.struct_libusb_device_descriptor
|
desc *C.struct_libusb_device_descriptor
|
||||||
|
|
||||||
Type DescriptorType // The type of this descriptor
|
Type DescriptorType // The type of this descriptor
|
||||||
Spec BCD // USB Specification Release Number
|
Spec BCD // USB Specification Release Number
|
||||||
Class Class // The class of this device
|
Class Class // The class of this device
|
||||||
SubClass uint8 // The sub-class (within 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
|
Protocol uint8 // The protocol (within the sub-class) of this device
|
||||||
Vendor ID // The 8-bit Vendor identifer
|
Vendor ID // The 8-bit Vendor identifer
|
||||||
Product ID // The 8-bit Product identifier
|
Product ID // The 8-bit Product identifier
|
||||||
Device BCD // The device version
|
Device BCD // The device version
|
||||||
Configs int // Number of configurations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
||||||
@@ -33,10 +32,36 @@ func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
|||||||
Vendor: ID(desc.idVendor),
|
Vendor: ID(desc.idVendor),
|
||||||
Product: ID(desc.idProduct),
|
Product: ID(desc.idProduct),
|
||||||
Device: BCD(desc.bcdDevice),
|
Device: BCD(desc.bcdDevice),
|
||||||
Configs: int(desc.bNumConfigurations),
|
|
||||||
}, nil
|
}, 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) {
|
func (d Descriptor) str(idx int) (string, error) {
|
||||||
str := [64]byte{}
|
str := [64]byte{}
|
||||||
|
@@ -6,7 +6,9 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeviceInfo struct {
|
type DeviceInfo struct {
|
||||||
@@ -80,6 +82,30 @@ func newDevice(handle *C.libusb_device_handle) *Device {
|
|||||||
return d
|
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 {
|
func (d *Device) Close() error {
|
||||||
if d.handle != nil {
|
if d.handle != nil {
|
||||||
log.Printf("device %p closed", d.handle)
|
log.Printf("device %p closed", d.handle)
|
||||||
|
@@ -15,7 +15,7 @@ const (
|
|||||||
func (d BCD) Int() (i int) {
|
func (d BCD) Int() (i int) {
|
||||||
ten := 1
|
ten := 1
|
||||||
for o := uint(0); o < 4; o++ {
|
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
|
i += int(n) * ten
|
||||||
ten *= 10
|
ten *= 10
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ func (d BCD) Int() (i int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d BCD) String() string {
|
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
|
type ID uint16
|
||||||
|
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBCD(t *testing.T) {
|
func TestBCD(t *testing.T) {
|
||||||
tests := []struct{
|
tests := []struct {
|
||||||
BCD
|
BCD
|
||||||
Int int
|
Int int
|
||||||
Str string
|
Str string
|
||||||
|
@@ -10,24 +10,18 @@ import (
|
|||||||
func TestNoop(t *testing.T) {
|
func TestNoop(t *testing.T) {
|
||||||
c := NewContext()
|
c := NewContext()
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
c.Debug(3)
|
c.Debug(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnum(t *testing.T) {
|
func TestEnum(t *testing.T) {
|
||||||
c := NewContext()
|
c := NewContext()
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
c.Debug(3)
|
c.Debug(0)
|
||||||
|
|
||||||
|
cnt := 0
|
||||||
devs, err := c.ListDevices(func(bus, addr int, desc *Descriptor) bool {
|
devs, err := c.ListDevices(func(bus, addr int, desc *Descriptor) bool {
|
||||||
t.Logf("%03d:%03d %+v", bus, addr, desc)
|
cnt++
|
||||||
if v, ok := usbid.Vendors[desc.Vendor]; ok {
|
return true
|
||||||
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
|
|
||||||
})
|
})
|
||||||
defer func() {
|
defer func() {
|
||||||
for _, d := range devs {
|
for _, d := range devs {
|
||||||
@@ -37,4 +31,51 @@ func TestEnum(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("list: %s", err)
|
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
|
package usbid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/kylelemons/gousb/usb"
|
"github.com/kylelemons/gousb/usb"
|
||||||
)
|
)
|
||||||
|
@@ -151,7 +151,8 @@ parseLines:
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case "": err = parseVendor(level, id, name)
|
case "":
|
||||||
|
err = parseVendor(level, id, name)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("line %d: %s", lineno, err)
|
return nil, fmt.Errorf("line %d: %s", lineno, err)
|
||||||
|
Reference in New Issue
Block a user