libusb 0.3.3-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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