Tidy up interfaces and pretty printing
This commit is contained in:
@@ -5,6 +5,7 @@ package usb
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -13,38 +14,64 @@ import (
|
|||||||
|
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
Type DescriptorType
|
Type DescriptorType
|
||||||
Address ID
|
Address uint8
|
||||||
|
Attributes uint8
|
||||||
MaxPacketSize uint16
|
MaxPacketSize uint16
|
||||||
PollInterval uint8
|
PollInterval uint8
|
||||||
RefreshRate uint8
|
RefreshRate uint8
|
||||||
SynchAddress ID
|
SynchAddress uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Endpoint) Number() int {
|
||||||
|
return int(e.Address) & ENDPOINT_NUM_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Endpoint) Direction() EndpointDirection {
|
||||||
|
return EndpointDirection(e.Address) & ENDPOINT_DIR_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Endpoint) String() string {
|
||||||
|
return fmt.Sprintf("Endpoint %d %-3s %s - %s %s",
|
||||||
|
e.Number(), e.Direction(),
|
||||||
|
TransferType(e.Attributes) & TRANSFER_TYPE_MASK,
|
||||||
|
IsoSyncType(e.Attributes) & ISO_SYNC_TYPE_MASK,
|
||||||
|
IsoUsageType(e.Attributes) & ISO_USAGE_TYPE_MASK,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Interface struct {
|
type Interface struct {
|
||||||
Type DescriptorType
|
Type DescriptorType
|
||||||
Number ID
|
Number uint8
|
||||||
Alternate ID
|
Alternate uint8
|
||||||
IfClass Class
|
IfClass uint8
|
||||||
IfSubClass uint8
|
IfSubClass uint8
|
||||||
IfProtocol uint8
|
IfProtocol uint8
|
||||||
Endpoints []*Endpoint
|
Endpoints []*Endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i Interface) String() string {
|
||||||
|
return fmt.Sprintf("Interface %02x (config %02x)", i.Number, i.Alternate)
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
cfg *C.struct_libusb_config_descriptor
|
cfg *C.struct_libusb_config_descriptor
|
||||||
|
|
||||||
Type DescriptorType
|
Type DescriptorType
|
||||||
Config ID
|
Config uint8
|
||||||
Attributes uint8
|
Attributes uint8
|
||||||
MaxPower uint8
|
MaxPower uint8
|
||||||
Interfaces [][]*Interface
|
Interfaces [][]*Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Config) String() string {
|
||||||
|
return fmt.Sprintf("Config %02x", c.Config)
|
||||||
|
}
|
||||||
|
|
||||||
func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
||||||
c := &Config{
|
c := &Config{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
Type: DescriptorType(cfg.bDescriptorType),
|
Type: DescriptorType(cfg.bDescriptorType),
|
||||||
Config: ID(cfg.bConfigurationValue),
|
Config: uint8(cfg.bConfigurationValue),
|
||||||
Attributes: uint8(cfg.bmAttributes),
|
Attributes: uint8(cfg.bmAttributes),
|
||||||
MaxPower: uint8(cfg.MaxPower),
|
MaxPower: uint8(cfg.MaxPower),
|
||||||
}
|
}
|
||||||
@@ -67,9 +94,9 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
|||||||
for _, alt := range alts {
|
for _, alt := range alts {
|
||||||
i := &Interface{
|
i := &Interface{
|
||||||
Type: DescriptorType(alt.bDescriptorType),
|
Type: DescriptorType(alt.bDescriptorType),
|
||||||
Number: ID(alt.bInterfaceNumber),
|
Number: uint8(alt.bInterfaceNumber),
|
||||||
Alternate: ID(alt.bAlternateSetting),
|
Alternate: uint8(alt.bAlternateSetting),
|
||||||
IfClass: Class(alt.bInterfaceClass),
|
IfClass: uint8(alt.bInterfaceClass),
|
||||||
IfSubClass: uint8(alt.bInterfaceSubClass),
|
IfSubClass: uint8(alt.bInterfaceSubClass),
|
||||||
IfProtocol: uint8(alt.bInterfaceProtocol),
|
IfProtocol: uint8(alt.bInterfaceProtocol),
|
||||||
}
|
}
|
||||||
@@ -83,11 +110,12 @@ func newConfig(cfg *C.struct_libusb_config_descriptor) *Config {
|
|||||||
for _, end := range ends {
|
for _, end := range ends {
|
||||||
i.Endpoints = append(i.Endpoints, &Endpoint{
|
i.Endpoints = append(i.Endpoints, &Endpoint{
|
||||||
Type: DescriptorType(end.bDescriptorType),
|
Type: DescriptorType(end.bDescriptorType),
|
||||||
Address: ID(end.bEndpointAddress),
|
Address: uint8(end.bEndpointAddress),
|
||||||
|
Attributes: uint8(end.bmAttributes),
|
||||||
MaxPacketSize: uint16(end.wMaxPacketSize),
|
MaxPacketSize: uint16(end.wMaxPacketSize),
|
||||||
PollInterval: uint8(end.bInterval),
|
PollInterval: uint8(end.bInterval),
|
||||||
RefreshRate: uint8(end.bRefresh),
|
RefreshRate: uint8(end.bRefresh),
|
||||||
SynchAddress: ID(end.bSynchAddress),
|
SynchAddress: uint8(end.bSynchAddress),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
descs = append(descs, i)
|
descs = append(descs, i)
|
||||||
|
@@ -9,9 +9,9 @@ type Descriptor struct {
|
|||||||
|
|
||||||
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 uint8 // 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
|
||||||
@@ -26,7 +26,7 @@ func newDescriptor(dev *C.libusb_device) (*Descriptor, error) {
|
|||||||
desc: &desc,
|
desc: &desc,
|
||||||
Type: DescriptorType(desc.bDescriptorType),
|
Type: DescriptorType(desc.bDescriptorType),
|
||||||
Spec: BCD(desc.bcdUSB),
|
Spec: BCD(desc.bcdUSB),
|
||||||
Class: Class(desc.bDeviceClass),
|
Class: uint8(desc.bDeviceClass),
|
||||||
SubClass: uint8(desc.bDeviceSubClass),
|
SubClass: uint8(desc.bDeviceSubClass),
|
||||||
Protocol: uint8(desc.bDeviceProtocol),
|
Protocol: uint8(desc.bDeviceProtocol),
|
||||||
Vendor: ID(desc.idVendor),
|
Vendor: ID(desc.idVendor),
|
||||||
@@ -147,13 +147,15 @@ func (dt DescriptorType) String() string {
|
|||||||
type EndpointDirection int
|
type EndpointDirection int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ENDPOINT_IN EndpointDirection = C.LIBUSB_ENDPOINT_IN
|
ENDPOINT_NUM_MASK = 0x03
|
||||||
ENDPOINT_OUT EndpointDirection = C.LIBUSB_ENDPOINT_OUT
|
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{
|
var endpointDirectionDescription = map[EndpointDirection]string{
|
||||||
ENDPOINT_IN: "device-to-host",
|
ENDPOINT_DIR_IN: "IN",
|
||||||
ENDPOINT_OUT: "host-to-device",
|
ENDPOINT_DIR_OUT: "OUT",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ed EndpointDirection) String() string {
|
func (ed EndpointDirection) String() string {
|
||||||
@@ -167,6 +169,7 @@ const (
|
|||||||
TRANSFER_TYPE_ISOCHRONOUS TransferType = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
|
TRANSFER_TYPE_ISOCHRONOUS TransferType = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
|
||||||
TRANSFER_TYPE_BULK TransferType = C.LIBUSB_TRANSFER_TYPE_BULK
|
TRANSFER_TYPE_BULK TransferType = C.LIBUSB_TRANSFER_TYPE_BULK
|
||||||
TRANSFER_TYPE_INTERRUPT TransferType = C.LIBUSB_TRANSFER_TYPE_INTERRUPT
|
TRANSFER_TYPE_INTERRUPT TransferType = C.LIBUSB_TRANSFER_TYPE_INTERRUPT
|
||||||
|
TRANSFER_TYPE_MASK TransferType = 0x03
|
||||||
)
|
)
|
||||||
|
|
||||||
var transferTypeDescription = map[TransferType]string{
|
var transferTypeDescription = map[TransferType]string{
|
||||||
@@ -183,14 +186,15 @@ func (tt TransferType) String() string {
|
|||||||
type IsoSyncType int
|
type IsoSyncType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ISO_SYNC_TYPE_NONE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_NONE
|
ISO_SYNC_TYPE_NONE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_NONE << 2
|
||||||
ISO_SYNC_TYPE_ASYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ASYNC
|
ISO_SYNC_TYPE_ASYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ASYNC << 2
|
||||||
ISO_SYNC_TYPE_ADAPTIVE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ADAPTIVE
|
ISO_SYNC_TYPE_ADAPTIVE IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ADAPTIVE << 2
|
||||||
ISO_SYNC_TYPE_SYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_SYNC
|
ISO_SYNC_TYPE_SYNC IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_SYNC << 2
|
||||||
|
ISO_SYNC_TYPE_MASK IsoSyncType = 0x0C
|
||||||
)
|
)
|
||||||
|
|
||||||
var isoSyncTypeDescription = map[IsoSyncType]string{
|
var isoSyncTypeDescription = map[IsoSyncType]string{
|
||||||
ISO_SYNC_TYPE_NONE: "no synchronization",
|
ISO_SYNC_TYPE_NONE: "unsynchronized",
|
||||||
ISO_SYNC_TYPE_ASYNC: "asynchronous",
|
ISO_SYNC_TYPE_ASYNC: "asynchronous",
|
||||||
ISO_SYNC_TYPE_ADAPTIVE: "adaptive",
|
ISO_SYNC_TYPE_ADAPTIVE: "adaptive",
|
||||||
ISO_SYNC_TYPE_SYNC: "synchronous",
|
ISO_SYNC_TYPE_SYNC: "synchronous",
|
||||||
@@ -203,9 +207,10 @@ func (ist IsoSyncType) String() string {
|
|||||||
type IsoUsageType int
|
type IsoUsageType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ISO_USAGE_TYPE_DATA IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_DATA
|
ISO_USAGE_TYPE_DATA IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_DATA << 4
|
||||||
ISO_USAGE_TYPE_FEEDBACK IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_FEEDBACK
|
ISO_USAGE_TYPE_FEEDBACK IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_FEEDBACK << 4
|
||||||
ISO_USAGE_TYPE_IMPLICIT IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_IMPLICIT
|
ISO_USAGE_TYPE_IMPLICIT IsoUsageType = C.LIBUSB_ISO_USAGE_TYPE_IMPLICIT << 4
|
||||||
|
ISO_USAGE_TYPE_MASK IsoUsageType = 0x30
|
||||||
)
|
)
|
||||||
|
|
||||||
var isoUsageTypeDescription = map[IsoUsageType]string{
|
var isoUsageTypeDescription = map[IsoUsageType]string{
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,6 +90,7 @@ func (d *Device) Reset() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ControlTimeout = 5*time.Second
|
||||||
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
||||||
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||||
n := C.libusb_control_transfer(
|
n := C.libusb_control_transfer(
|
||||||
@@ -99,13 +101,28 @@ func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (in
|
|||||||
C.uint16_t(idx),
|
C.uint16_t(idx),
|
||||||
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
||||||
C.uint16_t(len(data)),
|
C.uint16_t(len(data)),
|
||||||
0)
|
C.uint(ControlTimeout/time.Millisecond))
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
return int(n), usbError(n)
|
return int(n), usbError(n)
|
||||||
}
|
}
|
||||||
return int(n), nil
|
return int(n), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Device) ActiveConfig() (int, error) {
|
||||||
|
var cfg C.int
|
||||||
|
if errno := C.libusb_get_configuration(d.handle, &cfg); errno < 0 {
|
||||||
|
return 0, usbError(errno)
|
||||||
|
}
|
||||||
|
return int(cfg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) SetConfig(cfg int) error {
|
||||||
|
if errno := C.libusb_set_configuration(d.handle, C.int(cfg)); errno < 0 {
|
||||||
|
return usbError(errno)
|
||||||
|
}
|
||||||
|
return 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)
|
||||||
|
@@ -45,14 +45,8 @@ func TestEnum(t *testing.T) {
|
|||||||
bus := dev.BusNumber()
|
bus := dev.BusNumber()
|
||||||
addr := dev.Address()
|
addr := dev.Address()
|
||||||
|
|
||||||
t.Logf("%03d:%03d %+v", bus, addr, desc)
|
t.Logf("%03d:%03d %s", bus, addr, usbid.Describe(desc))
|
||||||
if v, ok := usbid.Vendors[desc.Vendor]; ok {
|
t.Logf("- Protocol: %s", usbid.Classify(desc))
|
||||||
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()
|
cfgs, err := dev.Configurations()
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -61,21 +55,23 @@ func TestEnum(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf(" - configs: %s", err)
|
t.Errorf(" - configs: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cfg := range cfgs {
|
for _, cfg := range cfgs {
|
||||||
t.Logf(" - %#v", cfg)
|
t.Logf("- %s:", cfg)
|
||||||
for _, alt := range cfg.Interfaces {
|
for _, alt := range cfg.Interfaces {
|
||||||
|
t.Logf(" --------------")
|
||||||
for _, iface := range alt {
|
for _, iface := range alt {
|
||||||
t.Logf(" - %#v", iface)
|
t.Logf(" - %s", iface)
|
||||||
|
t.Logf(" - %s", usbid.Classify(iface))
|
||||||
for _, end := range iface.Endpoints {
|
for _, end := range iface.Endpoints {
|
||||||
t.Logf(" - %#v", end)
|
t.Logf(" - %s", end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Logf(" -----")
|
|
||||||
}
|
}
|
||||||
|
t.Logf(" --------------")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
usbid/describe.go
Normal file
48
usbid/describe.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package usbid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/kylelemons/gousb/usb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Describe one of the following:
|
||||||
|
// - *usb.Descriptor Product (Vendor)
|
||||||
|
func Describe(val interface{}) string {
|
||||||
|
switch val := val.(type) {
|
||||||
|
case *usb.Descriptor:
|
||||||
|
if v, ok := Vendors[val.Vendor]; ok {
|
||||||
|
if d, ok := v.Product[val.Product]; ok {
|
||||||
|
return fmt.Sprintf("%s (%s)", d, v)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown (%s)", v)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown %s:%s", val.Vendor, val.Product)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown (%T)", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classify one of the following:
|
||||||
|
// - *usb.Descriptor Class SubClass Protocol
|
||||||
|
func Classify(val interface{}) string {
|
||||||
|
var class, sub, proto uint8
|
||||||
|
switch val := val.(type) {
|
||||||
|
case *usb.Descriptor:
|
||||||
|
class, sub, proto = val.Class, val.SubClass, val.Protocol
|
||||||
|
case *usb.Interface:
|
||||||
|
class, sub, proto = val.IfClass, val.IfSubClass, val.IfProtocol
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown (%T)", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c, ok := Classes[class]; ok {
|
||||||
|
if s, ok := c.SubClass[sub]; ok {
|
||||||
|
if p, ok := s.Protocol[proto]; ok {
|
||||||
|
return fmt.Sprintf("%s (%s) %s", c, s, p)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (%s)", c, s)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s", c)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown %s.%s.%s", class, sub, proto)
|
||||||
|
}
|
@@ -13,6 +13,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var Vendors map[usb.ID]*Vendor
|
var Vendors map[usb.ID]*Vendor
|
||||||
|
var Classes map[uint8]*Class
|
||||||
|
|
||||||
func LoadFromURL(url string) error {
|
func LoadFromURL(url string) error {
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
@@ -21,21 +22,23 @@ func LoadFromURL(url string) error {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
ids, err := ParseIDs(resp.Body)
|
ids, cls, err := ParseIDs(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
Vendors = ids
|
Vendors = ids
|
||||||
|
Classes = cls
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ids, err := ParseIDs(strings.NewReader(usbIdListData))
|
ids, cls, err := ParseIDs(strings.NewReader(usbIdListData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("usbid: failed to parse: %s", err)
|
log.Printf("usbid: failed to parse: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Vendors = ids
|
Vendors = ids
|
||||||
|
Classes = cls
|
||||||
}
|
}
|
||||||
|
108
usbid/parse.go
108
usbid/parse.go
@@ -12,39 +12,45 @@ import (
|
|||||||
|
|
||||||
type Vendor struct {
|
type Vendor struct {
|
||||||
Name string
|
Name string
|
||||||
Devices map[usb.ID]*Device
|
Product map[usb.ID]*Product
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vendor) String() string {
|
func (v Vendor) String() string {
|
||||||
return v.Name
|
return v.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(kevlar) s/device/
|
type Product struct {
|
||||||
type Device struct {
|
|
||||||
Name string
|
Name string
|
||||||
Interfaces map[usb.ID]string
|
Interface map[usb.ID]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) String() string {
|
func (p Product) String() string {
|
||||||
return d.Name
|
return p.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
type Class struct {
|
type Class struct {
|
||||||
Name string
|
Name string
|
||||||
SubClass map[usb.ID]*SubClass
|
SubClass map[uint8]*SubClass
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Class) String() string {
|
||||||
|
return c.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubClass struct {
|
type SubClass struct {
|
||||||
Name string
|
Name string
|
||||||
Protocol map[usb.ID]string
|
Protocol map[uint8]string
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
|
func (s SubClass) String() string {
|
||||||
|
return s.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, map[uint8]*Class, error) {
|
||||||
vendors := make(map[usb.ID]*Vendor, 2800)
|
vendors := make(map[usb.ID]*Vendor, 2800)
|
||||||
|
classes := make(map[uint8]*Class) // TODO(kevlar): count
|
||||||
|
|
||||||
split := func(s string) (kind string, level int, id usb.ID, name string, err error) {
|
split := func(s string) (kind string, level int, id uint64, name string, err error) {
|
||||||
pieces := strings.SplitN(s, " ", 2)
|
pieces := strings.SplitN(s, " ", 2)
|
||||||
if len(pieces) != 2 {
|
if len(pieces) != 2 {
|
||||||
err = fmt.Errorf("malformatted line %q", s)
|
err = fmt.Errorf("malformatted line %q", s)
|
||||||
@@ -71,16 +77,18 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
|
|||||||
err = fmt.Errorf("malformatted id %q: %s", pieces[0], err)
|
err = fmt.Errorf("malformatted id %q: %s", pieces[0], err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id = usb.ID(i)
|
id = i
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hold the interim values
|
// Hold the interim values
|
||||||
var vendor *Vendor
|
var vendor *Vendor
|
||||||
var device *Device
|
var device *Product
|
||||||
|
|
||||||
|
parseVendor := func(level int, raw uint64, name string) error {
|
||||||
|
id := usb.ID(raw)
|
||||||
|
|
||||||
parseVendor := func(level int, id usb.ID, name string) error {
|
|
||||||
switch level {
|
switch level {
|
||||||
case 0:
|
case 0:
|
||||||
vendor = &Vendor{
|
vendor = &Vendor{
|
||||||
@@ -93,23 +101,23 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
|
|||||||
return fmt.Errorf("product line without vendor line")
|
return fmt.Errorf("product line without vendor line")
|
||||||
}
|
}
|
||||||
|
|
||||||
device = &Device{
|
device = &Product{
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
if vendor.Devices == nil {
|
if vendor.Product == nil {
|
||||||
vendor.Devices = make(map[usb.ID]*Device)
|
vendor.Product = make(map[usb.ID]*Product)
|
||||||
}
|
}
|
||||||
vendor.Devices[id] = device
|
vendor.Product[id] = device
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
if device == nil {
|
if device == nil {
|
||||||
return fmt.Errorf("interface line without device line")
|
return fmt.Errorf("interface line without device line")
|
||||||
}
|
}
|
||||||
|
|
||||||
if device.Interfaces == nil {
|
if device.Interface == nil {
|
||||||
device.Interfaces = make(map[usb.ID]string)
|
device.Interface = make(map[usb.ID]string)
|
||||||
}
|
}
|
||||||
device.Interfaces[id] = name
|
device.Interface[id] = name
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("too many levels of nesting for vendor block")
|
return fmt.Errorf("too many levels of nesting for vendor block")
|
||||||
@@ -118,6 +126,50 @@ func ParseIDs(r io.Reader) (map[usb.ID]*Vendor, error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hold the interim values
|
||||||
|
var class *Class
|
||||||
|
var subclass *SubClass
|
||||||
|
|
||||||
|
parseClass := func(level int, raw uint64, name string) error {
|
||||||
|
id := uint8(raw)
|
||||||
|
|
||||||
|
switch level {
|
||||||
|
case 0:
|
||||||
|
class = &Class{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
classes[id] = class
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if class == nil {
|
||||||
|
return fmt.Errorf("subclass line without class line")
|
||||||
|
}
|
||||||
|
|
||||||
|
subclass = &SubClass{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
if class.SubClass == nil {
|
||||||
|
class.SubClass = make(map[uint8]*SubClass)
|
||||||
|
}
|
||||||
|
class.SubClass[id] = subclass
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if subclass == nil {
|
||||||
|
return fmt.Errorf("protocol line without subclass line")
|
||||||
|
}
|
||||||
|
|
||||||
|
if subclass.Protocol == nil {
|
||||||
|
subclass.Protocol = make(map[uint8]string)
|
||||||
|
}
|
||||||
|
subclass.Protocol[id] = name
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("too many levels of nesting for class")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(kevlar): Parse class information, etc
|
// TODO(kevlar): Parse class information, etc
|
||||||
//var class *Class
|
//var class *Class
|
||||||
//var subclass *SubClass
|
//var subclass *SubClass
|
||||||
@@ -132,9 +184,9 @@ parseLines:
|
|||||||
case err == io.EOF:
|
case err == io.EOF:
|
||||||
break parseLines
|
break parseLines
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
case isPrefix:
|
case isPrefix:
|
||||||
return nil, fmt.Errorf("line %d: line too long", lineno)
|
return nil, nil, fmt.Errorf("line %d: line too long", lineno)
|
||||||
}
|
}
|
||||||
line := string(b)
|
line := string(b)
|
||||||
|
|
||||||
@@ -144,7 +196,7 @@ parseLines:
|
|||||||
|
|
||||||
k, level, id, name, err := split(line)
|
k, level, id, name, err := split(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("line %d: %s", lineno, err)
|
return nil, nil, fmt.Errorf("line %d: %s", lineno, err)
|
||||||
}
|
}
|
||||||
if k != "" {
|
if k != "" {
|
||||||
kind = k
|
kind = k
|
||||||
@@ -153,11 +205,13 @@ parseLines:
|
|||||||
switch kind {
|
switch kind {
|
||||||
case "":
|
case "":
|
||||||
err = parseVendor(level, id, name)
|
err = parseVendor(level, id, name)
|
||||||
|
case "C":
|
||||||
|
err = parseClass(level, id, name)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("line %d: %s", lineno, err)
|
return nil, nil, fmt.Errorf("line %d: %s", lineno, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vendors, nil
|
return vendors, classes, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user