libusb 0.6.0-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +17 -0
  4. data/.yardopts +6 -0
  5. data/COPYING +165 -0
  6. data/Gemfile +11 -0
  7. data/History.md +124 -0
  8. data/README.md +159 -0
  9. data/Rakefile +145 -0
  10. data/appveyor.yml +23 -0
  11. data/lib/libusb.rb +58 -0
  12. data/lib/libusb/bos.rb +306 -0
  13. data/lib/libusb/call.rb +446 -0
  14. data/lib/libusb/compat.rb +376 -0
  15. data/lib/libusb/configuration.rb +155 -0
  16. data/lib/libusb/constants.rb +160 -0
  17. data/lib/libusb/context.rb +426 -0
  18. data/lib/libusb/dependencies.rb +7 -0
  19. data/lib/libusb/dev_handle.rb +564 -0
  20. data/lib/libusb/device.rb +365 -0
  21. data/lib/libusb/endpoint.rb +194 -0
  22. data/lib/libusb/eventmachine.rb +183 -0
  23. data/lib/libusb/interface.rb +60 -0
  24. data/lib/libusb/setting.rb +132 -0
  25. data/lib/libusb/ss_companion.rb +69 -0
  26. data/lib/libusb/stdio.rb +25 -0
  27. data/lib/libusb/transfer.rb +377 -0
  28. data/lib/libusb/version_gem.rb +19 -0
  29. data/lib/libusb/version_struct.rb +63 -0
  30. data/libusb.gemspec +30 -0
  31. data/test/test_libusb_bos.rb +118 -0
  32. data/test/test_libusb_bulk_stream_transfer.rb +50 -0
  33. data/test/test_libusb_capability.rb +23 -0
  34. data/test/test_libusb_compat.rb +78 -0
  35. data/test/test_libusb_compat_mass_storage.rb +81 -0
  36. data/test/test_libusb_descriptors.rb +212 -0
  37. data/test/test_libusb_event_machine.rb +118 -0
  38. data/test/test_libusb_gc.rb +37 -0
  39. data/test/test_libusb_hotplug.rb +127 -0
  40. data/test/test_libusb_iso_transfer.rb +50 -0
  41. data/test/test_libusb_mass_storage.rb +268 -0
  42. data/test/test_libusb_mass_storage2.rb +96 -0
  43. data/test/test_libusb_structs.rb +58 -0
  44. data/test/test_libusb_threads.rb +89 -0
  45. data/test/test_libusb_version.rb +40 -0
  46. data/wireshark-usb-sniffer.png +0 -0
  47. metadata +150 -0
@@ -0,0 +1,446 @@
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 'rubygems'
17
+ require 'ffi'
18
+
19
+ module LIBUSB
20
+ # C level interface - for internal use only
21
+ #
22
+ # All enum codes are available as constants in {LIBUSB} namespace.
23
+ module Call
24
+ extend FFI::Library
25
+
26
+ root_path = File.expand_path("../../..", __FILE__)
27
+ ext = FFI::Platform::LIBSUFFIX
28
+ prefix = FFI::Platform::LIBPREFIX.empty? ? 'lib' : FFI::Platform::LIBPREFIX
29
+ bundled_dll = File.join(root_path, "lib/#{prefix}usb-1.0.#{ext}")
30
+ bundled_dll_cygwin = File.join(root_path, "bin/#{prefix}usb-1.0.#{ext}")
31
+ ffi_lib([bundled_dll, bundled_dll_cygwin, "#{prefix}usb-1.0"])
32
+
33
+ ClassCodes = enum :libusb_class_code, [
34
+ :CLASS_PER_INTERFACE, 0,
35
+ :CLASS_AUDIO, 1,
36
+ :CLASS_COMM, 2,
37
+ :CLASS_HID, 3,
38
+ :CLASS_PRINTER, 7,
39
+ :CLASS_PTP, 6,
40
+ :CLASS_MASS_STORAGE, 8,
41
+ :CLASS_HUB, 9,
42
+ :CLASS_DATA, 10,
43
+ :CLASS_WIRELESS, 0xe0,
44
+ :CLASS_APPLICATION, 0xfe,
45
+ :CLASS_VENDOR_SPEC, 0xff
46
+ ]
47
+
48
+ Errors = enum :libusb_error, [
49
+ :SUCCESS, 0,
50
+ :ERROR_IO, -1,
51
+ :ERROR_INVALID_PARAM, -2,
52
+ :ERROR_ACCESS, -3,
53
+ :ERROR_NO_DEVICE, -4,
54
+ :ERROR_NOT_FOUND, -5,
55
+ :ERROR_BUSY, -6,
56
+ :ERROR_TIMEOUT, -7,
57
+ :ERROR_OVERFLOW, -8,
58
+ :ERROR_PIPE, -9,
59
+ :ERROR_INTERRUPTED, -10,
60
+ :ERROR_NO_MEM, -11,
61
+ :ERROR_NOT_SUPPORTED, -12,
62
+ :ERROR_OTHER, -99,
63
+ ]
64
+
65
+ # Transfer status codes
66
+ TransferStatus = enum :libusb_transfer_status, [
67
+ :TRANSFER_COMPLETED,
68
+ :TRANSFER_ERROR,
69
+ :TRANSFER_TIMED_OUT,
70
+ :TRANSFER_CANCELLED,
71
+ :TRANSFER_STALL,
72
+ :TRANSFER_NO_DEVICE,
73
+ :TRANSFER_OVERFLOW,
74
+ ]
75
+
76
+ # libusb_transfer.flags values
77
+ TransferFlags = enum :libusb_transfer_flags, [
78
+ :TRANSFER_SHORT_NOT_OK, 1 << 0,
79
+ :TRANSFER_FREE_BUFFER, 1 << 1,
80
+ :TRANSFER_FREE_TRANSFER, 1 << 2,
81
+ :TRANSFER_ADD_ZERO_PACKET, 1 << 3,
82
+ ]
83
+
84
+ # Values for {Endpoint#transfer_type}.
85
+ TransferTypes = enum :libusb_transfer_type, [
86
+ # Control endpoint
87
+ :TRANSFER_TYPE_CONTROL, 0,
88
+ # Isochronous endpoint
89
+ :TRANSFER_TYPE_ISOCHRONOUS, 1,
90
+ # Bulk endpoint
91
+ :TRANSFER_TYPE_BULK, 2,
92
+ # Interrupt endpoint
93
+ :TRANSFER_TYPE_INTERRUPT, 3,
94
+ # Stream endpoint
95
+ :TRANSFER_TYPE_BULK_STREAM, 4,
96
+ ]
97
+
98
+ StandardRequests = enum :libusb_standard_request, [
99
+ :REQUEST_GET_STATUS, 0x00,
100
+ :REQUEST_CLEAR_FEATURE, 0x01,
101
+ :REQUEST_SET_FEATURE, 0x03,
102
+ :REQUEST_SET_ADDRESS, 0x05,
103
+ :REQUEST_GET_DESCRIPTOR, 0x06,
104
+ :REQUEST_SET_DESCRIPTOR, 0x07,
105
+ :REQUEST_GET_CONFIGURATION, 0x08,
106
+ :REQUEST_SET_CONFIGURATION, 0x09,
107
+ :REQUEST_GET_INTERFACE, 0x0A,
108
+ :REQUEST_SET_INTERFACE, 0x0B,
109
+ :REQUEST_SYNCH_FRAME, 0x0C,
110
+ ]
111
+
112
+ EndpointDirections = enum :libusb_endpoint_direction, [
113
+ :ENDPOINT_IN, 0x80,
114
+ :ENDPOINT_OUT, 0x00,
115
+ ]
116
+
117
+ DescriptorTypes = enum :libusb_descriptor_type, [
118
+ # Device descriptor. See {Device}
119
+ :DT_DEVICE, 0x01,
120
+ # Configuration descriptor. See {Configuration}
121
+ :DT_CONFIG, 0x02,
122
+ # String descriptor
123
+ :DT_STRING, 0x03,
124
+ # Interface descriptor. See {Interface}
125
+ :DT_INTERFACE, 0x04,
126
+ # Endpoint descriptor. See {Endpoint}
127
+ :DT_ENDPOINT, 0x05,
128
+ # BOS descriptor
129
+ :DT_BOS, 0x0f,
130
+ # Device Capability descriptor
131
+ :DT_DEVICE_CAPABILITY, 0x10,
132
+ # HID descriptor
133
+ :DT_HID, 0x21,
134
+ # HID report descriptor
135
+ :DT_REPORT, 0x22,
136
+ # Physical descriptor
137
+ :DT_PHYSICAL, 0x23,
138
+ # Hub descriptor
139
+ :DT_HUB, 0x29,
140
+ # SuperSpeed Hub descriptor
141
+ :DT_SUPERSPEED_HUB, 0x2a,
142
+ # SuperSpeed Endpoint Companion descriptor
143
+ :DT_SS_ENDPOINT_COMPANION, 0x30,
144
+ ]
145
+
146
+ RequestTypes = enum :libusb_request_type, [
147
+ :REQUEST_TYPE_STANDARD, (0x00 << 5),
148
+ :REQUEST_TYPE_CLASS, (0x01 << 5),
149
+ :REQUEST_TYPE_VENDOR, (0x02 << 5),
150
+ :REQUEST_TYPE_RESERVED, (0x03 << 5),
151
+ ]
152
+
153
+ RequestRecipients = enum :libusb_request_recipient, [
154
+ :RECIPIENT_DEVICE, 0x00,
155
+ :RECIPIENT_INTERFACE, 0x01,
156
+ :RECIPIENT_ENDPOINT, 0x02,
157
+ :RECIPIENT_OTHER, 0x03,
158
+ ]
159
+
160
+ IsoSyncTypes = enum :libusb_iso_sync_type, [
161
+ :ISO_SYNC_TYPE_NONE, 0,
162
+ :ISO_SYNC_TYPE_ASYNC, 1,
163
+ :ISO_SYNC_TYPE_ADAPTIVE, 2,
164
+ :ISO_SYNC_TYPE_SYNC, 3,
165
+ ]
166
+
167
+ Speeds = enum :libusb_speed, [
168
+ :SPEED_UNKNOWN, 0,
169
+ :SPEED_LOW, 1,
170
+ :SPEED_FULL, 2,
171
+ :SPEED_HIGH, 3,
172
+ :SPEED_SUPER, 4,
173
+ ]
174
+
175
+ # Supported speeds (wSpeedSupported) bitfield. Indicates what
176
+ # speeds the device supports.
177
+ SupportedSpeeds = enum :libusb_supported_speed, [
178
+ # Low speed operation supported (1.5MBit/s).
179
+ :LOW_SPEED_OPERATION, 1,
180
+ # Full speed operation supported (12MBit/s).
181
+ :FULL_SPEED_OPERATION, 2,
182
+ # High speed operation supported (480MBit/s).
183
+ :HIGH_SPEED_OPERATION, 4,
184
+ # Superspeed operation supported (5000MBit/s).
185
+ :SUPER_SPEED_OPERATION, 8,
186
+ ]
187
+
188
+ Capabilities = enum :libusb_capability, [
189
+ :CAP_HAS_CAPABILITY, 0x0000,
190
+ # Hotplug support is available on this platform.
191
+ :CAP_HAS_HOTPLUG, 0x0001,
192
+ # The library can access HID devices without requiring user intervention.
193
+ # Note that before being able to actually access an HID device, you may
194
+ # still have to call additional libusb functions such as
195
+ # {DevHandle#detach_kernel_driver}.
196
+ :CAP_HAS_HID_ACCESS, 0x0100,
197
+ # The library supports detaching of the default USB driver, using
198
+ # {DevHandle#detach_kernel_driver}, if one is set by the OS kernel.
199
+ :CAP_SUPPORTS_DETACH_KERNEL_DRIVER, 0x0101,
200
+ ]
201
+
202
+ # Masks for the bits of the
203
+ # {Bos::Usb20Extension#bmAttributes} field
204
+ # of the USB 2.0 Extension descriptor.
205
+ Usb20ExtensionAttributes = enum :libusb_usb_2_0_extension_attributes, [
206
+ # Supports Link Power Management (LPM)
207
+ :BM_LPM_SUPPORT, 2,
208
+ ]
209
+
210
+ # Masks for the bits of the
211
+ # {Bos::SsUsbDeviceCapability#bmAttributes} field
212
+ # field of the SuperSpeed USB Device Capability descriptor.
213
+ SsUsbDeviceCapabilityAttributes = enum :libusb_ss_usb_device_capability_attributes, [
214
+ # Supports Latency Tolerance Messages (LTM)
215
+ :BM_LTM_SUPPORT, 2,
216
+ ]
217
+
218
+ # USB capability types
219
+ #
220
+ # @see Bos::DeviceCapability
221
+ BosTypes = enum :libusb_bos_type, [
222
+ # Wireless USB device capability
223
+ :BT_WIRELESS_USB_DEVICE_CAPABILITY, 1,
224
+ # USB 2.0 extensions
225
+ :BT_USB_2_0_EXTENSION, 2,
226
+ # SuperSpeed USB device capability
227
+ :BT_SS_USB_DEVICE_CAPABILITY, 3,
228
+ # Container ID type
229
+ :BT_CONTAINER_ID, 4,
230
+ ]
231
+
232
+ # Since libusb version 1.0.16.
233
+ #
234
+ # Hotplug events
235
+ HotplugEvents = enum :libusb_hotplug_event, [
236
+ # A device has been plugged in and is ready to use.
237
+ :HOTPLUG_EVENT_DEVICE_ARRIVED, 0x01,
238
+
239
+ # A device has left and is no longer available.
240
+ # It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
241
+ # It is safe to call libusb_get_device_descriptor on a device that has left.
242
+ :HOTPLUG_EVENT_DEVICE_LEFT, 0x02,
243
+ ]
244
+
245
+ # Since libusb version 1.0.16.
246
+ #
247
+ # Flags for hotplug events */
248
+ HotplugFlags = enum :libusb_hotplug_flag, [
249
+ # Arm the callback and fire it for all matching currently attached devices.
250
+ :HOTPLUG_ENUMERATE, 1,
251
+ ]
252
+
253
+ typedef :pointer, :libusb_context
254
+ typedef :pointer, :libusb_device
255
+ typedef :pointer, :libusb_device_handle
256
+ typedef :pointer, :libusb_transfer
257
+ typedef :int, :libusb_hotplug_callback_handle
258
+
259
+ def self.try_attach_function(method, *args)
260
+ if ffi_libraries.find{|lib| lib.find_function(method) }
261
+ attach_function method, *args
262
+ end
263
+ end
264
+
265
+ try_attach_function 'libusb_get_version', [], :pointer
266
+
267
+ attach_function 'libusb_init', [ :pointer ], :int
268
+ attach_function 'libusb_exit', [ :pointer ], :void
269
+ attach_function 'libusb_set_debug', [:pointer, :int], :void
270
+ try_attach_function 'libusb_has_capability', [:libusb_capability], :int
271
+
272
+ attach_function 'libusb_get_device_list', [:pointer, :pointer], :ssize_t
273
+ attach_function 'libusb_free_device_list', [:pointer, :int], :void
274
+ attach_function 'libusb_ref_device', [:pointer], :pointer
275
+ attach_function 'libusb_unref_device', [:pointer], :void
276
+
277
+ attach_function 'libusb_get_device_descriptor', [:pointer, :pointer], :int
278
+ attach_function 'libusb_get_active_config_descriptor', [:pointer, :pointer], :int
279
+ attach_function 'libusb_get_config_descriptor', [:pointer, :uint8, :pointer], :int
280
+ attach_function 'libusb_get_config_descriptor_by_value', [:pointer, :uint8, :pointer], :int
281
+ attach_function 'libusb_free_config_descriptor', [:pointer], :void
282
+ attach_function 'libusb_get_bus_number', [:pointer], :uint8
283
+ try_attach_function 'libusb_get_port_number', [:pointer], :uint8
284
+ try_attach_function 'libusb_get_parent', [:pointer], :pointer
285
+ try_attach_function 'libusb_get_port_path', [:pointer, :pointer, :pointer, :uint8], :uint8
286
+ try_attach_function 'libusb_get_port_numbers', [:pointer, :pointer, :uint8], :uint8
287
+ attach_function 'libusb_get_device_address', [:pointer], :uint8
288
+ try_attach_function 'libusb_get_device_speed', [:pointer], :libusb_speed
289
+ attach_function 'libusb_get_max_packet_size', [:pointer, :uint8], :int
290
+ attach_function 'libusb_get_max_iso_packet_size', [:pointer, :uint8], :int
291
+
292
+ try_attach_function 'libusb_get_ss_endpoint_companion_descriptor', [:pointer, :pointer, :pointer], :int
293
+ try_attach_function 'libusb_free_ss_endpoint_companion_descriptor', [:pointer], :void
294
+
295
+ try_attach_function 'libusb_get_bos_descriptor', [:libusb_device_handle, :pointer], :int, blocking: true
296
+ try_attach_function 'libusb_free_bos_descriptor', [:pointer], :void
297
+ try_attach_function 'libusb_get_usb_2_0_extension_descriptor', [:libusb_context, :pointer, :pointer], :int
298
+ try_attach_function 'libusb_free_usb_2_0_extension_descriptor', [:pointer], :void
299
+ try_attach_function 'libusb_get_ss_usb_device_capability_descriptor', [:libusb_context, :pointer, :pointer], :int
300
+ try_attach_function 'libusb_free_ss_usb_device_capability_descriptor', [:pointer], :void
301
+ try_attach_function 'libusb_get_container_id_descriptor', [:libusb_context, :pointer, :pointer], :int
302
+ try_attach_function 'libusb_free_container_id_descriptor', [:pointer], :void
303
+
304
+ attach_function 'libusb_open', [:pointer, :pointer], :int
305
+ attach_function 'libusb_close', [:pointer], :void
306
+ attach_function 'libusb_get_device', [:libusb_device_handle], :pointer
307
+
308
+ attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int, blocking: true
309
+ attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
310
+ attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int, blocking: true
311
+
312
+ attach_function 'libusb_open_device_with_vid_pid', [:pointer, :int, :int], :pointer
313
+
314
+ attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int, blocking: true
315
+ attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int, blocking: true
316
+ attach_function 'libusb_reset_device', [:libusb_device_handle], :int, blocking: true
317
+ try_attach_function 'libusb_alloc_streams', [:libusb_device_handle, :uint32, :pointer, :int], :int
318
+ try_attach_function 'libusb_free_streams', [:libusb_device_handle, :pointer, :int], :int
319
+ try_attach_function 'libusb_dev_mem_alloc', [:libusb_device_handle, :size_t], :pointer
320
+ try_attach_function 'libusb_dev_mem_free', [:libusb_device_handle, :pointer, :size_t], :int
321
+
322
+ attach_function 'libusb_kernel_driver_active', [:libusb_device_handle, :int], :int
323
+ attach_function 'libusb_detach_kernel_driver', [:libusb_device_handle, :int], :int
324
+ attach_function 'libusb_attach_kernel_driver', [:libusb_device_handle, :int], :int
325
+ try_attach_function 'libusb_set_auto_detach_kernel_driver', [:libusb_device_handle, :int], :int
326
+
327
+ attach_function 'libusb_get_string_descriptor_ascii', [:pointer, :uint8, :pointer, :int], :int
328
+
329
+ attach_function 'libusb_alloc_transfer', [:int], :pointer
330
+ attach_function 'libusb_submit_transfer', [:pointer], :int
331
+ attach_function 'libusb_cancel_transfer', [:pointer], :int
332
+ attach_function 'libusb_free_transfer', [:pointer], :void
333
+ try_attach_function 'libusb_transfer_set_stream_id', [:libusb_transfer, :uint32], :void
334
+ try_attach_function 'libusb_transfer_get_stream_id', [:libusb_transfer], :uint32
335
+
336
+ attach_function 'libusb_handle_events', [:libusb_context], :int, blocking: true
337
+ try_attach_function 'libusb_handle_events_completed', [:libusb_context, :pointer], :int, blocking: true
338
+ attach_function 'libusb_handle_events_timeout', [:libusb_context, :pointer], :int, blocking: true
339
+ try_attach_function 'libusb_handle_events_timeout_completed', [:libusb_context, :pointer, :pointer], :int, blocking: true
340
+ try_attach_function 'libusb_interrupt_event_handler', [:libusb_context], :void
341
+
342
+ callback :libusb_pollfd_added_cb, [:int, :short, :pointer], :void
343
+ callback :libusb_pollfd_removed_cb, [:int, :pointer], :void
344
+
345
+ attach_function 'libusb_get_pollfds', [:libusb_context], :pointer
346
+ attach_function 'libusb_get_next_timeout', [:libusb_context, :pointer], :int
347
+ attach_function 'libusb_set_pollfd_notifiers', [:libusb_context, :libusb_pollfd_added_cb, :libusb_pollfd_removed_cb, :pointer], :void
348
+ try_attach_function 'libusb_free_pollfds', [:pointer], :void
349
+
350
+ callback :libusb_transfer_cb_fn, [:pointer], :void
351
+
352
+ callback :libusb_hotplug_callback_fn, [:libusb_context, :libusb_device, :libusb_hotplug_event, :pointer], :int
353
+ try_attach_function 'libusb_hotplug_register_callback', [
354
+ :libusb_context, :libusb_hotplug_event, :libusb_hotplug_flag,
355
+ :int, :int, :int, :libusb_hotplug_callback_fn,
356
+ :pointer, :pointer], :int
357
+ try_attach_function 'libusb_hotplug_deregister_callback', [:libusb_context, :libusb_hotplug_callback_handle], :void
358
+
359
+ class IsoPacketDescriptor < FFI::Struct
360
+ layout :length, :uint,
361
+ :actual_length, :uint,
362
+ :status, :libusb_transfer_status
363
+ end
364
+
365
+ # Setup packet for control transfers.
366
+ class ControlSetup < FFI::Struct
367
+ layout :bmRequestType, :uint8,
368
+ :bRequest, :uint8,
369
+ :wValue, :uint16,
370
+ :wIndex, :uint16,
371
+ :wLength, :uint16
372
+ end
373
+
374
+ class Transfer < FFI::ManagedStruct
375
+ layout :dev_handle, :libusb_device_handle,
376
+ :flags, :uint8,
377
+ :endpoint, :uchar,
378
+ :type, :uchar,
379
+ :timeout, :uint,
380
+ :status, :libusb_transfer_status,
381
+ :length, :int,
382
+ :actual_length, :int,
383
+ :callback, :libusb_transfer_cb_fn,
384
+ :user_data, :pointer,
385
+ :buffer, :pointer,
386
+ :num_iso_packets, :int
387
+
388
+ def self.release(ptr)
389
+ Call.libusb_free_transfer(ptr)
390
+ end
391
+ end
392
+
393
+ class DeviceDescriptor < FFI::Struct
394
+ include Comparable
395
+
396
+ layout :bLength, :uint8,
397
+ :bDescriptorType, :uint8,
398
+ :bcdUSB, :uint16,
399
+ :bDeviceClass, :uint8,
400
+ :bDeviceSubClass, :uint8,
401
+ :bDeviceProtocol, :uint8,
402
+ :bMaxPacketSize0, :uint8,
403
+ :idVendor, :uint16,
404
+ :idProduct, :uint16,
405
+ :bcdDevice, :uint16,
406
+ :iManufacturer, :uint8,
407
+ :iProduct, :uint8,
408
+ :iSerialNumber, :uint8,
409
+ :bNumConfigurations, :uint8
410
+ end
411
+
412
+ class Timeval < FFI::Struct
413
+ layout :tv_sec, :long,
414
+ :tv_usec, :long
415
+
416
+ # set timeval to the number of milliseconds
417
+ # @param [Fixnum] value
418
+ def in_ms=(value)
419
+ self[:tv_sec], self[:tv_usec] = (value*1000).divmod(1000000)
420
+ end
421
+
422
+ # get the number of milliseconds in timeval
423
+ # @return [Fixnum]
424
+ def in_ms
425
+ self[:tv_sec]*1000 + self[:tv_usec]/1000
426
+ end
427
+
428
+ # set timeval to the number of seconds
429
+ # @param [Numeric] value
430
+ def in_s=(value)
431
+ self[:tv_sec], self[:tv_usec] = (value*1000000).divmod(1000000)
432
+ end
433
+
434
+ # get the number of seconds in timeval
435
+ # @return [Float]
436
+ def in_s
437
+ self[:tv_sec] + self[:tv_usec]/1000000.0
438
+ end
439
+ end
440
+
441
+ class Pollfd < FFI::Struct
442
+ layout :fd, :int,
443
+ :events, :short
444
+ end
445
+ end
446
+ end
@@ -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