libusb 0.3.3-x64-mingw32
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/.yardopts +6 -0
- data/COPYING +165 -0
- data/Gemfile +16 -0
- data/History.md +77 -0
- data/README.md +144 -0
- data/Rakefile +185 -0
- data/lib/libusb.rb +51 -0
- data/lib/libusb/call.rb +316 -0
- data/lib/libusb/compat.rb +376 -0
- data/lib/libusb/configuration.rb +155 -0
- data/lib/libusb/constants.rb +151 -0
- data/lib/libusb/context.rb +305 -0
- data/lib/libusb/dev_handle.rb +450 -0
- data/lib/libusb/device.rb +359 -0
- data/lib/libusb/endpoint.rb +174 -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/transfer.rb +282 -0
- data/lib/libusb/version_gem.rb +19 -0
- data/lib/libusb/version_struct.rb +63 -0
- data/libusb.gemspec +31 -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 +181 -0
- data/test/test_libusb_event_machine.rb +118 -0
- data/test/test_libusb_gc.rb +37 -0
- data/test/test_libusb_iso_transfer.rb +50 -0
- data/test/test_libusb_mass_storage.rb +278 -0
- data/test/test_libusb_mass_storage2.rb +73 -0
- data/test/test_libusb_structs.rb +45 -0
- data/test/test_libusb_threads.rb +89 -0
- data/test/test_libusb_version.rb +40 -0
- metadata +126 -0
data/lib/libusb.rb
ADDED
@@ -0,0 +1,51 @@
|
|
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
|
+
module LIBUSB
|
17
|
+
require 'libusb/call'
|
18
|
+
require 'libusb/constants'
|
19
|
+
require 'libusb/context'
|
20
|
+
autoload :VERSION, 'libusb/version_gem'
|
21
|
+
autoload :Version, 'libusb/version_struct'
|
22
|
+
autoload :Configuration, 'libusb/configuration'
|
23
|
+
autoload :DevHandle, 'libusb/dev_handle'
|
24
|
+
autoload :Device, 'libusb/device'
|
25
|
+
autoload :Endpoint, 'libusb/endpoint'
|
26
|
+
autoload :Interface, 'libusb/interface'
|
27
|
+
autoload :Setting, 'libusb/setting'
|
28
|
+
%w[ Transfer BulkTransfer ControlTransfer InterruptTransfer IsoPacket IsochronousTransfer ].each do |klass|
|
29
|
+
autoload klass, 'libusb/transfer'
|
30
|
+
end
|
31
|
+
|
32
|
+
if Call.respond_to?(:libusb_get_version)
|
33
|
+
# Get version of the underlying libusb library.
|
34
|
+
# Available since libusb-1.0.10.
|
35
|
+
# @return [Version] version object
|
36
|
+
def self.version
|
37
|
+
Version.new(Call.libusb_get_version)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
if Call.respond_to?(:libusb_has_capability)
|
42
|
+
# Check at runtime if the loaded library has a given capability.
|
43
|
+
# Available since libusb-1.0.9.
|
44
|
+
# @param [Symbol] capability the {Call::Capabilities Capabilities} symbol to check for
|
45
|
+
# @return [Boolean] +true+ if the running library has the capability, +false+ otherwise
|
46
|
+
def self.has_capability?(capability)
|
47
|
+
r = Call.libusb_has_capability(capability)
|
48
|
+
return r != 0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/libusb/call.rb
ADDED
@@ -0,0 +1,316 @@
|
|
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(["#{prefix}usb-1.0", bundled_dll, bundled_dll_cygwin])
|
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
|
+
TransferTypes = enum :libusb_transfer_type, [
|
85
|
+
:TRANSFER_TYPE_CONTROL, 0,
|
86
|
+
:TRANSFER_TYPE_ISOCHRONOUS, 1,
|
87
|
+
:TRANSFER_TYPE_BULK, 2,
|
88
|
+
:TRANSFER_TYPE_INTERRUPT, 3,
|
89
|
+
]
|
90
|
+
|
91
|
+
StandardRequests = enum :libusb_standard_request, [
|
92
|
+
:REQUEST_GET_STATUS, 0x00,
|
93
|
+
:REQUEST_CLEAR_FEATURE, 0x01,
|
94
|
+
:REQUEST_SET_FEATURE, 0x03,
|
95
|
+
:REQUEST_SET_ADDRESS, 0x05,
|
96
|
+
:REQUEST_GET_DESCRIPTOR, 0x06,
|
97
|
+
:REQUEST_SET_DESCRIPTOR, 0x07,
|
98
|
+
:REQUEST_GET_CONFIGURATION, 0x08,
|
99
|
+
:REQUEST_SET_CONFIGURATION, 0x09,
|
100
|
+
:REQUEST_GET_INTERFACE, 0x0A,
|
101
|
+
:REQUEST_SET_INTERFACE, 0x0B,
|
102
|
+
:REQUEST_SYNCH_FRAME, 0x0C,
|
103
|
+
]
|
104
|
+
|
105
|
+
EndpointDirections = enum :libusb_endpoint_direction, [
|
106
|
+
:ENDPOINT_IN, 0x80,
|
107
|
+
:ENDPOINT_OUT, 0x00,
|
108
|
+
]
|
109
|
+
|
110
|
+
DescriptorTypes = enum :libusb_descriptor_type, [
|
111
|
+
:DT_DEVICE, 0x01,
|
112
|
+
:DT_CONFIG, 0x02,
|
113
|
+
:DT_STRING, 0x03,
|
114
|
+
:DT_INTERFACE, 0x04,
|
115
|
+
:DT_ENDPOINT, 0x05,
|
116
|
+
:DT_HID, 0x21,
|
117
|
+
:DT_REPORT, 0x22,
|
118
|
+
:DT_PHYSICAL, 0x23,
|
119
|
+
:DT_HUB, 0x29,
|
120
|
+
]
|
121
|
+
|
122
|
+
RequestTypes = enum :libusb_request_type, [
|
123
|
+
:REQUEST_TYPE_STANDARD, (0x00 << 5),
|
124
|
+
:REQUEST_TYPE_CLASS, (0x01 << 5),
|
125
|
+
:REQUEST_TYPE_VENDOR, (0x02 << 5),
|
126
|
+
:REQUEST_TYPE_RESERVED, (0x03 << 5),
|
127
|
+
]
|
128
|
+
|
129
|
+
RequestRecipients = enum :libusb_request_recipient, [
|
130
|
+
:RECIPIENT_DEVICE, 0x00,
|
131
|
+
:RECIPIENT_INTERFACE, 0x01,
|
132
|
+
:RECIPIENT_ENDPOINT, 0x02,
|
133
|
+
:RECIPIENT_OTHER, 0x03,
|
134
|
+
]
|
135
|
+
|
136
|
+
IsoSyncTypes = enum :libusb_iso_sync_type, [
|
137
|
+
:ISO_SYNC_TYPE_NONE, 0,
|
138
|
+
:ISO_SYNC_TYPE_ASYNC, 1,
|
139
|
+
:ISO_SYNC_TYPE_ADAPTIVE, 2,
|
140
|
+
:ISO_SYNC_TYPE_SYNC, 3,
|
141
|
+
]
|
142
|
+
|
143
|
+
Speeds = enum :libusb_speed, [
|
144
|
+
:SPEED_UNKNOWN, 0,
|
145
|
+
:SPEED_LOW, 1,
|
146
|
+
:SPEED_FULL, 2,
|
147
|
+
:SPEED_HIGH, 3,
|
148
|
+
:SPEED_SUPER, 4,
|
149
|
+
]
|
150
|
+
|
151
|
+
Capabilities = enum :libusb_capability, [
|
152
|
+
:CAP_HAS_CAPABILITY, 0,
|
153
|
+
]
|
154
|
+
|
155
|
+
typedef :pointer, :libusb_context
|
156
|
+
typedef :pointer, :libusb_device_handle
|
157
|
+
|
158
|
+
def self.try_attach_function(method, *args)
|
159
|
+
if ffi_libraries.find{|lib| lib.find_function(method) }
|
160
|
+
attach_function method, *args
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
try_attach_function 'libusb_get_version', [], :pointer
|
165
|
+
|
166
|
+
attach_function 'libusb_init', [ :pointer ], :int
|
167
|
+
attach_function 'libusb_exit', [ :pointer ], :void
|
168
|
+
attach_function 'libusb_set_debug', [:pointer, :int], :void
|
169
|
+
try_attach_function 'libusb_has_capability', [:libusb_capability], :int
|
170
|
+
|
171
|
+
attach_function 'libusb_get_device_list', [:pointer, :pointer], :ssize_t
|
172
|
+
attach_function 'libusb_free_device_list', [:pointer, :int], :void
|
173
|
+
attach_function 'libusb_ref_device', [:pointer], :pointer
|
174
|
+
attach_function 'libusb_unref_device', [:pointer], :void
|
175
|
+
|
176
|
+
attach_function 'libusb_get_device_descriptor', [:pointer, :pointer], :int
|
177
|
+
attach_function 'libusb_get_active_config_descriptor', [:pointer, :pointer], :int
|
178
|
+
attach_function 'libusb_get_config_descriptor', [:pointer, :uint8, :pointer], :int
|
179
|
+
attach_function 'libusb_get_config_descriptor_by_value', [:pointer, :uint8, :pointer], :int
|
180
|
+
attach_function 'libusb_free_config_descriptor', [:pointer], :void
|
181
|
+
attach_function 'libusb_get_bus_number', [:pointer], :uint8
|
182
|
+
try_attach_function 'libusb_get_port_number', [:pointer], :uint8
|
183
|
+
try_attach_function 'libusb_get_parent', [:pointer], :pointer
|
184
|
+
try_attach_function 'libusb_get_port_path', [:pointer, :pointer, :pointer, :uint8], :uint8
|
185
|
+
attach_function 'libusb_get_device_address', [:pointer], :uint8
|
186
|
+
try_attach_function 'libusb_get_device_speed', [:pointer], :libusb_speed
|
187
|
+
attach_function 'libusb_get_max_packet_size', [:pointer, :uint8], :int
|
188
|
+
attach_function 'libusb_get_max_iso_packet_size', [:pointer, :uint8], :int
|
189
|
+
|
190
|
+
attach_function 'libusb_open', [:pointer, :pointer], :int
|
191
|
+
attach_function 'libusb_close', [:pointer], :void
|
192
|
+
attach_function 'libusb_get_device', [:libusb_device_handle], :pointer
|
193
|
+
|
194
|
+
attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int, :blocking=>true
|
195
|
+
attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
|
196
|
+
attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int, :blocking=>true
|
197
|
+
|
198
|
+
attach_function 'libusb_open_device_with_vid_pid', [:pointer, :int, :int], :pointer
|
199
|
+
|
200
|
+
attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int, :blocking=>true
|
201
|
+
attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int, :blocking=>true
|
202
|
+
attach_function 'libusb_reset_device', [:libusb_device_handle], :int, :blocking=>true
|
203
|
+
|
204
|
+
attach_function 'libusb_kernel_driver_active', [:libusb_device_handle, :int], :int
|
205
|
+
attach_function 'libusb_detach_kernel_driver', [:libusb_device_handle, :int], :int
|
206
|
+
attach_function 'libusb_attach_kernel_driver', [:libusb_device_handle, :int], :int
|
207
|
+
|
208
|
+
attach_function 'libusb_get_string_descriptor_ascii', [:pointer, :uint8, :pointer, :int], :int
|
209
|
+
|
210
|
+
attach_function 'libusb_alloc_transfer', [:int], :pointer
|
211
|
+
attach_function 'libusb_submit_transfer', [:pointer], :int
|
212
|
+
attach_function 'libusb_cancel_transfer', [:pointer], :int
|
213
|
+
attach_function 'libusb_free_transfer', [:pointer], :void
|
214
|
+
|
215
|
+
attach_function 'libusb_handle_events', [:libusb_context], :int, :blocking=>true
|
216
|
+
try_attach_function 'libusb_handle_events_completed', [:libusb_context, :pointer], :int, :blocking=>true
|
217
|
+
attach_function 'libusb_handle_events_timeout', [:libusb_context, :pointer], :int, :blocking=>true
|
218
|
+
try_attach_function 'libusb_handle_events_timeout_completed', [:libusb_context, :pointer, :pointer], :int, :blocking=>true
|
219
|
+
|
220
|
+
callback :libusb_pollfd_added_cb, [:int, :short, :pointer], :void
|
221
|
+
callback :libusb_pollfd_removed_cb, [:int, :pointer], :void
|
222
|
+
|
223
|
+
attach_function 'libusb_get_pollfds', [:libusb_context], :pointer
|
224
|
+
attach_function 'libusb_get_next_timeout', [:libusb_context, :pointer], :int
|
225
|
+
attach_function 'libusb_set_pollfd_notifiers', [:libusb_context, :libusb_pollfd_added_cb, :libusb_pollfd_removed_cb, :pointer], :void
|
226
|
+
|
227
|
+
callback :libusb_transfer_cb_fn, [:pointer], :void
|
228
|
+
|
229
|
+
class IsoPacketDescriptor < FFI::Struct
|
230
|
+
layout :length, :uint,
|
231
|
+
:actual_length, :uint,
|
232
|
+
:status, :libusb_transfer_status
|
233
|
+
end
|
234
|
+
|
235
|
+
# Setup packet for control transfers.
|
236
|
+
class ControlSetup < FFI::Struct
|
237
|
+
layout :bmRequestType, :uint8,
|
238
|
+
:bRequest, :uint8,
|
239
|
+
:wValue, :uint16,
|
240
|
+
:wIndex, :uint16,
|
241
|
+
:wLength, :uint16
|
242
|
+
end
|
243
|
+
|
244
|
+
class Transfer < FFI::ManagedStruct
|
245
|
+
layout :dev_handle, :libusb_device_handle,
|
246
|
+
:flags, :uint8,
|
247
|
+
:endpoint, :uchar,
|
248
|
+
:type, :uchar,
|
249
|
+
:timeout, :uint,
|
250
|
+
:status, :libusb_transfer_status,
|
251
|
+
:length, :int,
|
252
|
+
:actual_length, :int,
|
253
|
+
:callback, :libusb_transfer_cb_fn,
|
254
|
+
:user_data, :pointer,
|
255
|
+
:buffer, :pointer,
|
256
|
+
:num_iso_packets, :int
|
257
|
+
|
258
|
+
def self.release(ptr)
|
259
|
+
Call.libusb_free_transfer(ptr)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
class DeviceDescriptor < FFI::Struct
|
264
|
+
include Comparable
|
265
|
+
|
266
|
+
layout :bLength, :uint8,
|
267
|
+
:bDescriptorType, :uint8,
|
268
|
+
:bcdUSB, :uint16,
|
269
|
+
:bDeviceClass, :uint8,
|
270
|
+
:bDeviceSubClass, :uint8,
|
271
|
+
:bDeviceProtocol, :uint8,
|
272
|
+
:bMaxPacketSize0, :uint8,
|
273
|
+
:idVendor, :uint16,
|
274
|
+
:idProduct, :uint16,
|
275
|
+
:bcdDevice, :uint16,
|
276
|
+
:iManufacturer, :uint8,
|
277
|
+
:iProduct, :uint8,
|
278
|
+
:iSerialNumber, :uint8,
|
279
|
+
:bNumConfigurations, :uint8
|
280
|
+
end
|
281
|
+
|
282
|
+
class Timeval < FFI::Struct
|
283
|
+
layout :tv_sec, :long,
|
284
|
+
:tv_usec, :long
|
285
|
+
|
286
|
+
# set timeval to the number of milliseconds
|
287
|
+
# @param [Fixnum] value
|
288
|
+
def in_ms=(value)
|
289
|
+
self[:tv_sec], self[:tv_usec] = (value*1000).divmod(1000000)
|
290
|
+
end
|
291
|
+
|
292
|
+
# get the number of milliseconds in timeval
|
293
|
+
# @return [Fixnum]
|
294
|
+
def in_ms
|
295
|
+
self[:tv_sec]*1000 + self[:tv_usec]/1000
|
296
|
+
end
|
297
|
+
|
298
|
+
# set timeval to the number of seconds
|
299
|
+
# @param [Numeric] value
|
300
|
+
def in_s=(value)
|
301
|
+
self[:tv_sec], self[:tv_usec] = (value*1000000).divmod(1000000)
|
302
|
+
end
|
303
|
+
|
304
|
+
# get the number of seconds in timeval
|
305
|
+
# @return [Float]
|
306
|
+
def in_s
|
307
|
+
self[:tv_sec] + self[:tv_usec]/1000000.0
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
class Pollfd < FFI::Struct
|
312
|
+
layout :fd, :int,
|
313
|
+
:events, :short
|
314
|
+
end
|
315
|
+
end
|
316
|
+
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
|