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.
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
@@ -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