libusb 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -95,23 +95,87 @@ module LIBUSB
95
95
  end
96
96
  end
97
97
 
98
-
99
98
  # Initialize libusb context.
100
- def initialize
99
+ #
100
+ # @param [Hash{Call::Options => Object}] options Options are available since libusb-1.0.27
101
+ # @option options [Integer, Symbol] :OPTION_LOG_LEVEL The log Level as a Integer or Symbol. See Call::LogLevels
102
+ # @option options [nil] :OPTION_USE_USBDK Enable the use of USBDK driver. Pass a +nil+ as value like so: +OPTION_USE_USBDK: nil+
103
+ # @option options [nil] :OPTION_NO_DEVICE_DISCOVERY Disable device discovery for use with libusb_wrap_sys_device(). Pass a +nil+ as value like so: +OPTION_NO_DEVICE_DISCOVERY: nil+
104
+ # @option options [Proc] :OPTION_LOG_CB Set a context related log callback Proc. It is called with parameters (context, level, logstring).
105
+ def initialize(options={})
101
106
  m = FFI::MemoryPointer.new :pointer
102
- res = Call.libusb_init(m)
103
- LIBUSB.raise_error res, "in libusb_init" if res!=0
107
+ if options.empty?
108
+ res = Call.libusb_init(m)
109
+ LIBUSB.raise_error res, "in libusb_init" if res!=0
110
+ else
111
+ raise ArgumentError, "options require libusb-1.0.27+" unless Call.respond_to?(:libusb_init_context)
112
+ i_opts = options.size
113
+ p_opts = FFI::MemoryPointer.new(Call::InitOption, i_opts)
114
+ options.each_with_index do |(k, v), i|
115
+ opt = Call::InitOption.new(p_opts + i * Call::InitOption.size)
116
+ opt[:option] = k
117
+
118
+ ffitype, ffival = LIBUSB.send(:option_args_to_ffi, k, Array(v), self)
119
+ case ffitype
120
+ when NilClass then nil
121
+ when :libusb_log_level then
122
+ opt[:value][:ival] = ffival
123
+ when :libusb_log_cb then
124
+ opt[:value][:log_cbval] = ffival
125
+ else raise ArgumentError, "internal error: unexpected ffitype: #{ffitype.inspect}"
126
+ end
127
+ end
128
+ res = Call.libusb_init_context(m, p_opts, i_opts)
129
+ LIBUSB.raise_error res, "in libusb_init_context" if res!=0
130
+ end
104
131
  @ctx = m.read_pointer
105
132
  @on_pollfd_added = nil
106
133
  @on_pollfd_removed = nil
107
134
  @hotplug_callbacks = {}
135
+
136
+ def @ctx.free_context(id)
137
+ @free_context = true
138
+ if @refs == 0
139
+ # puts "final libusb_exit #{to_i} #{id} #{caller[0]}"
140
+ if id # Is Context is about to be garbage collected?
141
+ # In GC mode there's no way to call the registered collbacks, since they are GC'ed as well.
142
+ # So disable callbacks now.
143
+ Call.libusb_set_log_cb(self, nil, LOG_CB_CONTEXT)
144
+ Call.libusb_set_pollfd_notifiers(self, nil, nil, nil)
145
+ end
146
+ Call.libusb_exit(self)
147
+ @refs = nil
148
+ end
149
+ end
150
+ def @ctx.ref_context
151
+ @refs += 1
152
+ # puts "ref_context #{to_i} #{@refs} #{caller[1]}"
153
+ self
154
+ end
155
+ def @ctx.unref_context
156
+ @refs -= 1
157
+ # puts "unref_context #{to_i} #{@refs}"
158
+ raise "more unref_context than ref_context" if @refs < 0
159
+ free_context(true) if @refs == 0 && @free_context
160
+ self
161
+ end
162
+ def @ctx.setref_context
163
+ @refs = 0
164
+ @free_context = false
165
+ end
166
+ def @ctx.refs
167
+ @refs
168
+ end
169
+ @ctx.setref_context
170
+ ObjectSpace.define_finalizer(self, @ctx.method(:free_context))
108
171
  end
109
172
 
110
173
  # Deinitialize libusb.
111
174
  #
112
175
  # Should be called after closing all open devices and before your application terminates.
113
176
  def exit
114
- Call.libusb_exit(@ctx)
177
+ raise RemainingReferencesError, "#{@ctx.refs} remaining references to LIBUSB::Context" if @ctx.refs.to_i > 0
178
+ @ctx.free_context nil
115
179
  end
116
180
 
117
181
  # @deprecated Use {Context#set_option} instead using the +:OPTION_LOG_LEVEL+ option.
@@ -119,30 +183,37 @@ module LIBUSB
119
183
  Call.libusb_set_debug(@ctx, level)
120
184
  end
121
185
 
122
- def expect_option_args(exp, is)
123
- raise ArgumentError, "wrong number of arguments (given #{is+1}, expected #{exp+1})" if is != exp
186
+ private def wrap_log_cb(block, mode)
187
+ if block
188
+ cb_proc = proc do |p_ctx, lev, str|
189
+ ctx = case p_ctx
190
+ when FFI::Pointer::NULL then nil
191
+ when @ctx then self
192
+ else p_ctx.to_i
193
+ end
194
+ block.call(ctx, lev, str)
195
+ end
196
+ end
197
+
198
+ # Avoid garbage collection of the proc, since only the function pointer is given to libusb
199
+ if Call::LogCbMode.to_native(mode, nil) & LOG_CB_GLOBAL != 0
200
+ @@log_cb_proc = cb_proc
201
+ end
202
+ if Call::LogCbMode.to_native(mode, nil) & LOG_CB_CONTEXT != 0
203
+ @log_cb_proc = cb_proc
204
+ end
205
+ cb_proc
124
206
  end
125
- private :expect_option_args
126
207
 
127
- # Set a libusb option from the {Call::Options option list}.
208
+ # Set a context related libusb option from the {Call::Options option list}.
128
209
  #
129
210
  # @param [Symbol, Fixnum] option
130
211
  # @param args Zero or more arguments depending on +option+
212
+ # @see set_options
131
213
  def set_option(option, *args)
132
214
  if Call.respond_to?(:libusb_set_option)
133
215
  # Available since libusb-1.0.22
134
-
135
- ffi_args = case option
136
- when :OPTION_LOG_LEVEL, LIBUSB::OPTION_LOG_LEVEL
137
- expect_option_args(1, args.length)
138
- [:libusb_log_level, args[0]]
139
- when :OPTION_USE_USBDK, LIBUSB::OPTION_USE_USBDK
140
- expect_option_args(0, args.length)
141
- []
142
- else
143
- raise ArgumentError, "unknown option #{option.inspect}"
144
- end
145
-
216
+ ffi_args = LIBUSB.send(:option_args_to_ffi, option, args, self)
146
217
  res = Call.libusb_set_option(@ctx, option, *ffi_args)
147
218
  LIBUSB.raise_error res, "in libusb_set_option" if res<0
148
219
 
@@ -154,6 +225,69 @@ module LIBUSB
154
225
  end
155
226
  end
156
227
 
228
+ # Convenience function to set context related options in the libusb library.
229
+ #
230
+ # Use this function to configure any number of options within the library.
231
+ # It takes a Hash the same way as given to {Context.initialize}.
232
+ # See also {Call::Options option list}.
233
+ #
234
+ # @param [Hash{Call::Options => Object}] options Option hash
235
+ # @see set_option
236
+ def set_options(options={})
237
+ options.each do |k, v|
238
+ set_option(k, *Array(v))
239
+ end
240
+ end
241
+
242
+ if Call.respond_to?(:libusb_set_log_cb)
243
+ # Set log handler.
244
+ #
245
+ # libusb will redirect its log messages to the provided method block.
246
+ # libusb supports redirection of per context and global log messages.
247
+ # Log messages sent to the context will be sent to the global log handler too.
248
+ #
249
+ # If libusb is compiled without message logging or USE_SYSTEM_LOGGING_FACILITY
250
+ # is defined then global callback function will never be called.
251
+ # If ENABLE_DEBUG_LOGGING is defined then per context callback function will
252
+ # never be called.
253
+ #
254
+ # To disable the log callback, execute set_log_cb without a block.
255
+ #
256
+ # Available since libusb-1.0.23, LIBUSB_API_VERSION >= 0x01000107
257
+ #
258
+ # @param [Symbol, Integer] mode mode of callback function operation.
259
+ # Several modes can be selected for a single callback function, see Call::LogCbMode for a description.
260
+ #
261
+ # @yieldparam [Context, nil] context The context which is related to the log message, or +nil+ if it is a global log message.
262
+ # @yieldparam [Symbol] level The log level, see Call::LogLevels for a description.
263
+ # @yieldparam [String] str The log message.
264
+ #
265
+ # @see Call::LogCbMode
266
+ #
267
+ def set_log_cb(mode, &block)
268
+ cb_proc = wrap_log_cb(block, mode)
269
+ Call.libusb_set_log_cb(@ctx, cb_proc, mode)
270
+ self
271
+ end
272
+ end
273
+
274
+ if Call.respond_to?(:libusb_wrap_sys_device)
275
+ def wrap_sys_device(dev_io)
276
+ dev_io = dev_io.is_a?(IO) ? dev_io.fileno : dev_io
277
+
278
+ ppHandle = FFI::MemoryPointer.new :pointer
279
+ res = Call.libusb_wrap_sys_device(@ctx, dev_io, ppHandle)
280
+ LIBUSB.raise_error res, "in libusb_wrap_sys_device" if res!=0
281
+ handle = DevHandle.new self, ppHandle.read_pointer
282
+ return handle unless block_given?
283
+ begin
284
+ yield handle
285
+ ensure
286
+ handle.close
287
+ end
288
+ end
289
+ end
290
+
157
291
  def device_list
158
292
  pppDevs = FFI::MemoryPointer.new :pointer
159
293
  size = Call.libusb_get_device_list(@ctx, pppDevs)
@@ -327,14 +461,18 @@ module LIBUSB
327
461
  # This block will be invoked for every new file descriptor that
328
462
  # libusb uses as an event source.
329
463
  #
464
+ # To disable the notification callback, execute on_pollfd_added without a block.
465
+ #
330
466
  # Note that file descriptors may have been added even before you register these
331
467
  # notifiers (e.g. at {Context#initialize} time).
332
468
  #
333
469
  # @yieldparam [Pollfd] pollfd The added file descriptor is yielded to the block
334
470
  def on_pollfd_added &block
335
- @on_pollfd_added = proc do |fd, events, _|
336
- pollfd = Pollfd.new fd, events
337
- block.call pollfd
471
+ @on_pollfd_added = if block
472
+ proc do |fd, events, _|
473
+ pollfd = Pollfd.new fd, events
474
+ block.call pollfd
475
+ end
338
476
  end
339
477
  Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
340
478
  end
@@ -344,6 +482,8 @@ module LIBUSB
344
482
  # This block will be invoked for every removed file descriptor that
345
483
  # libusb uses as an event source.
346
484
  #
485
+ # To disable the notification callback, execute on_pollfd_removed without a block.
486
+ #
347
487
  # Note that the removal notifier may be called during {Context#exit}
348
488
  # (e.g. when it is closing file descriptors that were opened and added to the poll
349
489
  # set at {Context#initialize} time). If you don't want this, overwrite the notifier
@@ -351,9 +491,11 @@ module LIBUSB
351
491
  #
352
492
  # @yieldparam [Pollfd] pollfd The removed file descriptor is yielded to the block
353
493
  def on_pollfd_removed &block
354
- @on_pollfd_removed = proc do |fd, _|
355
- pollfd = Pollfd.new fd
356
- block.call pollfd
494
+ @on_pollfd_removed = if block
495
+ proc do |fd, _|
496
+ pollfd = Pollfd.new fd
497
+ block.call pollfd
498
+ end
357
499
  end
358
500
  Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil
359
501
  end
@@ -393,19 +535,18 @@ module LIBUSB
393
535
  # @yieldparam [Symbol] event a {Call::HotplugEvents HotplugEvents} symbol
394
536
  # @yieldreturn [Symbol] +:finish+ to deregister the callback, +:repeat+ to receive additional events
395
537
  # @raise [ArgumentError, LIBUSB::Error] in case of failure
396
- def on_hotplug_event(args={}, &block)
397
- events = args.delete(:events) || (HOTPLUG_EVENT_DEVICE_ARRIVED | HOTPLUG_EVENT_DEVICE_LEFT)
398
- flags = args.delete(:flags) || 0
399
- vendor_id = args.delete(:vendor_id) || HOTPLUG_MATCH_ANY
400
- product_id = args.delete(:product_id) || HOTPLUG_MATCH_ANY
401
- dev_class = args.delete(:dev_class) || HOTPLUG_MATCH_ANY
402
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
538
+ def on_hotplug_event(events: HOTPLUG_EVENT_DEVICE_ARRIVED | HOTPLUG_EVENT_DEVICE_LEFT,
539
+ flags: 0,
540
+ vendor_id: HOTPLUG_MATCH_ANY,
541
+ product_id: HOTPLUG_MATCH_ANY,
542
+ dev_class: HOTPLUG_MATCH_ANY,
543
+ &block)
403
544
 
404
545
  handle = HotplugCallback.new self, @ctx, @hotplug_callbacks
405
546
 
406
547
  block2 = proc do |ctx, pDevice, event, _user_data|
407
548
  raise "internal error: unexpected context" unless @ctx==ctx
408
- dev = Device.new @ctx, pDevice
549
+ dev = Device.new self, pDevice
409
550
 
410
551
  blres = block.call(dev, event)
411
552
 
@@ -0,0 +1,38 @@
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
+ module ContextReference
18
+ def register_context(ctx, free_sym)
19
+ ptr = pointer
20
+ def ptr.free_struct(id)
21
+ return unless @ctx
22
+ Call.send(@free_sym, self)
23
+ @ctx.unref_context
24
+ end
25
+ ptr.instance_variable_set(:@free_sym, free_sym)
26
+ ptr.instance_variable_set(:@ctx, ctx.ref_context)
27
+ ObjectSpace.define_finalizer(self, ptr.method(:free_struct))
28
+ end
29
+
30
+ def free
31
+ ptr = pointer
32
+ ptr.free_struct nil
33
+ ptr.instance_variable_set(:@ctx, nil)
34
+ end
35
+ end
36
+
37
+ private_constant :ContextReference
38
+ end
@@ -1,7 +1,7 @@
1
1
  module LIBUSB
2
- LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '1.0.22'
2
+ LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '1.0.27'
3
3
  LIBUSB_SOURCE_URI = "https://github.com/libusb/libusb/releases/download/v#{LIBUSB_VERSION}/libusb-#{LIBUSB_VERSION}.tar.bz2"
4
- LIBUSB_SOURCE_SHA1 = '10116aa265aac4273a0c894faa089370262ec0dc'
4
+ LIBUSB_SOURCE_SHA256 = 'ffaa41d741a8a3bee244ac8e54a72ea05bf2879663c098c82fc5757853441575'
5
5
 
6
6
  MINI_PORTILE_VERSION = '~> 2.1'
7
7
  end
@@ -372,19 +372,22 @@ module LIBUSB
372
372
  # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
373
373
  # when the asynchronous transfer has finished
374
374
  # @raise [ArgumentError, LIBUSB::Error] in case of failure
375
- def bulk_transfer(args={}, &block)
376
- timeout = args.delete(:timeout) || 1000
377
- endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
375
+ def bulk_transfer(timeout: 1000,
376
+ endpoint:,
377
+ dataIn: nil,
378
+ dataOut: nil,
379
+ allow_device_memory: false,
380
+ &block)
381
+
378
382
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
379
383
  if endpoint&ENDPOINT_IN != 0
380
- dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for bulk read")
384
+ dataIn || raise(ArgumentError, "no :dataIn given for bulk read")
381
385
  else
382
- dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for bulk write")
386
+ dataOut || raise(ArgumentError, "no :dataOut given for bulk write")
383
387
  end
384
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
385
388
 
386
389
  # reuse transfer struct to speed up transfer
387
- @bulk_transfer ||= BulkTransfer.new dev_handle: self, allow_device_memory: true
390
+ @bulk_transfer ||= BulkTransfer.new dev_handle: self, allow_device_memory: allow_device_memory
388
391
  tr = @bulk_transfer
389
392
  tr.endpoint = endpoint
390
393
  tr.timeout = timeout
@@ -440,19 +443,21 @@ module LIBUSB
440
443
  # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
441
444
  # when the asynchronous transfer has finished
442
445
  # @raise [ArgumentError, LIBUSB::Error] in case of failure
443
- def interrupt_transfer(args={}, &block)
444
- timeout = args.delete(:timeout) || 1000
445
- endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
446
+ def interrupt_transfer(timeout: 1000,
447
+ endpoint:,
448
+ dataIn: nil,
449
+ dataOut: nil,
450
+ allow_device_memory: false,
451
+ &block)
446
452
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
447
453
  if endpoint&ENDPOINT_IN != 0
448
- dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for interrupt read")
454
+ dataIn || raise(ArgumentError, "no :dataIn given for interrupt read")
449
455
  else
450
- dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for interrupt write")
456
+ dataOut || raise(ArgumentError, "no :dataOut given for interrupt write")
451
457
  end
452
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
453
458
 
454
459
  # reuse transfer struct to speed up transfer
455
- @interrupt_transfer ||= InterruptTransfer.new dev_handle: self, allow_device_memory: true
460
+ @interrupt_transfer ||= InterruptTransfer.new dev_handle: self, allow_device_memory: allow_device_memory
456
461
  tr = @interrupt_transfer
457
462
  tr.endpoint = endpoint
458
463
  tr.timeout = timeout
@@ -497,22 +502,27 @@ module LIBUSB
497
502
  # @yieldparam [String, Integer, LIBUSB::Error] result result of the transfer is yielded to the block,
498
503
  # when the asynchronous transfer has finished
499
504
  # @raise [ArgumentError, LIBUSB::Error] in case of failure
500
- def control_transfer(args={}, &block)
501
- bmRequestType = args.delete(:bmRequestType) || raise(ArgumentError, "param :bmRequestType not given")
502
- bRequest = args.delete(:bRequest) || raise(ArgumentError, "param :bRequest not given")
503
- wValue = args.delete(:wValue) || raise(ArgumentError, "param :wValue not given")
504
- wIndex = args.delete(:wIndex) || raise(ArgumentError, "param :wIndex not given")
505
- timeout = args.delete(:timeout) || 1000
505
+ def control_transfer(bmRequestType:,
506
+ bRequest:,
507
+ wValue:,
508
+ wIndex:,
509
+ timeout: 1000,
510
+ dataIn: nil,
511
+ dataOut: nil,
512
+ allow_device_memory: false,
513
+ &block)
514
+
506
515
  if bmRequestType&ENDPOINT_IN != 0
507
- dataIn = args.delete(:dataIn) || 0
516
+ raise ArgumentError, "invalid param :dataOut" unless dataOut.nil?
517
+ dataIn ||= 0
508
518
  dataOut = ''
509
519
  else
510
- dataOut = args.delete(:dataOut) || ''
520
+ raise ArgumentError, "invalid param :dataIn" unless dataIn.nil?
521
+ dataOut ||= ''
511
522
  end
512
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
513
523
 
514
524
  # reuse transfer struct to speed up transfer
515
- @control_transfer ||= ControlTransfer.new dev_handle: self, allow_device_memory: true
525
+ @control_transfer ||= ControlTransfer.new dev_handle: self, allow_device_memory: allow_device_memory
516
526
  tr = @control_transfer
517
527
  tr.timeout = timeout
518
528
  if dataIn
data/lib/libusb/device.rb CHANGED
@@ -21,24 +21,27 @@ module LIBUSB
21
21
  # Devices of the system can be obtained with {Context#devices} .
22
22
  class Device
23
23
  include Comparable
24
+ include ContextReference
24
25
 
25
26
  # @return [Context] the context this device belongs to.
26
27
  attr_reader :context
27
28
 
28
29
  def initialize context, pDev
29
30
  @context = context
30
- def pDev.unref_device(id)
31
- Call.libusb_unref_device(self)
32
- end
33
- ObjectSpace.define_finalizer(self, pDev.method(:unref_device))
34
- Call.libusb_ref_device(pDev)
35
31
  @pDev = pDev
32
+ register_context(context.instance_variable_get(:@ctx), :libusb_unref_device)
33
+ Call.libusb_ref_device(pDev)
36
34
 
37
35
  @pDevDesc = Call::DeviceDescriptor.new
38
36
  res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
39
37
  LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
40
38
  end
41
39
 
40
+ # The pointer for ContextReference
41
+ private def pointer
42
+ @pDev
43
+ end
44
+
42
45
  # Open the device and obtain a device handle.
43
46
  #
44
47
  # A handle allows you to perform I/O on the device in question.
@@ -160,6 +163,44 @@ module LIBUSB
160
163
  res
161
164
  end
162
165
 
166
+ if Call.respond_to?(:libusb_get_max_alt_packet_size)
167
+
168
+ # Calculate the maximum packet size which a specific endpoint is capable of
169
+ # sending or receiving in the duration of 1 microframe
170
+ #
171
+ # Only the active configuration is examined. The calculation is based on the
172
+ # wMaxPacketSize field in the endpoint descriptor as described in section
173
+ # 9.6.6 in the USB 2.0 specifications.
174
+ #
175
+ # If acting on an isochronous or interrupt endpoint, this function will
176
+ # multiply the value found in bits 0:10 by the number of transactions per
177
+ # microframe (determined by bits 11:12). Otherwise, this function just
178
+ # returns the numeric value found in bits 0:10. For USB 3.0 device, it
179
+ # will attempts to retrieve the Endpoint Companion Descriptor to return
180
+ # wBytesPerInterval.
181
+ #
182
+ # This function is useful for setting up isochronous transfers, for example
183
+ # you might pass the return value from this function to
184
+ # +IsochronousTransfer.packet_lengths=+ in order to set the length field of every
185
+ # isochronous packet in a transfer.
186
+ #
187
+ # Available since libusb-1.0.27.
188
+ #
189
+ # @param [Interface, Fixnum] interface the interface or its bInterfaceNumber of the interface the endpoint belongs to
190
+ # @param [Setting, Fixnum] alternate_setting the alternate setting or its bAlternateSetting
191
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
192
+ # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
193
+ # @see max_iso_packet_size
194
+ def max_alt_packet_size(interface, alternate_setting, endpoint)
195
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
196
+ alternate_setting = alternate_setting.bAlternateSetting if alternate_setting.respond_to? :bAlternateSetting
197
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
198
+ res = Call.libusb_get_max_alt_packet_size(@pDev, interface, alternate_setting, endpoint)
199
+ LIBUSB.raise_error res, "in libusb_get_max_alt_packet_size" unless res>=0
200
+ res
201
+ end
202
+ end
203
+
163
204
  # Calculate the maximum packet size which a specific endpoint is capable is
164
205
  # sending or receiving in the duration of 1 microframe.
165
206
  #
@@ -179,6 +220,7 @@ module LIBUSB
179
220
  #
180
221
  # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
181
222
  # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
223
+ # @see max_alt_packet_size
182
224
  def max_iso_packet_size(endpoint)
183
225
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
184
226
  res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
@@ -310,7 +352,7 @@ module LIBUSB
310
352
  def manufacturer
311
353
  return @manufacturer if defined? @manufacturer
312
354
  @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
313
- @manufacturer.strip! if @manufacturer
355
+ @manufacturer = @manufacturer.strip if @manufacturer
314
356
  @manufacturer
315
357
  end
316
358
 
@@ -319,7 +361,7 @@ module LIBUSB
319
361
  def product
320
362
  return @product if defined? @product
321
363
  @product = try_string_descriptor_ascii(self.iProduct)
322
- @product.strip! if @product
364
+ @product = @product.strip if @product
323
365
  @product
324
366
  end
325
367
 
@@ -328,7 +370,7 @@ module LIBUSB
328
370
  def serial_number
329
371
  return @serial_number if defined? @serial_number
330
372
  @serial_number = try_string_descriptor_ascii(self.iSerialNumber)
331
- @serial_number.strip! if @serial_number
373
+ @serial_number = @serial_number.strip if @serial_number
332
374
  @serial_number
333
375
  end
334
376
 
@@ -181,13 +181,14 @@ module LIBUSB
181
181
  # @return [SsCompanion]
182
182
  def ss_companion
183
183
  ep_comp = FFI::MemoryPointer.new :pointer
184
+ ctx = device.context.instance_variable_get(:@ctx)
184
185
  res = Call.libusb_get_ss_endpoint_companion_descriptor(
185
- device.context.instance_variable_get(:@ctx),
186
+ ctx,
186
187
  pointer,
187
188
  ep_comp
188
189
  )
189
190
  LIBUSB.raise_error res, "in libusb_get_ss_endpoint_companion_descriptor" if res!=0
190
- SsCompanion.new ep_comp.read_pointer
191
+ SsCompanion.new ctx, ep_comp.read_pointer
191
192
  end
192
193
  end
193
194
  end
@@ -62,6 +62,10 @@ class Context
62
62
  @eventmachine_attached_fds.each do |fd, watcher|
63
63
  watcher.detach
64
64
  end
65
+
66
+ # Deregister callbacks
67
+ on_pollfd_added
68
+ on_pollfd_removed
65
69
  end
66
70
 
67
71
  class EMPollfdHandler < EventMachine::Connection
@@ -118,7 +122,7 @@ class DevHandle
118
122
  include EM::Deferrable
119
123
 
120
124
  def initialize(opts, dev_handle, transfer_method)
121
- dev_handle.send(transfer_method, opts) do |res|
125
+ dev_handle.send(transfer_method, **opts) do |res|
122
126
  EM.next_tick do
123
127
  if res.kind_of?(LIBUSB::Error)
124
128
  fail res
@@ -134,7 +138,7 @@ class DevHandle
134
138
  #
135
139
  # @see Context#eventmachine_register
136
140
  # DevHandle#interrupt_transfer
137
- def eventmachine_interrupt_transfer(opts={})
141
+ def eventmachine_interrupt_transfer(**opts)
138
142
  eventmachine_transfer(opts, :interrupt_transfer)
139
143
  end
140
144
 
@@ -151,7 +155,7 @@ class DevHandle
151
155
  #
152
156
  # @see Context#eventmachine_register
153
157
  # DevHandle#bulk_transfer
154
- def eventmachine_bulk_transfer(opts={})
158
+ def eventmachine_bulk_transfer(**opts)
155
159
  eventmachine_transfer(opts, :bulk_transfer)
156
160
  end
157
161
 
@@ -171,7 +175,7 @@ class DevHandle
171
175
  #
172
176
  # @see Context#eventmachine_register
173
177
  # DevHandle#control_transfer
174
- def eventmachine_control_transfer(opts={})
178
+ def eventmachine_control_transfer(**opts)
175
179
  eventmachine_transfer(opts, :control_transfer)
176
180
  end
177
181
 
@@ -87,9 +87,9 @@ module LIBUSB
87
87
 
88
88
  self.ruby_platform = ruby_platform
89
89
  self.recipe = LIBUSB::LibusbRecipe.new
90
- recipe.host = host_platform
91
- recipe.configure_options << "--host=#{recipe.host}"
92
- recipe.configure_options << "CC=#{recipe.host}-gcc -static-libgcc" if recipe.host =~ /mingw/
90
+ recipe.host = ruby_platform
91
+ recipe.configure_options << "--host=#{host_platform}"
92
+ recipe.configure_options << "CC=#{host_platform}-gcc -static-libgcc" if recipe.host =~ /mingw/
93
93
  self.libusb_dll = Pathname.new(recipe.path) + libusb_dllname
94
94
 
95
95
  file libusb_dll do
@@ -98,8 +98,11 @@ module LIBUSB
98
98
 
99
99
  task "libusb_dll:#{ruby_platform}" => libusb_dll
100
100
 
101
- desc 'Cross compile libusb for win32'
102
- task :cross => [ "libusb_dll:#{ruby_platform}" ] do |t|
101
+ desc 'Cross compile libusb for all targets'
102
+ task :cross => "cross:#{ruby_platform}"
103
+
104
+ desc "Cross compile libusb for #{ruby_platform}"
105
+ task "cross:#{ruby_platform}" => [ "libusb_dll:#{ruby_platform}" ] do |t|
103
106
  spec = Gem::Specification::load("libusb.gemspec").dup
104
107
  spec.platform = Gem::Platform.new(ruby_platform)
105
108
  spec.extensions = []
@@ -11,7 +11,8 @@ module LIBUSB
11
11
  def initialize
12
12
  super("libusb", LIBUSB_VERSION)
13
13
  self.target = File.join(ROOT, "ports")
14
- self.files = [url: LIBUSB_SOURCE_URI, sha1: LIBUSB_SOURCE_SHA1]
14
+ self.files = [url: LIBUSB_SOURCE_URI, sha256: LIBUSB_SOURCE_SHA256]
15
+ self.patch_files = Dir[File.join(ROOT, "patches", self.name, self.version, "*.patch")].sort
15
16
  self.configure_options = []
16
17
  end
17
18
 
@@ -24,7 +25,5 @@ module LIBUSB
24
25
  self.activate
25
26
  self
26
27
  end
27
-
28
- public :files_hashs
29
28
  end
30
29
  end