libusb 0.7.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.appveyor.yml +33 -0
  3. data/.github/workflows/ci.yml +185 -0
  4. data/.gitignore +9 -0
  5. data/.travis.yml +26 -0
  6. data/.yardopts +6 -0
  7. data/COPYING +165 -0
  8. data/Gemfile +19 -0
  9. data/History.md +193 -0
  10. data/README.md +184 -0
  11. data/Rakefile +79 -0
  12. data/lib/libusb/bos.rb +362 -0
  13. data/lib/libusb/call.rb +622 -0
  14. data/lib/libusb/compat.rb +376 -0
  15. data/lib/libusb/configuration.rb +154 -0
  16. data/lib/libusb/constants.rb +170 -0
  17. data/lib/libusb/context.rb +576 -0
  18. data/lib/libusb/context_reference.rb +38 -0
  19. data/lib/libusb/dependencies.rb +7 -0
  20. data/lib/libusb/dev_handle.rb +574 -0
  21. data/lib/libusb/device.rb +407 -0
  22. data/lib/libusb/endpoint.rb +195 -0
  23. data/lib/libusb/eventmachine.rb +187 -0
  24. data/lib/libusb/gem_helper.rb +151 -0
  25. data/lib/libusb/interface.rb +60 -0
  26. data/lib/libusb/libusb_recipe.rb +29 -0
  27. data/lib/libusb/setting.rb +132 -0
  28. data/lib/libusb/ss_companion.rb +72 -0
  29. data/lib/libusb/stdio.rb +25 -0
  30. data/lib/libusb/transfer.rb +418 -0
  31. data/lib/libusb/version_gem.rb +19 -0
  32. data/lib/libusb/version_struct.rb +63 -0
  33. data/lib/libusb-1.0.dll +0 -0
  34. data/lib/libusb.rb +146 -0
  35. data/libusb.gemspec +28 -0
  36. data/test/test_libusb.rb +42 -0
  37. data/test/test_libusb_bos.rb +140 -0
  38. data/test/test_libusb_bulk_stream_transfer.rb +61 -0
  39. data/test/test_libusb_compat.rb +78 -0
  40. data/test/test_libusb_compat_mass_storage.rb +81 -0
  41. data/test/test_libusb_context.rb +88 -0
  42. data/test/test_libusb_descriptors.rb +245 -0
  43. data/test/test_libusb_event_machine.rb +118 -0
  44. data/test/test_libusb_gc.rb +52 -0
  45. data/test/test_libusb_hotplug.rb +129 -0
  46. data/test/test_libusb_iso_transfer.rb +56 -0
  47. data/test/test_libusb_mass_storage.rb +268 -0
  48. data/test/test_libusb_mass_storage2.rb +96 -0
  49. data/test/test_libusb_structs.rb +87 -0
  50. data/test/test_libusb_threads.rb +89 -0
  51. data/wireshark-usb-sniffer.png +0 -0
  52. metadata +112 -0
@@ -0,0 +1,407 @@
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
+ include ContextReference
25
+
26
+ # @return [Context] the context this device belongs to.
27
+ attr_reader :context
28
+
29
+ def initialize context, pDev
30
+ @context = context
31
+ @pDev = pDev
32
+ register_context(context.instance_variable_get(:@ctx), :libusb_unref_device)
33
+ Call.libusb_ref_device(pDev)
34
+
35
+ @pDevDesc = Call::DeviceDescriptor.new
36
+ res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
37
+ LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
38
+ end
39
+
40
+ # The pointer for ContextReference
41
+ private def pointer
42
+ @pDev
43
+ end
44
+
45
+ # Open the device and obtain a device handle.
46
+ #
47
+ # A handle allows you to perform I/O on the device in question.
48
+ # This is a non-blocking function; no requests are sent over the bus.
49
+ #
50
+ # If called with a block, the handle is passed to the block
51
+ # and is closed when the block has finished.
52
+ #
53
+ # You need proper device access:
54
+ # * Linux: read+write permissions to <tt>/dev/bus/usb/<bus>/<dev></tt>
55
+ # * Windows: by installing a WinUSB-driver for the device (see {file:README.rdoc#Usage_on_Windows} )
56
+ #
57
+ # @return [DevHandle] Handle to the device.
58
+ def open
59
+ ppHandle = FFI::MemoryPointer.new :pointer
60
+ res = Call.libusb_open(@pDev, ppHandle)
61
+ LIBUSB.raise_error res, "in libusb_open" if res!=0
62
+ handle = DevHandle.new self, ppHandle.read_pointer
63
+ return handle unless block_given?
64
+ begin
65
+ yield handle
66
+ ensure
67
+ handle.close
68
+ end
69
+ end
70
+
71
+ # Open the device and claim an interface.
72
+ #
73
+ # This is a convenience method to {Device#open} and {DevHandle#claim_interface}.
74
+ # Must be called with a block. When the block has finished, the interface
75
+ # will be released and the device will be closed.
76
+ #
77
+ # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
78
+ def open_interface(interface)
79
+ open do |dev|
80
+ dev.claim_interface(interface) do
81
+ yield dev
82
+ end
83
+ end
84
+ end
85
+
86
+ # Get the number of the bus that a device is connected to.
87
+ def bus_number
88
+ Call.libusb_get_bus_number(@pDev)
89
+ end
90
+
91
+ # Get the address of the device on the bus it is connected to.
92
+ def device_address
93
+ Call.libusb_get_device_address(@pDev)
94
+ end
95
+
96
+ if Call.respond_to?(:libusb_get_port_number)
97
+ # Get the number of the port that a device is connected to.
98
+ # Available since libusb-1.0.12.
99
+ #
100
+ # @return [Fixnum, nil] the port number (+nil+ if not available)
101
+ # @see #port_numbers
102
+ def port_number
103
+ r = Call.libusb_get_port_number(@pDev)
104
+ r==0 ? nil : r
105
+ end
106
+
107
+ # Get the the parent from the specified device [EXPERIMENTAL].
108
+ # Available since libusb-1.0.12.
109
+ #
110
+ # @return [Device, nil] the device parent or +nil+ if not available
111
+ # @see #port_numbers
112
+ def parent
113
+ pppDevs = FFI::MemoryPointer.new :pointer
114
+ Call.libusb_get_device_list(@context.instance_variable_get(:@ctx), pppDevs)
115
+ ppDevs = pppDevs.read_pointer
116
+ pParent = Call.libusb_get_parent(@pDev)
117
+ parent = pParent.null? ? nil : Device.new(@context, pParent)
118
+ Call.libusb_free_device_list(ppDevs, 1)
119
+ parent
120
+ end
121
+
122
+ # Get the list of all port numbers from root for the specified device.
123
+ # Available since libusb-1.0.12.
124
+ #
125
+ # @return [Array<Fixnum>]
126
+ # @see #parent
127
+ # @see #port_number
128
+ def port_numbers
129
+ # As per the USB 3.0 specs, the current maximum limit for the depth is 7.
130
+ path_len = 7
131
+ pPath = FFI::MemoryPointer.new :pointer, path_len
132
+
133
+ l = if Call.respond_to?(:libusb_get_port_numbers)
134
+ Call.libusb_get_port_numbers(@pDev, pPath, path_len)
135
+ else
136
+ Call.libusb_get_port_path(@context.instance_variable_get(:@ctx), @pDev, pPath, path_len)
137
+ end
138
+ pPath.read_array_of_uint8(l)
139
+ end
140
+ alias port_path port_numbers
141
+ end
142
+
143
+ if Call.respond_to?(:libusb_get_device_speed)
144
+ # Get the negotiated connection speed for a device.
145
+ # Available since libusb-1.0.9.
146
+ #
147
+ # @return [Symbol] a {Call::Speeds Speeds} symbol, where +:SPEED_UNKNOWN+ means that
148
+ # the OS doesn't know or doesn't support returning the negotiated speed.
149
+ def device_speed
150
+ Call.libusb_get_device_speed(@pDev)
151
+ end
152
+ end
153
+
154
+ # Convenience function to retrieve the wMaxPacketSize value for a
155
+ # particular endpoint in the active device configuration.
156
+ #
157
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
158
+ # @return [Fixnum] the wMaxPacketSize value
159
+ def max_packet_size(endpoint)
160
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
161
+ res = Call.libusb_get_max_packet_size(@pDev, endpoint)
162
+ LIBUSB.raise_error res, "in libusb_get_max_packet_size" unless res>=0
163
+ res
164
+ end
165
+
166
+ if Call.respond_to?(:libusb_get_max_alt_packet_size)
167
+
168
+ # Calculate the maximum packet size which a specific endpoint is capable of
169
+ # sending or receiving in the duration of 1 microframe
170
+ #
171
+ # Only the active configuration is examined. The calculation is based on the
172
+ # wMaxPacketSize field in the endpoint descriptor as described in section
173
+ # 9.6.6 in the USB 2.0 specifications.
174
+ #
175
+ # If acting on an isochronous or interrupt endpoint, this function will
176
+ # multiply the value found in bits 0:10 by the number of transactions per
177
+ # microframe (determined by bits 11:12). Otherwise, this function just
178
+ # returns the numeric value found in bits 0:10. For USB 3.0 device, it
179
+ # will attempts to retrieve the Endpoint Companion Descriptor to return
180
+ # wBytesPerInterval.
181
+ #
182
+ # This function is useful for setting up isochronous transfers, for example
183
+ # you might pass the return value from this function to
184
+ # +IsochronousTransfer.packet_lengths=+ in order to set the length field of every
185
+ # isochronous packet in a transfer.
186
+ #
187
+ # Available since libusb-1.0.27.
188
+ #
189
+ # @param [Interface, Fixnum] interface the interface or its bInterfaceNumber of the interface the endpoint belongs to
190
+ # @param [Setting, Fixnum] alternate_setting the alternate setting or its bAlternateSetting
191
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
192
+ # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
193
+ # @see max_iso_packet_size
194
+ def max_alt_packet_size(interface, alternate_setting, endpoint)
195
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
196
+ alternate_setting = alternate_setting.bAlternateSetting if alternate_setting.respond_to? :bAlternateSetting
197
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
198
+ res = Call.libusb_get_max_alt_packet_size(@pDev, interface, alternate_setting, endpoint)
199
+ LIBUSB.raise_error res, "in libusb_get_max_alt_packet_size" unless res>=0
200
+ res
201
+ end
202
+ end
203
+
204
+ # Calculate the maximum packet size which a specific endpoint is capable is
205
+ # sending or receiving in the duration of 1 microframe.
206
+ #
207
+ # Only the active configution is examined. The calculation is based on the
208
+ # wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6
209
+ # in the USB 2.0 specifications.
210
+ #
211
+ # If acting on an isochronous or interrupt endpoint, this function will
212
+ # multiply the value found in bits 0:10 by the number of transactions per
213
+ # microframe (determined by bits 11:12). Otherwise, this function just returns
214
+ # the numeric value found in bits 0:10.
215
+ #
216
+ # This function is useful for setting up isochronous transfers, for example
217
+ # you might use the return value from this function to call
218
+ # IsoPacket#alloc_buffer in order to set the length field
219
+ # of an isochronous packet in a transfer.
220
+ #
221
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
222
+ # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
223
+ # @see max_alt_packet_size
224
+ def max_iso_packet_size(endpoint)
225
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
226
+ res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
227
+ LIBUSB.raise_error res, "in libusb_get_max_iso_packet_size" unless res>=0
228
+ res
229
+ end
230
+
231
+ # Obtain a config descriptor of the device.
232
+ #
233
+ # @param [Fixnum] index number of the config descriptor
234
+ # @return Configuration
235
+ def config_descriptor(index)
236
+ ppConfig = FFI::MemoryPointer.new :pointer
237
+ res = Call.libusb_get_config_descriptor(@pDev, index, ppConfig)
238
+ LIBUSB.raise_error res, "in libusb_get_config_descriptor" if res!=0
239
+ pConfig = ppConfig.read_pointer
240
+ config = Configuration.new(self, pConfig)
241
+ config
242
+ end
243
+
244
+ # Size of the Descriptor in Bytes (18 bytes)
245
+ def bLength
246
+ @pDevDesc[:bLength]
247
+ end
248
+
249
+ # Device Descriptor (0x01)
250
+ def bDescriptorType
251
+ @pDevDesc[:bDescriptorType]
252
+ end
253
+
254
+ # USB specification release number which device complies too
255
+ #
256
+ # @return [Integer] in binary-coded decimal
257
+ def bcdUSB
258
+ @pDevDesc[:bcdUSB]
259
+ end
260
+
261
+ # USB-IF class code for the device (Assigned by USB Org)
262
+ #
263
+ # * If equal to 0x00, each interface specifies it's own class code
264
+ # * If equal to 0xFF, the class code is vendor specified
265
+ # * Otherwise field is valid Class Code
266
+ def bDeviceClass
267
+ @pDevDesc[:bDeviceClass]
268
+ end
269
+
270
+ # USB-IF subclass code for the device, qualified by the {Device#bDeviceClass}
271
+ # value (Assigned by USB Org)
272
+ def bDeviceSubClass
273
+ @pDevDesc[:bDeviceSubClass]
274
+ end
275
+
276
+ # USB-IF protocol code for the device, qualified by the {Device#bDeviceClass}
277
+ # and {Device#bDeviceSubClass} values (Assigned by USB Org)
278
+ def bDeviceProtocol
279
+ @pDevDesc[:bDeviceProtocol]
280
+ end
281
+
282
+ # Maximum Packet Size for Endpoint 0. Valid Sizes are 8, 16, 32, 64
283
+ def bMaxPacketSize0
284
+ @pDevDesc[:bMaxPacketSize0]
285
+ end
286
+
287
+ # USB-IF vendor ID (Assigned by USB Org)
288
+ def idVendor
289
+ @pDevDesc[:idVendor]
290
+ end
291
+
292
+ # USB-IF product ID (Assigned by Manufacturer)
293
+ def idProduct
294
+ @pDevDesc[:idProduct]
295
+ end
296
+
297
+ # Device release number in binary-coded decimal.
298
+ def bcdDevice
299
+ @pDevDesc[:bcdDevice]
300
+ end
301
+
302
+ # Index of string descriptor describing manufacturer.
303
+ def iManufacturer
304
+ @pDevDesc[:iManufacturer]
305
+ end
306
+
307
+ # Index of string descriptor describing product.
308
+ def iProduct
309
+ @pDevDesc[:iProduct]
310
+ end
311
+
312
+ # Index of string descriptor containing device serial number.
313
+ def iSerialNumber
314
+ @pDevDesc[:iSerialNumber]
315
+ end
316
+
317
+ # Number of Possible Configurations
318
+ def bNumConfigurations
319
+ @pDevDesc[:bNumConfigurations]
320
+ end
321
+
322
+
323
+ def inspect
324
+ attrs = []
325
+ attrs << "#{self.bus_number}/#{self.device_address}"
326
+ attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
327
+ attrs << self.manufacturer
328
+ attrs << self.product
329
+ attrs << self.serial_number
330
+ if self.bDeviceClass == LIBUSB::CLASS_PER_INTERFACE
331
+ devclass = self.settings.map {|i|
332
+ LIBUSB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
333
+ }.join(", ")
334
+ else
335
+ devclass = LIBUSB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
336
+ end
337
+ attrs << "(#{devclass})"
338
+ attrs.compact!
339
+ "\#<#{self.class} #{attrs.join(' ')}>"
340
+ end
341
+
342
+ def try_string_descriptor_ascii(i)
343
+ begin
344
+ open{|h| h.string_descriptor_ascii(i) }
345
+ rescue
346
+ "?"
347
+ end
348
+ end
349
+
350
+ # Return manufacturer of the device
351
+ # @return String
352
+ def manufacturer
353
+ return @manufacturer if defined? @manufacturer
354
+ @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
355
+ @manufacturer = @manufacturer.strip if @manufacturer
356
+ @manufacturer
357
+ end
358
+
359
+ # Return product name of the device.
360
+ # @return String
361
+ def product
362
+ return @product if defined? @product
363
+ @product = try_string_descriptor_ascii(self.iProduct)
364
+ @product = @product.strip if @product
365
+ @product
366
+ end
367
+
368
+ # Return serial number of the device.
369
+ # @return String
370
+ def serial_number
371
+ return @serial_number if defined? @serial_number
372
+ @serial_number = try_string_descriptor_ascii(self.iSerialNumber)
373
+ @serial_number = @serial_number.strip if @serial_number
374
+ @serial_number
375
+ end
376
+
377
+ # Return configurations of the device.
378
+ # @return [Array<Configuration>]
379
+ def configurations
380
+ configs = []
381
+ bNumConfigurations.times do |config_index|
382
+ begin
383
+ configs << config_descriptor(config_index)
384
+ rescue RuntimeError
385
+ # On Windows some devices don't return it's configuration.
386
+ end
387
+ end
388
+ configs
389
+ end
390
+
391
+ # Return all interfaces of this device.
392
+ # @return [Array<Interface>]
393
+ def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
394
+ # Return all interface decriptions of this device.
395
+ # @return [Array<Setting>]
396
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
397
+ # Return all endpoints of all interfaces of this device.
398
+ # @return [Array<Endpoint>]
399
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
400
+
401
+ def <=>(o)
402
+ t = bus_number<=>o.bus_number
403
+ t = device_address<=>o.device_address if t==0
404
+ t
405
+ end
406
+ end
407
+ end
@@ -0,0 +1,195 @@
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
+ ctx = device.context.instance_variable_get(:@ctx)
185
+ res = Call.libusb_get_ss_endpoint_companion_descriptor(
186
+ ctx,
187
+ pointer,
188
+ ep_comp
189
+ )
190
+ LIBUSB.raise_error res, "in libusb_get_ss_endpoint_companion_descriptor" if res!=0
191
+ SsCompanion.new ctx, ep_comp.read_pointer
192
+ end
193
+ end
194
+ end
195
+ end