forked from google/gousb
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinterface.go
139 lines (124 loc) · 4.43 KB
/
interface.go
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
139
// 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, a zero-based index in the array
// of interfaces supported by the device configuration.
Number int
// AltSettings is a list of alternate settings supported by the interface.
AltSettings []InterfaceSetting
}
// String returns a human-readable descripton 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 descripton 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
}