libusb 0.7.0-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,376 @@
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
+ # This file is for compatibility with ruby-usb and libusb-0.1.
17
+ #
18
+ # Please visit the project website at http://github.com/larskanis/libusb
19
+ # for support.
20
+
21
+ require 'libusb'
22
+ require 'forwardable'
23
+
24
+ # Compatibility layer for ruby-usb[http://www.a-k-r.org/ruby-usb/] (API based on libusb-0.1)
25
+ #
26
+ # This module provides some limited compatibility to ruby-usb.
27
+ #
28
+ # Usage example:
29
+ # begin
30
+ # require 'usb'
31
+ # rescue LoadError
32
+ # require 'libusb/compat'
33
+ # end
34
+ # p USB.devices => [#<USB::Device ...>]
35
+ #
36
+ # Known issues:
37
+ # * Exceptions are different between ruby-usb and libusb and they don't get converted
38
+ # * libusb-1.0 doesn't explicitly manage USB-buses, so only one Bus is used currently
39
+ module USB
40
+ @default_context = nil
41
+ def self.default_context
42
+ @default_context ||= LIBUSB::Context.new
43
+ end
44
+
45
+ @default_bus = nil
46
+ def self.default_bus
47
+ @default_bus ||= Bus.new(default_context)
48
+ end
49
+
50
+ USB_CLASS_PER_INTERFACE = LIBUSB::CLASS_PER_INTERFACE
51
+ USB_CLASS_AUDIO = LIBUSB::CLASS_AUDIO
52
+ USB_CLASS_COMM = LIBUSB::CLASS_COMM
53
+ USB_CLASS_HID = LIBUSB::CLASS_HID
54
+ USB_CLASS_PRINTER = LIBUSB::CLASS_PRINTER
55
+ USB_CLASS_PTP = LIBUSB::CLASS_PTP
56
+ USB_CLASS_MASS_STORAGE = LIBUSB::CLASS_MASS_STORAGE
57
+ USB_CLASS_HUB = LIBUSB::CLASS_HUB
58
+ USB_CLASS_DATA = LIBUSB::CLASS_DATA
59
+ USB_CLASS_VENDOR_SPEC = LIBUSB::CLASS_VENDOR_SPEC
60
+
61
+ USB_DT_DEVICE = LIBUSB::DT_DEVICE
62
+ USB_DT_CONFIG = LIBUSB::DT_CONFIG
63
+ USB_DT_STRING = LIBUSB::DT_STRING
64
+ USB_DT_INTERFACE = LIBUSB::DT_INTERFACE
65
+ USB_DT_ENDPOINT = LIBUSB::DT_ENDPOINT
66
+ USB_DT_HID = LIBUSB::DT_HID
67
+ USB_DT_REPORT = LIBUSB::DT_REPORT
68
+ USB_DT_PHYSICAL = LIBUSB::DT_PHYSICAL
69
+ USB_DT_HUB = LIBUSB::DT_HUB
70
+ USB_DT_DEVICE_SIZE = LIBUSB::DT_DEVICE_SIZE
71
+ USB_DT_CONFIG_SIZE = LIBUSB::DT_CONFIG_SIZE
72
+ USB_DT_INTERFACE_SIZE = LIBUSB::DT_INTERFACE_SIZE
73
+ USB_DT_ENDPOINT_SIZE = LIBUSB::DT_ENDPOINT_SIZE
74
+ USB_DT_ENDPOINT_AUDIO_SIZE = LIBUSB::DT_ENDPOINT_AUDIO_SIZE
75
+ USB_DT_HUB_NONVAR_SIZE = LIBUSB::DT_HUB_NONVAR_SIZE
76
+
77
+ USB_ENDPOINT_ADDRESS_MASK = LIBUSB::ENDPOINT_ADDRESS_MASK
78
+ USB_ENDPOINT_DIR_MASK = LIBUSB::ENDPOINT_DIR_MASK
79
+ USB_ENDPOINT_IN = LIBUSB::ENDPOINT_IN
80
+ USB_ENDPOINT_OUT = LIBUSB::ENDPOINT_OUT
81
+
82
+ USB_ENDPOINT_TYPE_MASK = LIBUSB::TRANSFER_TYPE_MASK
83
+ USB_ENDPOINT_TYPE_CONTROL = LIBUSB::TRANSFER_TYPE_CONTROL
84
+ USB_ENDPOINT_TYPE_ISOCHRONOUS = LIBUSB::TRANSFER_TYPE_ISOCHRONOUS
85
+ USB_ENDPOINT_TYPE_BULK = LIBUSB::TRANSFER_TYPE_BULK
86
+ USB_ENDPOINT_TYPE_INTERRUPT = LIBUSB::TRANSFER_TYPE_INTERRUPT
87
+
88
+ USB_REQ_GET_STATUS = LIBUSB::REQUEST_GET_STATUS
89
+ USB_REQ_CLEAR_FEATURE = LIBUSB::REQUEST_CLEAR_FEATURE
90
+ USB_REQ_SET_FEATURE = LIBUSB::REQUEST_SET_FEATURE
91
+ USB_REQ_SET_ADDRESS = LIBUSB::REQUEST_SET_ADDRESS
92
+ USB_REQ_GET_DESCRIPTOR = LIBUSB::REQUEST_GET_DESCRIPTOR
93
+ USB_REQ_SET_DESCRIPTOR = LIBUSB::REQUEST_SET_DESCRIPTOR
94
+ USB_REQ_GET_CONFIGURATION = LIBUSB::REQUEST_GET_CONFIGURATION
95
+ USB_REQ_SET_CONFIGURATION = LIBUSB::REQUEST_SET_CONFIGURATION
96
+ USB_REQ_GET_INTERFACE = LIBUSB::REQUEST_GET_INTERFACE
97
+ USB_REQ_SET_INTERFACE = LIBUSB::REQUEST_SET_INTERFACE
98
+ USB_REQ_SYNCH_FRAME = LIBUSB::REQUEST_SYNCH_FRAME
99
+ USB_TYPE_STANDARD = LIBUSB::REQUEST_TYPE_STANDARD
100
+ USB_TYPE_CLASS = LIBUSB::REQUEST_TYPE_CLASS
101
+ USB_TYPE_VENDOR = LIBUSB::REQUEST_TYPE_VENDOR
102
+ USB_TYPE_RESERVED = LIBUSB::REQUEST_TYPE_RESERVED
103
+ USB_RECIP_DEVICE = LIBUSB::RECIPIENT_DEVICE
104
+ USB_RECIP_INTERFACE = LIBUSB::RECIPIENT_INTERFACE
105
+ USB_RECIP_ENDPOINT = LIBUSB::RECIPIENT_ENDPOINT
106
+ USB_RECIP_OTHER = LIBUSB::RECIPIENT_OTHER
107
+
108
+ HAS_GET_DRIVER_NP = !FFI::Platform.windows?
109
+ HAS_DETACH_KERNEL_DRIVER_NP = !FFI::Platform.windows?
110
+
111
+ # not defined by libusb-1.0, but typical values are:
112
+ USB_MAXENDPOINTS = 32
113
+ USB_MAXINTERFACES = 32
114
+ USB_MAXALTSETTING = 128
115
+ USB_MAXCONFIG = 8
116
+
117
+
118
+ def USB.busses
119
+ [default_bus]
120
+ end
121
+
122
+ def USB.devices; default_context.devices.map{|c| Device.new(c) }; end
123
+ def USB.configurations() USB.devices.map {|d| d.configurations }.flatten end
124
+ def USB.interfaces() USB.configurations.map {|d| d.interfaces }.flatten end
125
+ def USB.settings() USB.interfaces.map {|d| d.settings }.flatten end
126
+ def USB.endpoints() USB.settings.map {|d| d.endpoints }.flatten end
127
+
128
+ def USB.find_bus(n)
129
+ default_bus
130
+ end
131
+
132
+ def USB.each_device_by_class(devclass, subclass=nil, protocol=nil)
133
+ devs = default_context.devices bClass: devclass, bSubClass: subclass, bProtocol: protocol
134
+ devs.each do |dev|
135
+ yield Device.new(dev)
136
+ end
137
+ nil
138
+ end
139
+
140
+ class Bus
141
+ def initialize(context)
142
+ @ct = context
143
+ end
144
+ def devices
145
+ @ct.devices.map{|d| Device.new(d) }
146
+ end
147
+
148
+ def configurations() self.devices.map{|d| d.configurations }.flatten end
149
+ def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
150
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
151
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
152
+
153
+ def find_device(n)
154
+ raise NotImplementedError
155
+ end
156
+ end
157
+
158
+ def USB.dev_string(base_class, sub_class, protocol)
159
+ LIBUSB.dev_string(base_class, sub_class, protocol)
160
+ end
161
+
162
+ class Device
163
+ extend Forwardable
164
+ include Comparable
165
+
166
+ def initialize(dev)
167
+ @dev = dev
168
+ end
169
+
170
+ def_delegators :@dev, :bLength, :bDescriptorType, :bcdUSB, :bDeviceClass,
171
+ :bDeviceSubClass, :bDeviceProtocol, :bMaxPacketSize0, :idVendor, :idProduct,
172
+ :bcdDevice, :iManufacturer, :iProduct, :iSerialNumber, :bNumConfigurations,
173
+ :manufacturer, :product, :serial_number,
174
+ :inspect
175
+
176
+ def <=>(o)
177
+ @dev<=>o.instance_variable_get(:@dev)
178
+ end
179
+
180
+ def open
181
+ h = DevHandle.new(@dev.open)
182
+ if block_given?
183
+ begin
184
+ yield h
185
+ ensure
186
+ h.usb_close
187
+ end
188
+ else
189
+ h
190
+ end
191
+ end
192
+
193
+ def bus; default_bus; end
194
+ def configurations; @dev.configurations.map{|c| Configuration.new(c) }; end
195
+ def interfaces; @dev.interfaces.map{|c| Interface.new(c) }; end
196
+ def settings; @dev.settings.map{|c| Setting.new(c) }; end
197
+ def endpoints; @dev.endpoints.map{|c| Endpoint.new(c) }; end
198
+ end
199
+
200
+ class Configuration
201
+ extend Forwardable
202
+ include Comparable
203
+
204
+ def initialize(cd)
205
+ @cd = cd
206
+ end
207
+
208
+ def_delegators :@cd, :bLength, :bDescriptorType, :wTotalLength, :bNumInterfaces,
209
+ :bConfigurationValue, :iConfiguration, :bmAttributes, :bMaxPower,
210
+ :inspect
211
+
212
+ def <=>(o)
213
+ @cd<=>o.instance_variable_get(:@cd)
214
+ end
215
+
216
+ def bus; default_bus; end
217
+ def device() Device.new(@cd.device) end
218
+ def interfaces; @cd.interfaces.map{|c| Interface.new(c) }; end
219
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
220
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
221
+ end
222
+
223
+ class Interface
224
+ extend Forwardable
225
+ include Comparable
226
+
227
+ def initialize(i)
228
+ @i = i
229
+ end
230
+
231
+ def_delegators :@i, :inspect
232
+
233
+ def <=>(o)
234
+ @i<=>o.instance_variable_get(:@i)
235
+ end
236
+
237
+ def bus() self.configuration.device.bus end
238
+ def device() self.configuration.device end
239
+ def configuration; Configuration.new(@i.configuration); end
240
+ def settings; @i.alt_settings.map{|c| Setting.new(c) }; end
241
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
242
+ end
243
+
244
+ class Setting
245
+ extend Forwardable
246
+ include Comparable
247
+
248
+ def initialize(id)
249
+ @id = id
250
+ end
251
+
252
+ def_delegators :@id, :bLength, :bDescriptorType, :bInterfaceNumber, :bAlternateSetting,
253
+ :bNumEndpoints, :bInterfaceClass, :bInterfaceSubClass, :bInterfaceProtocol,
254
+ :iInterface, :inspect
255
+
256
+ def <=>(o)
257
+ @id<=>o.instance_variable_get(:@id)
258
+ end
259
+
260
+ def bus() self.interface.configuration.device.bus end
261
+ def device() self.interface.configuration.device end
262
+ def configuration() self.interface.configuration end
263
+ def interface; Interface.new(@id.interface); end
264
+ def endpoints() @id.endpoints.map {|d| Endpoint.new(d) }.flatten end
265
+ end
266
+
267
+ class Endpoint
268
+ extend Forwardable
269
+ include Comparable
270
+
271
+ def initialize(ep)
272
+ @ep = ep
273
+ end
274
+
275
+ def_delegators :@ep, :bLength, :bDescriptorType, :bEndpointAddress, :bmAttributes,
276
+ :wMaxPacketSize, :bInterval, :bRefresh, :bSynchAddress,
277
+ :inspect
278
+
279
+ def <=>(o)
280
+ @ep<=>o.instance_variable_get(:@ep)
281
+ end
282
+
283
+ def bus() self.setting.interface.configuration.device.bus end
284
+ def device() self.setting.interface.configuration.device end
285
+ def configuration() self.setting.interface.configuration end
286
+ def interface() self.setting.interface end
287
+ def setting; Setting.new(@ep.setting); end
288
+ end
289
+
290
+ class DevHandle
291
+ def initialize(dev)
292
+ @dev = dev
293
+ end
294
+
295
+ def usb_close; @dev.close; end
296
+ def usb_set_configuration(c); @dev.configuration=c; end
297
+ def usb_set_altinterface(c); @dev.set_interface_alt_setting=c; end
298
+ def usb_clear_halt(c); @dev.clear_halt(c); end
299
+ def usb_reset; @dev.reset_device; end
300
+ def usb_claim_interface(c); @dev.claim_interface(c); end
301
+ def usb_release_interface(c); @dev.release_interface(c); end
302
+ def usb_get_string(index, langid, buffer)
303
+ t = @dev.string_descriptor(index, langid)
304
+ buffer[0, t.length] = t
305
+ t.length
306
+ end
307
+ def usb_get_string_simple(index, buffer)
308
+ t = @dev.string_descriptor_ascii(index)
309
+ buffer[0, t.length] = t
310
+ t.length
311
+ end
312
+
313
+ def usb_control_msg(requesttype, request, value, index, bytes, timeout)
314
+ if requesttype&LIBUSB::ENDPOINT_IN != 0
315
+ # transfer direction in
316
+ res = @dev.control_transfer(bmRequestType: requesttype, bRequest: request,
317
+ wValue: value, wIndex: index, dataIn: bytes.bytesize, timeout: timeout)
318
+ bytes[0, res.bytesize] = res
319
+ res.bytesize
320
+ else
321
+ # transfer direction out
322
+ @dev.control_transfer(bmRequestType: requesttype, bRequest: request, wValue: value,
323
+ wIndex: index, dataOut: bytes, timeout: timeout)
324
+ end
325
+ end
326
+
327
+ def usb_bulk_write(endpoint, bytes, timeout)
328
+ @dev.bulk_transfer(endpoint: endpoint, dataOut: bytes, timeout: timeout)
329
+ end
330
+ def usb_bulk_read(endpoint, bytes, timeout)
331
+ res = @dev.bulk_transfer(endpoint: endpoint, dataIn: bytes.bytesize, timeout: timeout)
332
+ bytes[0, res.bytesize] = res
333
+ res.bytesize
334
+ end
335
+
336
+ def usb_interrupt_write(endpoint, bytes, timeout)
337
+ @dev.interrupt_transfer(endpoint: endpoint, dataOut: bytes, timeout: timeout)
338
+ end
339
+ def usb_interrupt_read(endpoint, bytes, timeout)
340
+ res = @dev.interrupt_transfer(endpoint: endpoint, dataIn: bytes.bytesize, timeout: timeout)
341
+ bytes[0, res.bytesize] = res
342
+ res.bytesize
343
+ end
344
+
345
+ # rb_define_method(rb_cUSB_DevHandle, "usb_get_descriptor", rusb_get_descriptor, 3);
346
+ # rb_define_method(rb_cUSB_DevHandle, "usb_get_descriptor_by_endpoint", rusb_get_descriptor_by_endpoint, 4);
347
+
348
+ if HAS_DETACH_KERNEL_DRIVER_NP
349
+ def usb_detach_kernel_driver_np(interface, dummy=nil)
350
+ @dev.detach_kernel_driver(interface)
351
+ end
352
+ end
353
+
354
+ if HAS_GET_DRIVER_NP
355
+ def usb_get_driver_np(interface, buffer)
356
+ if @dev.kernel_driver_active?(interface)
357
+ t = "unknown driver"
358
+ buffer[0, t.length] = t
359
+ else
360
+ raise Errno::ENODATA, "No data available"
361
+ end
362
+ nil
363
+ end
364
+ end
365
+
366
+ alias set_configuration usb_set_configuration
367
+ alias set_altinterface usb_set_altinterface
368
+ alias clear_halt usb_clear_halt
369
+ alias claim_interface usb_claim_interface
370
+ alias release_interface usb_release_interface
371
+
372
+ def get_string_simple(index)
373
+ @dev.string_descriptor_ascii(index)
374
+ end
375
+ end
376
+ end
@@ -0,0 +1,154 @@
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 Configuration < FFI::Struct
20
+ include Comparable
21
+ include ContextReference
22
+
23
+ layout :bLength, :uint8,
24
+ :bDescriptorType, :uint8,
25
+ :wTotalLength, :uint16,
26
+ :bNumInterfaces, :uint8,
27
+ :bConfigurationValue, :uint8,
28
+ :iConfiguration, :uint8,
29
+ :bmAttributes, :uint8,
30
+ :bMaxPower, :uint8,
31
+ :interface, :pointer,
32
+ :extra, :pointer,
33
+ :extra_length, :int
34
+
35
+ # Size of this descriptor (in bytes).
36
+ def bLength
37
+ self[:bLength]
38
+ end
39
+
40
+ # Descriptor type (0x02)
41
+ def bDescriptorType
42
+ self[:bDescriptorType]
43
+ end
44
+
45
+ # Total length of data returned for this configuration.
46
+ def wTotalLength
47
+ self[:wTotalLength]
48
+ end
49
+
50
+ # Number of interfaces supported by this configuration.
51
+ def bNumInterfaces
52
+ self[:bNumInterfaces]
53
+ end
54
+
55
+ # Identifier value for this configuration.
56
+ def bConfigurationValue
57
+ self[:bConfigurationValue]
58
+ end
59
+
60
+ # Index of string descriptor describing this configuration.
61
+ def iConfiguration
62
+ self[:iConfiguration]
63
+ end
64
+
65
+ # Configuration characteristics.
66
+ #
67
+ # * Bit 7: Reserved, set to 1. (USB 1.0 Bus Powered)
68
+ # * Bit 6: Self Powered
69
+ # * Bit 5: Remote Wakeup
70
+ # * Bit 4..0: Reserved, set to 0.
71
+ #
72
+ # @return [Integer]
73
+ #
74
+ # @see #self_powered?
75
+ # @see #remote_wakeup?
76
+ def bmAttributes
77
+ self[:bmAttributes]
78
+ end
79
+
80
+ # @return [Boolean]
81
+ def self_powered?
82
+ bmAttributes & 0b1000000 != 0
83
+ end
84
+
85
+ # @return [Boolean]
86
+ def remote_wakeup?
87
+ bmAttributes & 0b100000 != 0
88
+ end
89
+
90
+ # Maximum power consumption of the USB device from this bus in this configuration when the device is fully opreation.
91
+ #
92
+ # @return [Integer] Maximum Power Consumption in 2mA units
93
+ def bMaxPower
94
+ self[:bMaxPower]
95
+ end
96
+
97
+ # @deprecated Use {#bMaxPower} instead.
98
+ alias maxPower bMaxPower
99
+
100
+
101
+ # Extra descriptors.
102
+ #
103
+ # @return [String]
104
+ def extra
105
+ return if self[:extra].null?
106
+ self[:extra].read_string(self[:extra_length])
107
+ end
108
+
109
+ def initialize(device, *args)
110
+ @device = device
111
+ super(*args)
112
+
113
+ register_context(device.context.instance_variable_get(:@ctx), :libusb_free_config_descriptor)
114
+ end
115
+
116
+ # @return [Device] the device this configuration belongs to.
117
+ attr_reader :device
118
+
119
+ def interfaces
120
+ ifs = []
121
+ self[:bNumInterfaces].times do |i|
122
+ ifs << Interface.new(self, self[:interface] + i*Interface.size)
123
+ end
124
+ return ifs
125
+ end
126
+
127
+ def inspect
128
+ attrs = []
129
+ attrs << self.bConfigurationValue.to_s
130
+ attrs << "SelfPowered" if self_powered?
131
+ attrs << "RemoteWakeup" if remote_wakeup?
132
+ desc = self.description
133
+ attrs << desc if desc != '?'
134
+ "\#<#{self.class} #{attrs.join(' ')}>"
135
+ end
136
+
137
+ # Return name of this configuration as String.
138
+ def description
139
+ return @description if defined? @description
140
+ @description = device.try_string_descriptor_ascii(self.iConfiguration)
141
+ end
142
+
143
+ # Return all interface decriptions of the configuration as Array of {Setting}s.
144
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
145
+ # Return all endpoints of all interfaces of the configuration as Array of {Endpoint}s.
146
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
147
+
148
+ def <=>(o)
149
+ t = device<=>o.device
150
+ t = bConfigurationValue<=>o.bConfigurationValue if t==0
151
+ t
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,170 @@
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
+ [
20
+ Call::ClassCodes,
21
+ Call::TransferTypes,
22
+ Call::StandardRequests,
23
+ Call::RequestTypes,
24
+ Call::DescriptorTypes,
25
+ Call::EndpointDirections,
26
+ Call::RequestRecipients,
27
+ Call::IsoSyncTypes,
28
+ Call::Speeds,
29
+ Call::Capabilities,
30
+ Call::SupportedSpeeds,
31
+ Call::Usb20ExtensionAttributes,
32
+ Call::SsUsbDeviceCapabilityAttributes,
33
+ Call::BosTypes,
34
+ Call::HotplugEvents,
35
+ Call::HotplugFlags,
36
+ Call::LogLevels,
37
+ Call::LogCbMode,
38
+ Call::Options,
39
+ ].each do |enum|
40
+ enum.to_h.each{|k,v| const_set(k,v) }
41
+ end
42
+
43
+ # Base class of libusb errors
44
+ class Error < RuntimeError
45
+ # The data already transferred before the exception was raised
46
+ # @return [Fixnum] Number of bytes sent for an outgoing transfer
47
+ # @return [String] Received data for an ingoing transfer
48
+ attr_reader :transferred
49
+
50
+ def initialize(msg=nil, transferred=nil)
51
+ super(msg)
52
+ @transferred = transferred
53
+ end
54
+ end
55
+
56
+ class RemainingReferencesError < Error
57
+ end
58
+
59
+ # @private
60
+ ErrorClassForResult = {}
61
+
62
+ # define an exception class for each error code
63
+ Call::Errors.to_h.each do |k,v|
64
+ klass = Class.new(Error)
65
+ klass.send(:define_method, :code){ v }
66
+ const_set(k, klass)
67
+ ErrorClassForResult[v] = klass
68
+ end
69
+
70
+ def self.raise_error(res, text)
71
+ klass = ErrorClassForResult[res]
72
+ raise klass, "#{klass} #{text}"
73
+ end
74
+
75
+ CONTROL_SETUP_SIZE = 8
76
+ DT_DEVICE_SIZE = 18
77
+ DT_CONFIG_SIZE = 9
78
+ DT_INTERFACE_SIZE = 9
79
+ DT_ENDPOINT_SIZE = 7
80
+ DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
81
+ DT_HUB_NONVAR_SIZE = 7
82
+
83
+ ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
84
+ ENDPOINT_DIR_MASK = 0x80
85
+ TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
86
+ ISO_SYNC_TYPE_MASK = 0x0C
87
+ ISO_USAGE_TYPE_MASK = 0x30
88
+
89
+ POLLIN = 1
90
+ POLLOUT = 4
91
+
92
+ # Wildcard matching for hotplug events.
93
+ HOTPLUG_MATCH_ANY = -1
94
+
95
+
96
+ # http://www.usb.org/developers/defined_class
97
+ # @private
98
+ CLASS_CODES = [
99
+ [0x01, nil, nil, "Audio"],
100
+ [0x02, nil, nil, "Comm"],
101
+ [0x03, nil, nil, "HID"],
102
+ [0x05, nil, nil, "Physical"],
103
+ [0x06, 0x01, 0x01, "StillImaging"],
104
+ [0x06, nil, nil, "Image"],
105
+ [0x07, nil, nil, "Printer"],
106
+ [0x08, 0x01, nil, "MassStorage RBC Bulk-Only"],
107
+ [0x08, 0x02, 0x50, "MassStorage ATAPI Bulk-Only"],
108
+ [0x08, 0x03, 0x50, "MassStorage QIC-157 Bulk-Only"],
109
+ [0x08, 0x04, nil, "MassStorage UFI"],
110
+ [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bulk-Only"],
111
+ [0x08, 0x06, 0x50, "MassStorage SCSI Bulk-Only"],
112
+ [0x08, nil, nil, "MassStorage"],
113
+ [0x09, 0x00, 0x00, "Full speed Hub"],
114
+ [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
115
+ [0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
116
+ [0x09, nil, nil, "Hub"],
117
+ [0x0a, nil, nil, "CDC"],
118
+ [0x0b, nil, nil, "SmartCard"],
119
+ [0x0d, 0x00, 0x00, "ContentSecurity"],
120
+ [0x0e, nil, nil, "Video"],
121
+ [0xdc, 0x01, 0x01, "Diagnostic USB2"],
122
+ [0xdc, nil, nil, "Diagnostic"],
123
+ [0xe0, 0x01, 0x01, "Bluetooth"],
124
+ [0xe0, 0x01, 0x02, "UWB"],
125
+ [0xe0, 0x01, 0x03, "RemoteNDIS"],
126
+ [0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
127
+ [0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
128
+ [0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
129
+ [0xe0, nil, nil, "Wireless Controller"],
130
+ [0xef, 0x01, 0x01, "Active Sync"],
131
+ [0xef, 0x01, 0x02, "Palm Sync"],
132
+ [0xef, 0x02, 0x01, "Interface Association Descriptor"],
133
+ [0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
134
+ [0xef, 0x03, 0x01, "Cable Based Association Framework"],
135
+ [0xef, nil, nil, "Miscellaneous"],
136
+ [0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
137
+ [0xfe, 0x02, 0x00, "IRDA Bridge"],
138
+ [0xfe, 0x03, 0x00, "USB Test and Measurement"],
139
+ [0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
140
+ [0xfe, nil, nil, "Application Specific"],
141
+ [0xff, nil, nil, "Vendor specific"],
142
+ ]
143
+ # @private
144
+ CLASS_CODES_HASH1 = {}
145
+ # @private
146
+ CLASS_CODES_HASH2 = {}
147
+ # @private
148
+ CLASS_CODES_HASH3 = {}
149
+ CLASS_CODES.each {|base_class, sub_class, protocol, desc|
150
+ if protocol
151
+ CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
152
+ elsif sub_class
153
+ CLASS_CODES_HASH2[[base_class, sub_class]] = desc
154
+ else
155
+ CLASS_CODES_HASH1[base_class] = desc
156
+ end
157
+ }
158
+
159
+ def self.dev_string(base_class, sub_class, protocol)
160
+ if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
161
+ desc
162
+ elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
163
+ desc + " (%02x)" % [protocol]
164
+ elsif desc = CLASS_CODES_HASH1[base_class]
165
+ desc + " (%02x,%02x)" % [sub_class, protocol]
166
+ else
167
+ "Unknown(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
168
+ end
169
+ end
170
+ end