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.
@@ -0,0 +1,155 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ class Configuration < FFI::ManagedStruct
20
+ include Comparable
21
+
22
+ layout :bLength, :uint8,
23
+ :bDescriptorType, :uint8,
24
+ :wTotalLength, :uint16,
25
+ :bNumInterfaces, :uint8,
26
+ :bConfigurationValue, :uint8,
27
+ :iConfiguration, :uint8,
28
+ :bmAttributes, :uint8,
29
+ :bMaxPower, :uint8,
30
+ :interface, :pointer,
31
+ :extra, :pointer,
32
+ :extra_length, :int
33
+
34
+ # Size of this descriptor (in bytes).
35
+ def bLength
36
+ self[:bLength]
37
+ end
38
+
39
+ # Descriptor type (0x02)
40
+ def bDescriptorType
41
+ self[:bDescriptorType]
42
+ end
43
+
44
+ # Total length of data returned for this configuration.
45
+ def wTotalLength
46
+ self[:wTotalLength]
47
+ end
48
+
49
+ # Number of interfaces supported by this configuration.
50
+ def bNumInterfaces
51
+ self[:bNumInterfaces]
52
+ end
53
+
54
+ # Identifier value for this configuration.
55
+ def bConfigurationValue
56
+ self[:bConfigurationValue]
57
+ end
58
+
59
+ # Index of string descriptor describing this configuration.
60
+ def iConfiguration
61
+ self[:iConfiguration]
62
+ end
63
+
64
+ # Configuration characteristics.
65
+ #
66
+ # * Bit 7: Reserved, set to 1. (USB 1.0 Bus Powered)
67
+ # * Bit 6: Self Powered
68
+ # * Bit 5: Remote Wakeup
69
+ # * Bit 4..0: Reserved, set to 0.
70
+ #
71
+ # @return [Integer]
72
+ #
73
+ # @see #self_powered?
74
+ # @see #remote_wakeup?
75
+ def bmAttributes
76
+ self[:bmAttributes]
77
+ end
78
+
79
+ # @return [Boolean]
80
+ def self_powered?
81
+ bmAttributes & 0b1000000 != 0
82
+ end
83
+
84
+ # @return [Boolean]
85
+ def remote_wakeup?
86
+ bmAttributes & 0b100000 != 0
87
+ end
88
+
89
+ # Maximum power consumption of the USB device from this bus in this configuration when the device is fully opreation.
90
+ #
91
+ # @return [Integer] Maximum Power Consumption in 2mA units
92
+ def bMaxPower
93
+ self[:bMaxPower]
94
+ end
95
+
96
+ # @deprecated Use {#bMaxPower} instead.
97
+ alias maxPower bMaxPower
98
+
99
+
100
+ # Extra descriptors.
101
+ #
102
+ # @return [String]
103
+ def extra
104
+ return if self[:extra].null?
105
+ self[:extra].read_string(self[:extra_length])
106
+ end
107
+
108
+ def initialize(device, *args)
109
+ @device = device
110
+ super(*args)
111
+ end
112
+
113
+ def self.release(ptr)
114
+ Call.libusb_free_config_descriptor(ptr)
115
+ end
116
+
117
+ # @return [Device] the device this configuration belongs to.
118
+ attr_reader :device
119
+
120
+ def interfaces
121
+ ifs = []
122
+ self[:bNumInterfaces].times do |i|
123
+ ifs << Interface.new(self, self[:interface] + i*Interface.size)
124
+ end
125
+ return ifs
126
+ end
127
+
128
+ def inspect
129
+ attrs = []
130
+ attrs << self.bConfigurationValue.to_s
131
+ attrs << "SelfPowered" if self_powered?
132
+ attrs << "RemoteWakeup" if remote_wakeup?
133
+ desc = self.description
134
+ attrs << desc if desc != '?'
135
+ "\#<#{self.class} #{attrs.join(' ')}>"
136
+ end
137
+
138
+ # Return name of this configuration as String.
139
+ def description
140
+ return @description if defined? @description
141
+ @description = device.try_string_descriptor_ascii(self.iConfiguration)
142
+ end
143
+
144
+ # Return all interface decriptions of the configuration as Array of {Setting}s.
145
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
146
+ # Return all endpoints of all interfaces of the configuration as Array of {Endpoint}s.
147
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
148
+
149
+ def <=>(o)
150
+ t = device<=>o.device
151
+ t = bConfigurationValue<=>o.bConfigurationValue if t==0
152
+ t
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,151 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ Call::ClassCodes.to_h.each{|k,v| const_set(k,v) }
20
+ Call::TransferTypes.to_h.each{|k,v| const_set(k,v) }
21
+ Call::StandardRequests.to_h.each{|k,v| const_set(k,v) }
22
+ Call::RequestTypes.to_h.each{|k,v| const_set(k,v) }
23
+ Call::DescriptorTypes.to_h.each{|k,v| const_set(k,v) }
24
+ Call::EndpointDirections.to_h.each{|k,v| const_set(k,v) }
25
+ Call::RequestRecipients.to_h.each{|k,v| const_set(k,v) }
26
+ Call::IsoSyncTypes.to_h.each{|k,v| const_set(k,v) }
27
+ Call::Speeds.to_h.each{|k,v| const_set(k,v) }
28
+ Call::Capabilities.to_h.each{|k,v| const_set(k,v) }
29
+
30
+ # Base class of libusb errors
31
+ class Error < RuntimeError
32
+ # The data already transferred before the exception was raised
33
+ # @return [Fixnum] Number of bytes sent for an outgoing transfer
34
+ # @return [String] Received data for an ingoing transfer
35
+ attr_reader :transferred
36
+
37
+ def initialize(msg=nil, transferred=nil)
38
+ super(msg)
39
+ @transferred = transferred
40
+ end
41
+ end
42
+
43
+ # @private
44
+ ErrorClassForResult = {}
45
+
46
+ # define an exception class for each error code
47
+ Call::Errors.to_h.each do |k,v|
48
+ klass = Class.new(Error)
49
+ klass.send(:define_method, :code){ v }
50
+ const_set(k, klass)
51
+ ErrorClassForResult[v] = klass
52
+ end
53
+
54
+ def self.raise_error(res, text)
55
+ klass = ErrorClassForResult[res]
56
+ raise klass, "#{klass} #{text}"
57
+ end
58
+
59
+ CONTROL_SETUP_SIZE = 8
60
+ DT_DEVICE_SIZE = 18
61
+ DT_CONFIG_SIZE = 9
62
+ DT_INTERFACE_SIZE = 9
63
+ DT_ENDPOINT_SIZE = 7
64
+ DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
65
+ DT_HUB_NONVAR_SIZE = 7
66
+
67
+ ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
68
+ ENDPOINT_DIR_MASK = 0x80
69
+ TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
70
+ ISO_SYNC_TYPE_MASK = 0x0C
71
+ ISO_USAGE_TYPE_MASK = 0x30
72
+
73
+ POLLIN = 1
74
+ POLLOUT = 4
75
+
76
+
77
+ # http://www.usb.org/developers/defined_class
78
+ # @private
79
+ CLASS_CODES = [
80
+ [0x01, nil, nil, "Audio"],
81
+ [0x02, nil, nil, "Comm"],
82
+ [0x03, nil, nil, "HID"],
83
+ [0x05, nil, nil, "Physical"],
84
+ [0x06, 0x01, 0x01, "StillImaging"],
85
+ [0x06, nil, nil, "Image"],
86
+ [0x07, nil, nil, "Printer"],
87
+ [0x08, 0x01, nil, "MassStorage RBC Bulk-Only"],
88
+ [0x08, 0x02, 0x50, "MassStorage ATAPI Bulk-Only"],
89
+ [0x08, 0x03, 0x50, "MassStorage QIC-157 Bulk-Only"],
90
+ [0x08, 0x04, nil, "MassStorage UFI"],
91
+ [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bulk-Only"],
92
+ [0x08, 0x06, 0x50, "MassStorage SCSI Bulk-Only"],
93
+ [0x08, nil, nil, "MassStorage"],
94
+ [0x09, 0x00, 0x00, "Full speed Hub"],
95
+ [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
96
+ [0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
97
+ [0x09, nil, nil, "Hub"],
98
+ [0x0a, nil, nil, "CDC"],
99
+ [0x0b, nil, nil, "SmartCard"],
100
+ [0x0d, 0x00, 0x00, "ContentSecurity"],
101
+ [0x0e, nil, nil, "Video"],
102
+ [0xdc, 0x01, 0x01, "Diagnostic USB2"],
103
+ [0xdc, nil, nil, "Diagnostic"],
104
+ [0xe0, 0x01, 0x01, "Bluetooth"],
105
+ [0xe0, 0x01, 0x02, "UWB"],
106
+ [0xe0, 0x01, 0x03, "RemoteNDIS"],
107
+ [0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
108
+ [0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
109
+ [0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
110
+ [0xe0, nil, nil, "Wireless Controller"],
111
+ [0xef, 0x01, 0x01, "Active Sync"],
112
+ [0xef, 0x01, 0x02, "Palm Sync"],
113
+ [0xef, 0x02, 0x01, "Interface Association Descriptor"],
114
+ [0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
115
+ [0xef, 0x03, 0x01, "Cable Based Association Framework"],
116
+ [0xef, nil, nil, "Miscellaneous"],
117
+ [0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
118
+ [0xfe, 0x02, 0x00, "IRDA Bridge"],
119
+ [0xfe, 0x03, 0x00, "USB Test and Measurement"],
120
+ [0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
121
+ [0xfe, nil, nil, "Application Specific"],
122
+ [0xff, nil, nil, "Vendor specific"],
123
+ ]
124
+ # @private
125
+ CLASS_CODES_HASH1 = {}
126
+ # @private
127
+ CLASS_CODES_HASH2 = {}
128
+ # @private
129
+ CLASS_CODES_HASH3 = {}
130
+ CLASS_CODES.each {|base_class, sub_class, protocol, desc|
131
+ if protocol
132
+ CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
133
+ elsif sub_class
134
+ CLASS_CODES_HASH2[[base_class, sub_class]] = desc
135
+ else
136
+ CLASS_CODES_HASH1[base_class] = desc
137
+ end
138
+ }
139
+
140
+ def self.dev_string(base_class, sub_class, protocol)
141
+ if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
142
+ desc
143
+ elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
144
+ desc + " (%02x)" % [protocol]
145
+ elsif desc = CLASS_CODES_HASH1[base_class]
146
+ desc + " (%02x,%02x)" % [sub_class, protocol]
147
+ else
148
+ "Unknown(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,305 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ # Class representing a libusb session.
20
+ class Context
21
+ class Pollfd
22
+ include Comparable
23
+
24
+ def initialize(fd, events=0)
25
+ @fd, @events = fd, events
26
+ end
27
+
28
+ def <=>(other)
29
+ @fd <=> other.fd
30
+ end
31
+
32
+ # @return [IO] IO object bound to the file descriptor.
33
+ def io
34
+ IO.new @fd
35
+ end
36
+
37
+ # @return [Integer] Numeric file descriptor
38
+ attr_reader :fd
39
+
40
+ # @return [Integer] Event flags to poll for
41
+ attr_reader :events
42
+
43
+ # @return [Boolean] True if the file descriptor has to be observed for incoming/readable data
44
+ def pollin?
45
+ @events & POLLIN != 0
46
+ end
47
+
48
+ # @return [Boolean] True if the file descriptor has to be observed for outgoing/writeable data
49
+ def pollout?
50
+ @events & POLLOUT != 0
51
+ end
52
+
53
+ def inspect
54
+ "\#<#{self.class} fd:#{@fd}#{' POLLIN' if pollin?}#{' POLLOUT' if pollout?}>"
55
+ end
56
+ end
57
+
58
+ class CompletionFlag < FFI::Struct
59
+ layout :completed, :int
60
+
61
+ def completed?
62
+ self[:completed] != 0
63
+ end
64
+
65
+ def completed=(flag)
66
+ self[:completed] = flag ? 1 : 0
67
+ end
68
+ end
69
+
70
+
71
+ # Initialize libusb context.
72
+ def initialize
73
+ m = FFI::MemoryPointer.new :pointer
74
+ res = Call.libusb_init(m)
75
+ LIBUSB.raise_error res, "in libusb_init" if res!=0
76
+ @ctx = m.read_pointer
77
+ @on_pollfd_added = nil
78
+ @on_pollfd_removed = nil
79
+ end
80
+
81
+ # Deinitialize libusb.
82
+ #
83
+ # Should be called after closing all open devices and before your application terminates.
84
+ def exit
85
+ Call.libusb_exit(@ctx)
86
+ end
87
+
88
+ # Set message verbosity.
89
+ #
90
+ # * Level 0: no messages ever printed by the library (default)
91
+ # * Level 1: error messages are printed to stderr
92
+ # * Level 2: warning and error messages are printed to stderr
93
+ # * Level 3: informational messages are printed to stdout, warning and
94
+ # error messages are printed to stderr
95
+ #
96
+ # The default level is 0, which means no messages are ever printed. If you
97
+ # choose to increase the message verbosity level, ensure that your
98
+ # application does not close the stdout/stderr file descriptors.
99
+ #
100
+ # You are advised to set level 3. libusb is conservative with its message
101
+ # logging and most of the time, will only log messages that explain error
102
+ # conditions and other oddities. This will help you debug your software.
103
+ #
104
+ # If the LIBUSB_DEBUG environment variable was set when libusb was
105
+ # initialized, this method does nothing: the message verbosity is
106
+ # fixed to the value in the environment variable.
107
+ #
108
+ # If libusb was compiled without any message logging, this method
109
+ # does nothing: you'll never get any messages.
110
+ #
111
+ # If libusb was compiled with verbose debug message logging, this
112
+ # method does nothing: you'll always get messages from all levels.
113
+ #
114
+ # @param [Fixnum] level debug level to set
115
+ def debug=(level)
116
+ Call.libusb_set_debug(@ctx, level)
117
+ end
118
+
119
+ def device_list
120
+ pppDevs = FFI::MemoryPointer.new :pointer
121
+ size = Call.libusb_get_device_list(@ctx, pppDevs)
122
+ LIBUSB.raise_error size, "in libusb_get_device_list" if size<0
123
+ ppDevs = pppDevs.read_pointer
124
+ pDevs = []
125
+ size.times do |devi|
126
+ pDev = ppDevs.get_pointer(devi*FFI.type_size(:pointer))
127
+ pDevs << Device.new(self, pDev)
128
+ end
129
+ Call.libusb_free_device_list(ppDevs, 1)
130
+ pDevs
131
+ end
132
+ private :device_list
133
+
134
+ # Handle any pending events in blocking mode.
135
+ #
136
+ # This method must be called when libusb is running asynchronous transfers.
137
+ # This gives libusb the opportunity to reap pending transfers,
138
+ # invoke callbacks, etc.
139
+ #
140
+ # If a zero timeout is passed, this function will handle any already-pending
141
+ # events and then immediately return in non-blocking style.
142
+ #
143
+ # If a non-zero timeout is passed and no events are currently pending, this
144
+ # method will block waiting for events to handle up until the specified timeout.
145
+ # If an event arrives or a signal is raised, this method will return early.
146
+ #
147
+ # If the parameter completion_flag is used, then after obtaining the event
148
+ # handling lock this function will return immediately if the flag is set to completed.
149
+ # This allows for race free waiting for the completion of a specific transfer.
150
+ # See source of {Transfer#submit_and_wait} for a use case of completion_flag.
151
+ #
152
+ # @param [Integer, nil] timeout the maximum time (in millseconds) to block waiting for
153
+ # events, or 0 for non-blocking mode
154
+ # @param [Context::CompletionFlag, nil] completion_flag CompletionFlag to check
155
+ def handle_events(timeout=nil, completion_flag=nil)
156
+ if completion_flag && !completion_flag.is_a?(Context::CompletionFlag)
157
+ raise ArgumentError, "completion_flag is not a CompletionFlag"
158
+ end
159
+ if timeout
160
+ timeval = Call::Timeval.new
161
+ timeval.in_ms = timeout
162
+ res = if Call.respond_to?(:libusb_handle_events_timeout_completed)
163
+ Call.libusb_handle_events_timeout_completed(@ctx, timeval, completion_flag)
164
+ else
165
+ Call.libusb_handle_events_timeout(@ctx, timeval)
166
+ end
167
+ else
168
+ res = if Call.respond_to?(:libusb_handle_events_completed)
169
+ Call.libusb_handle_events_completed(@ctx, completion_flag )
170
+ else
171
+ Call.libusb_handle_events(@ctx)
172
+ end
173
+ end
174
+ LIBUSB.raise_error res, "in libusb_handle_events" if res<0
175
+ end
176
+
177
+ # Obtain a list of devices currently attached to the USB system, optionally matching certain criteria.
178
+ #
179
+ # @param [Hash] filter_hash A number of criteria can be defined in key-value pairs.
180
+ # Only devices that equal all given criterions will be returned. If a criterion is
181
+ # not specified or its value is +nil+, any device will match that criterion.
182
+ # The following criteria can be filtered:
183
+ # * <tt>:idVendor</tt>, <tt>:idProduct</tt> (+FixNum+) for matching vendor/product ID,
184
+ # * <tt>:bClass</tt>, <tt>:bSubClass</tt>, <tt>:bProtocol</tt> (+FixNum+) for the device type -
185
+ # Devices using CLASS_PER_INTERFACE will match, if any of the interfaces match.
186
+ # * <tt>:bcdUSB</tt>, <tt>:bcdDevice</tt>, <tt>:bMaxPacketSize0</tt> (+FixNum+) for the
187
+ # USB and device release numbers.
188
+ # Criteria can also specified as Array of several alternative values.
189
+ #
190
+ # @example
191
+ # # Return all devices of vendor 0x0ab1 where idProduct is 3 or 4:
192
+ # context.device :idVendor=>0x0ab1, :idProduct=>[0x0003, 0x0004]
193
+ #
194
+ # @return [Array<LIBUSB::Device>]
195
+ def devices(filter_hash={})
196
+ device_list.select do |dev|
197
+ ( !filter_hash[:bClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
198
+ dev.settings.map(&:bInterfaceClass).&([filter_hash[:bClass]].flatten).any? :
199
+ [filter_hash[:bClass]].flatten.include?(dev.bDeviceClass))) &&
200
+ ( !filter_hash[:bSubClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
201
+ dev.settings.map(&:bInterfaceSubClass).&([filter_hash[:bSubClass]].flatten).any? :
202
+ [filter_hash[:bSubClass]].flatten.include?(dev.bDeviceSubClass))) &&
203
+ ( !filter_hash[:bProtocol] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
204
+ dev.settings.map(&:bInterfaceProtocol).&([filter_hash[:bProtocol]].flatten).any? :
205
+ [filter_hash[:bProtocol]].flatten.include?(dev.bDeviceProtocol))) &&
206
+ ( !filter_hash[:bMaxPacketSize0] || [filter_hash[:bMaxPacketSize0]].flatten.include?(dev.bMaxPacketSize0) ) &&
207
+ ( !filter_hash[:idVendor] || [filter_hash[:idVendor]].flatten.include?(dev.idVendor) ) &&
208
+ ( !filter_hash[:idProduct] || [filter_hash[:idProduct]].flatten.include?(dev.idProduct) ) &&
209
+ ( !filter_hash[:bcdUSB] || [filter_hash[:bcdUSB]].flatten.include?(dev.bcdUSB) ) &&
210
+ ( !filter_hash[:bcdDevice] || [filter_hash[:bcdDevice]].flatten.include?(dev.bcdDevice) )
211
+ end
212
+ end
213
+
214
+
215
+ # Retrieve a list of file descriptors that should be polled by your main
216
+ # loop as libusb event sources.
217
+ #
218
+ # As file descriptors are a Unix-specific concept, this function is not
219
+ # available on Windows and will always return +nil+.
220
+ #
221
+ # @return [Array<Pollfd>] list of Pollfd objects,
222
+ # +nil+ on error,
223
+ # +nil+ on platforms where the functionality is not available
224
+ def pollfds
225
+ ppPollfds = Call.libusb_get_pollfds(@ctx)
226
+ return nil if ppPollfds.null?
227
+ offs = 0
228
+ pollfds = []
229
+ while !(pPollfd=ppPollfds.get_pointer(offs)).null?
230
+ pollfd = Call::Pollfd.new pPollfd
231
+ pollfds << Pollfd.new(pollfd[:fd], pollfd[:events])
232
+ offs += FFI.type_size :pointer
233
+ end
234
+ # ppPollfds has to be released by free() -> give the GC this job
235
+ ppPollfds.autorelease = true
236
+ pollfds
237
+ end
238
+
239
+ # Determine the next internal timeout that libusb needs to handle.
240
+ #
241
+ # You only need to use this function if you are calling poll() or select() or
242
+ # similar on libusb's file descriptors yourself - you do not need to use it if
243
+ # you are calling {#handle_events} directly.
244
+ #
245
+ # You should call this function in your main loop in order to determine how long
246
+ # to wait for select() or poll() to return results. libusb needs to be called
247
+ # into at this timeout, so you should use it as an upper bound on your select() or
248
+ # poll() call.
249
+ #
250
+ # When the timeout has expired, call into {#handle_events} (perhaps
251
+ # in non-blocking mode) so that libusb can handle the timeout.
252
+ #
253
+ # This function may return zero. If this is the
254
+ # case, it indicates that libusb has a timeout that has already expired so you
255
+ # should call {#handle_events} immediately. A return code
256
+ # of +nil+ indicates that there are no pending timeouts.
257
+ #
258
+ # On some platforms, this function will always returns +nil+ (no pending timeouts).
259
+ # See libusb's notes on time-based events.
260
+ #
261
+ # @return [Float, nil] the timeout in seconds
262
+ def next_timeout
263
+ timeval = Call::Timeval.new
264
+ res = Call.libusb_get_next_timeout @ctx, timeval
265
+ LIBUSB.raise_error res, "in libusb_get_next_timeout" if res<0
266
+ res == 1 ? timeval.in_s : nil
267
+ end
268
+
269
+ # Register a notification block for file descriptor additions.
270
+ #
271
+ # This block will be invoked for every new file descriptor that
272
+ # libusb uses as an event source.
273
+ #
274
+ # Note that file descriptors may have been added even before you register these
275
+ # notifiers (e.g. at {Context#initialize} time).
276
+ #
277
+ # @yieldparam [Pollfd] pollfd The added file descriptor is yielded to the block
278
+ def on_pollfd_added &block
279
+ @on_pollfd_added = proc do |fd, events, _|
280
+ pollfd = Pollfd.new fd, events
281
+ block.call pollfd
282
+ end
283
+ Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
284
+ end
285
+
286
+ # Register a notification block for file descriptor removals.
287
+ #
288
+ # This block will be invoked for every removed file descriptor that
289
+ # libusb uses as an event source.
290
+ #
291
+ # Note that the removal notifier may be called during {Context#exit}
292
+ # (e.g. when it is closing file descriptors that were opened and added to the poll
293
+ # set at {Context#initialize} time). If you don't want this, overwrite the notifier
294
+ # immediately before calling {Context#exit}.
295
+ #
296
+ # @yieldparam [Pollfd] pollfd The removed file descriptor is yielded to the block
297
+ def on_pollfd_removed &block
298
+ @on_pollfd_removed = proc do |fd, _|
299
+ pollfd = Pollfd.new fd
300
+ block.call pollfd
301
+ end
302
+ Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
303
+ end
304
+ end
305
+ end