1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// Copyright 2013 Google Inc. All rights reserved.
// Copyright 2016 the gousb Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gousb
import (
"fmt"
"sort"
)
// InterfaceDesc contains information about a USB interface, extracted from
// the descriptor.
type InterfaceDesc struct {
// Number is the number of this interface.
Number int
// AltSettings is a list of alternate settings supported by the interface.
AltSettings []InterfaceSetting
}
// String returns a human-readable description of the interface descriptor and
// its alternate settings.
func (i InterfaceDesc) String() string {
return fmt.Sprintf("Interface %d (%d alternate settings)", i.Number, len(i.AltSettings))
}
// InterfaceSetting contains information about a USB interface with a particular
// alternate setting, extracted from the descriptor.
type InterfaceSetting struct {
// Number is the number of this interface, the same as in InterfaceDesc.
Number int
// Alternate is the number of this alternate setting.
Alternate int
// Class is the USB-IF (Implementers Forum) class code, as defined by the USB spec.
Class Class
// SubClass is the USB-IF (Implementers Forum) subclass code, as defined by the USB spec.
SubClass Class
// Protocol is USB protocol code, as defined by the USB spe.c
Protocol Protocol
// Endpoints enumerates the endpoints available on this interface with
// this alternate setting.
Endpoints map[EndpointAddress]EndpointDesc
iInterface int // index of a string descriptor describing this interface.
}
func (a InterfaceSetting) sortedEndpointIds() []string {
var eps []string
for _, ei := range a.Endpoints {
eps = append(eps, fmt.Sprintf("%s(%d,%s)", ei.Address, ei.Number, ei.Direction))
}
sort.Strings(eps)
return eps
}
// String returns a human-readable description of the particular
// alternate setting of an interface.
func (a InterfaceSetting) String() string {
return fmt.Sprintf("Interface %d alternate setting %d (available endpoints: %v)", a.Number, a.Alternate, a.sortedEndpointIds())
}
// Interface is a representation of a claimed interface with a particular setting.
// To access device endpoints use InEndpoint() and OutEndpoint() methods.
// The interface should be Close()d after use.
type Interface struct {
Setting InterfaceSetting
config *Config
}
func (i *Interface) String() string {
return fmt.Sprintf("%s,if=%d,alt=%d", i.config, i.Setting.Number, i.Setting.Alternate)
}
// Close releases the interface.
func (i *Interface) Close() {
if i.config == nil {
return
}
i.config.dev.ctx.libusb.release(i.config.dev.handle, uint8(i.Setting.Number))
i.config.mu.Lock()
defer i.config.mu.Unlock()
delete(i.config.claimed, i.Setting.Number)
i.config = nil
}
func (i *Interface) openEndpoint(epAddr EndpointAddress) (*endpoint, error) {
var ep EndpointDesc
ep, ok := i.Setting.Endpoints[epAddr]
if !ok {
return nil, fmt.Errorf("%s does not have endpoint with address %s. Available endpoints: %v", i, epAddr, i.Setting.sortedEndpointIds())
}
return &endpoint{
InterfaceSetting: i.Setting,
Desc: ep,
h: i.config.dev.handle,
ctx: i.config.dev.ctx,
}, nil
}
// InEndpoint prepares an IN endpoint for transfer.
func (i *Interface) InEndpoint(epNum int) (*InEndpoint, error) {
if i.config == nil {
return nil, fmt.Errorf("InEndpoint(%d) called on %s after Close", epNum, i)
}
ep, err := i.openEndpoint(EndpointAddress(0x80 | epNum))
if err != nil {
return nil, err
}
return &InEndpoint{
endpoint: ep,
}, nil
}
// OutEndpoint prepares an OUT endpoint for transfer.
func (i *Interface) OutEndpoint(epNum int) (*OutEndpoint, error) {
if i.config == nil {
return nil, fmt.Errorf("OutEndpoint(%d) called on %s after Close", epNum, i)
}
ep, err := i.openEndpoint(EndpointAddress(epNum))
if err != nil {
return nil, err
}
return &OutEndpoint{
endpoint: ep,
}, nil
}
|