usb-ruby 0.1.0

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.
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ module EventHandling
5
+ def handle_events(timeout: nil)
6
+ if timeout.nil?
7
+ Error.raise_on_error(FFIBindings.libusb_handle_events(@ptr))
8
+ else
9
+ timeval = build_timeval(timeout)
10
+ Error.raise_on_error(FFIBindings.libusb_handle_events_timeout(@ptr, timeval.pointer))
11
+ end
12
+ end
13
+
14
+ def handle_events_completed(completed: nil, timeout: nil)
15
+ completed_ptr = completed_pointer(completed)
16
+
17
+ if timeout.nil?
18
+ Error.raise_on_error(FFIBindings.libusb_handle_events_completed(@ptr, completed_ptr))
19
+ else
20
+ timeval = build_timeval(timeout)
21
+ Error.raise_on_error(FFIBindings.libusb_handle_events_timeout_completed(@ptr, timeval.pointer, completed_ptr))
22
+ end
23
+ end
24
+
25
+ def handle_events_locked(timeout: nil)
26
+ timeval = build_timeval(timeout)
27
+ Error.raise_on_error(FFIBindings.libusb_handle_events_locked(@ptr, timeval&.pointer || FFI::Pointer::NULL))
28
+ end
29
+
30
+ def try_lock_events
31
+ result = FFIBindings.libusb_try_lock_events(@ptr)
32
+ Error.raise_on_error(result) if result.negative?
33
+ result.zero?
34
+ end
35
+
36
+ def lock_events
37
+ FFIBindings.libusb_lock_events(@ptr)
38
+ self
39
+ end
40
+
41
+ def unlock_events
42
+ FFIBindings.libusb_unlock_events(@ptr)
43
+ self
44
+ end
45
+
46
+ def event_handling_ok?
47
+ FFIBindings.libusb_event_handling_ok(@ptr) != 0
48
+ end
49
+
50
+ def event_handler_active?
51
+ FFIBindings.libusb_event_handler_active(@ptr) != 0
52
+ end
53
+
54
+ def lock_event_waiters
55
+ FFIBindings.libusb_lock_event_waiters(@ptr)
56
+ self
57
+ end
58
+
59
+ def unlock_event_waiters
60
+ FFIBindings.libusb_unlock_event_waiters(@ptr)
61
+ self
62
+ end
63
+
64
+ def wait_for_event(timeout: nil)
65
+ timeval = build_timeval(timeout)
66
+ Error.raise_on_error(FFIBindings.libusb_wait_for_event(@ptr, timeval&.pointer || FFI::Pointer::NULL))
67
+ end
68
+
69
+ def interrupt_event_handler
70
+ FFIBindings.libusb_interrupt_event_handler(@ptr)
71
+ self
72
+ end
73
+
74
+ def pollfds
75
+ pollfd_ptr = FFIBindings.libusb_get_pollfds(@ptr)
76
+ return [] if pollfd_ptr.null?
77
+
78
+ pollfds = []
79
+ index = 0
80
+
81
+ loop do
82
+ entry_ptr = pollfd_ptr.get_pointer(index * FFI::Pointer.size)
83
+ break if entry_ptr.null?
84
+
85
+ pollfds << Pollfd.new(entry_ptr)
86
+ index += 1
87
+ end
88
+
89
+ pollfds
90
+ ensure
91
+ FFIBindings.libusb_free_pollfds(pollfd_ptr) if defined?(pollfd_ptr) && pollfd_ptr && !pollfd_ptr.null?
92
+ end
93
+
94
+ def next_timeout
95
+ timeval = FFIBindings::TimevalStruct.new(FFI::MemoryPointer.new(FFIBindings::TimevalStruct))
96
+ result = FFIBindings.libusb_get_next_timeout(@ptr, timeval.pointer)
97
+ Error.raise_on_error(result) if result.negative?
98
+ return nil if result.zero?
99
+
100
+ timeval[:tv_sec] + (timeval[:tv_usec] / 1_000_000.0)
101
+ end
102
+
103
+ def pollfds_handle_timeouts?
104
+ FFIBindings.libusb_pollfds_handle_timeouts(@ptr) != 0
105
+ end
106
+
107
+ def set_pollfd_notifiers(added:, removed:)
108
+ added_callback = FFI::Function.new(:void, [:int, :short, :pointer]) do |fd, events, _user_data|
109
+ added&.call(Pollfd.from_values(fd, events))
110
+ end
111
+
112
+ removed_callback = FFI::Function.new(:void, [:int, :pointer]) do |fd, _user_data|
113
+ removed&.call(fd)
114
+ end
115
+
116
+ @pollfd_notifiers[:added] = added_callback
117
+ @pollfd_notifiers[:removed] = removed_callback
118
+ FFIBindings.libusb_set_pollfd_notifiers(@ptr, added_callback, removed_callback, nil)
119
+ self
120
+ end
121
+
122
+ private
123
+
124
+ def build_timeval(timeout)
125
+ return nil if timeout.nil?
126
+
127
+ seconds = timeout.to_f
128
+ timeval = FFIBindings::TimevalStruct.new(FFI::MemoryPointer.new(FFIBindings::TimevalStruct))
129
+ timeval[:tv_sec] = seconds.floor
130
+ timeval[:tv_usec] = ((seconds - seconds.floor) * 1_000_000).round
131
+ timeval
132
+ end
133
+
134
+ def completed_pointer(completed)
135
+ case completed
136
+ when nil
137
+ FFI::Pointer::NULL
138
+ when FFI::Pointer
139
+ completed
140
+ else
141
+ pointer = FFI::MemoryPointer.new(:int)
142
+ pointer.write_int(completed ? 1 : 0)
143
+ pointer
144
+ end
145
+ end
146
+ end
147
+
148
+ Context.include(EventHandling)
149
+ end
@@ -0,0 +1,319 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+
5
+ module USB
6
+ module FFIBindings
7
+ extend FFI::Library
8
+
9
+ ffi_lib_flags :now, :global
10
+
11
+ LIB_NAMES = case RbConfig::CONFIG["host_os"]
12
+ when /darwin/
13
+ ["libusb-1.0.dylib", "libusb-1.0"]
14
+ when /linux|bsd/
15
+ ["libusb-1.0.so.0", "libusb-1.0.so", "libusb-1.0"]
16
+ when /mingw|mswin/
17
+ ["libusb-1.0.dll", "libusb-1.0"]
18
+ else
19
+ ["libusb-1.0"]
20
+ end.freeze
21
+
22
+ @available_functions = {}
23
+
24
+ begin
25
+ ffi_lib(*LIB_NAMES)
26
+ @library_loaded = true
27
+ rescue LoadError => e
28
+ @library_loaded = false
29
+ @load_error = e
30
+ end
31
+
32
+ class << self
33
+ attr_reader :load_error
34
+
35
+ def library_loaded?
36
+ @library_loaded
37
+ end
38
+
39
+ def ensure_loaded!
40
+ return if library_loaded?
41
+
42
+ raise LoadError, (@load_error&.message || "Unable to load libusb")
43
+ end
44
+
45
+ def function_available?(name)
46
+ @available_functions.fetch(name.to_sym, false)
47
+ end
48
+
49
+ def attach_function_safe(name, args, returns, optional: false)
50
+ if library_loaded?
51
+ attach_function(name, args, returns)
52
+ @available_functions[name.to_sym] = true
53
+ else
54
+ define_unavailable_function(name, optional: optional)
55
+ end
56
+ rescue FFI::NotFoundError => e
57
+ define_unavailable_function(name, error: e, optional: optional)
58
+ end
59
+
60
+ def define_unavailable_function(name, error: nil, optional: false)
61
+ @available_functions[name.to_sym] = false
62
+
63
+ define_singleton_method(name) do |_ = nil, *|
64
+ if optional
65
+ raise NotImplementedError, (error&.message || "#{name} is not available in this libusb build")
66
+ end
67
+
68
+ ensure_loaded!
69
+ raise LoadError, (error&.message || "#{name} is not available")
70
+ end
71
+ end
72
+ end
73
+
74
+ callback :hotplug_callback, [:pointer, :pointer, :int, :pointer], :int
75
+
76
+ class TimevalStruct < FFI::Struct
77
+ layout :tv_sec, :long,
78
+ :tv_usec, :long
79
+ end
80
+
81
+ class DeviceDescriptorStruct < FFI::Struct
82
+ layout :bLength, :uint8,
83
+ :bDescriptorType, :uint8,
84
+ :bcdUSB, :uint16,
85
+ :bDeviceClass, :uint8,
86
+ :bDeviceSubClass, :uint8,
87
+ :bDeviceProtocol, :uint8,
88
+ :bMaxPacketSize0, :uint8,
89
+ :idVendor, :uint16,
90
+ :idProduct, :uint16,
91
+ :bcdDevice, :uint16,
92
+ :iManufacturer, :uint8,
93
+ :iProduct, :uint8,
94
+ :iSerialNumber, :uint8,
95
+ :bNumConfigurations, :uint8
96
+ end
97
+
98
+ class EndpointDescriptorStruct < FFI::Struct
99
+ layout :bLength, :uint8,
100
+ :bDescriptorType, :uint8,
101
+ :bEndpointAddress, :uint8,
102
+ :bmAttributes, :uint8,
103
+ :wMaxPacketSize, :uint16,
104
+ :bInterval, :uint8,
105
+ :bRefresh, :uint8,
106
+ :bSynchAddress, :uint8,
107
+ :extra, :pointer,
108
+ :extra_length, :int
109
+ end
110
+
111
+ class InterfaceDescriptorStruct < FFI::Struct
112
+ layout :bLength, :uint8,
113
+ :bDescriptorType, :uint8,
114
+ :bInterfaceNumber, :uint8,
115
+ :bAlternateSetting, :uint8,
116
+ :bNumEndpoints, :uint8,
117
+ :bInterfaceClass, :uint8,
118
+ :bInterfaceSubClass, :uint8,
119
+ :bInterfaceProtocol, :uint8,
120
+ :iInterface, :uint8,
121
+ :endpoint, :pointer,
122
+ :extra, :pointer,
123
+ :extra_length, :int
124
+ end
125
+
126
+ class InterfaceStruct < FFI::Struct
127
+ layout :altsetting, :pointer,
128
+ :num_altsetting, :int
129
+ end
130
+
131
+ class ConfigDescriptorStruct < FFI::Struct
132
+ layout :bLength, :uint8,
133
+ :bDescriptorType, :uint8,
134
+ :wTotalLength, :uint16,
135
+ :bNumInterfaces, :uint8,
136
+ :bConfigurationValue, :uint8,
137
+ :iConfiguration, :uint8,
138
+ :bmAttributes, :uint8,
139
+ :MaxPower, :uint8,
140
+ :interface, :pointer,
141
+ :extra, :pointer,
142
+ :extra_length, :int
143
+ end
144
+
145
+ class SSEndpointCompanionStruct < FFI::Struct
146
+ layout :bLength, :uint8,
147
+ :bDescriptorType, :uint8,
148
+ :bMaxBurst, :uint8,
149
+ :bmAttributes, :uint8,
150
+ :wBytesPerInterval, :uint16
151
+ end
152
+
153
+ class BOSDescriptorStruct < FFI::Struct
154
+ layout :bLength, :uint8,
155
+ :bDescriptorType, :uint8,
156
+ :wTotalLength, :uint16,
157
+ :bNumDeviceCaps, :uint8,
158
+ :dev_capability, :pointer
159
+ end
160
+
161
+ class BOSDevCapabilityStruct < FFI::Struct
162
+ layout :bLength, :uint8,
163
+ :bDescriptorType, :uint8,
164
+ :bDevCapabilityType, :uint8
165
+ end
166
+
167
+ class USB20ExtensionStruct < FFI::Struct
168
+ layout :bLength, :uint8,
169
+ :bDescriptorType, :uint8,
170
+ :bDevCapabilityType, :uint8,
171
+ :bmAttributes, :uint32
172
+ end
173
+
174
+ class SSDeviceCapabilityStruct < FFI::Struct
175
+ layout :bLength, :uint8,
176
+ :bDescriptorType, :uint8,
177
+ :bDevCapabilityType, :uint8,
178
+ :bmAttributes, :uint8,
179
+ :wSpeedSupported, :uint16,
180
+ :bFunctionalitySupport, :uint8,
181
+ :bU1DevExitLat, :uint8,
182
+ :bU2DevExitLat, :uint16
183
+ end
184
+
185
+ class ContainerIDStruct < FFI::Struct
186
+ layout :bLength, :uint8,
187
+ :bDescriptorType, :uint8,
188
+ :bDevCapabilityType, :uint8,
189
+ :bReserved, :uint8,
190
+ :ContainerID, [:uint8, 16]
191
+ end
192
+
193
+ class TransferStruct < FFI::Struct
194
+ layout :dev_handle, :pointer,
195
+ :flags, :uint8,
196
+ :endpoint, :uint8,
197
+ :type, :uint8,
198
+ :timeout, :uint,
199
+ :status, :int,
200
+ :length, :int,
201
+ :actual_length, :int,
202
+ :callback, :pointer,
203
+ :user_data, :pointer,
204
+ :buffer, :pointer,
205
+ :num_iso_packets, :int
206
+ end
207
+
208
+ class IsoPacketDescriptorStruct < FFI::Struct
209
+ layout :length, :uint,
210
+ :actual_length, :uint,
211
+ :status, :int
212
+ end
213
+
214
+ class PollfdStruct < FFI::Struct
215
+ layout :fd, :int,
216
+ :events, :short
217
+ end
218
+
219
+ class VersionStruct < FFI::Struct
220
+ layout :major, :uint16,
221
+ :minor, :uint16,
222
+ :micro, :uint16,
223
+ :nano, :uint16,
224
+ :rc, :string,
225
+ :describe, :string
226
+ end
227
+
228
+ attach_function_safe :libusb_init, [:pointer], :int
229
+ attach_function_safe :libusb_init_context, [:pointer, :pointer, :int], :int, optional: true
230
+ attach_function_safe :libusb_exit, [:pointer], :void
231
+ attach_function_safe :libusb_set_debug, [:pointer, :int], :void
232
+ attach_function_safe :libusb_set_option, [:pointer, :int, :varargs], :int, optional: true
233
+ attach_function_safe :libusb_set_log_cb, [:pointer, :pointer, :int], :void, optional: true
234
+ attach_function_safe :libusb_get_version, [], :pointer
235
+ attach_function_safe :libusb_get_device_list, [:pointer, :pointer], :ssize_t
236
+ attach_function_safe :libusb_free_device_list, [:pointer, :int], :void
237
+ attach_function_safe :libusb_ref_device, [:pointer], :pointer
238
+ attach_function_safe :libusb_unref_device, [:pointer], :void
239
+ attach_function_safe :libusb_open, [:pointer, :pointer], :int
240
+ attach_function_safe :libusb_close, [:pointer], :void
241
+ attach_function_safe :libusb_open_device_with_vid_pid, [:pointer, :uint16, :uint16], :pointer
242
+ attach_function_safe :libusb_get_device, [:pointer], :pointer
243
+ attach_function_safe :libusb_get_bus_number, [:pointer], :uint8
244
+ attach_function_safe :libusb_get_port_number, [:pointer], :uint8
245
+ attach_function_safe :libusb_get_port_numbers, [:pointer, :pointer, :int], :int
246
+ attach_function_safe :libusb_get_parent, [:pointer], :pointer
247
+ attach_function_safe :libusb_get_device_address, [:pointer], :uint8
248
+ attach_function_safe :libusb_get_device_speed, [:pointer], :int
249
+ attach_function_safe :libusb_get_max_packet_size, [:pointer, :uint8], :int
250
+ attach_function_safe :libusb_get_max_iso_packet_size, [:pointer, :uint8], :int
251
+ attach_function_safe :libusb_get_max_alt_packet_size, [:pointer, :int, :int, :uint8], :int, optional: true
252
+ attach_function_safe :libusb_wrap_sys_device, [:pointer, :long, :pointer], :int, optional: true
253
+ attach_function_safe :libusb_get_configuration, [:pointer, :pointer], :int
254
+ attach_function_safe :libusb_set_configuration, [:pointer, :int], :int
255
+ attach_function_safe :libusb_claim_interface, [:pointer, :int], :int
256
+ attach_function_safe :libusb_release_interface, [:pointer, :int], :int
257
+ attach_function_safe :libusb_set_interface_alt_setting, [:pointer, :int, :int], :int
258
+ attach_function_safe :libusb_clear_halt, [:pointer, :uint8], :int
259
+ attach_function_safe :libusb_reset_device, [:pointer], :int
260
+ attach_function_safe :libusb_kernel_driver_active, [:pointer, :int], :int
261
+ attach_function_safe :libusb_detach_kernel_driver, [:pointer, :int], :int
262
+ attach_function_safe :libusb_attach_kernel_driver, [:pointer, :int], :int
263
+ attach_function_safe :libusb_set_auto_detach_kernel_driver, [:pointer, :int], :int
264
+ attach_function_safe :libusb_has_capability, [:uint32], :int
265
+ attach_function_safe :libusb_get_device_descriptor, [:pointer, :pointer], :int
266
+ attach_function_safe :libusb_get_active_config_descriptor, [:pointer, :pointer], :int
267
+ attach_function_safe :libusb_get_config_descriptor, [:pointer, :uint8, :pointer], :int
268
+ attach_function_safe :libusb_get_config_descriptor_by_value, [:pointer, :uint8, :pointer], :int
269
+ attach_function_safe :libusb_free_config_descriptor, [:pointer], :void
270
+ attach_function_safe :libusb_get_ss_endpoint_companion_descriptor, [:pointer, :pointer, :pointer], :int, optional: true
271
+ attach_function_safe :libusb_free_ss_endpoint_companion_descriptor, [:pointer], :void, optional: true
272
+ attach_function_safe :libusb_get_bos_descriptor, [:pointer, :pointer], :int, optional: true
273
+ attach_function_safe :libusb_free_bos_descriptor, [:pointer], :void, optional: true
274
+ attach_function_safe :libusb_get_usb_2_0_extension_descriptor, [:pointer, :pointer, :pointer], :int, optional: true
275
+ attach_function_safe :libusb_free_usb_2_0_extension_descriptor, [:pointer], :void, optional: true
276
+ attach_function_safe :libusb_get_ss_usb_device_capability_descriptor, [:pointer, :pointer, :pointer], :int, optional: true
277
+ attach_function_safe :libusb_free_ss_usb_device_capability_descriptor, [:pointer], :void, optional: true
278
+ attach_function_safe :libusb_get_container_id_descriptor, [:pointer, :pointer, :pointer], :int, optional: true
279
+ attach_function_safe :libusb_free_container_id_descriptor, [:pointer], :void, optional: true
280
+ attach_function_safe :libusb_get_string_descriptor_ascii, [:pointer, :uint8, :pointer, :int], :int
281
+ attach_function_safe :libusb_get_descriptor, [:pointer, :uint8, :uint8, :pointer, :int], :int
282
+ attach_function_safe :libusb_get_string_descriptor, [:pointer, :uint8, :uint16, :pointer, :int], :int
283
+ attach_function_safe :libusb_control_transfer, [:pointer, :uint8, :uint8, :uint16, :uint16, :pointer, :uint16, :uint], :int
284
+ attach_function_safe :libusb_bulk_transfer, [:pointer, :uint8, :pointer, :int, :pointer, :uint], :int
285
+ attach_function_safe :libusb_interrupt_transfer, [:pointer, :uint8, :pointer, :int, :pointer, :uint], :int
286
+ attach_function_safe :libusb_alloc_transfer, [:int], :pointer, optional: true
287
+ attach_function_safe :libusb_free_transfer, [:pointer], :void, optional: true
288
+ attach_function_safe :libusb_submit_transfer, [:pointer], :int, optional: true
289
+ attach_function_safe :libusb_cancel_transfer, [:pointer], :int, optional: true
290
+ attach_function_safe :libusb_alloc_streams, [:pointer, :uint32, :pointer, :int], :int, optional: true
291
+ attach_function_safe :libusb_free_streams, [:pointer, :pointer, :int], :int, optional: true
292
+ attach_function_safe :libusb_try_lock_events, [:pointer], :int, optional: true
293
+ attach_function_safe :libusb_lock_events, [:pointer], :void, optional: true
294
+ attach_function_safe :libusb_unlock_events, [:pointer], :void, optional: true
295
+ attach_function_safe :libusb_event_handling_ok, [:pointer], :int, optional: true
296
+ attach_function_safe :libusb_event_handler_active, [:pointer], :int, optional: true
297
+ attach_function_safe :libusb_interrupt_event_handler, [:pointer], :void, optional: true
298
+ attach_function_safe :libusb_lock_event_waiters, [:pointer], :void, optional: true
299
+ attach_function_safe :libusb_unlock_event_waiters, [:pointer], :void, optional: true
300
+ attach_function_safe :libusb_wait_for_event, [:pointer, :pointer], :int, optional: true
301
+ attach_function_safe :libusb_handle_events, [:pointer], :int, optional: true
302
+ attach_function_safe :libusb_handle_events_timeout, [:pointer, :pointer], :int, optional: true
303
+ attach_function_safe :libusb_handle_events_timeout_completed, [:pointer, :pointer, :pointer], :int, optional: true
304
+ attach_function_safe :libusb_handle_events_completed, [:pointer, :pointer], :int, optional: true
305
+ attach_function_safe :libusb_handle_events_locked, [:pointer, :pointer], :int, optional: true
306
+ attach_function_safe :libusb_get_next_timeout, [:pointer, :pointer], :int, optional: true
307
+ attach_function_safe :libusb_get_pollfds, [:pointer], :pointer, optional: true
308
+ attach_function_safe :libusb_free_pollfds, [:pointer], :void, optional: true
309
+ attach_function_safe :libusb_set_pollfd_notifiers, [:pointer, :pointer, :pointer, :pointer], :void, optional: true
310
+ attach_function_safe :libusb_pollfds_handle_timeouts, [:pointer], :int, optional: true
311
+ attach_function_safe :libusb_hotplug_register_callback, [:pointer, :int, :int, :int, :int, :int, :hotplug_callback, :pointer, :pointer], :int, optional: true
312
+ attach_function_safe :libusb_hotplug_deregister_callback, [:pointer, :int], :void, optional: true
313
+ attach_function_safe :libusb_error_name, [:int], :string
314
+ attach_function_safe :libusb_strerror, [:int], :string
315
+ attach_function_safe :libusb_setlocale, [:string], :int, optional: true
316
+ attach_function_safe :libusb_dev_mem_alloc, [:pointer, :size_t], :pointer, optional: true
317
+ attach_function_safe :libusb_dev_mem_free, [:pointer, :pointer, :size_t], :int, optional: true
318
+ end
319
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ module Hotplug
5
+ def on_hotplug_event(events:, vendor_id: HOTPLUG_MATCH_ANY, product_id: HOTPLUG_MATCH_ANY,
6
+ device_class: HOTPLUG_MATCH_ANY, flags: 0, &block)
7
+ raise ArgumentError, "block required" unless block
8
+
9
+ callback_handle = nil
10
+ callback = FFI::Function.new(:int, [:pointer, :pointer, :int, :pointer]) do |_ctx_ptr, device_ptr, event, _user_data|
11
+ device = Device.new(self, device_ptr)
12
+ result = block.call(device, event)
13
+ @hotplug_callbacks.delete(callback_handle) if result == true && callback_handle
14
+ result == true ? 1 : 0
15
+ end
16
+
17
+ handle_ptr = FFI::MemoryPointer.new(:int)
18
+ Error.raise_on_error(
19
+ FFIBindings.libusb_hotplug_register_callback(
20
+ @ptr,
21
+ events,
22
+ flags,
23
+ vendor_id,
24
+ product_id,
25
+ device_class,
26
+ callback,
27
+ nil,
28
+ handle_ptr
29
+ )
30
+ )
31
+
32
+ callback_handle = handle_ptr.read_int
33
+ @hotplug_callbacks[callback_handle] = callback
34
+ callback_handle
35
+ end
36
+
37
+ def deregister_hotplug(handle)
38
+ callback = @hotplug_callbacks.delete(handle)
39
+ return unless callback
40
+
41
+ FFIBindings.libusb_hotplug_deregister_callback(@ptr, handle)
42
+ nil
43
+ end
44
+ end
45
+
46
+ Context.include(Hotplug)
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ class Interface
5
+ include Enumerable
6
+
7
+ def initialize(config_descriptor, struct)
8
+ @config_descriptor = config_descriptor
9
+ @struct = struct
10
+ end
11
+
12
+ def alt_settings
13
+ count = @struct[:num_altsetting]
14
+ base_ptr = @struct[:altsetting]
15
+ return [] if base_ptr.null?
16
+
17
+ Array.new(count) do |index|
18
+ offset = index * FFIBindings::InterfaceDescriptorStruct.size
19
+ InterfaceDescriptor.new(self, FFIBindings::InterfaceDescriptorStruct.new(base_ptr + offset))
20
+ end
21
+ end
22
+
23
+ def each(&block)
24
+ alt_settings.each(&block)
25
+ end
26
+
27
+ def inspect
28
+ "#<USB::Interface alt_settings=#{@struct[:num_altsetting]}>"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ class InterfaceDescriptor
5
+ include Enumerable
6
+
7
+ def initialize(interface, struct)
8
+ @interface = interface
9
+ @struct = struct
10
+ end
11
+
12
+ def interface_number
13
+ @struct[:bInterfaceNumber]
14
+ end
15
+
16
+ def alternate_setting
17
+ @struct[:bAlternateSetting]
18
+ end
19
+
20
+ def num_endpoints
21
+ @struct[:bNumEndpoints]
22
+ end
23
+
24
+ def interface_class
25
+ @struct[:bInterfaceClass]
26
+ end
27
+
28
+ def interface_sub_class
29
+ @struct[:bInterfaceSubClass]
30
+ end
31
+
32
+ def interface_protocol
33
+ @struct[:bInterfaceProtocol]
34
+ end
35
+
36
+ def description_index
37
+ @struct[:iInterface]
38
+ end
39
+
40
+ def endpoints
41
+ count = num_endpoints
42
+ base_ptr = @struct[:endpoint]
43
+ return [] if base_ptr.null?
44
+
45
+ Array.new(count) do |index|
46
+ offset = index * FFIBindings::EndpointDescriptorStruct.size
47
+ EndpointDescriptor.new(self, FFIBindings::EndpointDescriptorStruct.new(base_ptr + offset))
48
+ end
49
+ end
50
+
51
+ def each(&block)
52
+ endpoints.each(&block)
53
+ end
54
+
55
+ def extra
56
+ return "".b if @struct[:extra].null? || @struct[:extra_length].zero?
57
+
58
+ @struct[:extra].read_bytes(@struct[:extra_length])
59
+ end
60
+
61
+ def inspect
62
+ "#<USB::InterfaceDescriptor number=#{interface_number} alt=#{alternate_setting} endpoints=#{num_endpoints}>"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ class IsoPacket
5
+ def initialize(transfer, struct)
6
+ @transfer = transfer
7
+ @struct = struct
8
+ end
9
+
10
+ def length
11
+ @struct[:length]
12
+ end
13
+
14
+ def length=(value)
15
+ @struct[:length] = value
16
+ end
17
+
18
+ def actual_length
19
+ @struct[:actual_length]
20
+ end
21
+
22
+ def status
23
+ @struct[:status]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USB
4
+ class Pollfd
5
+ def self.from_values(fd, events)
6
+ new(FFIBindings::PollfdStruct.new(build_pointer(fd, events)))
7
+ end
8
+
9
+ def self.build_pointer(fd, events)
10
+ pointer = FFI::MemoryPointer.new(FFIBindings::PollfdStruct)
11
+ struct = FFIBindings::PollfdStruct.new(pointer)
12
+ struct[:fd] = fd
13
+ struct[:events] = events
14
+ pointer
15
+ end
16
+
17
+ def initialize(source)
18
+ @struct = source.is_a?(FFIBindings::PollfdStruct) ? source : FFIBindings::PollfdStruct.new(source)
19
+ end
20
+
21
+ def fd
22
+ @struct[:fd]
23
+ end
24
+
25
+ def events
26
+ @struct[:events]
27
+ end
28
+
29
+ def inspect
30
+ "#<USB::Pollfd fd=#{fd} events=0x#{events.to_s(16)}>"
31
+ end
32
+ end
33
+ end