libusb 0.6.4-x86-mingw32 → 0.7.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.appveyor.yml +33 -0
- data/.github/workflows/ci.yml +185 -0
- data/.gitignore +1 -0
- data/.travis.yml +12 -7
- data/Gemfile +4 -1
- data/History.md +38 -0
- data/README.md +29 -4
- data/Rakefile +41 -12
- data/lib/libusb/bos.rb +85 -29
- data/lib/libusb/call.rb +132 -16
- data/lib/libusb/configuration.rb +3 -4
- data/lib/libusb/constants.rb +4 -0
- data/lib/libusb/context.rb +176 -35
- data/lib/libusb/context_reference.rb +38 -0
- data/lib/libusb/dependencies.rb +2 -2
- data/lib/libusb/dev_handle.rb +34 -24
- data/lib/libusb/device.rb +50 -8
- data/lib/libusb/endpoint.rb +3 -2
- data/lib/libusb/eventmachine.rb +8 -4
- data/lib/libusb/gem_helper.rb +9 -6
- data/lib/libusb/libusb_recipe.rb +2 -3
- data/lib/libusb/ss_companion.rb +9 -6
- data/lib/libusb/transfer.rb +10 -6
- data/lib/libusb/version_gem.rb +1 -1
- data/lib/libusb-1.0.dll +0 -0
- data/lib/libusb.rb +106 -18
- data/libusb.gemspec +1 -5
- data/test/test_libusb_bos.rb +22 -0
- data/test/test_libusb_bulk_stream_transfer.rb +23 -12
- data/test/test_libusb_context.rb +47 -0
- data/test/test_libusb_descriptors.rb +44 -11
- data/test/test_libusb_gc.rb +15 -0
- data/test/test_libusb_hotplug.rb +3 -1
- data/test/test_libusb_iso_transfer.rb +6 -0
- data/test/test_libusb_mass_storage.rb +6 -6
- metadata +7 -62
- data/appveyor.yml +0 -36
data/lib/libusb/dev_handle.rb
CHANGED
@@ -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(
|
376
|
-
|
377
|
-
|
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
|
384
|
+
dataIn || raise(ArgumentError, "no :dataIn given for bulk read")
|
381
385
|
else
|
382
|
-
dataOut
|
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:
|
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(
|
444
|
-
|
445
|
-
|
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
|
454
|
+
dataIn || raise(ArgumentError, "no :dataIn given for interrupt read")
|
449
455
|
else
|
450
|
-
dataOut
|
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:
|
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(
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
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
|
-
|
516
|
+
raise ArgumentError, "invalid param :dataOut" unless dataOut.nil?
|
517
|
+
dataIn ||= 0
|
508
518
|
dataOut = ''
|
509
519
|
else
|
510
|
-
|
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:
|
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
|
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
|
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
|
373
|
+
@serial_number = @serial_number.strip if @serial_number
|
332
374
|
@serial_number
|
333
375
|
end
|
334
376
|
|
data/lib/libusb/endpoint.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/libusb/eventmachine.rb
CHANGED
@@ -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
|
|
data/lib/libusb/gem_helper.rb
CHANGED
@@ -66,7 +66,7 @@ module LIBUSB
|
|
66
66
|
yield if block_given?
|
67
67
|
rescue
|
68
68
|
Bundler.ui.error "Untagging #{version_tag} due to error."
|
69
|
-
|
69
|
+
sh "git tag -d #{version_tag}"
|
70
70
|
raise
|
71
71
|
end
|
72
72
|
|
@@ -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 =
|
91
|
-
recipe.configure_options << "--host=#{
|
92
|
-
recipe.configure_options << "CC=#{
|
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
|
102
|
-
task :cross =>
|
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 = []
|
data/lib/libusb/libusb_recipe.rb
CHANGED
@@ -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,
|
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
|
data/lib/libusb/ss_companion.rb
CHANGED
@@ -19,13 +19,21 @@ module LIBUSB
|
|
19
19
|
# A structure representing the superspeed endpoint companion descriptor.
|
20
20
|
#
|
21
21
|
# This descriptor is documented in section 9.6.7 of the USB 3.0 specification. All multiple-byte fields are represented in host-endian format.
|
22
|
-
class SsCompanion < FFI::
|
22
|
+
class SsCompanion < FFI::Struct
|
23
|
+
include ContextReference
|
24
|
+
|
23
25
|
layout :bLength, :uint8,
|
24
26
|
:bDescriptorType, :uint8,
|
25
27
|
:bMaxBurst, :uint8,
|
26
28
|
:bmAttributes, :uint8,
|
27
29
|
:wBytesPerInterval, :uint16
|
28
30
|
|
31
|
+
def initialize(ctx, *args)
|
32
|
+
super(*args)
|
33
|
+
|
34
|
+
register_context(ctx, :libusb_free_ss_endpoint_companion_descriptor)
|
35
|
+
end
|
36
|
+
|
29
37
|
# Size of this descriptor (in bytes)
|
30
38
|
def bLength
|
31
39
|
self[:bLength]
|
@@ -60,10 +68,5 @@ module LIBUSB
|
|
60
68
|
def inspect
|
61
69
|
"\#<#{self.class} burst: #{bMaxBurst} attrs: #{bmAttributes}>"
|
62
70
|
end
|
63
|
-
|
64
|
-
# @private
|
65
|
-
def self.release(ptr)
|
66
|
-
Call.libusb_free_ss_endpoint_companion_descriptor(ptr)
|
67
|
-
end
|
68
71
|
end
|
69
72
|
end
|
data/lib/libusb/transfer.rb
CHANGED
@@ -28,16 +28,16 @@ module LIBUSB
|
|
28
28
|
class ZeroCopyMemory < FFI::Pointer
|
29
29
|
attr_reader :size
|
30
30
|
|
31
|
-
def initialize(
|
32
|
-
@
|
31
|
+
def initialize(pDevhandle, ptr, size)
|
32
|
+
@pDevhandle = pDevhandle
|
33
33
|
@size = size
|
34
34
|
super(ptr)
|
35
35
|
end
|
36
36
|
|
37
37
|
def free(id=nil)
|
38
|
+
# puts format("libusb_dev_mem_free(%#x, %d)%s", address, @size||0, id ? " by GC" : '')
|
38
39
|
return unless @size
|
39
|
-
|
40
|
-
res = Call.libusb_dev_mem_free( @dev_handle.pHandle, self, @size )
|
40
|
+
res = Call.libusb_dev_mem_free( @pDevhandle, self, @size )
|
41
41
|
LIBUSB.raise_error res, "in libusb_dev_mem_free" if res!=0
|
42
42
|
@size = nil
|
43
43
|
end
|
@@ -60,6 +60,10 @@ module LIBUSB
|
|
60
60
|
def dev_handle=(dev)
|
61
61
|
@dev_handle = dev
|
62
62
|
@transfer[:dev_handle] = @dev_handle.pHandle
|
63
|
+
# Now that the transfer is bound to a DevHandle, it must be registered in the Context.
|
64
|
+
# This ensures that the Call::Transfer is freed before libusb_exit, avoiding warnings about still referenced devices.
|
65
|
+
ctx = dev.device.context.instance_variable_get(:@ctx)
|
66
|
+
@transfer.instance_variable_set(:@ctx, ctx.ref_context)
|
63
67
|
end
|
64
68
|
|
65
69
|
# The handle for the device to communicate with.
|
@@ -163,7 +167,7 @@ module LIBUSB
|
|
163
167
|
ptr = Call.libusb_dev_mem_alloc( @dev_handle.pHandle, len )
|
164
168
|
# puts format("libusb_dev_mem_alloc(%d) => %#x", len, ptr.address)
|
165
169
|
unless ptr.null?
|
166
|
-
buffer = ZeroCopyMemory.new(@dev_handle, ptr, len)
|
170
|
+
buffer = ZeroCopyMemory.new(@dev_handle.pHandle, ptr, len)
|
167
171
|
ObjectSpace.define_finalizer(self, buffer.method(:free))
|
168
172
|
end
|
169
173
|
end
|
@@ -252,7 +256,7 @@ module LIBUSB
|
|
252
256
|
@dev_handle.device.context.handle_events nil, @completion_flag
|
253
257
|
rescue ERROR_INTERRUPTED
|
254
258
|
next
|
255
|
-
rescue
|
259
|
+
rescue Exception
|
256
260
|
cancel!
|
257
261
|
until @completion_flag.completed?
|
258
262
|
@dev_handle.device.context.handle_events nil, @completion_flag
|
data/lib/libusb/version_gem.rb
CHANGED
data/lib/libusb-1.0.dll
CHANGED
Binary file
|
data/lib/libusb.rb
CHANGED
@@ -20,6 +20,7 @@ module LIBUSB
|
|
20
20
|
autoload :VERSION, 'libusb/version_gem'
|
21
21
|
autoload :Version, 'libusb/version_struct'
|
22
22
|
autoload :Configuration, 'libusb/configuration'
|
23
|
+
autoload :ContextReference, 'libusb/context_reference'
|
23
24
|
autoload :DevHandle, 'libusb/dev_handle'
|
24
25
|
autoload :Device, 'libusb/device'
|
25
26
|
autoload :Endpoint, 'libusb/endpoint'
|
@@ -32,27 +33,114 @@ module LIBUSB
|
|
32
33
|
autoload klass, 'libusb/transfer'
|
33
34
|
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
class << self
|
37
|
+
if Call.respond_to?(:libusb_get_version)
|
38
|
+
# Get version of the underlying libusb library.
|
39
|
+
# Available since libusb-1.0.10.
|
40
|
+
# @return [Version] version object
|
41
|
+
def version
|
42
|
+
Version.new(Call.libusb_get_version)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if Call.respond_to?(:libusb_has_capability)
|
47
|
+
# Check at runtime if the loaded library has a given capability.
|
48
|
+
# Available since libusb-1.0.9.
|
49
|
+
# @param [Symbol] capability the {Call::Capabilities Capabilities} symbol to check for
|
50
|
+
# @return [Boolean] +true+ if the running library has the capability, +false+ otherwise
|
51
|
+
def has_capability?(capability)
|
52
|
+
r = Call.libusb_has_capability(capability)
|
53
|
+
return r != 0
|
54
|
+
end
|
55
|
+
else
|
56
|
+
def has_capability?(capability)
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private def expect_option_args(exp, is)
|
62
|
+
raise ArgumentError, "wrong number of arguments (given #{is+1}, expected #{exp+1})" if is != exp
|
41
63
|
end
|
42
|
-
end
|
43
64
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
65
|
+
private def wrap_log_cb(block, mode)
|
66
|
+
if block
|
67
|
+
cb_proc = proc do |p_ctx, lev, str|
|
68
|
+
ctx = case p_ctx
|
69
|
+
when FFI::Pointer::NULL then nil
|
70
|
+
else p_ctx.to_i
|
71
|
+
end
|
72
|
+
block.call(ctx, lev, str)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Avoid garbage collection of the proc, since only the function pointer is given to libusb
|
77
|
+
if Call::LogCbMode.to_native(mode, nil) & LOG_CB_GLOBAL != 0
|
78
|
+
@log_cb_global_proc = cb_proc
|
79
|
+
end
|
80
|
+
if Call::LogCbMode.to_native(mode, nil) & LOG_CB_CONTEXT != 0
|
81
|
+
@log_cb_context_proc = cb_proc
|
82
|
+
end
|
83
|
+
cb_proc
|
84
|
+
end
|
85
|
+
|
86
|
+
private def option_args_to_ffi(option, args, ctx)
|
87
|
+
case option
|
88
|
+
when :OPTION_LOG_LEVEL, LIBUSB::OPTION_LOG_LEVEL
|
89
|
+
expect_option_args(1, args.length)
|
90
|
+
[:libusb_log_level, args[0]]
|
91
|
+
when :OPTION_USE_USBDK, LIBUSB::OPTION_USE_USBDK
|
92
|
+
expect_option_args(0, args.length)
|
93
|
+
[]
|
94
|
+
when :OPTION_NO_DEVICE_DISCOVERY, LIBUSB::OPTION_NO_DEVICE_DISCOVERY
|
95
|
+
expect_option_args(0, args.length)
|
96
|
+
[]
|
97
|
+
when :OPTION_LOG_CB, LIBUSB::OPTION_LOG_CB
|
98
|
+
expect_option_args(1, args.length)
|
99
|
+
cb_proc = ctx.send(:wrap_log_cb, args[0], LOG_CB_CONTEXT)
|
100
|
+
[:libusb_log_cb, cb_proc]
|
101
|
+
else
|
102
|
+
raise ArgumentError, "unknown option #{option.inspect}"
|
103
|
+
end
|
52
104
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
105
|
+
|
106
|
+
if Call.respond_to?(:libusb_set_option)
|
107
|
+
# Set an default option in the libusb library.
|
108
|
+
#
|
109
|
+
# Use this function to configure a specific option within the library.
|
110
|
+
# See {Call::Options option list}.
|
111
|
+
#
|
112
|
+
# Some options require one or more arguments to be provided.
|
113
|
+
# Consult each option's documentation for specific requirements.
|
114
|
+
#
|
115
|
+
# The option will be added to a list of default options that will be applied to all subsequently created contexts.
|
116
|
+
#
|
117
|
+
# Available since libusb-1.0.22, LIBUSB_API_VERSION >= 0x01000106
|
118
|
+
#
|
119
|
+
# @param [Symbol, Fixnum] option
|
120
|
+
# @param args Zero or more arguments depending on +option+
|
121
|
+
#
|
122
|
+
# Available since libusb-1.0.22
|
123
|
+
def set_option(option, *args)
|
124
|
+
ffi_args = option_args_to_ffi(option, args, self)
|
125
|
+
res = Call.libusb_set_option(nil, option, *ffi_args)
|
126
|
+
LIBUSB.raise_error res, "in libusb_set_option" if res<0
|
127
|
+
end
|
128
|
+
|
129
|
+
# Convenience function to set default options in the libusb library.
|
130
|
+
#
|
131
|
+
# Use this function to configure any number of options within the library.
|
132
|
+
# It takes a Hash the same way as given to {Context.initialize}.
|
133
|
+
# See also {Call::Options option list}.
|
134
|
+
#
|
135
|
+
# Available since libusb-1.0.22, LIBUSB_API_VERSION >= 0x01000106
|
136
|
+
#
|
137
|
+
# @param [Hash{Call::Options => Object}] options Option hash
|
138
|
+
# @see set_option
|
139
|
+
def set_options(options={})
|
140
|
+
options.each do |k, v|
|
141
|
+
set_option(k, *Array(v))
|
142
|
+
end
|
143
|
+
end
|
56
144
|
end
|
57
145
|
end
|
58
146
|
end
|
data/libusb.gemspec
CHANGED
@@ -22,11 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.extensions = ['ext/extconf.rb']
|
23
23
|
s.metadata["yard.run"] = "yri"
|
24
24
|
|
25
|
-
s.required_ruby_version = Gem::Requirement.new(">=
|
25
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
26
26
|
s.add_runtime_dependency 'ffi', '~> 1.0'
|
27
27
|
s.add_runtime_dependency 'mini_portile2', LIBUSB::MINI_PORTILE_VERSION
|
28
|
-
s.add_development_dependency 'rake-compiler', '~> 1.0'
|
29
|
-
s.add_development_dependency 'rake-compiler-dock', '~> 0.2'
|
30
|
-
s.add_development_dependency 'bundler', '~> 1.0'
|
31
|
-
s.add_development_dependency 'yard', '~> 0.6'
|
32
28
|
end
|
data/test/test_libusb_bos.rb
CHANGED
@@ -53,6 +53,23 @@ class TestLibusbBos < Minitest::Test
|
|
53
53
|
:BT_USB_2_0_EXTENSION,
|
54
54
|
:BT_SS_USB_DEVICE_CAPABILITY,
|
55
55
|
:BT_CONTAINER_ID,
|
56
|
+
:BT_WIRELESS_USB_DEVICE_CAPABILITY,
|
57
|
+
:BT_USB_2_0_EXTENSION,
|
58
|
+
:BT_SS_USB_DEVICE_CAPABILITY,
|
59
|
+
:BT_CONTAINER_ID,
|
60
|
+
:BT_PLATFORM_DESCRIPTOR,
|
61
|
+
:BT_POWER_DELIVERY_CAPABILITY,
|
62
|
+
:BT_BATTERY_INFO_CAPABILITY,
|
63
|
+
:BT_PD_CONSUMER_PORT_CAPABILITY,
|
64
|
+
:BT_PD_PROVIDER_PORT_CAPABILITY,
|
65
|
+
:BT_SUPERSPEED_PLUS,
|
66
|
+
:BT_PRECISION_TIME_MEASUREMENT,
|
67
|
+
:BT_Wireless_USB_Ext,
|
68
|
+
:BT_BILLBOARD,
|
69
|
+
:BT_AUTHENTICATION,
|
70
|
+
:BT_BILLBOARD_EX,
|
71
|
+
:BT_CONFIGURATION_SUMMARY,
|
72
|
+
:BT_FWStatus_Capability,
|
56
73
|
], :include?, cap_type
|
57
74
|
end
|
58
75
|
|
@@ -90,6 +107,11 @@ class TestLibusbBos < Minitest::Test
|
|
90
107
|
assert_operator 0, :<=, cap.bReserved
|
91
108
|
assert_operator 16, :==, cap.container_id.bytesize, "container_id should be 16 bytes long"
|
92
109
|
|
110
|
+
when Bos::PlatformDescriptor
|
111
|
+
assert_operator 0, :<=, cap.bReserved
|
112
|
+
assert_operator 16, :==, cap.platformCapabilityUUID.bytesize, "container_id should be 16 bytes long"
|
113
|
+
assert_kind_of String, cap.capabilityData
|
114
|
+
|
93
115
|
else
|
94
116
|
refute true, "invalid device capability class"
|
95
117
|
end
|
@@ -21,11 +21,18 @@ class TestLibusbBulkStreamTransfer < Minitest::Test
|
|
21
21
|
|
22
22
|
def setup
|
23
23
|
c = Context.new
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
c.devices.each do |dev|
|
25
|
+
if [:SPEED_SUPER, :SPEED_SUPER_PLUS].include?(dev.device_speed)
|
26
|
+
dev.endpoints.each do |ep|
|
27
|
+
if ep.transfer_type == :bulk
|
28
|
+
ss = ep.ss_companion
|
29
|
+
if ss.bmAttributes & 0x1f > 0
|
30
|
+
@dev = dev.open
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
@@ -34,17 +41,21 @@ class TestLibusbBulkStreamTransfer < Minitest::Test
|
|
34
41
|
end
|
35
42
|
|
36
43
|
def test_alloc_streams
|
37
|
-
|
38
|
-
nr_allocated = @dev.alloc_streams( 2, @dev.device.endpoints )
|
39
|
-
end
|
44
|
+
skip "no device found with bulk stream support" unless @dev
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
46
|
+
nr_allocated = @dev.alloc_streams( 2, @dev.device.endpoints )
|
47
|
+
assert_equal 2, nr_allocated
|
48
|
+
|
49
|
+
# TODO: test with a OS that supports bulk streams and against a real device
|
50
|
+
|
51
|
+
@dev.free_streams( [0x01,0x82] )
|
44
52
|
end
|
45
53
|
|
46
54
|
def test_bulk_stream_transfer
|
47
|
-
|
55
|
+
c = Context.new
|
56
|
+
dev = c.devices.first.open
|
57
|
+
tr = BulkStreamTransfer.new dev_handle: dev, stream_id: 123, buffer: ' '*100
|
48
58
|
assert_equal 123, tr.stream_id, "stream_id should match"
|
59
|
+
dev.close
|
49
60
|
end
|
50
61
|
end
|