libusb 0.6.0-x86-linux

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +17 -0
  4. data/.yardopts +6 -0
  5. data/COPYING +165 -0
  6. data/Gemfile +11 -0
  7. data/History.md +124 -0
  8. data/README.md +159 -0
  9. data/Rakefile +145 -0
  10. data/appveyor.yml +23 -0
  11. data/lib/libusb.rb +58 -0
  12. data/lib/libusb/bos.rb +306 -0
  13. data/lib/libusb/call.rb +446 -0
  14. data/lib/libusb/compat.rb +376 -0
  15. data/lib/libusb/configuration.rb +155 -0
  16. data/lib/libusb/constants.rb +160 -0
  17. data/lib/libusb/context.rb +426 -0
  18. data/lib/libusb/dependencies.rb +7 -0
  19. data/lib/libusb/dev_handle.rb +564 -0
  20. data/lib/libusb/device.rb +365 -0
  21. data/lib/libusb/endpoint.rb +194 -0
  22. data/lib/libusb/eventmachine.rb +183 -0
  23. data/lib/libusb/interface.rb +60 -0
  24. data/lib/libusb/setting.rb +132 -0
  25. data/lib/libusb/ss_companion.rb +69 -0
  26. data/lib/libusb/stdio.rb +25 -0
  27. data/lib/libusb/transfer.rb +377 -0
  28. data/lib/libusb/version_gem.rb +19 -0
  29. data/lib/libusb/version_struct.rb +63 -0
  30. data/libusb.gemspec +30 -0
  31. data/test/test_libusb_bos.rb +118 -0
  32. data/test/test_libusb_bulk_stream_transfer.rb +50 -0
  33. data/test/test_libusb_capability.rb +23 -0
  34. data/test/test_libusb_compat.rb +78 -0
  35. data/test/test_libusb_compat_mass_storage.rb +81 -0
  36. data/test/test_libusb_descriptors.rb +212 -0
  37. data/test/test_libusb_event_machine.rb +118 -0
  38. data/test/test_libusb_gc.rb +37 -0
  39. data/test/test_libusb_hotplug.rb +127 -0
  40. data/test/test_libusb_iso_transfer.rb +50 -0
  41. data/test/test_libusb_mass_storage.rb +268 -0
  42. data/test/test_libusb_mass_storage2.rb +96 -0
  43. data/test/test_libusb_structs.rb +58 -0
  44. data/test/test_libusb_threads.rb +89 -0
  45. data/test/test_libusb_version.rb +40 -0
  46. data/wireshark-usb-sniffer.png +0 -0
  47. metadata +150 -0
data/Rakefile ADDED
@@ -0,0 +1,145 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -*- ruby -*-
3
+
4
+ require 'bundler/gem_tasks'
5
+ require 'rubygems/package_task'
6
+ require 'pathname'
7
+ require 'uri'
8
+ require 'ostruct'
9
+ require 'rake/clean'
10
+ require 'rake_compiler_dock'
11
+ require_relative 'ext/libusb_recipe'
12
+
13
+ task :gem => :build
14
+ task :compile do
15
+ sh "ruby ext/extconf.rb --disable-system-libusb"
16
+ end
17
+
18
+ task :test=>:compile do
19
+ sh "ruby -w -W2 -I. -Ilib -e \"#{Dir["test/test_*.rb"].map{|f| "require '#{f}';"}.join}\" -- -v"
20
+ end
21
+
22
+ travis_tests = %w[test_libusb_capability.rb test_libusb_structs.rb test_libusb_version.rb]
23
+ task :travis=>:compile do
24
+ sh "ruby -w -W2 -I. -Ilib -e \"#{travis_tests.map{|f| "require 'test/#{f}';"}.join}\" -- -v"
25
+ end
26
+ task :default => :test
27
+
28
+ task "release:tag" do
29
+ hfile = "History.md"
30
+ version = LIBUSB::VERSION
31
+ reldate = Time.now.strftime("%Y-%m-%d")
32
+ headline = '([^\w]*)(\d+\.\d+\.\d+)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)'
33
+
34
+ hin = File.read(hfile)
35
+ hout = hin.sub(/#{headline}/) do
36
+ raise "#{hfile} isn't up-to-date for version #{version}" unless $2==version
37
+ $1 + $2 + $3 + reldate + $5
38
+ end
39
+ if hout != hin
40
+ Bundler.ui.confirm "Updating #{hfile} for release."
41
+ File.write(hfile, hout)
42
+ sh "git", "commit", hfile, "-m", "Update release date in #{hfile}"
43
+ end
44
+
45
+ Bundler.ui.confirm "Tag release with annotation:"
46
+ m = hout.match(/(?<annotation>#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}")
47
+ Bundler.ui.info(m[:annotation].gsub(/^/, " "))
48
+ IO.popen(["git", "tag", "--file=-", version], "w") do |fd|
49
+ fd.write m[:annotation]
50
+ end
51
+ end
52
+
53
+ task "release:guard_clean" => "release:tag"
54
+
55
+ task "release:rubygem_push" => "gem:native" do
56
+ CrossLibraries.each do |ruby_platform, _|
57
+ gh = Bundler::GemHelper.new
58
+ gh.rubygem_push(gh.spec_path.gsub(".gem", "-#{ruby_platform}.gem"))
59
+ end
60
+ end
61
+
62
+ task 'gem:native' do
63
+ sh "bundle package"
64
+ RakeCompilerDock.sh <<-EOT
65
+ bundle --local &&
66
+ rake cross gem
67
+ EOT
68
+ end
69
+
70
+ class CrossLibrary < OpenStruct
71
+ include Rake::DSL
72
+
73
+ def initialize(ruby_platform, host_platform, libusb_dllname)
74
+ super()
75
+
76
+ self.ruby_platform = ruby_platform
77
+ self.recipe = LibusbRecipe.new
78
+ recipe.host = host_platform
79
+ recipe.configure_options << "--host=#{recipe.host}"
80
+ self.libusb_dll = Pathname.new(recipe.path) + libusb_dllname
81
+
82
+ file libusb_dll do
83
+ recipe.cook
84
+ end
85
+
86
+ task "libusb_dll:#{ruby_platform}" => libusb_dll
87
+
88
+ desc 'Cross compile libusb for win32'
89
+ task :cross => [ "libusb_dll:#{ruby_platform}" ] do |t|
90
+ spec = Gem::Specification::load("libusb.gemspec").dup
91
+ spec.platform = Gem::Platform.new(ruby_platform)
92
+ spec.extensions = []
93
+
94
+ # Remove files unnecessary for native gems
95
+ spec.files -= `git ls-files ext`.split("\n")
96
+ spec.files.reject!{|f| f.start_with?('ports') }
97
+ spec_text_files = spec.files.dup
98
+
99
+ # Add native libusb-dll
100
+ spec.files << "lib/#{libusb_dll.basename}"
101
+
102
+ # MiniPortile isn't required for native gems
103
+ spec.dependencies.reject!{|d| d.name=="mini_portile2" }
104
+
105
+ # Generate a package for this gem
106
+ pkg = Gem::PackageTask.new(spec) do |pkg|
107
+ pkg.need_zip = false
108
+ pkg.need_tar = false
109
+ # Do not copy any files per PackageTask, because
110
+ # we need the files from the platform specific directory
111
+ pkg.package_files.clear
112
+ end
113
+
114
+ # copy files of the gem to pkg directory
115
+ file pkg.package_dir_path => spec_text_files do
116
+ spec_text_files.each do |fn|
117
+ f = File.join(pkg.package_dir_path, fn)
118
+ fdir = File.dirname(f)
119
+ mkdir_p(fdir) if !File.exist?(fdir)
120
+ rm_f f
121
+ safe_ln(fn, f)
122
+ end
123
+
124
+ # copy libusb.dll to pkg directory
125
+ f = "#{pkg.package_dir_path}/lib/#{libusb_dll.basename}"
126
+ mkdir_p File.dirname(f)
127
+ rm_f f
128
+ safe_ln libusb_dll.realpath, f
129
+ end
130
+
131
+ file "lib/#{libusb_dll.basename}" => [libusb_dll]
132
+ end
133
+ end
134
+ end
135
+
136
+ CrossLibraries = [
137
+ ['i386-mingw32', 'i686-w64-mingw32', 'bin/libusb-1.0.dll'],
138
+ ['x64-mingw32', 'x86_64-w64-mingw32', 'bin/libusb-1.0.dll'],
139
+ ['x86-linux', 'i686-linux-gnu', 'lib/libusb-1.0.so'],
140
+ ['x86_64-linux', 'x86_64-linux-gnu', 'lib/libusb-1.0.so'],
141
+ ].each do |ruby_platform, host_platform, libusb_dll|
142
+ CrossLibrary.new ruby_platform, host_platform, libusb_dll
143
+ end
144
+
145
+ # vim: syntax=ruby
data/appveyor.yml ADDED
@@ -0,0 +1,23 @@
1
+ init:
2
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
3
+ - SET PATH=C:\MinGW\msys\1.0\bin;%PATH%
4
+ - SET RAKEOPT=-rdevkit
5
+ install:
6
+ - ruby --version
7
+ - gem --version
8
+ - bundle install
9
+ build_script:
10
+ - bundle exec rake compile
11
+ test_script:
12
+ - bundle exec rake travis
13
+ environment:
14
+ matrix:
15
+ - ruby_version: "193"
16
+ - ruby_version: "200"
17
+ - ruby_version: "200-x64"
18
+ - ruby_version: "21"
19
+ - ruby_version: "21-x64"
20
+ - ruby_version: "22"
21
+ - ruby_version: "22-x64"
22
+ - ruby_version: "23"
23
+ - ruby_version: "23-x64"
data/lib/libusb.rb ADDED
@@ -0,0 +1,58 @@
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
+ require 'libusb/call'
18
+ require 'libusb/constants'
19
+ require 'libusb/context'
20
+ autoload :VERSION, 'libusb/version_gem'
21
+ autoload :Version, 'libusb/version_struct'
22
+ autoload :Configuration, 'libusb/configuration'
23
+ autoload :DevHandle, 'libusb/dev_handle'
24
+ autoload :Device, 'libusb/device'
25
+ autoload :Endpoint, 'libusb/endpoint'
26
+ autoload :Interface, 'libusb/interface'
27
+ autoload :Setting, 'libusb/setting'
28
+ autoload :SsCompanion, 'libusb/ss_companion'
29
+ autoload :Stdio, 'libusb/stdio'
30
+ autoload :Bos, 'libusb/bos'
31
+ %w[ Transfer BulkTransfer BulkStreamTransfer ControlTransfer InterruptTransfer IsoPacket IsochronousTransfer ].each do |klass|
32
+ autoload klass, 'libusb/transfer'
33
+ end
34
+
35
+ if Call.respond_to?(:libusb_get_version)
36
+ # Get version of the underlying libusb library.
37
+ # Available since libusb-1.0.10.
38
+ # @return [Version] version object
39
+ def self.version
40
+ Version.new(Call.libusb_get_version)
41
+ end
42
+ end
43
+
44
+ if Call.respond_to?(:libusb_has_capability)
45
+ # Check at runtime if the loaded library has a given capability.
46
+ # Available since libusb-1.0.9.
47
+ # @param [Symbol] capability the {Call::Capabilities Capabilities} symbol to check for
48
+ # @return [Boolean] +true+ if the running library has the capability, +false+ otherwise
49
+ def self.has_capability?(capability)
50
+ r = Call.libusb_has_capability(capability)
51
+ return r != 0
52
+ end
53
+ else
54
+ def self.has_capability?(capability)
55
+ false
56
+ end
57
+ end
58
+ end
data/lib/libusb/bos.rb ADDED
@@ -0,0 +1,306 @@
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
+ # A structure representing the Binary Device Object Store (BOS) descriptor.
20
+ # This descriptor is documented in section 9.6.2 of the USB 3.0 specification.
21
+ # All multiple-byte fields are represented in host-endian format.
22
+ class Bos < FFI::ManagedStruct
23
+
24
+ module GenericMethods
25
+ # @return [Integer] Size of this descriptor (in bytes)
26
+ def bLength
27
+ self[:bLength]
28
+ end
29
+
30
+ # @return [Integer] Descriptor type. Will have value LIBUSB::DT_DEVICE_CAPABILITY
31
+ # in this context.
32
+ def bDescriptorType
33
+ self[:bDescriptorType]
34
+ end
35
+
36
+ # @return [Integer] Device Capability type
37
+ def bDevCapabilityType
38
+ self[:bDevCapabilityType]
39
+ end
40
+
41
+ def inspect
42
+ "\#<#{self.class} cap: #{bDevCapabilityType} data: #{dev_capability_data.unpack("H*")[0]}>"
43
+ end
44
+
45
+ # @return [String] Device Capability data (bLength - 3 bytes)
46
+ def dev_capability_data
47
+ pointer.read_bytes(bLength - 3)
48
+ end
49
+ end
50
+
51
+ # A generic representation of a BOS Device Capability descriptor.
52
+ class DeviceCapability < FFI::Struct
53
+ include GenericMethods
54
+
55
+ layout :bLength, :uint8,
56
+ :bDescriptorType, :uint8,
57
+ :bDevCapabilityType, :uint8
58
+
59
+ def initialize( bos, *args)
60
+ # Avoid that the bos struct is GC'ed before this instance
61
+ @bos = bos
62
+ super(*args)
63
+ end
64
+ end
65
+
66
+ # A structure representing the USB 2.0 Extension descriptor
67
+ # This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification.
68
+ # All multiple-byte fields are represented in host-endian format.
69
+ class Usb20Extension < FFI::ManagedStruct
70
+ include GenericMethods
71
+
72
+ layout :bLength, :uint8,
73
+ :bDescriptorType, :uint8,
74
+ :bDevCapabilityType, :uint8,
75
+ :bmAttributes, :uint32
76
+
77
+ # Bitmap encoding of supported device level features.
78
+ # A value of one in a bit location indicates a feature is
79
+ # supported; a value of zero indicates it is not supported.
80
+ # @see Call::Usb20ExtensionAttributes
81
+ def bmAttributes
82
+ self[:bmAttributes]
83
+ end
84
+
85
+ # @return [Boolean] Supports Link Power Management (LPM)
86
+ def bm_lpm_support?
87
+ (bmAttributes & BM_LPM_SUPPORT) != 0
88
+ end
89
+
90
+ def inspect
91
+ attrs = Call::Usb20ExtensionAttributes.to_h.map do |k, v|
92
+ (bmAttributes & v) ? k.to_s : nil
93
+ end
94
+ "\#<#{self.class} #{attrs.compact.join(",")}>"
95
+ end
96
+
97
+ # @private
98
+ def self.release(ptr)
99
+ Call.libusb_free_usb_2_0_extension_descriptor(ptr)
100
+ end
101
+ end
102
+
103
+ # A structure representing the SuperSpeed USB Device Capability descriptor
104
+ # This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
105
+ # All multiple-byte fields are represented in host-endian format.
106
+ class SsUsbDeviceCapability < FFI::ManagedStruct
107
+ include GenericMethods
108
+
109
+ layout :bLength, :uint8,
110
+ :bDescriptorType, :uint8,
111
+ :bDevCapabilityType, :uint8,
112
+ :bmAttributes, :uint32,
113
+ :wSpeedSupported, :uint16,
114
+ :bFunctionalitySupport, :uint8,
115
+ :bU1DevExitLat, :uint8,
116
+ :bU2DevExitLat, :uint16
117
+
118
+ # Bitmap encoding of supported device level features.
119
+ # A value of one in a bit location indicates a feature is
120
+ # supported; a value of zero indicates it is not supported.
121
+ #
122
+ # @return [Integer]
123
+ # @see Call::SsUsbDeviceCapabilityAttributes
124
+ def bmAttributes
125
+ self[:bmAttributes]
126
+ end
127
+
128
+ # @return [Boolean] Supports Latency Tolerance Messages (LTM)
129
+ def bm_ltm_support?
130
+ (bmAttributes & BM_LTM_SUPPORT) != 0
131
+ end
132
+
133
+ def inspect
134
+ attrs = Call::SsUsbDeviceCapabilityAttributes.to_h.map do |k,v|
135
+ (bmAttributes & v) != 0 ? k.to_s : nil
136
+ end
137
+ "\#<#{self.class} #{attrs.compact.join(",")} #{supported_speeds.join(",")}>"
138
+ end
139
+
140
+ # Bitmap encoding of the speed supported by this device when
141
+ # operating in SuperSpeed mode.
142
+ #
143
+ # @return [Integer]
144
+ # @see Call::SupportedSpeeds
145
+ def wSpeedSupported
146
+ self[:wSpeedSupported]
147
+ end
148
+
149
+ # @return [Array<Symbol>] speeds supported by this device when
150
+ # operating in SuperSpeed mode {Call::SupportedSpeeds}
151
+ def supported_speeds
152
+ speeds = Call::SupportedSpeeds.to_h.map do |k,v|
153
+ (wSpeedSupported & v) != 0 ? k : nil
154
+ end
155
+ speeds.compact
156
+ end
157
+
158
+ # The lowest speed at which all the functionality supported
159
+ # by the device is available to the user. For example if the
160
+ # device supports all its functionality when connected at
161
+ # full speed and above then it sets this value to 1.
162
+ #
163
+ # 0 - low speed
164
+ # 1 - full speed
165
+ # 2 - high speed
166
+ # 3 - super speed
167
+ # @return [Integer]
168
+ def bFunctionalitySupport
169
+ self[:bFunctionalitySupport]
170
+ end
171
+
172
+ # @return [Integer] U1 Device Exit Latency.
173
+ def bU1DevExitLat
174
+ self[:bU1DevExitLat]
175
+ end
176
+
177
+ # @return [Integer] U2 Device Exit Latency.
178
+ def bU2DevExitLat
179
+ self[:bU2DevExitLat]
180
+ end
181
+
182
+ # @private
183
+ def self.release(ptr)
184
+ Call.libusb_free_ss_usb_device_capability_descriptor(ptr)
185
+ end
186
+ end
187
+
188
+ # A structure representing the Container ID descriptor.
189
+ # This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification.
190
+ # All multiple-byte fields, except UUIDs, are represented in host-endian format.
191
+ class ContainerId < FFI::ManagedStruct
192
+ include GenericMethods
193
+
194
+ layout :bLength, :uint8,
195
+ :bDescriptorType, :uint8,
196
+ :bDevCapabilityType, :uint8,
197
+ :bReserved, :uint8,
198
+ :ContainerID, [:uint8, 16]
199
+
200
+ # Reserved field
201
+ def bReserved
202
+ self[:bReserved]
203
+ end
204
+
205
+ # @return [String] 128 bit UUID
206
+ def container_id
207
+ self[:ContainerID].to_ptr.read_bytes(16)
208
+ end
209
+
210
+ def inspect
211
+ "\#<#{self.class} #{container_id.unpack("H*")[0]}>"
212
+ end
213
+
214
+ # @private
215
+ def self.release(ptr)
216
+ Call.libusb_free_container_id_descriptor(ptr)
217
+ end
218
+ end
219
+
220
+ def initialize( ctx, *args)
221
+ @ctx = ctx
222
+ super(*args)
223
+ end
224
+
225
+ layout :bLength, :uint8,
226
+ :bDescriptorType, :uint8,
227
+ :wTotalLength, :uint16,
228
+ :bNumDeviceCaps, :uint8,
229
+ :dev_capability, [:pointer, 0]
230
+
231
+ # @return [Integer] Size of this descriptor (in bytes)
232
+ def bLength
233
+ self[:bLength]
234
+ end
235
+
236
+ # @return [Integer] Descriptor type. Will have value LIBUSB::DT_BOS LIBUSB_DT_BOS
237
+ # in this context.
238
+ def bDescriptorType
239
+ self[:bDescriptorType]
240
+ end
241
+
242
+ # @return [Integer] Length of this descriptor and all of its sub descriptors
243
+ def wTotalLength
244
+ self[:wTotalLength]
245
+ end
246
+
247
+ # @return [Integer] The number of separate device capability descriptors in
248
+ # the BOS
249
+ def bNumDeviceCaps
250
+ self[:bNumDeviceCaps]
251
+ end
252
+
253
+ # bNumDeviceCap Device Capability Descriptors
254
+ #
255
+ # @return [Array<Bos::DeviceCapability, Bos::Usb20Extension, Bos::SsUsbDeviceCapability, Bos::ContainerId>]
256
+ def device_capabilities
257
+ pp_ext = FFI::MemoryPointer.new :pointer
258
+ caps = []
259
+ # Capabilities are appended to the bos header
260
+ ptr = pointer + offset_of(:dev_capability)
261
+ bNumDeviceCaps.times do
262
+ cap = DeviceCapability.new self, ptr.read_pointer
263
+ case cap.bDevCapabilityType
264
+ when LIBUSB::BT_WIRELESS_USB_DEVICE_CAPABILITY
265
+ # no struct defined in libusb -> use generic DeviceCapability
266
+ when LIBUSB::BT_USB_2_0_EXTENSION
267
+ res = Call.libusb_get_usb_2_0_extension_descriptor(@ctx, cap.pointer, pp_ext)
268
+ cap = Usb20Extension.new(pp_ext.read_pointer) if res==0
269
+ when LIBUSB::BT_SS_USB_DEVICE_CAPABILITY
270
+ res = Call.libusb_get_ss_usb_device_capability_descriptor(@ctx, cap.pointer, pp_ext)
271
+ cap = SsUsbDeviceCapability.new(pp_ext.read_pointer) if res==0
272
+ when LIBUSB::BT_CONTAINER_ID
273
+ res = Call.libusb_get_container_id_descriptor(@ctx, cap.pointer, pp_ext)
274
+ cap = ContainerId.new(pp_ext.read_pointer) if res==0
275
+ else
276
+ # unknown capability -> use generic DeviceCapability
277
+ end
278
+ ptr += FFI.type_size(:pointer)
279
+ caps << cap
280
+ end
281
+ caps
282
+ end
283
+
284
+ # @return [Array<Symbol>] Types of Capabilities
285
+ #
286
+ # @see Call::BosTypes
287
+ def device_capability_types
288
+ # Capabilities are appended to the bos header
289
+ ptr = pointer + offset_of(:dev_capability)
290
+ bNumDeviceCaps.times.map do
291
+ cap = DeviceCapability.new self, ptr.read_pointer
292
+ ptr += FFI.type_size(:pointer)
293
+ Call::BosTypes.find cap.bDevCapabilityType
294
+ end
295
+ end
296
+
297
+ def inspect
298
+ "\#<#{self.class} #{device_capability_types.join(", ")}>"
299
+ end
300
+
301
+ # @private
302
+ def self.release(ptr)
303
+ Call.libusb_free_bos_descriptor(ptr)
304
+ end
305
+ end
306
+ end