libusb 0.6.0-x86-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +17 -0
- data/.yardopts +6 -0
- data/COPYING +165 -0
- data/Gemfile +11 -0
- data/History.md +124 -0
- data/README.md +159 -0
- data/Rakefile +145 -0
- data/appveyor.yml +23 -0
- data/lib/libusb.rb +58 -0
- data/lib/libusb/bos.rb +306 -0
- data/lib/libusb/call.rb +446 -0
- data/lib/libusb/compat.rb +376 -0
- data/lib/libusb/configuration.rb +155 -0
- data/lib/libusb/constants.rb +160 -0
- data/lib/libusb/context.rb +426 -0
- data/lib/libusb/dependencies.rb +7 -0
- data/lib/libusb/dev_handle.rb +564 -0
- data/lib/libusb/device.rb +365 -0
- data/lib/libusb/endpoint.rb +194 -0
- data/lib/libusb/eventmachine.rb +183 -0
- data/lib/libusb/interface.rb +60 -0
- data/lib/libusb/setting.rb +132 -0
- data/lib/libusb/ss_companion.rb +69 -0
- data/lib/libusb/stdio.rb +25 -0
- data/lib/libusb/transfer.rb +377 -0
- data/lib/libusb/version_gem.rb +19 -0
- data/lib/libusb/version_struct.rb +63 -0
- data/libusb.gemspec +30 -0
- data/test/test_libusb_bos.rb +118 -0
- data/test/test_libusb_bulk_stream_transfer.rb +50 -0
- data/test/test_libusb_capability.rb +23 -0
- data/test/test_libusb_compat.rb +78 -0
- data/test/test_libusb_compat_mass_storage.rb +81 -0
- data/test/test_libusb_descriptors.rb +212 -0
- data/test/test_libusb_event_machine.rb +118 -0
- data/test/test_libusb_gc.rb +37 -0
- data/test/test_libusb_hotplug.rb +127 -0
- data/test/test_libusb_iso_transfer.rb +50 -0
- data/test/test_libusb_mass_storage.rb +268 -0
- data/test/test_libusb_mass_storage2.rb +96 -0
- data/test/test_libusb_structs.rb +58 -0
- data/test/test_libusb_threads.rb +89 -0
- data/test/test_libusb_version.rb +40 -0
- data/wireshark-usb-sniffer.png +0 -0
- metadata +150 -0
@@ -0,0 +1,365 @@
|
|
1
|
+
# This file is part of Libusb for Ruby.
|
2
|
+
#
|
3
|
+
# Libusb for Ruby is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# Libusb for Ruby is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public License
|
14
|
+
# along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'libusb/call'
|
17
|
+
|
18
|
+
module LIBUSB
|
19
|
+
# Class representing a USB device detected on the system.
|
20
|
+
#
|
21
|
+
# Devices of the system can be obtained with {Context#devices} .
|
22
|
+
class Device
|
23
|
+
include Comparable
|
24
|
+
|
25
|
+
# @return [Context] the context this device belongs to.
|
26
|
+
attr_reader :context
|
27
|
+
|
28
|
+
def initialize context, pDev
|
29
|
+
@context = context
|
30
|
+
def pDev.unref_device(id)
|
31
|
+
Call.libusb_unref_device(self)
|
32
|
+
end
|
33
|
+
ObjectSpace.define_finalizer(self, pDev.method(:unref_device))
|
34
|
+
Call.libusb_ref_device(pDev)
|
35
|
+
@pDev = pDev
|
36
|
+
|
37
|
+
@pDevDesc = Call::DeviceDescriptor.new
|
38
|
+
res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
|
39
|
+
LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
|
40
|
+
end
|
41
|
+
|
42
|
+
# Open the device and obtain a device handle.
|
43
|
+
#
|
44
|
+
# A handle allows you to perform I/O on the device in question.
|
45
|
+
# This is a non-blocking function; no requests are sent over the bus.
|
46
|
+
#
|
47
|
+
# If called with a block, the handle is passed to the block
|
48
|
+
# and is closed when the block has finished.
|
49
|
+
#
|
50
|
+
# You need proper device access:
|
51
|
+
# * Linux: read+write permissions to <tt>/dev/bus/usb/<bus>/<dev></tt>
|
52
|
+
# * Windows: by installing a WinUSB-driver for the device (see {file:README.rdoc#Usage_on_Windows} )
|
53
|
+
#
|
54
|
+
# @return [DevHandle] Handle to the device.
|
55
|
+
def open
|
56
|
+
ppHandle = FFI::MemoryPointer.new :pointer
|
57
|
+
res = Call.libusb_open(@pDev, ppHandle)
|
58
|
+
LIBUSB.raise_error res, "in libusb_open" if res!=0
|
59
|
+
handle = DevHandle.new self, ppHandle.read_pointer
|
60
|
+
return handle unless block_given?
|
61
|
+
begin
|
62
|
+
yield handle
|
63
|
+
ensure
|
64
|
+
handle.close
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Open the device and claim an interface.
|
69
|
+
#
|
70
|
+
# This is a convenience method to {Device#open} and {DevHandle#claim_interface}.
|
71
|
+
# Must be called with a block. When the block has finished, the interface
|
72
|
+
# will be released and the device will be closed.
|
73
|
+
#
|
74
|
+
# @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
|
75
|
+
def open_interface(interface)
|
76
|
+
open do |dev|
|
77
|
+
dev.claim_interface(interface) do
|
78
|
+
yield dev
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the number of the bus that a device is connected to.
|
84
|
+
def bus_number
|
85
|
+
Call.libusb_get_bus_number(@pDev)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the address of the device on the bus it is connected to.
|
89
|
+
def device_address
|
90
|
+
Call.libusb_get_device_address(@pDev)
|
91
|
+
end
|
92
|
+
|
93
|
+
if Call.respond_to?(:libusb_get_port_number)
|
94
|
+
# Get the number of the port that a device is connected to.
|
95
|
+
# Available since libusb-1.0.12.
|
96
|
+
#
|
97
|
+
# @return [Fixnum, nil] the port number (+nil+ if not available)
|
98
|
+
# @see #port_numbers
|
99
|
+
def port_number
|
100
|
+
r = Call.libusb_get_port_number(@pDev)
|
101
|
+
r==0 ? nil : r
|
102
|
+
end
|
103
|
+
|
104
|
+
# Get the the parent from the specified device [EXPERIMENTAL].
|
105
|
+
# Available since libusb-1.0.12.
|
106
|
+
#
|
107
|
+
# @return [Device, nil] the device parent or +nil+ if not available
|
108
|
+
# @see #port_numbers
|
109
|
+
def parent
|
110
|
+
pppDevs = FFI::MemoryPointer.new :pointer
|
111
|
+
Call.libusb_get_device_list(@context.instance_variable_get(:@ctx), pppDevs)
|
112
|
+
ppDevs = pppDevs.read_pointer
|
113
|
+
pParent = Call.libusb_get_parent(@pDev)
|
114
|
+
parent = pParent.null? ? nil : Device.new(@context, pParent)
|
115
|
+
Call.libusb_free_device_list(ppDevs, 1)
|
116
|
+
parent
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the list of all port numbers from root for the specified device.
|
120
|
+
# Available since libusb-1.0.12.
|
121
|
+
#
|
122
|
+
# @return [Array<Fixnum>]
|
123
|
+
# @see #parent
|
124
|
+
# @see #port_number
|
125
|
+
def port_numbers
|
126
|
+
# As per the USB 3.0 specs, the current maximum limit for the depth is 7.
|
127
|
+
path_len = 7
|
128
|
+
pPath = FFI::MemoryPointer.new :pointer, path_len
|
129
|
+
|
130
|
+
l = if Call.respond_to?(:libusb_get_port_numbers)
|
131
|
+
Call.libusb_get_port_numbers(@pDev, pPath, path_len)
|
132
|
+
else
|
133
|
+
Call.libusb_get_port_path(@context.instance_variable_get(:@ctx), @pDev, pPath, path_len)
|
134
|
+
end
|
135
|
+
pPath.read_array_of_uint8(l)
|
136
|
+
end
|
137
|
+
alias port_path port_numbers
|
138
|
+
end
|
139
|
+
|
140
|
+
if Call.respond_to?(:libusb_get_device_speed)
|
141
|
+
# Get the negotiated connection speed for a device.
|
142
|
+
# Available since libusb-1.0.9.
|
143
|
+
#
|
144
|
+
# @return [Symbol] a {Call::Speeds Speeds} symbol, where +:SPEED_UNKNOWN+ means that
|
145
|
+
# the OS doesn't know or doesn't support returning the negotiated speed.
|
146
|
+
def device_speed
|
147
|
+
Call.libusb_get_device_speed(@pDev)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Convenience function to retrieve the wMaxPacketSize value for a
|
152
|
+
# particular endpoint in the active device configuration.
|
153
|
+
#
|
154
|
+
# @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
|
155
|
+
# @return [Fixnum] the wMaxPacketSize value
|
156
|
+
def max_packet_size(endpoint)
|
157
|
+
endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
|
158
|
+
res = Call.libusb_get_max_packet_size(@pDev, endpoint)
|
159
|
+
LIBUSB.raise_error res, "in libusb_get_max_packet_size" unless res>=0
|
160
|
+
res
|
161
|
+
end
|
162
|
+
|
163
|
+
# Calculate the maximum packet size which a specific endpoint is capable is
|
164
|
+
# sending or receiving in the duration of 1 microframe.
|
165
|
+
#
|
166
|
+
# Only the active configution is examined. The calculation is based on the
|
167
|
+
# wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6
|
168
|
+
# in the USB 2.0 specifications.
|
169
|
+
#
|
170
|
+
# If acting on an isochronous or interrupt endpoint, this function will
|
171
|
+
# multiply the value found in bits 0:10 by the number of transactions per
|
172
|
+
# microframe (determined by bits 11:12). Otherwise, this function just returns
|
173
|
+
# the numeric value found in bits 0:10.
|
174
|
+
#
|
175
|
+
# This function is useful for setting up isochronous transfers, for example
|
176
|
+
# you might use the return value from this function to call
|
177
|
+
# IsoPacket#alloc_buffer in order to set the length field
|
178
|
+
# of an isochronous packet in a transfer.
|
179
|
+
#
|
180
|
+
# @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
|
181
|
+
# @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
|
182
|
+
def max_iso_packet_size(endpoint)
|
183
|
+
endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
|
184
|
+
res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
|
185
|
+
LIBUSB.raise_error res, "in libusb_get_max_iso_packet_size" unless res>=0
|
186
|
+
res
|
187
|
+
end
|
188
|
+
|
189
|
+
# Obtain a config descriptor of the device.
|
190
|
+
#
|
191
|
+
# @param [Fixnum] index number of the config descriptor
|
192
|
+
# @return Configuration
|
193
|
+
def config_descriptor(index)
|
194
|
+
ppConfig = FFI::MemoryPointer.new :pointer
|
195
|
+
res = Call.libusb_get_config_descriptor(@pDev, index, ppConfig)
|
196
|
+
LIBUSB.raise_error res, "in libusb_get_config_descriptor" if res!=0
|
197
|
+
pConfig = ppConfig.read_pointer
|
198
|
+
config = Configuration.new(self, pConfig)
|
199
|
+
config
|
200
|
+
end
|
201
|
+
|
202
|
+
# Size of the Descriptor in Bytes (18 bytes)
|
203
|
+
def bLength
|
204
|
+
@pDevDesc[:bLength]
|
205
|
+
end
|
206
|
+
|
207
|
+
# Device Descriptor (0x01)
|
208
|
+
def bDescriptorType
|
209
|
+
@pDevDesc[:bDescriptorType]
|
210
|
+
end
|
211
|
+
|
212
|
+
# USB specification release number which device complies too
|
213
|
+
#
|
214
|
+
# @return [Integer] in binary-coded decimal
|
215
|
+
def bcdUSB
|
216
|
+
@pDevDesc[:bcdUSB]
|
217
|
+
end
|
218
|
+
|
219
|
+
# USB-IF class code for the device (Assigned by USB Org)
|
220
|
+
#
|
221
|
+
# * If equal to 0x00, each interface specifies it's own class code
|
222
|
+
# * If equal to 0xFF, the class code is vendor specified
|
223
|
+
# * Otherwise field is valid Class Code
|
224
|
+
def bDeviceClass
|
225
|
+
@pDevDesc[:bDeviceClass]
|
226
|
+
end
|
227
|
+
|
228
|
+
# USB-IF subclass code for the device, qualified by the {Device#bDeviceClass}
|
229
|
+
# value (Assigned by USB Org)
|
230
|
+
def bDeviceSubClass
|
231
|
+
@pDevDesc[:bDeviceSubClass]
|
232
|
+
end
|
233
|
+
|
234
|
+
# USB-IF protocol code for the device, qualified by the {Device#bDeviceClass}
|
235
|
+
# and {Device#bDeviceSubClass} values (Assigned by USB Org)
|
236
|
+
def bDeviceProtocol
|
237
|
+
@pDevDesc[:bDeviceProtocol]
|
238
|
+
end
|
239
|
+
|
240
|
+
# Maximum Packet Size for Endpoint 0. Valid Sizes are 8, 16, 32, 64
|
241
|
+
def bMaxPacketSize0
|
242
|
+
@pDevDesc[:bMaxPacketSize0]
|
243
|
+
end
|
244
|
+
|
245
|
+
# USB-IF vendor ID (Assigned by USB Org)
|
246
|
+
def idVendor
|
247
|
+
@pDevDesc[:idVendor]
|
248
|
+
end
|
249
|
+
|
250
|
+
# USB-IF product ID (Assigned by Manufacturer)
|
251
|
+
def idProduct
|
252
|
+
@pDevDesc[:idProduct]
|
253
|
+
end
|
254
|
+
|
255
|
+
# Device release number in binary-coded decimal.
|
256
|
+
def bcdDevice
|
257
|
+
@pDevDesc[:bcdDevice]
|
258
|
+
end
|
259
|
+
|
260
|
+
# Index of string descriptor describing manufacturer.
|
261
|
+
def iManufacturer
|
262
|
+
@pDevDesc[:iManufacturer]
|
263
|
+
end
|
264
|
+
|
265
|
+
# Index of string descriptor describing product.
|
266
|
+
def iProduct
|
267
|
+
@pDevDesc[:iProduct]
|
268
|
+
end
|
269
|
+
|
270
|
+
# Index of string descriptor containing device serial number.
|
271
|
+
def iSerialNumber
|
272
|
+
@pDevDesc[:iSerialNumber]
|
273
|
+
end
|
274
|
+
|
275
|
+
# Number of Possible Configurations
|
276
|
+
def bNumConfigurations
|
277
|
+
@pDevDesc[:bNumConfigurations]
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
def inspect
|
282
|
+
attrs = []
|
283
|
+
attrs << "#{self.bus_number}/#{self.device_address}"
|
284
|
+
attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
|
285
|
+
attrs << self.manufacturer
|
286
|
+
attrs << self.product
|
287
|
+
attrs << self.serial_number
|
288
|
+
if self.bDeviceClass == LIBUSB::CLASS_PER_INTERFACE
|
289
|
+
devclass = self.settings.map {|i|
|
290
|
+
LIBUSB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
|
291
|
+
}.join(", ")
|
292
|
+
else
|
293
|
+
devclass = LIBUSB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
|
294
|
+
end
|
295
|
+
attrs << "(#{devclass})"
|
296
|
+
attrs.compact!
|
297
|
+
"\#<#{self.class} #{attrs.join(' ')}>"
|
298
|
+
end
|
299
|
+
|
300
|
+
def try_string_descriptor_ascii(i)
|
301
|
+
begin
|
302
|
+
open{|h| h.string_descriptor_ascii(i) }
|
303
|
+
rescue
|
304
|
+
"?"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# Return manufacturer of the device
|
309
|
+
# @return String
|
310
|
+
def manufacturer
|
311
|
+
return @manufacturer if defined? @manufacturer
|
312
|
+
@manufacturer = try_string_descriptor_ascii(self.iManufacturer)
|
313
|
+
@manufacturer.strip! if @manufacturer
|
314
|
+
@manufacturer
|
315
|
+
end
|
316
|
+
|
317
|
+
# Return product name of the device.
|
318
|
+
# @return String
|
319
|
+
def product
|
320
|
+
return @product if defined? @product
|
321
|
+
@product = try_string_descriptor_ascii(self.iProduct)
|
322
|
+
@product.strip! if @product
|
323
|
+
@product
|
324
|
+
end
|
325
|
+
|
326
|
+
# Return serial number of the device.
|
327
|
+
# @return String
|
328
|
+
def serial_number
|
329
|
+
return @serial_number if defined? @serial_number
|
330
|
+
@serial_number = try_string_descriptor_ascii(self.iSerialNumber)
|
331
|
+
@serial_number.strip! if @serial_number
|
332
|
+
@serial_number
|
333
|
+
end
|
334
|
+
|
335
|
+
# Return configurations of the device.
|
336
|
+
# @return [Array<Configuration>]
|
337
|
+
def configurations
|
338
|
+
configs = []
|
339
|
+
bNumConfigurations.times do |config_index|
|
340
|
+
begin
|
341
|
+
configs << config_descriptor(config_index)
|
342
|
+
rescue RuntimeError
|
343
|
+
# On Windows some devices don't return it's configuration.
|
344
|
+
end
|
345
|
+
end
|
346
|
+
configs
|
347
|
+
end
|
348
|
+
|
349
|
+
# Return all interfaces of this device.
|
350
|
+
# @return [Array<Interface>]
|
351
|
+
def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
|
352
|
+
# Return all interface decriptions of this device.
|
353
|
+
# @return [Array<Setting>]
|
354
|
+
def settings() self.interfaces.map {|d| d.settings }.flatten end
|
355
|
+
# Return all endpoints of all interfaces of this device.
|
356
|
+
# @return [Array<Endpoint>]
|
357
|
+
def endpoints() self.settings.map {|d| d.endpoints }.flatten end
|
358
|
+
|
359
|
+
def <=>(o)
|
360
|
+
t = bus_number<=>o.bus_number
|
361
|
+
t = device_address<=>o.device_address if t==0
|
362
|
+
t
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# This file is part of Libusb for Ruby.
|
2
|
+
#
|
3
|
+
# Libusb for Ruby is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# Libusb for Ruby is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public License
|
14
|
+
# along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'libusb/call'
|
17
|
+
|
18
|
+
module LIBUSB
|
19
|
+
class Endpoint < FFI::Struct
|
20
|
+
include Comparable
|
21
|
+
|
22
|
+
layout :bLength, :uint8,
|
23
|
+
:bDescriptorType, :uint8,
|
24
|
+
:bEndpointAddress, :uint8,
|
25
|
+
:bmAttributes, :uint8,
|
26
|
+
:wMaxPacketSize, :uint16,
|
27
|
+
:bInterval, :uint8,
|
28
|
+
:bRefresh, :uint8,
|
29
|
+
:bSynchAddress, :uint8,
|
30
|
+
:extra, :pointer,
|
31
|
+
:extra_length, :int
|
32
|
+
|
33
|
+
# Size of Descriptor in Bytes (7 bytes)
|
34
|
+
def bLength
|
35
|
+
self[:bLength]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Descriptor type (0x05)
|
39
|
+
def bDescriptorType
|
40
|
+
self[:bDescriptorType]
|
41
|
+
end
|
42
|
+
|
43
|
+
# The address of the endpoint described by this descriptor.
|
44
|
+
#
|
45
|
+
# * Bits 0..3: Endpoint Number.
|
46
|
+
# * Bits 4..6: Reserved. Set to Zero
|
47
|
+
# * Bits 7: Direction 0 = Out, 1 = In (Ignored for Control Endpoints)
|
48
|
+
#
|
49
|
+
# @return [Integer]
|
50
|
+
#
|
51
|
+
# @see #endpoint_number
|
52
|
+
# @see #direction
|
53
|
+
def bEndpointAddress
|
54
|
+
self[:bEndpointAddress]
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Integer]
|
58
|
+
def endpoint_number
|
59
|
+
bEndpointAddress & 0b1111
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Symbol] Either +:in+ or +:out+
|
63
|
+
def direction
|
64
|
+
bEndpointAddress & ENDPOINT_IN == 0 ? :out : :in
|
65
|
+
end
|
66
|
+
|
67
|
+
# Attributes which apply to the endpoint when it is configured using the {Configuration#bConfigurationValue}.
|
68
|
+
#
|
69
|
+
# * Bits 1..0: Transfer Type
|
70
|
+
# * 00 = Control
|
71
|
+
# * 01 = Isochronous
|
72
|
+
# * 10 = Bulk
|
73
|
+
# * 11 = Interrupt
|
74
|
+
# * Bits 7..2: are reserved. If Isochronous endpoint,
|
75
|
+
# * Bits 3..2: Synchronisation Type (Iso Mode)
|
76
|
+
# * 00 = No Synchonisation
|
77
|
+
# * 01 = Asynchronous
|
78
|
+
# * 10 = Adaptive
|
79
|
+
# * 11 = Synchronous
|
80
|
+
# * Bits 5..4: Usage Type (Iso Mode)
|
81
|
+
# * 00 = Data Endpoint
|
82
|
+
# * 01 = Feedback Endpoint
|
83
|
+
# * 10 = Explicit Feedback Data Endpoint
|
84
|
+
# * 11 = Reserved
|
85
|
+
#
|
86
|
+
# @return [Integer]
|
87
|
+
#
|
88
|
+
# @see #transfer_type
|
89
|
+
# @see #usage_type
|
90
|
+
# @see #synchronization_type
|
91
|
+
def bmAttributes
|
92
|
+
self[:bmAttributes]
|
93
|
+
end
|
94
|
+
|
95
|
+
TransferTypes = [:control, :isochronous, :bulk, :interrupt]
|
96
|
+
# @return [Symbol] One of {TransferTypes}
|
97
|
+
def transfer_type
|
98
|
+
TransferTypes[bmAttributes & 0b11]
|
99
|
+
end
|
100
|
+
|
101
|
+
SynchronizationTypes = [:no_synchronization, :asynchronous, :adaptive, :synchronous]
|
102
|
+
# @return [Symbol] One of {SynchronizationTypes}
|
103
|
+
def synchronization_type
|
104
|
+
return unless transfer_type == :isochronous
|
105
|
+
SynchronizationTypes[(bmAttributes & 0b1100) >> 2]
|
106
|
+
end
|
107
|
+
|
108
|
+
UsageTypes = [:data, :feedback, :implicit_feedback, :unknown]
|
109
|
+
# @return [Symbol] One of {UsageTypes}
|
110
|
+
def usage_type
|
111
|
+
return unless transfer_type == :isochronous
|
112
|
+
UsageTypes[(bmAttributes & 0b110000) >> 4]
|
113
|
+
end
|
114
|
+
|
115
|
+
# Maximum Packet Size this endpoint is capable of sending or receiving
|
116
|
+
def wMaxPacketSize
|
117
|
+
self[:wMaxPacketSize]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Interval for polling endpoint data transfers. Value in frame counts.
|
121
|
+
# Ignored for Bulk & Control Endpoints. Isochronous must equal 1 and field
|
122
|
+
# may range from 1 to 255 for interrupt endpoints.
|
123
|
+
#
|
124
|
+
# The interval is respected by the kernel driver, so user mode processes
|
125
|
+
# using libusb don't need to care about it.
|
126
|
+
def bInterval
|
127
|
+
self[:bInterval]
|
128
|
+
end
|
129
|
+
|
130
|
+
# For audio devices only: the rate at which synchronization feedback is provided.
|
131
|
+
def bRefresh
|
132
|
+
self[:bRefresh]
|
133
|
+
end
|
134
|
+
|
135
|
+
# For audio devices only: the address if the synch endpoint.
|
136
|
+
def bSynchAddress
|
137
|
+
self[:bSynchAddress]
|
138
|
+
end
|
139
|
+
|
140
|
+
# Extra descriptors.
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
def extra
|
144
|
+
return if self[:extra].null?
|
145
|
+
self[:extra].read_string(self[:extra_length])
|
146
|
+
end
|
147
|
+
|
148
|
+
def initialize(setting, *args)
|
149
|
+
@setting = setting
|
150
|
+
super(*args)
|
151
|
+
end
|
152
|
+
|
153
|
+
# @return [Setting] the setting this endpoint belongs to.
|
154
|
+
attr_reader :setting
|
155
|
+
|
156
|
+
def inspect
|
157
|
+
type = [transfer_type, synchronization_type, usage_type].compact
|
158
|
+
"\#<#{self.class} #{endpoint_number} #{direction} #{type.join(" ")}>"
|
159
|
+
end
|
160
|
+
|
161
|
+
# The {Device} this Endpoint belongs to.
|
162
|
+
def device() self.setting.interface.configuration.device end
|
163
|
+
# The {Configuration} this Endpoint belongs to.
|
164
|
+
def configuration() self.setting.interface.configuration end
|
165
|
+
# The {Interface} this Endpoint belongs to.
|
166
|
+
def interface() self.setting.interface end
|
167
|
+
|
168
|
+
def <=>(o)
|
169
|
+
t = setting<=>o.setting
|
170
|
+
t = bEndpointAddress<=>o.bEndpointAddress if t==0
|
171
|
+
t
|
172
|
+
end
|
173
|
+
|
174
|
+
if Call.respond_to?(:libusb_get_ss_endpoint_companion_descriptor)
|
175
|
+
|
176
|
+
# @method ss_companion
|
177
|
+
# Get the endpoints superspeed endpoint companion descriptor (if any).
|
178
|
+
#
|
179
|
+
# Since libusb version 1.0.16.
|
180
|
+
#
|
181
|
+
# @return [SsCompanion]
|
182
|
+
def ss_companion
|
183
|
+
ep_comp = FFI::MemoryPointer.new :pointer
|
184
|
+
res = Call.libusb_get_ss_endpoint_companion_descriptor(
|
185
|
+
device.context.instance_variable_get(:@ctx),
|
186
|
+
pointer,
|
187
|
+
ep_comp
|
188
|
+
)
|
189
|
+
LIBUSB.raise_error res, "in libusb_get_ss_endpoint_companion_descriptor" if res!=0
|
190
|
+
SsCompanion.new ep_comp.read_pointer
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|