libusb 0.1.3-x86-mingw32 → 0.2.0-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --title "libusb-1.0 Ruby Interface" --no-private lib/**/*.rb
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ === 0.2.0 / 2012-06-15
2
+
3
+ * Divide up the libusb library across multiple files, required with autoload
4
+ * add methods: LIBUSB.has_capability?, Device#device_speed (libusb-1.0.9+)
5
+ * add possibility to read out libusb version: LIBUSB.version (libusbx-1.0.10+)
6
+ * add methods: Device#parent, Device#port_number, Device#port_path (libusbx-1.0.12+)
7
+ * switch to libusbx-1.0.12 for windows build
8
+
1
9
  === 0.1.3 / 2012-03-15
2
10
 
3
11
  * Add documentation of descriptor accessors
data/Manifest.txt CHANGED
@@ -1,16 +1,3 @@
1
- .autotest
2
- .gemtest
3
- COPYING
4
- History.txt
5
- Manifest.txt
6
- README.rdoc
7
- Rakefile
1
+ # List of files is auto generated by 'git ls-files',
2
+ # but let Hoe find the VERSION string:
8
3
  lib/libusb.rb
9
- lib/libusb/compat.rb
10
- test/test_libusb_compat.rb
11
- test/test_libusb_compat_mass_storage.rb
12
- test/test_libusb_descriptors.rb
13
- test/test_libusb_gc.rb
14
- test/test_libusb_iso_transfer.rb
15
- test/test_libusb_mass_storage.rb
16
- test/test_libusb_mass_storage2.rb
data/README.rdoc CHANGED
@@ -3,14 +3,13 @@
3
3
  = Access USB devices from Ruby via libusb-1.0.
4
4
 
5
5
  * http://github.com/larskanis/libusb
6
- * API documentation: http://rubydoc.info/gems/libusb/frames
7
6
 
8
7
  == DESCRIPTION:
9
8
 
10
- LIBUSB is a Ruby binding that gives a Ruby programmer access to all functionality of libusb[http://www.libusb.org], version 1.0.
9
+ LIBUSB is a Ruby binding that gives Ruby programmers access to arbitrary USB devices.
11
10
 
12
- * libusb is a library that gives full access to devices connected via the USB bus. No special kernel driver is thus necessary for accessing USB devices.
13
- * This Ruby binding supports the API version 1.0 of libusb. Note that the old "legacy" version 0.1.x of libusb uses a completely different API that is covered by the ruby extension ruby-usb[http://www.a-k-r.org/ruby-usb/] . LIBUSB has a compatibility API to ruby-usb[http://www.a-k-r.org/ruby-usb/].
11
+ * libusb[http://libusbx.org] is a library that gives full access to devices connected via the USB bus. No special kernel driver is thus necessary for accessing USB devices.
12
+ * This Ruby binding supports the API version 1.0 of libusb[http://libusbx.org]. Note that the old "legacy" version 0.1.x of libusb uses a completely different API that is covered by the ruby extension ruby-usb[http://www.a-k-r.org/ruby-usb/] .
14
13
 
15
14
 
16
15
  LIBUSB for Ruby is covered by the GNU Lesser General Public License version 3.
@@ -26,13 +25,11 @@ LIBUSB for Ruby is covered by the GNU Lesser General Public License version 3.
26
25
 
27
26
  usb = LIBUSB::Context.new
28
27
  device = usb.devices(:idVendor => 0x04b4, :idProduct => 0x8613).first
29
- device.open do |handle|
30
- handle.claim_interface(0) do
31
- handle.control_transfer(:bmRequestType => 0x40, :bRequest => 0xa0, :wValue => 0xe600, :wIndex => 0x0000, :dataOut => 1.chr)
32
- end
28
+ device.open_interface(0) do |handle|
29
+ handle.control_transfer(:bmRequestType => 0x40, :bRequest => 0xa0, :wValue => 0xe600, :wIndex => 0x0000, :dataOut => 1.chr)
33
30
  end
34
31
  {LIBUSB::Context#devices} is used to get all or only particular devices.
35
- After opening the {LIBUSB::Device} the resulting {LIBUSB::DevHandle} can be
32
+ After {LIBUSB::Device#open_interface opening and claiming} the {LIBUSB::Device} the resulting {LIBUSB::DevHandle} can be
36
33
  used to communicate with the connected USB device
37
34
  by {LIBUSB::DevHandle#control_transfer}, {LIBUSB::DevHandle#bulk_transfer},
38
35
  {LIBUSB::DevHandle#interrupt_transfer} or by using the {LIBUSB::Transfer} classes.
@@ -55,17 +52,20 @@ maximum packet size.
55
52
 
56
53
  == REQUIREMENTS:
57
54
 
58
- * libusb version 1.0 or greater (bundled with Windows binary gem)
59
- * FFI-gem[http://github.com/ffi/ffi]
60
55
  * Linux, MacOSX or Windows system with Ruby MRI 1.8.7/1.9.x or JRuby
61
56
 
62
57
  == INSTALL:
63
58
 
64
59
  gem install libusb
65
60
 
66
- In order to use LIBUSB, you need the libusb-1.0 library (but not its header files).
67
- * On Debian and Ubuntu system, install the +libusb-1.0-0+ package.
68
- * The gem for Windows comes with a precompiled +libusb.dll+, so there is no need for a compiler.
61
+ In order to use LIBUSB, you also need the libusb-1.0[http://libusbx.org] library (but not necessarily its header files).
62
+ * Debian or Ubuntu:
63
+ sudo apt-get install libusb-1.0-0
64
+ * OS-X: install with homebrew:
65
+ brew install libusb
66
+ or macports:
67
+ port install libusb
68
+ * Windows: libusb.gem comes with a precompiled +libusb.dll+, but you need to install a device driver (see below)
69
69
 
70
70
  Latest code can be used in this way:
71
71
 
@@ -77,8 +77,8 @@ Latest code can be used in this way:
77
77
 
78
78
  In contrast to Linux, any access to an USB device by LIBUSB on Windows requires a proper driver
79
79
  installed in the system. Fortunately creating such a driver is quite easy with
80
- Zadig[http://sourceforge.net/apps/mediawiki/libwdi/index.php?title=Main_Page]. Select the interesting USB device
81
- and press "Install Driver". That's it. You may take the generated output directory
80
+ Zadig[http://sourceforge.net/apps/mediawiki/libwdi/index.php?title=Main_Page]. Select the interesting USB device,
81
+ choose WinUSB driver and press "Install Driver". That's it. You may take the generated output directory
82
82
  with it's INI-file and use it for driver installation on other 32 or 64 bit Windows
83
83
  systems.
84
84
 
@@ -104,6 +104,12 @@ Download and cross compile libusb for win32:
104
104
  If everything works, there should be libusb-VERSION-x86-mingw32.gem in the pkg
105
105
  directory.
106
106
 
107
+ == Resources
108
+
109
+ * API documentation of Libusb for Ruby: http://rubydoc.info/gems/libusb/frames
110
+ * Mailinglist: http://rubyforge.org/mailman/listinfo/libusb-hackers
111
+ * Overall introduction to USB: http://www.usbmadesimple.co.uk
112
+
107
113
  == Todo
108
114
 
109
115
  * add proper handling for polling and timing: http://libusb.sourceforge.net/api-1.0/group__poll.html
data/Rakefile CHANGED
@@ -13,9 +13,16 @@ require 'rake/extensioncompiler'
13
13
  COMPILE_HOME = Pathname( "./tmp" ).expand_path
14
14
  STATIC_SOURCESDIR = COMPILE_HOME + 'sources'
15
15
  STATIC_BUILDDIR = COMPILE_HOME + 'builds'
16
+ RUBY_BUILD = RbConfig::CONFIG["host"]
17
+ CROSS_PREFIX = begin
18
+ Rake::ExtensionCompiler.mingw_host
19
+ rescue => err
20
+ $stderr.puts "Cross-compilation disabled -- %s" % [ err.message ]
21
+ 'unknown'
22
+ end
16
23
 
17
24
  # Fetch tarball from sourceforge
18
- # LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '1.0.8'
25
+ # LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '1.0.9'
19
26
  # LIBUSB_SOURCE_URI = URI( "http://downloads.sourceforge.net/project/libusb/libusb-1.0/libusb-#{LIBUSB_VERSION}/libusb-#{LIBUSB_VERSION}.tar.bz2" )
20
27
  # LIBUSB_TARBALL = STATIC_SOURCESDIR + File.basename( LIBUSB_SOURCE_URI.path )
21
28
 
@@ -24,10 +31,15 @@ STATIC_BUILDDIR = COMPILE_HOME + 'builds'
24
31
  # LIBUSB_SOURCE_URI = URI( "http://git.libusb.org/?p=libusb.git;a=snapshot;h=#{LIBUSB_VERSION};sf=tbz2" )
25
32
  # LIBUSB_TARBALL = STATIC_SOURCESDIR + "libusb-#{LIBUSB_VERSION}.tar.bz2"
26
33
 
34
+ # Fetch tarball from libusbx
35
+ LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '1.0.12'
36
+ LIBUSB_SOURCE_URI = URI( "http://downloads.sourceforge.net/project/libusbx/releases/#{LIBUSB_VERSION[/^\d+\.\d+\.\d+/]}/source/libusbx-#{LIBUSB_VERSION}.tar.bz2" )
37
+ LIBUSB_TARBALL = STATIC_SOURCESDIR + File.basename( LIBUSB_SOURCE_URI.path )
38
+
27
39
  # Fetch tarball from Pete Batard's git repo
28
- LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '4cc72d0'
29
- LIBUSB_SOURCE_URI = URI( "http://git.libusb.org/?p=libusb-pbatard.git;a=snapshot;h=#{LIBUSB_VERSION};sf=tbz2" )
30
- LIBUSB_TARBALL = STATIC_SOURCESDIR + "libusb-pbatard-#{LIBUSB_VERSION}.tar.bz2"
40
+ # LIBUSB_VERSION = ENV['LIBUSB_VERSION'] || '4cc72d0'
41
+ # LIBUSB_SOURCE_URI = URI( "http://git.libusb.org/?p=libusb-pbatard.git;a=snapshot;h=#{LIBUSB_VERSION};sf=tbz2" )
42
+ # LIBUSB_TARBALL = STATIC_SOURCESDIR + "libusb-pbatard-#{LIBUSB_VERSION}.tar.bz2"
31
43
 
32
44
  # Static libusb build vars
33
45
  STATIC_LIBUSB_BUILDDIR = STATIC_BUILDDIR + LIBUSB_TARBALL.basename(".tar.bz2")
@@ -44,10 +56,11 @@ hoe = Hoe.spec 'libusb' do
44
56
 
45
57
  self.url = 'http://github.com/larskanis/libusb'
46
58
  self.summary = 'Access USB devices from Ruby via libusb-1.0'
47
- self.description = 'LIBUSB is a Ruby binding that gives Ruby programmers access to all functionality of libusb, version 1.0'
59
+ self.description = 'LIBUSB is a Ruby binding that gives Ruby programmers access to arbitrary USB devices'
48
60
 
49
61
  self.readme_file = 'README.rdoc'
50
62
  spec_extras[:rdoc_options] = ['--main', readme_file, "--charset=UTF-8"]
63
+ spec_extras[:files] = `git ls-files`.split
51
64
  self.extra_rdoc_files << self.readme_file
52
65
 
53
66
  # clean intermediate files and folders
@@ -87,18 +100,21 @@ file LIBUSB_CONFIGURE => STATIC_LIBUSB_BUILDDIR do |t|
87
100
  end
88
101
  end
89
102
 
103
+ LIBUSB_ENV = [
104
+ "CFLAGS='-fno-omit-frame-pointer'",
105
+ ]
106
+
90
107
  # generate the makefile in a clean build location
91
108
  file LIBUSB_MAKEFILE => LIBUSB_CONFIGURE do |t|
92
109
  Dir.chdir( STATIC_LIBUSB_BUILDDIR ) do
93
110
  options = [
94
- '--target=i386-mingw32',
95
- "--host=#{Rake::ExtensionCompiler.mingw_host}",
96
- "--build=#{RbConfig::CONFIG["host"]}",
111
+ "--target=#{CROSS_PREFIX}",
112
+ "--host=#{CROSS_PREFIX}",
113
+ "--build=#{RUBY_BUILD}",
97
114
  ]
98
115
 
99
116
  configure_path = STATIC_LIBUSB_BUILDDIR + 'configure'
100
- cmd = [ configure_path.to_s, *options ]
101
- sh *cmd
117
+ sh "env #{[LIBUSB_ENV, configure_path.to_s, *options].join(" ")}"
102
118
  end
103
119
  end
104
120
 
data/lib/libusb-1.0.dll CHANGED
Binary file
data/lib/libusb.rb CHANGED
@@ -13,1780 +13,40 @@
13
13
  # You should have received a copy of the GNU Lesser General Public License
14
14
  # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
15
 
16
- require 'rubygems'
17
- require 'ffi'
18
-
19
-
20
16
  module LIBUSB
21
- VERSION = "0.1.3"
22
-
23
- module Call
24
- extend FFI::Library
25
- if RUBY_PLATFORM=~/mingw|mswin/i
26
- bundled_dll = File.join(File.dirname(__FILE__), 'libusb-1.0.dll')
27
- ffi_lib(['libusb-1.0', bundled_dll])
28
- else
29
- ffi_lib 'libusb-1.0'
30
- end
31
-
32
- ClassCodes = enum :libusb_class_code, [
33
- :CLASS_PER_INTERFACE, 0,
34
- :CLASS_AUDIO, 1,
35
- :CLASS_COMM, 2,
36
- :CLASS_HID, 3,
37
- :CLASS_PRINTER, 7,
38
- :CLASS_PTP, 6,
39
- :CLASS_MASS_STORAGE, 8,
40
- :CLASS_HUB, 9,
41
- :CLASS_DATA, 10,
42
- :CLASS_WIRELESS, 0xe0,
43
- :CLASS_APPLICATION, 0xfe,
44
- :CLASS_VENDOR_SPEC, 0xff
45
- ]
46
-
47
- Errors = enum :libusb_error, [
48
- :SUCCESS, 0,
49
- :ERROR_IO, -1,
50
- :ERROR_INVALID_PARAM, -2,
51
- :ERROR_ACCESS, -3,
52
- :ERROR_NO_DEVICE, -4,
53
- :ERROR_NOT_FOUND, -5,
54
- :ERROR_BUSY, -6,
55
- :ERROR_TIMEOUT, -7,
56
- :ERROR_OVERFLOW, -8,
57
- :ERROR_PIPE, -9,
58
- :ERROR_INTERRUPTED, -10,
59
- :ERROR_NO_MEM, -11,
60
- :ERROR_NOT_SUPPORTED, -12,
61
- :ERROR_OTHER, -99,
62
- ]
63
-
64
- # Transfer status codes
65
- TransferStatus = enum :libusb_transfer_status, [
66
- :TRANSFER_COMPLETED,
67
- :TRANSFER_ERROR,
68
- :TRANSFER_TIMED_OUT,
69
- :TRANSFER_CANCELLED,
70
- :TRANSFER_STALL,
71
- :TRANSFER_NO_DEVICE,
72
- :TRANSFER_OVERFLOW,
73
- ]
74
-
75
- # libusb_transfer.flags values
76
- TransferFlags = enum :libusb_transfer_flags, [
77
- :TRANSFER_SHORT_NOT_OK, 1 << 0,
78
- :TRANSFER_FREE_BUFFER, 1 << 1,
79
- :TRANSFER_FREE_TRANSFER, 1 << 2,
80
- ]
81
-
82
- TransferTypes = enum :libusb_transfer_type, [
83
- :TRANSFER_TYPE_CONTROL, 0,
84
- :TRANSFER_TYPE_ISOCHRONOUS, 1,
85
- :TRANSFER_TYPE_BULK, 2,
86
- :TRANSFER_TYPE_INTERRUPT, 3,
87
- ]
88
-
89
- StandardRequests = enum :libusb_standard_request, [
90
- :REQUEST_GET_STATUS, 0x00,
91
- :REQUEST_CLEAR_FEATURE, 0x01,
92
- :REQUEST_SET_FEATURE, 0x03,
93
- :REQUEST_SET_ADDRESS, 0x05,
94
- :REQUEST_GET_DESCRIPTOR, 0x06,
95
- :REQUEST_SET_DESCRIPTOR, 0x07,
96
- :REQUEST_GET_CONFIGURATION, 0x08,
97
- :REQUEST_SET_CONFIGURATION, 0x09,
98
- :REQUEST_GET_INTERFACE, 0x0A,
99
- :REQUEST_SET_INTERFACE, 0x0B,
100
- :REQUEST_SYNCH_FRAME, 0x0C,
101
- ]
102
-
103
- EndpointDirections = enum :libusb_endpoint_direction, [
104
- :ENDPOINT_IN, 0x80,
105
- :ENDPOINT_OUT, 0x00,
106
- ]
107
-
108
- DescriptorTypes = enum :libusb_descriptor_type, [
109
- :DT_DEVICE, 0x01,
110
- :DT_CONFIG, 0x02,
111
- :DT_STRING, 0x03,
112
- :DT_INTERFACE, 0x04,
113
- :DT_ENDPOINT, 0x05,
114
- :DT_HID, 0x21,
115
- :DT_REPORT, 0x22,
116
- :DT_PHYSICAL, 0x23,
117
- :DT_HUB, 0x29,
118
- ]
119
-
120
- RequestTypes = enum :libusb_request_type, [
121
- :REQUEST_TYPE_STANDARD, (0x00 << 5),
122
- :REQUEST_TYPE_CLASS, (0x01 << 5),
123
- :REQUEST_TYPE_VENDOR, (0x02 << 5),
124
- :REQUEST_TYPE_RESERVED, (0x03 << 5),
125
- ]
126
-
127
- RequestRecipients = enum :libusb_request_recipient, [
128
- :RECIPIENT_DEVICE, 0x00,
129
- :RECIPIENT_INTERFACE, 0x01,
130
- :RECIPIENT_ENDPOINT, 0x02,
131
- :RECIPIENT_OTHER, 0x03,
132
- ]
133
-
134
- IsoSyncTypes = enum :libusb_iso_sync_type, [
135
- :ISO_SYNC_TYPE_NONE, 0,
136
- :ISO_SYNC_TYPE_ASYNC, 1,
137
- :ISO_SYNC_TYPE_ADAPTIVE, 2,
138
- :ISO_SYNC_TYPE_SYNC, 3,
139
- ]
140
-
141
-
142
- typedef :pointer, :libusb_context
143
- typedef :pointer, :libusb_device_handle
144
-
145
- attach_function 'libusb_init', [ :pointer ], :int
146
- attach_function 'libusb_exit', [ :pointer ], :void
147
- attach_function 'libusb_set_debug', [:pointer, :int], :void
148
-
149
- attach_function 'libusb_get_device_list', [:pointer, :pointer], :size_t
150
- attach_function 'libusb_free_device_list', [:pointer, :int], :void
151
- attach_function 'libusb_ref_device', [:pointer], :pointer
152
- attach_function 'libusb_unref_device', [:pointer], :void
153
-
154
- attach_function 'libusb_get_device_descriptor', [:pointer, :pointer], :int
155
- attach_function 'libusb_get_active_config_descriptor', [:pointer, :pointer], :int
156
- attach_function 'libusb_get_config_descriptor', [:pointer, :uint8, :pointer], :int
157
- attach_function 'libusb_get_config_descriptor_by_value', [:pointer, :uint8, :pointer], :int
158
- attach_function 'libusb_free_config_descriptor', [:pointer], :void
159
- attach_function 'libusb_get_bus_number', [:pointer], :uint8
160
- attach_function 'libusb_get_device_address', [:pointer], :uint8
161
- attach_function 'libusb_get_max_packet_size', [:pointer, :uint8], :int
162
- attach_function 'libusb_get_max_iso_packet_size', [:pointer, :uint8], :int
163
-
164
- attach_function 'libusb_open', [:pointer, :pointer], :int
165
- attach_function 'libusb_close', [:pointer], :void
166
- attach_function 'libusb_get_device', [:libusb_device_handle], :pointer
167
-
168
- attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int, :blocking=>true
169
- attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
170
- attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int, :blocking=>true
171
-
172
- attach_function 'libusb_open_device_with_vid_pid', [:pointer, :int, :int], :pointer
173
-
174
- attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int, :blocking=>true
175
- attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int, :blocking=>true
176
- attach_function 'libusb_reset_device', [:libusb_device_handle], :int, :blocking=>true
177
-
178
- attach_function 'libusb_kernel_driver_active', [:libusb_device_handle, :int], :int
179
- attach_function 'libusb_detach_kernel_driver', [:libusb_device_handle, :int], :int
180
- attach_function 'libusb_attach_kernel_driver', [:libusb_device_handle, :int], :int
181
-
182
- attach_function 'libusb_get_string_descriptor_ascii', [:pointer, :uint8, :pointer, :int], :int
183
-
184
- attach_function 'libusb_alloc_transfer', [:int], :pointer
185
- attach_function 'libusb_submit_transfer', [:pointer], :int
186
- attach_function 'libusb_cancel_transfer', [:pointer], :int
187
- attach_function 'libusb_free_transfer', [:pointer], :void
188
-
189
- attach_function 'libusb_handle_events', [:libusb_context], :int, :blocking=>true
190
-
191
-
192
- callback :libusb_transfer_cb_fn, [:pointer], :void
193
-
194
- class IsoPacketDescriptor < FFI::Struct
195
- layout :length, :uint,
196
- :actual_length, :uint,
197
- :status, :libusb_transfer_status
198
- end
199
-
200
- # Setup packet for control transfers.
201
- class ControlSetup < FFI::Struct
202
- layout :bmRequestType, :uint8,
203
- :bRequest, :uint8,
204
- :wValue, :uint16,
205
- :wIndex, :uint16,
206
- :wLength, :uint16
207
- end
208
-
209
- class Transfer < FFI::ManagedStruct
210
- layout :dev_handle, :libusb_device_handle,
211
- :flags, :uint8,
212
- :endpoint, :uchar,
213
- :type, :uchar,
214
- :timeout, :uint,
215
- :status, :libusb_transfer_status,
216
- :length, :int,
217
- :actual_length, :int,
218
- :callback, :libusb_transfer_cb_fn,
219
- :user_data, :pointer,
220
- :buffer, :pointer,
221
- :num_iso_packets, :int
222
-
223
- def self.release(ptr)
224
- Call.libusb_free_transfer(ptr)
225
- end
226
- end
227
- end
228
-
229
- Call::ClassCodes.to_h.each{|k,v| const_set(k,v) }
230
- Call::TransferTypes.to_h.each{|k,v| const_set(k,v) }
231
- Call::StandardRequests.to_h.each{|k,v| const_set(k,v) }
232
- Call::RequestTypes.to_h.each{|k,v| const_set(k,v) }
233
- Call::DescriptorTypes.to_h.each{|k,v| const_set(k,v) }
234
- Call::EndpointDirections.to_h.each{|k,v| const_set(k,v) }
235
- Call::RequestRecipients.to_h.each{|k,v| const_set(k,v) }
236
- Call::IsoSyncTypes.to_h.each{|k,v| const_set(k,v) }
237
-
238
- # Base class of libusb errors
239
- class Error < RuntimeError
240
- end
241
- ErrorClassForResult = {}
242
-
243
- # define an exception class for each error code
244
- Call::Errors.to_h.each do |k,v|
245
- klass = Class.new(Error)
246
- klass.send(:define_method, :code){ v }
247
- const_set(k, klass)
248
- ErrorClassForResult[v] = klass
249
- end
250
-
251
- def self.raise_error(res, text)
252
- klass = ErrorClassForResult[res]
253
- raise klass, "#{klass} #{text}"
254
- end
255
-
256
- CONTROL_SETUP_SIZE = 8
257
- DT_DEVICE_SIZE = 18
258
- DT_CONFIG_SIZE = 9
259
- DT_INTERFACE_SIZE = 9
260
- DT_ENDPOINT_SIZE = 7
261
- DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
262
- DT_HUB_NONVAR_SIZE = 7
263
-
264
- ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
265
- ENDPOINT_DIR_MASK = 0x80
266
- TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
267
- ISO_SYNC_TYPE_MASK = 0x0C
268
- ISO_USAGE_TYPE_MASK = 0x30
269
-
270
-
271
- # :stopdoc:
272
- # http://www.usb.org/developers/defined_class
273
- CLASS_CODES = [
274
- [0x01, nil, nil, "Audio"],
275
- [0x02, nil, nil, "Comm"],
276
- [0x03, nil, nil, "HID"],
277
- [0x05, nil, nil, "Physical"],
278
- [0x06, 0x01, 0x01, "StillImaging"],
279
- [0x06, nil, nil, "Image"],
280
- [0x07, nil, nil, "Printer"],
281
- [0x08, 0x01, nil, "MassStorage RBC Bluk-Only"],
282
- [0x08, 0x02, 0x50, "MassStorage ATAPI Bluk-Only"],
283
- [0x08, 0x03, 0x50, "MassStorage QIC-157 Bluk-Only"],
284
- [0x08, 0x04, nil, "MassStorage UFI"],
285
- [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bluk-Only"],
286
- [0x08, 0x06, 0x50, "MassStorage SCSI Bluk-Only"],
287
- [0x08, nil, nil, "MassStorage"],
288
- [0x09, 0x00, 0x00, "Full speed Hub"],
289
- [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
290
- [0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
291
- [0x09, nil, nil, "Hub"],
292
- [0x0a, nil, nil, "CDC"],
293
- [0x0b, nil, nil, "SmartCard"],
294
- [0x0d, 0x00, 0x00, "ContentSecurity"],
295
- [0x0e, nil, nil, "Video"],
296
- [0xdc, 0x01, 0x01, "Diagnostic USB2"],
297
- [0xdc, nil, nil, "Diagnostic"],
298
- [0xe0, 0x01, 0x01, "Bluetooth"],
299
- [0xe0, 0x01, 0x02, "UWB"],
300
- [0xe0, 0x01, 0x03, "RemoteNDIS"],
301
- [0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
302
- [0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
303
- [0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
304
- [0xe0, nil, nil, "Wireless Controller"],
305
- [0xef, 0x01, 0x01, "Active Sync"],
306
- [0xef, 0x01, 0x02, "Palm Sync"],
307
- [0xef, 0x02, 0x01, "Interface Association Descriptor"],
308
- [0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
309
- [0xef, 0x03, 0x01, "Cable Based Association Framework"],
310
- [0xef, nil, nil, "Miscellaneous"],
311
- [0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
312
- [0xfe, 0x02, 0x00, "IRDA Bridge"],
313
- [0xfe, 0x03, 0x00, "USB Test and Measurement"],
314
- [0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
315
- [0xfe, nil, nil, "Application Specific"],
316
- [0xff, nil, nil, "Vendor specific"],
317
- ]
318
- CLASS_CODES_HASH1 = {}
319
- CLASS_CODES_HASH2 = {}
320
- CLASS_CODES_HASH3 = {}
321
- CLASS_CODES.each {|base_class, sub_class, protocol, desc|
322
- if protocol
323
- CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
324
- elsif sub_class
325
- CLASS_CODES_HASH2[[base_class, sub_class]] = desc
326
- else
327
- CLASS_CODES_HASH1[base_class] = desc
328
- end
329
- }
330
-
331
- def self.dev_string(base_class, sub_class, protocol)
332
- if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
333
- desc
334
- elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
335
- desc + " (%02x)" % [protocol]
336
- elsif desc = CLASS_CODES_HASH1[base_class]
337
- desc + " (%02x,%02x)" % [sub_class, protocol]
338
- else
339
- "Unkonwn(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
340
- end
341
- end
342
- # :startdoc:
343
-
344
-
345
- # Abstract base class for USB transfers. Use
346
- # {ControlTransfer}, {BulkTransfer}, {InterruptTransfer}, {IsochronousTransfer}
347
- # to do transfers.
348
- class Transfer
349
- def initialize(args={})
350
- args.each{|k,v| send("#{k}=", v) }
351
- @buffer = nil
352
- end
353
- private :initialize
354
-
355
- # Set the handle for the device to communicate with.
356
- def dev_handle=(dev)
357
- @dev_handle = dev
358
- @transfer[:dev_handle] = @dev_handle.pHandle
359
- end
360
-
361
- # Timeout for this transfer in millseconds.
362
- #
363
- # A value of 0 indicates no timeout.
364
- def timeout=(value)
365
- @transfer[:timeout] = value
366
- end
367
-
368
- # Set the address of a valid endpoint to communicate with.
369
- def endpoint=(endpoint)
370
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
371
- @transfer[:endpoint] = endpoint
372
- end
373
-
374
- # Set output data that should be sent.
375
- def buffer=(data)
376
- if !@buffer || data.bytesize>@buffer.size
377
- free_buffer
378
- @buffer = FFI::MemoryPointer.new(data.bytesize, 1, false)
379
- end
380
- @buffer.put_bytes(0, data)
381
- @transfer[:buffer] = @buffer
382
- @transfer[:length] = data.bytesize
383
- end
384
-
385
- # Retrieve the current data buffer.
386
- def buffer
387
- @transfer[:buffer].read_string(@transfer[:length])
388
- end
389
-
390
- # Clear the current data buffer.
391
- def free_buffer
392
- if @buffer
393
- @buffer.free
394
- @buffer = nil
395
- @transfer[:buffer] = nil
396
- @transfer[:length] = 0
397
- end
398
- end
399
-
400
- # Allocate +len+ bytes of data buffer for input transfer.
401
- #
402
- # @param [Fixnum] len Number of bytes to allocate
403
- # @param [String, nil] data some data to initialize the buffer with
404
- def alloc_buffer(len, data=nil)
405
- if !@buffer || len>@buffer.size
406
- free_buffer
407
- @buffer = FFI::MemoryPointer.new(len, 1, false)
408
- end
409
- @buffer.put_bytes(0, data) if data
410
- @transfer[:buffer] = @buffer
411
- @transfer[:length] = len
412
- end
413
-
414
- # The number of bytes actually transferred.
415
- def actual_length
416
- @transfer[:actual_length]
417
- end
418
-
419
- # Retrieve the data actually transferred.
420
- #
421
- # @param [Fixnum] offset optional offset of the retrieved data in the buffer.
422
- def actual_buffer(offset=0)
423
- @transfer[:buffer].get_bytes(offset, @transfer[:actual_length])
424
- end
425
-
426
- # Set the block that will be invoked when the transfer completes,
427
- # fails, or is cancelled.
428
- #
429
- # @param [Proc] proc The block that should be called
430
- def callback=(proc)
431
- # Save proc to instance variable so that GC doesn't free
432
- # the proc object before the transfer.
433
- @callback_proc = proc do |pTrans|
434
- proc.call(self)
435
- end
436
- @transfer[:callback] = @callback_proc
437
- end
438
-
439
- # The status of the transfer.
440
- #
441
- # Only for use within transfer callback function or after the callback was called.
442
- #
443
- # If this is an isochronous transfer, this field may read :TRANSFER_COMPLETED even if there
444
- # were errors in the frames. Use the status field in each packet to determine if
445
- # errors occurred.
446
- def status
447
- @transfer[:status]
448
- end
449
-
450
- # Submit a transfer.
451
- #
452
- # This function will fire off the USB transfer and then return immediately.
453
- # This method can be called with block. It is called when the transfer completes,
454
- # fails, or is cancelled.
455
- def submit!(&block)
456
- self.callback = block if block_given?
457
-
458
- # puts "submit transfer #{@transfer.inspect} buffer: #{@transfer[:buffer].inspect} length: #{@transfer[:length].inspect} status: #{@transfer[:status].inspect} callback: #{@transfer[:callback].inspect} dev_handle: #{@transfer[:dev_handle].inspect}"
459
-
460
- res = Call.libusb_submit_transfer( @transfer )
461
- LIBUSB.raise_error res, "in libusb_submit_transfer" if res!=0
462
- end
463
-
464
- # Asynchronously cancel a previously submitted transfer.
465
- #
466
- # This function returns immediately, but this does not indicate cancellation is
467
- # complete. Your callback function will be invoked at some later time with a
468
- # transfer status of :TRANSFER_CANCELLED.
469
- def cancel!
470
- res = Call.libusb_cancel_transfer( @transfer )
471
- LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0
472
- end
473
-
474
- TransferStatusToError = {
475
- :TRANSFER_ERROR => LIBUSB::ERROR_IO,
476
- :TRANSFER_TIMED_OUT => LIBUSB::ERROR_TIMEOUT,
477
- :TRANSFER_CANCELLED => LIBUSB::ERROR_INTERRUPTED,
478
- :TRANSFER_STALL => LIBUSB::ERROR_PIPE,
479
- :TRANSFER_NO_DEVICE => LIBUSB::ERROR_NO_DEVICE,
480
- :TRANSFER_OVERFLOW => LIBUSB::ERROR_OVERFLOW,
481
- }
482
-
483
- # Submit the transfer and wait until the transfer completes or fails.
484
- #
485
- # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
486
- def submit_and_wait!
487
- completed = false
488
- submit! do |tr2|
489
- completed = true
490
- end
491
-
492
- until completed
493
- begin
494
- @dev_handle.device.context.handle_events
495
- rescue ERROR_INTERRUPTED
496
- next
497
- rescue LIBUSB::Error
498
- cancel!
499
- until completed
500
- @dev_handle.device.context.handle_events
501
- end
502
- raise
503
- end
504
- end
505
-
506
- raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
507
- end
508
- end
509
-
510
- class BulkTransfer < Transfer
511
- def initialize(args={})
512
- @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
513
- @transfer[:type] = TRANSFER_TYPE_BULK
514
- @transfer[:timeout] = 1000
515
- super
516
- end
517
- end
518
-
519
- class ControlTransfer < Transfer
520
- def initialize(args={})
521
- @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
522
- @transfer[:type] = TRANSFER_TYPE_CONTROL
523
- @transfer[:timeout] = 1000
524
- super
525
- end
526
- end
527
-
528
- class InterruptTransfer < Transfer
529
- def initialize(args={})
530
- @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
531
- @transfer[:type] = TRANSFER_TYPE_INTERRUPT
532
- @transfer[:timeout] = 1000
533
- super
534
- end
535
- end
536
-
537
- class IsoPacket
538
- def initialize(ptr, pkg_nr)
539
- @packet = Call::IsoPacketDescriptor.new ptr
540
- @pkg_nr = pkg_nr
541
- end
542
-
543
- def status
544
- @packet[:status]
545
- end
546
-
547
- def length
548
- @packet[:length]
549
- end
550
- def length=(len)
551
- @packet[:length] = len
552
- end
553
-
554
- def actual_length
555
- @packet[:actual_length]
556
- end
557
- end
558
-
559
- class IsochronousTransfer < Transfer
560
- def initialize(num_packets, args={})
561
- @ptr = Call.libusb_alloc_transfer(num_packets)
562
- @transfer = Call::Transfer.new @ptr
563
- @transfer[:type] = TRANSFER_TYPE_ISOCHRONOUS
564
- @transfer[:timeout] = 1000
565
- @transfer[:num_iso_packets] = num_packets
566
- super(args)
567
- end
568
-
569
- def num_packets
570
- @transfer[:num_iso_packets]
571
- end
572
- def num_packets=(number)
573
- @transfer[:num_iso_packets] = number
574
- end
575
-
576
- def [](nr)
577
- IsoPacket.new( @ptr + Call::Transfer.size + nr*Call::IsoPacketDescriptor.size, nr)
578
- end
579
-
580
- # Convenience function to set the length of all packets in an
581
- # isochronous transfer, based on {IsochronousTransfer#num_packets}.
582
- def packet_lengths=(len)
583
- ptr = @ptr + Call::Transfer.size
584
- num_packets.times do
585
- ptr.write_uint(len)
586
- ptr += Call::IsoPacketDescriptor.size
587
- end
588
- end
589
-
590
- # The actual_length field of the transfer is meaningless and should not
591
- # be examined; instead you must refer to the actual_length field of
592
- # each individual packet.
593
- private :actual_length, :actual_buffer
594
- end
595
-
596
- # @private
597
- class DeviceDescriptor < FFI::Struct
598
- include Comparable
599
-
600
- layout :bLength, :uint8,
601
- :bDescriptorType, :uint8,
602
- :bcdUSB, :uint16,
603
- :bDeviceClass, :uint8,
604
- :bDeviceSubClass, :uint8,
605
- :bDeviceProtocol, :uint8,
606
- :bMaxPacketSize0, :uint8,
607
- :idVendor, :uint16,
608
- :idProduct, :uint16,
609
- :bcdDevice, :uint16,
610
- :iManufacturer, :uint8,
611
- :iProduct, :uint8,
612
- :iSerialNumber, :uint8,
613
- :bNumConfigurations, :uint8
614
- end
615
-
616
- class Configuration < FFI::ManagedStruct
617
- include Comparable
618
-
619
- layout :bLength, :uint8,
620
- :bDescriptorType, :uint8,
621
- :wTotalLength, :uint16,
622
- :bNumInterfaces, :uint8,
623
- :bConfigurationValue, :uint8,
624
- :iConfiguration, :uint8,
625
- :bmAttributes, :uint8,
626
- :maxPower, :uint8,
627
- :interface, :pointer,
628
- :extra, :pointer,
629
- :extra_length, :int
630
-
631
- # Size of this descriptor (in bytes).
632
- def bLength
633
- self[:bLength]
634
- end
635
-
636
- # Descriptor type (0x02)
637
- def bDescriptorType
638
- self[:bDescriptorType]
639
- end
640
-
641
- # Total length of data returned for this configuration.
642
- def wTotalLength
643
- self[:wTotalLength]
644
- end
645
-
646
- # Number of interfaces supported by this configuration.
647
- def bNumInterfaces
648
- self[:bNumInterfaces]
649
- end
650
-
651
- # Identifier value for this configuration.
652
- def bConfigurationValue
653
- self[:bConfigurationValue]
654
- end
655
-
656
- # Index of string descriptor describing this configuration.
657
- def iConfiguration
658
- self[:iConfiguration]
659
- end
660
-
661
- # Configuration characteristics.
662
- #
663
- # * Bit 7: Reserved, set to 1. (USB 1.0 Bus Powered)
664
- # * Bit 6: Self Powered
665
- # * Bit 5: Remote Wakeup
666
- # * Bit 4..0: Reserved, set to 0.
667
- #
668
- # @return [Integer]
669
- def bmAttributes
670
- self[:bmAttributes]
671
- end
672
-
673
- # Maximum power consumption of the USB device from this bus in this configuration when the device is fully opreation.
674
- #
675
- # @result [Integer] Maximum Power Consumption in 2mA units
676
- def maxPower
677
- self[:maxPower]
678
- end
679
-
680
- # Extra descriptors.
681
- #
682
- # @return [String]
683
- def extra
684
- return if self[:extra].null?
685
- self[:extra].read_string(self[:extra_length])
686
- end
687
-
688
- def initialize(device, *args)
689
- @device = device
690
- super(*args)
691
- end
692
-
693
- def self.release(ptr)
694
- Call.libusb_free_config_descriptor(ptr)
695
- end
696
-
697
- # @return [Device] the device this configuration belongs to.
698
- attr_reader :device
699
-
700
- def interfaces
701
- ifs = []
702
- self[:bNumInterfaces].times do |i|
703
- ifs << Interface.new(self, self[:interface] + i*Interface.size)
704
- end
705
- return ifs
706
- end
707
-
708
- def inspect
709
- attrs = []
710
- attrs << self.bConfigurationValue.to_s
711
- bits = self.bmAttributes
712
- attrs << "SelfPowered" if (bits & 0b1000000) != 0
713
- attrs << "RemoteWakeup" if (bits & 0b100000) != 0
714
- desc = self.description
715
- attrs << desc if desc != '?'
716
- "\#<#{self.class} #{attrs.join(' ')}>"
717
- end
718
-
719
- # Return name of this configuration as String.
720
- def description
721
- return @description if defined? @description
722
- @description = device.try_string_descriptor_ascii(self.iConfiguration)
723
- end
724
-
725
- # Return all interface decriptions of the configuration as Array of {Setting}s.
726
- def settings() self.interfaces.map {|d| d.settings }.flatten end
727
- # Return all endpoints of all interfaces of the configuration as Array of {Endpoint}s.
728
- def endpoints() self.settings.map {|d| d.endpoints }.flatten end
729
-
730
- def <=>(o)
731
- t = device<=>o.device
732
- t = bConfigurationValue<=>o.bConfigurationValue if t==0
733
- t
734
- end
735
- end
736
-
737
- class Interface < FFI::Struct
738
- include Comparable
739
-
740
- layout :altsetting, :pointer,
741
- :num_altsetting, :int
742
-
743
- def initialize(configuration, *args)
744
- @configuration = configuration
745
- super(*args)
746
- end
747
-
748
- # @return [Configuration] the configuration this interface belongs to.
749
- attr_reader :configuration
750
-
751
- def alt_settings
752
- ifs = []
753
- self[:num_altsetting].times do |i|
754
- ifs << Setting.new(self, self[:altsetting] + i*Setting.size)
755
- end
756
- return ifs
757
- end
758
- alias settings alt_settings
759
-
760
- # The {Device} this Interface belongs to.
761
- def device() self.configuration.device end
762
- # Return all endpoints of all alternative settings as Array of {Endpoint}s.
763
- def endpoints() self.alt_settings.map {|d| d.endpoints }.flatten end
764
-
765
- def <=>(o)
766
- configuration<=>o.configuration
767
- end
768
- end
769
-
770
- class Setting < FFI::Struct
771
- include Comparable
772
-
773
- layout :bLength, :uint8,
774
- :bDescriptorType, :uint8,
775
- :bInterfaceNumber, :uint8,
776
- :bAlternateSetting, :uint8,
777
- :bNumEndpoints, :uint8,
778
- :bInterfaceClass, :uint8,
779
- :bInterfaceSubClass, :uint8,
780
- :bInterfaceProtocol, :uint8,
781
- :iInterface, :uint8,
782
- :endpoint, :pointer,
783
- :extra, :pointer,
784
- :extra_length, :int
785
-
786
- # Size of this descriptor (in bytes).
787
- def bLength
788
- self[:bLength]
789
- end
17
+ VERSION = "0.2.0"
790
18
 
791
- # Descriptor type (0x04)
792
- def bDescriptorType
793
- self[:bDescriptorType]
794
- end
795
-
796
- # Number of this interface.
797
- def bInterfaceNumber
798
- self[:bInterfaceNumber]
799
- end
800
-
801
- # Value used to select this alternate setting for this interface.
802
- def bAlternateSetting
803
- self[:bAlternateSetting]
804
- end
805
-
806
- # Number of endpoints used by this interface (excluding the control endpoint).
807
- def bNumEndpoints
808
- self[:bNumEndpoints]
809
- end
810
-
811
- # USB-IF class code for this interface.
812
- def bInterfaceClass
813
- self[:bInterfaceClass]
814
- end
815
-
816
- # USB-IF subclass code for this interface, qualified by the {bInterfaceClass} value.
817
- def bInterfaceSubClass
818
- self[:bInterfaceSubClass]
819
- end
820
-
821
- # USB-IF protocol code for this interface, qualified by the {bInterfaceClass} and {bInterfaceSubClass} values.
822
- def bInterfaceProtocol
823
- self[:bInterfaceProtocol]
824
- end
825
-
826
- # Index of string descriptor describing this interface.
827
- def iInterface
828
- self[:iInterface]
829
- end
830
-
831
- # Extra descriptors.
832
- #
833
- # @return [String]
834
- def extra
835
- return if self[:extra].null?
836
- self[:extra].read_string(self[:extra_length])
837
- end
838
-
839
- def initialize(interface, *args)
840
- @interface = interface
841
- super(*args)
842
- end
843
-
844
- # @return [Interface] the interface this setting belongs to.
845
- attr_reader :interface
846
-
847
- def endpoints
848
- ifs = []
849
- self[:bNumEndpoints].times do |i|
850
- ifs << Endpoint.new(self, self[:endpoint] + i*Endpoint.size)
851
- end
852
- return ifs
853
- end
854
-
855
- def inspect
856
- attrs = []
857
- attrs << self.bAlternateSetting.to_s
858
- devclass = LIBUSB.dev_string(self.bInterfaceClass, self.bInterfaceSubClass, self.bInterfaceProtocol)
859
- attrs << devclass
860
- desc = self.description
861
- attrs << desc if desc != '?'
862
- "\#<#{self.class} #{attrs.join(' ')}>"
863
- end
864
-
865
- # Return name of this interface as String.
866
- def description
867
- return @description if defined? @description
868
- @description = device.try_string_descriptor_ascii(self.iInterface)
869
- end
870
-
871
- # The {Device} this Setting belongs to.
872
- def device() self.interface.configuration.device end
873
- # The {Configuration} this Setting belongs to.
874
- def configuration() self.interface.configuration end
875
-
876
- def <=>(o)
877
- t = interface<=>o.interface
878
- t = bInterfaceNumber<=>o.bInterfaceNumber if t==0
879
- t = bAlternateSetting<=>o.bAlternateSetting if t==0
880
- t
881
- end
19
+ require 'libusb/call'
20
+ require 'libusb/constants'
21
+ require 'libusb/context'
22
+ autoload :Version, 'libusb/version'
23
+ autoload :Configuration, 'libusb/configuration'
24
+ autoload :DevHandle, 'libusb/dev_handle'
25
+ autoload :Device, 'libusb/device'
26
+ autoload :Endpoint, 'libusb/endpoint'
27
+ autoload :Interface, 'libusb/interface'
28
+ autoload :Setting, 'libusb/setting'
29
+ %w[ Transfer BulkTransfer ControlTransfer InterruptTransfer IsoPacket IsochronousTransfer ].each do |klass|
30
+ autoload klass, 'libusb/transfer'
882
31
  end
883
32
 
884
- class Endpoint < FFI::Struct
885
- include Comparable
886
-
887
- layout :bLength, :uint8,
888
- :bDescriptorType, :uint8,
889
- :bEndpointAddress, :uint8,
890
- :bmAttributes, :uint8,
891
- :wMaxPacketSize, :uint16,
892
- :bInterval, :uint8,
893
- :bRefresh, :uint8,
894
- :bSynchAddress, :uint8,
895
- :extra, :pointer,
896
- :extra_length, :int
897
-
898
- # Size of Descriptor in Bytes (7 bytes)
899
- def bLength
900
- self[:bLength]
901
- end
902
-
903
- # Descriptor type (0x05)
904
- def bDescriptorType
905
- self[:bDescriptorType]
906
- end
907
-
908
- # The address of the endpoint described by this descriptor.
909
- #
910
- # * Bits 0..3: Endpoint Number.
911
- # * Bits 4..6: Reserved. Set to Zero
912
- # * Bits 7: Direction 0 = Out, 1 = In (Ignored for Control Endpoints)
913
- #
914
- # @return [Integer]
915
- def bEndpointAddress
916
- self[:bEndpointAddress]
917
- end
918
-
919
- # Attributes which apply to the endpoint when it is configured using the {Configuration#bConfigurationValue}.
920
- #
921
- # * Bits 0..1: Transfer Type
922
- # * 00 = Control
923
- # * 01 = Isochronous
924
- # * 10 = Bulk
925
- # * 11 = Interrupt
926
- # * Bits 2..7: are reserved. If Isochronous endpoint,
927
- # * Bits 3..2: Synchronisation Type (Iso Mode)
928
- # * 00 = No Synchonisation
929
- # * 01 = Asynchronous
930
- # * 10 = Adaptive
931
- # * 11 = Synchronous
932
- # * Bits 5..4: Usage Type (Iso Mode)
933
- # * 00 = Data Endpoint
934
- # * 01 = Feedback Endpoint
935
- # * 10 = Explicit Feedback Data Endpoint
936
- # * 11 = Reserved
937
- #
938
- # @return [Integer]
939
- def bmAttributes
940
- self[:bmAttributes]
941
- end
942
-
943
- # Maximum Packet Size this endpoint is capable of sending or receiving
944
- def wMaxPacketSize
945
- self[:wMaxPacketSize]
946
- end
947
-
948
- # Interval for polling endpoint data transfers. Value in frame counts.
949
- # Ignored for Bulk & Control Endpoints. Isochronous must equal 1 and field
950
- # may range from 1 to 255 for interrupt endpoints.
951
- #
952
- # The interval is respected by the kernel driver, so user mode processes
953
- # using libusb don't need to care about it.
954
- def bInterval
955
- self[:bInterval]
956
- end
957
-
958
- # For audio devices only: the rate at which synchronization feedback is provided.
959
- def bRefresh
960
- self[:bRefresh]
961
- end
962
-
963
- # For audio devices only: the address if the synch endpoint.
964
- def bSynchAddress
965
- self[:bSynchAddress]
966
- end
967
-
968
- # Extra descriptors.
969
- #
970
- # @return [String]
971
- def extra
972
- return if self[:extra].null?
973
- self[:extra].read_string(self[:extra_length])
974
- end
975
-
976
- def initialize(setting, *args)
977
- @setting = setting
978
- super(*args)
979
- end
980
-
981
- # @return [Setting] the setting this endpoint belongs to.
982
- attr_reader :setting
983
-
984
- def inspect
985
- endpoint_address = self.bEndpointAddress
986
- num = endpoint_address & 0b00001111
987
- inout = (endpoint_address & 0b10000000) == 0 ? "OUT" : "IN "
988
- bits = self.bmAttributes
989
- transfer_type = %w[Control Isochronous Bulk Interrupt][0b11 & bits]
990
- type = [transfer_type]
991
- if transfer_type == 'Isochronous'
992
- synchronization_type = %w[NoSynchronization Asynchronous Adaptive Synchronous][(0b1100 & bits) >> 2]
993
- usage_type = %w[Data Feedback ImplicitFeedback ?][(0b110000 & bits) >> 4]
994
- type << synchronization_type << usage_type
995
- end
996
- "\#<#{self.class} #{num} #{inout} #{type.join(" ")}>"
997
- end
998
-
999
- # The {Device} this Endpoint belongs to.
1000
- def device() self.setting.interface.configuration.device end
1001
- # The {Configuration} this Endpoint belongs to.
1002
- def configuration() self.setting.interface.configuration end
1003
- # The {Interface} this Endpoint belongs to.
1004
- def interface() self.setting.interface end
1005
-
1006
- def <=>(o)
1007
- t = setting<=>o.setting
1008
- t = bEndpointAddress<=>o.bEndpointAddress if t==0
1009
- t
33
+ if Call.respond_to?(:libusb_get_version)
34
+ # Get version of the underlying libusb library.
35
+ # Available since libusb-1.0.10.
36
+ # @return [Version] version object
37
+ def self.version
38
+ Version.new(Call.libusb_get_version)
1010
39
  end
1011
40
  end
1012
41
 
1013
-
1014
- # Class representing a libusb session.
1015
- class Context
1016
- # Initialize libusb context.
1017
- def initialize
1018
- m = FFI::MemoryPointer.new :pointer
1019
- Call.libusb_init(m)
1020
- @ctx = m.read_pointer
1021
- end
1022
-
1023
- # Deinitialize libusb.
1024
- #
1025
- # Should be called after closing all open devices and before your application terminates.
1026
- def exit
1027
- Call.libusb_exit(@ctx)
1028
- end
1029
-
1030
- # Set message verbosity.
1031
- #
1032
- # * Level 0: no messages ever printed by the library (default)
1033
- # * Level 1: error messages are printed to stderr
1034
- # * Level 2: warning and error messages are printed to stderr
1035
- # * Level 3: informational messages are printed to stdout, warning and
1036
- # error messages are printed to stderr
1037
- #
1038
- # The default level is 0, which means no messages are ever printed. If you
1039
- # choose to increase the message verbosity level, ensure that your
1040
- # application does not close the stdout/stderr file descriptors.
1041
- #
1042
- # You are advised to set level 3. libusb is conservative with its message
1043
- # logging and most of the time, will only log messages that explain error
1044
- # conditions and other oddities. This will help you debug your software.
1045
- #
1046
- # If the LIBUSB_DEBUG environment variable was set when libusb was
1047
- # initialized, this method does nothing: the message verbosity is
1048
- # fixed to the value in the environment variable.
1049
- #
1050
- # If libusb was compiled without any message logging, this method
1051
- # does nothing: you'll never get any messages.
1052
- #
1053
- # If libusb was compiled with verbose debug message logging, this
1054
- # method does nothing: you'll always get messages from all levels.
1055
- #
1056
- # @param [Fixnum] level debug level to set
1057
- def debug=(level)
1058
- Call.libusb_set_debug(@ctx, level)
1059
- end
1060
-
1061
- def device_list
1062
- pppDevs = FFI::MemoryPointer.new :pointer
1063
- size = Call.libusb_get_device_list(@ctx, pppDevs)
1064
- ppDevs = pppDevs.read_pointer
1065
- pDevs = []
1066
- size.times do |devi|
1067
- pDev = ppDevs.get_pointer(devi*FFI.type_size(:pointer))
1068
- pDevs << Device.new(self, pDev)
1069
- end
1070
- Call.libusb_free_device_list(ppDevs, 1)
1071
- pDevs
1072
- end
1073
- private :device_list
1074
-
1075
- # Handle any pending events in blocking mode.
1076
- #
1077
- # This method must be called when libusb is running asynchronous transfers.
1078
- # This gives libusb the opportunity to reap pending transfers,
1079
- # invoke callbacks, etc.
1080
- def handle_events
1081
- res = Call.libusb_handle_events(@ctx)
1082
- LIBUSB.raise_error res, "in libusb_handle_events" if res<0
1083
- end
1084
-
1085
- # Obtain a list of devices currently attached to the USB system, optionally matching certain criteria.
1086
- #
1087
- # @param [Hash] filter_hash A number of criteria can be defined in key-value pairs.
1088
- # Only devices that equal all given criterions will be returned. If a criterion is
1089
- # not specified or its value is +nil+, any device will match that criterion.
1090
- # The following criteria can be filtered:
1091
- # * <tt>:idVendor</tt>, <tt>:idProduct</tt> (+FixNum+) for matching vendor/product ID,
1092
- # * <tt>:bClass</tt>, <tt>:bSubClass</tt>, <tt>:bProtocol</tt> (+FixNum+) for the device type -
1093
- # Devices using CLASS_PER_INTERFACE will match, if any of the interfaces match.
1094
- # * <tt>:bcdUSB</tt>, <tt>:bcdDevice</tt>, <tt>:bMaxPacketSize0</tt> (+FixNum+) for the
1095
- # USB and device release numbers.
1096
- # Criteria can also specified as Array of several alternative values.
1097
- #
1098
- # @example
1099
- # # Return all devices of vendor 0x0ab1 where idProduct is 3 or 4:
1100
- # context.device :idVendor=>0x0ab1, :idProduct=>[0x0003, 0x0004]
1101
- #
1102
- # @return [Array<LIBUSB::Device>]
1103
- def devices(filter_hash={})
1104
- device_list.select do |dev|
1105
- ( !filter_hash[:bClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
1106
- dev.settings.map(&:bInterfaceClass).&([filter_hash[:bClass]].flatten).any? :
1107
- [filter_hash[:bClass]].flatten.include?(dev.bDeviceClass))) &&
1108
- ( !filter_hash[:bSubClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
1109
- dev.settings.map(&:bInterfaceSubClass).&([filter_hash[:bSubClass]].flatten).any? :
1110
- [filter_hash[:bSubClass]].flatten.include?(dev.bDeviceSubClass))) &&
1111
- ( !filter_hash[:bProtocol] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
1112
- dev.settings.map(&:bInterfaceProtocol).&([filter_hash[:bProtocol]].flatten).any? :
1113
- [filter_hash[:bProtocol]].flatten.include?(dev.bDeviceProtocol))) &&
1114
- ( !filter_hash[:bMaxPacketSize0] || [filter_hash[:bMaxPacketSize0]].flatten.include?(dev.bMaxPacketSize0) ) &&
1115
- ( !filter_hash[:idVendor] || [filter_hash[:idVendor]].flatten.include?(dev.idVendor) ) &&
1116
- ( !filter_hash[:idProduct] || [filter_hash[:idProduct]].flatten.include?(dev.idProduct) ) &&
1117
- ( !filter_hash[:bcdUSB] || [filter_hash[:bcdUSB]].flatten.include?(dev.bcdUSB) ) &&
1118
- ( !filter_hash[:bcdDevice] || [filter_hash[:bcdDevice]].flatten.include?(dev.bcdDevice) )
1119
- end
42
+ if Call.respond_to?(:libusb_has_capability)
43
+ # Check at runtime if the loaded library has a given capability.
44
+ # Available since libusb-1.0.9.
45
+ # @param [Symbol] capability the {Call::Capabilities Capabilities} symbol to check for
46
+ # @return [Boolean] +true+ if the running library has the capability, +false+ otherwise
47
+ def self.has_capability?(capability)
48
+ r = Call.libusb_has_capability(capability)
49
+ return r != 0
1120
50
  end
1121
51
  end
1122
-
1123
- # Class representing a USB device detected on the system.
1124
- #
1125
- # Devices of the system can be obtained with {Context#devices} .
1126
- class Device
1127
- include Comparable
1128
-
1129
- # @return [Context] the context this device belongs to.
1130
- attr_reader :context
1131
-
1132
- def initialize context, pDev
1133
- @context = context
1134
- def pDev.unref_device(id)
1135
- Call.libusb_unref_device(self)
1136
- end
1137
- ObjectSpace.define_finalizer(self, pDev.method(:unref_device))
1138
- Call.libusb_ref_device(pDev)
1139
- @pDev = pDev
1140
-
1141
- @pDevDesc = DeviceDescriptor.new
1142
- res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
1143
- LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
1144
- end
1145
-
1146
- # Open the device and obtain a device handle.
1147
- #
1148
- # A handle allows you to perform I/O on the device in question.
1149
- # This is a non-blocking function; no requests are sent over the bus.
1150
- #
1151
- # If called with a block, the handle is passed to the block
1152
- # and is closed when the block has finished.
1153
- #
1154
- # You need proper access permissions on:
1155
- # * Linux: <tt>/dev/bus/usb/<bus>/<dev></tt>
1156
- #
1157
- # @return [DevHandle] Handle to the device.
1158
- def open
1159
- ppHandle = FFI::MemoryPointer.new :pointer
1160
- res = Call.libusb_open(@pDev, ppHandle)
1161
- LIBUSB.raise_error res, "in libusb_open" if res!=0
1162
- handle = DevHandle.new self, ppHandle.read_pointer
1163
- return handle unless block_given?
1164
- begin
1165
- yield handle
1166
- ensure
1167
- handle.close
1168
- end
1169
- end
1170
-
1171
- # Open the device and claim an interface.
1172
- #
1173
- # This is a convenience method to {Device#open} and {DevHandle#claim_interface}.
1174
- # Must be called with a block. When the block has finished, the interface
1175
- # will be released and the device will be closed.
1176
- #
1177
- # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
1178
- def open_interface(interface)
1179
- open do |dev|
1180
- dev.claim_interface(interface) do
1181
- yield dev
1182
- end
1183
- end
1184
- end
1185
-
1186
- # Get the number of the bus that a device is connected to.
1187
- def bus_number
1188
- Call.libusb_get_bus_number(@pDev)
1189
- end
1190
-
1191
- # Get the address of the device on the bus it is connected to.
1192
- def device_address
1193
- Call.libusb_get_device_address(@pDev)
1194
- end
1195
-
1196
- # Convenience function to retrieve the wMaxPacketSize value for a
1197
- # particular endpoint in the active device configuration.
1198
- #
1199
- # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
1200
- # @return [Fixnum] the wMaxPacketSize value
1201
- def max_packet_size(endpoint)
1202
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1203
- res = Call.libusb_get_max_packet_size(@pDev, endpoint)
1204
- LIBUSB.raise_error res, "in libusb_get_max_packet_size" unless res>=0
1205
- res
1206
- end
1207
-
1208
- # Calculate the maximum packet size which a specific endpoint is capable is
1209
- # sending or receiving in the duration of 1 microframe.
1210
- #
1211
- # Only the active configution is examined. The calculation is based on the
1212
- # wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6
1213
- # in the USB 2.0 specifications.
1214
- #
1215
- # If acting on an isochronous or interrupt endpoint, this function will
1216
- # multiply the value found in bits 0:10 by the number of transactions per
1217
- # microframe (determined by bits 11:12). Otherwise, this function just returns
1218
- # the numeric value found in bits 0:10.
1219
- #
1220
- # This function is useful for setting up isochronous transfers, for example
1221
- # you might use the return value from this function to call
1222
- # IsoPacket#alloc_buffer in order to set the length field
1223
- # of an isochronous packet in a transfer.
1224
- #
1225
- # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
1226
- # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
1227
- def max_iso_packet_size(endpoint)
1228
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1229
- res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
1230
- LIBUSB.raise_error res, "in libusb_get_max_iso_packet_size" unless res>=0
1231
- res
1232
- end
1233
-
1234
- # Obtain a config descriptor of the device.
1235
- #
1236
- # @param [Fixnum] index number of the config descriptor
1237
- # @return Configuration
1238
- def config_descriptor(index)
1239
- ppConfig = FFI::MemoryPointer.new :pointer
1240
- res = Call.libusb_get_config_descriptor(@pDev, index, ppConfig)
1241
- LIBUSB.raise_error res, "in libusb_get_config_descriptor" if res!=0
1242
- pConfig = ppConfig.read_pointer
1243
- config = Configuration.new(self, pConfig)
1244
- config
1245
- end
1246
-
1247
- # Size of the Descriptor in Bytes (18 bytes)
1248
- def bLength
1249
- @pDevDesc[:bLength]
1250
- end
1251
-
1252
- # Device Descriptor (0x01)
1253
- def bDescriptorType
1254
- @pDevDesc[:bDescriptorType]
1255
- end
1256
-
1257
- # USB specification release number which device complies too
1258
- #
1259
- # @return [Integer] in binary-coded decimal
1260
- def bcdUSB
1261
- @pDevDesc[:bcdUSB]
1262
- end
1263
-
1264
- # USB-IF class code for the device (Assigned by USB Org)
1265
- #
1266
- # * If equal to 0x00, each interface specifies it's own class code
1267
- # * If equal to 0xFF, the class code is vendor specified
1268
- # * Otherwise field is valid Class Code
1269
- def bDeviceClass
1270
- @pDevDesc[:bDeviceClass]
1271
- end
1272
-
1273
- # USB-IF subclass code for the device, qualified by the {bDeviceClass}
1274
- # value (Assigned by USB Org)
1275
- def bDeviceSubClass
1276
- @pDevDesc[:bDeviceSubClass]
1277
- end
1278
-
1279
- # USB-IF protocol code for the device, qualified by the {bDeviceClass}
1280
- # and {bDeviceSubClass} values (Assigned by USB Org)
1281
- def bDeviceProtocol
1282
- @pDevDesc[:bDeviceProtocol]
1283
- end
1284
-
1285
- # Maximum Packet Size for Endpoint 0. Valid Sizes are 8, 16, 32, 64
1286
- def bMaxPacketSize0
1287
- @pDevDesc[:bMaxPacketSize0]
1288
- end
1289
-
1290
- # USB-IF vendor ID (Assigned by USB Org)
1291
- def idVendor
1292
- @pDevDesc[:idVendor]
1293
- end
1294
-
1295
- # USB-IF product ID (Assigned by Manufacturer)
1296
- def idProduct
1297
- @pDevDesc[:idProduct]
1298
- end
1299
-
1300
- # Device release number in binary-coded decimal.
1301
- def bcdDevice
1302
- @pDevDesc[:bcdDevice]
1303
- end
1304
-
1305
- # Index of string descriptor describing manufacturer.
1306
- def iManufacturer
1307
- @pDevDesc[:iManufacturer]
1308
- end
1309
-
1310
- # Index of string descriptor describing product.
1311
- def iProduct
1312
- @pDevDesc[:iProduct]
1313
- end
1314
-
1315
- # Index of string descriptor containing device serial number.
1316
- def iSerialNumber
1317
- @pDevDesc[:iSerialNumber]
1318
- end
1319
-
1320
- # Number of Possible Configurations
1321
- def bNumConfigurations
1322
- @pDevDesc[:bNumConfigurations]
1323
- end
1324
-
1325
-
1326
- def inspect
1327
- attrs = []
1328
- attrs << "#{self.bus_number}/#{self.device_address}"
1329
- attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
1330
- attrs << self.manufacturer
1331
- attrs << self.product
1332
- attrs << self.serial_number
1333
- if self.bDeviceClass == LIBUSB::CLASS_PER_INTERFACE
1334
- devclass = self.settings.map {|i|
1335
- LIBUSB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
1336
- }.join(", ")
1337
- else
1338
- devclass = LIBUSB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
1339
- end
1340
- attrs << "(#{devclass})"
1341
- attrs.compact!
1342
- "\#<#{self.class} #{attrs.join(' ')}>"
1343
- end
1344
-
1345
- def try_string_descriptor_ascii(i)
1346
- begin
1347
- open{|h| h.string_descriptor_ascii(i) }
1348
- rescue
1349
- "?"
1350
- end
1351
- end
1352
-
1353
- # Return manufacturer of the device
1354
- # @return String
1355
- def manufacturer
1356
- return @manufacturer if defined? @manufacturer
1357
- @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
1358
- @manufacturer.strip! if @manufacturer
1359
- @manufacturer
1360
- end
1361
-
1362
- # Return product name of the device.
1363
- # @return String
1364
- def product
1365
- return @product if defined? @product
1366
- @product = try_string_descriptor_ascii(self.iProduct)
1367
- @product.strip! if @product
1368
- @product
1369
- end
1370
-
1371
- # Return serial number of the device.
1372
- # @return String
1373
- def serial_number
1374
- return @serial_number if defined? @serial_number
1375
- @serial_number = try_string_descriptor_ascii(self.iSerialNumber)
1376
- @serial_number.strip! if @serial_number
1377
- @serial_number
1378
- end
1379
-
1380
- # Return configurations of the device.
1381
- # @return [Array<Configuration>]
1382
- def configurations
1383
- configs = []
1384
- bNumConfigurations.times do |config_index|
1385
- begin
1386
- configs << config_descriptor(config_index)
1387
- rescue RuntimeError
1388
- # On Windows some devices don't return it's configuration.
1389
- end
1390
- end
1391
- configs
1392
- end
1393
-
1394
- # Return all interfaces of this device.
1395
- # @return [Array<Interface>]
1396
- def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
1397
- # Return all interface decriptions of this device.
1398
- # @return [Array<Setting>]
1399
- def settings() self.interfaces.map {|d| d.settings }.flatten end
1400
- # Return all endpoints of all interfaces of this device.
1401
- # @return [Array<Endpoint>]
1402
- def endpoints() self.settings.map {|d| d.endpoints }.flatten end
1403
-
1404
- def <=>(o)
1405
- t = bus_number<=>o.bus_number
1406
- t = device_address<=>o.device_address if t==0
1407
- t
1408
- end
1409
- end
1410
-
1411
- # Class representing a handle on a USB device.
1412
- #
1413
- # A device handle is used to perform I/O and other operations. When finished
1414
- # with a device handle, you should call DevHandle#close .
1415
- class DevHandle
1416
- # @private
1417
- attr_reader :pHandle
1418
- # @return [Device] the device this handle belongs to.
1419
- attr_reader :device
1420
-
1421
- def initialize device, pHandle
1422
- @device = device
1423
- @pHandle = pHandle
1424
- @bulk_transfer = @control_transfer = @interrupt_transfer = nil
1425
- end
1426
-
1427
- # Close a device handle.
1428
- #
1429
- # Should be called on all open handles before your application exits.
1430
- #
1431
- # Internally, this function destroys the reference that was added by {Device#open}
1432
- # on the given device.
1433
- #
1434
- # This is a non-blocking function; no requests are sent over the bus.
1435
- def close
1436
- Call.libusb_close(@pHandle)
1437
- end
1438
-
1439
- def string_descriptor_ascii(index)
1440
- pString = FFI::MemoryPointer.new 0x100
1441
- res = Call.libusb_get_string_descriptor_ascii(@pHandle, index, pString, pString.size)
1442
- LIBUSB.raise_error res, "in libusb_get_string_descriptor_ascii" unless res>=0
1443
- pString.read_string(res)
1444
- end
1445
-
1446
- # Claim an interface on a given device handle.
1447
- #
1448
- # You must claim the interface you wish to use before you can perform I/O on any
1449
- # of its endpoints.
1450
- #
1451
- # It is legal to attempt to claim an already-claimed interface, in which case
1452
- # libusb just returns without doing anything.
1453
- #
1454
- # Claiming of interfaces is a purely logical operation; it does not cause any
1455
- # requests to be sent over the bus. Interface claiming is used to instruct the
1456
- # underlying operating system that your application wishes to take ownership of
1457
- # the interface.
1458
- #
1459
- # This is a non-blocking function.
1460
- #
1461
- # If called with a block, the device handle is passed through to the block
1462
- # and the interface is released when the block has finished.
1463
- #
1464
- # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
1465
- def claim_interface(interface)
1466
- interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1467
- res = Call.libusb_claim_interface(@pHandle, interface)
1468
- LIBUSB.raise_error res, "in libusb_claim_interface" if res!=0
1469
- return self unless block_given?
1470
- begin
1471
- yield self
1472
- ensure
1473
- release_interface(interface)
1474
- end
1475
- end
1476
-
1477
- # Release an interface previously claimed with {DevHandle#claim_interface}.
1478
- #
1479
- # You should release all claimed interfaces before closing a device handle.
1480
- #
1481
- # This is a blocking function. A SET_INTERFACE control request will be sent to the
1482
- # device, resetting interface state to the first alternate setting.
1483
- #
1484
- # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you
1485
- # claimed previously
1486
- def release_interface(interface)
1487
- interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1488
- res = Call.libusb_release_interface(@pHandle, interface)
1489
- LIBUSB.raise_error res, "in libusb_release_interface" if res!=0
1490
- end
1491
-
1492
- # Set the active configuration for a device.
1493
- #
1494
- # The operating system may or may not have already set an active configuration on
1495
- # the device. It is up to your application to ensure the correct configuration is
1496
- # selected before you attempt to claim interfaces and perform other operations.
1497
- #
1498
- # If you call this function on a device already configured with the selected
1499
- # configuration, then this function will act as a lightweight device reset: it
1500
- # will issue a SET_CONFIGURATION request using the current configuration, causing
1501
- # most USB-related device state to be reset (altsetting reset to zero, endpoint
1502
- # halts cleared, toggles reset).
1503
- #
1504
- # You cannot change/reset configuration if your application has claimed interfaces -
1505
- # you should free them with {DevHandle#release_interface} first. You cannot
1506
- # change/reset configuration if other applications or drivers have claimed
1507
- # interfaces.
1508
- #
1509
- # A configuration value of +nil+ will put the device in unconfigured state. The USB
1510
- # specifications state that a configuration value of 0 does this, however buggy
1511
- # devices exist which actually have a configuration 0.
1512
- #
1513
- # You should always use this function rather than formulating your own
1514
- # SET_CONFIGURATION control request. This is because the underlying operating
1515
- # system needs to know when such changes happen.
1516
- #
1517
- # This is a blocking function.
1518
- #
1519
- # @param [Configuration, Fixnum] configuration the configuration or it's
1520
- # bConfigurationValue you wish to activate, or +nil+ if you wish to put
1521
- # the device in unconfigured state
1522
- def set_configuration(configuration)
1523
- configuration = configuration.bConfigurationValue if configuration.respond_to? :bConfigurationValue
1524
- res = Call.libusb_set_configuration(@pHandle, configuration || -1)
1525
- LIBUSB.raise_error res, "in libusb_set_configuration" if res!=0
1526
- end
1527
- alias configuration= set_configuration
1528
-
1529
- # Activate an alternate setting for an interface.
1530
- #
1531
- # The interface must have been previously claimed with {DevHandle#claim_interface}.
1532
- #
1533
- # You should always use this function rather than formulating your own
1534
- # SET_INTERFACE control request. This is because the underlying operating system
1535
- # needs to know when such changes happen.
1536
- #
1537
- # This is a blocking function.
1538
- #
1539
- # @param [Setting, Fixnum] setting_or_interface_number the alternate setting
1540
- # to activate or the bInterfaceNumber of the previously-claimed interface
1541
- # @param [Fixnum, nil] alternate_setting the bAlternateSetting of the alternate setting to activate
1542
- # (only if first param is a Fixnum)
1543
- def set_interface_alt_setting(setting_or_interface_number, alternate_setting=nil)
1544
- alternate_setting ||= setting_or_interface_number.bAlternateSetting if setting_or_interface_number.respond_to? :bAlternateSetting
1545
- setting_or_interface_number = setting_or_interface_number.bInterfaceNumber if setting_or_interface_number.respond_to? :bInterfaceNumber
1546
- res = Call.libusb_set_interface_alt_setting(@pHandle, setting_or_interface_number, alternate_setting)
1547
- LIBUSB.raise_error res, "in libusb_set_interface_alt_setting" if res!=0
1548
- end
1549
-
1550
- # Clear the halt/stall condition for an endpoint.
1551
- #
1552
- # Endpoints with halt status are unable to receive or transmit
1553
- # data until the halt condition is stalled.
1554
- #
1555
- # You should cancel all pending transfers before attempting to
1556
- # clear the halt condition.
1557
- #
1558
- # This is a blocking function.
1559
- #
1560
- # @param [Endpoint, Fixnum] endpoint the endpoint in question or it's bEndpointAddress
1561
- def clear_halt(endpoint)
1562
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1563
- res = Call.libusb_clear_halt(@pHandle, endpoint)
1564
- LIBUSB.raise_error res, "in libusb_clear_halt" if res!=0
1565
- end
1566
-
1567
- # Perform a USB port reset to reinitialize a device.
1568
- #
1569
- # The system will attempt to restore the previous configuration and
1570
- # alternate settings after the reset has completed.
1571
- #
1572
- # If the reset fails, the descriptors change, or the previous
1573
- # state cannot be restored, the device will appear to be disconnected
1574
- # and reconnected. This means that the device handle is no longer
1575
- # valid (you should close it) and rediscover the device. A Exception
1576
- # of LIBUSB::ERROR_NOT_FOUND indicates when this is the case.
1577
- #
1578
- # This is a blocking function which usually incurs a noticeable delay.
1579
- def reset_device
1580
- res = Call.libusb_reset_device(@pHandle)
1581
- LIBUSB.raise_error res, "in libusb_reset_device" if res!=0
1582
- end
1583
-
1584
- # Determine if a kernel driver is active on an interface.
1585
- #
1586
- # If a kernel driver is active, you cannot claim the interface,
1587
- # and libusb will be unable to perform I/O.
1588
- #
1589
- # @param [Interface, Fixnum] interface the interface to check or it's bInterfaceNumber
1590
- # @return [Boolean]
1591
- def kernel_driver_active?(interface)
1592
- interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1593
- res = Call.libusb_kernel_driver_active(@pHandle, interface)
1594
- LIBUSB.raise_error res, "in libusb_kernel_driver_active" unless res>=0
1595
- return res==1
1596
- end
1597
-
1598
- # Detach a kernel driver from an interface.
1599
- #
1600
- # If successful, you will then be able to claim the interface and perform I/O.
1601
- #
1602
- # @param [Interface, Fixnum] interface the interface to detach the driver
1603
- # from or it's bInterfaceNumber
1604
- def detach_kernel_driver(interface)
1605
- interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1606
- res = Call.libusb_detach_kernel_driver(@pHandle, interface)
1607
- LIBUSB.raise_error res, "in libusb_detach_kernel_driver" if res!=0
1608
- end
1609
-
1610
- # Re-attach an interface's kernel driver, which was previously detached
1611
- # using {DevHandle#detach_kernel_driver}.
1612
- #
1613
- # @param [Interface, Fixnum] interface the interface to attach the driver to
1614
- def attach_kernel_driver(interface)
1615
- interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1616
- res = Call.libusb_attach_kernel_driver(@pHandle, interface)
1617
- LIBUSB.raise_error res, "in libusb_attach_kernel_driver" if res!=0
1618
- end
1619
-
1620
-
1621
- # Perform a USB bulk transfer.
1622
- #
1623
- # The direction of the transfer is inferred from the direction bits of the
1624
- # endpoint address.
1625
- #
1626
- # For bulk reads, the +:dataIn+ param indicates the maximum length of data you are
1627
- # expecting to receive. If less data arrives than expected, this function will
1628
- # return that data.
1629
- #
1630
- # You should also check the returned number of bytes for bulk writes. Not all of the
1631
- # data may have been written.
1632
- #
1633
- # Also check transferred bytes when dealing with a timeout error code. libusb may have
1634
- # to split your transfer into a number of chunks to satisfy underlying O/S
1635
- # requirements, meaning that the timeout may expire after the first few chunks
1636
- # have completed. libusb is careful not to lose any data that may have been
1637
- # transferred; do not assume that timeout conditions indicate a complete lack of
1638
- # I/O.
1639
- #
1640
- # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1641
- # @param [String] :dataOut the data to send with an outgoing transfer
1642
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1643
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1644
- # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1645
- #
1646
- # @return [Fixnum] Number of bytes sent for an outgoing transfer
1647
- # @return [String] Received data for an ingoing transfer
1648
- def bulk_transfer(args={})
1649
- timeout = args.delete(:timeout) || 1000
1650
- endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
1651
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1652
- if endpoint&ENDPOINT_IN != 0
1653
- dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for bulk read")
1654
- else
1655
- dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for bulk write")
1656
- end
1657
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1658
-
1659
- # reuse transfer struct to speed up transfer
1660
- @bulk_transfer ||= BulkTransfer.new :dev_handle => self
1661
- tr = @bulk_transfer
1662
- tr.endpoint = endpoint
1663
- tr.timeout = timeout
1664
- if dataOut
1665
- tr.buffer = dataOut
1666
- else
1667
- tr.alloc_buffer(dataIn)
1668
- end
1669
-
1670
- tr.submit_and_wait!
1671
-
1672
- if dataOut
1673
- tr.actual_length
1674
- else
1675
- tr.actual_buffer
1676
- end
1677
- end
1678
-
1679
- # Perform a USB interrupt transfer.
1680
- #
1681
- # The direction of the transfer is inferred from the direction bits of the
1682
- # endpoint address.
1683
- #
1684
- # For interrupt reads, the +:dataIn+ param indicates the maximum length of data you
1685
- # are expecting to receive. If less data arrives than expected, this function will
1686
- # return that data.
1687
- #
1688
- # You should also check the returned number of bytes for interrupt writes. Not all of
1689
- # the data may have been written.
1690
- #
1691
- # Also check transferred when dealing with a timeout error code. libusb may have
1692
- # to split your transfer into a number of chunks to satisfy underlying O/S
1693
- # requirements, meaning that the timeout may expire after the first few chunks
1694
- # have completed. libusb is careful not to lose any data that may have been
1695
- # transferred; do not assume that timeout conditions indicate a complete lack of
1696
- # I/O.
1697
- #
1698
- # The default endpoint bInterval value is used as the polling interval.
1699
- #
1700
- # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1701
- # @param [String] :dataOut the data to send with an outgoing transfer
1702
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1703
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1704
- # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1705
- #
1706
- # @return [Fixnum] Number of bytes sent for an outgoing transfer
1707
- # @return [String] Received data for an ingoing transfer
1708
- def interrupt_transfer(args={})
1709
- timeout = args.delete(:timeout) || 1000
1710
- endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
1711
- endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1712
- if endpoint&ENDPOINT_IN != 0
1713
- dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for interrupt read")
1714
- else
1715
- dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for interrupt write")
1716
- end
1717
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1718
-
1719
- # reuse transfer struct to speed up transfer
1720
- @interrupt_transfer ||= InterruptTransfer.new :dev_handle => self
1721
- tr = @interrupt_transfer
1722
- tr.endpoint = endpoint
1723
- tr.timeout = timeout
1724
- if dataOut
1725
- tr.buffer = dataOut
1726
- else
1727
- tr.alloc_buffer(dataIn)
1728
- end
1729
-
1730
- tr.submit_and_wait!
1731
-
1732
- if dataOut
1733
- tr.actual_length
1734
- else
1735
- tr.actual_buffer
1736
- end
1737
- end
1738
-
1739
- # Perform a USB control transfer.
1740
- #
1741
- # The direction of the transfer is inferred from the +:bmRequestType+ field of the
1742
- # setup packet.
1743
- #
1744
- # @param [Fixnum] :bmRequestType the request type field for the setup packet
1745
- # @param [Fixnum] :bRequest the request field for the setup packet
1746
- # @param [Fixnum] :wValue the value field for the setup packet
1747
- # @param [Fixnum] :wIndex the index field for the setup packet
1748
- # @param [String] :dataOut the data to send with an outgoing transfer, it
1749
- # is appended to the setup packet
1750
- # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1751
- # (excluding setup packet)
1752
- # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1753
- # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1754
- #
1755
- # @return [Fixnum] Number of bytes sent (excluding setup packet) for outgoing transfer
1756
- # @return [String] Received data (without setup packet) for ingoing transfer
1757
- def control_transfer(args={})
1758
- bmRequestType = args.delete(:bmRequestType) || raise(ArgumentError, "param :bmRequestType not given")
1759
- bRequest = args.delete(:bRequest) || raise(ArgumentError, "param :bRequest not given")
1760
- wValue = args.delete(:wValue) || raise(ArgumentError, "param :wValue not given")
1761
- wIndex = args.delete(:wIndex) || raise(ArgumentError, "param :wIndex not given")
1762
- timeout = args.delete(:timeout) || 1000
1763
- if bmRequestType&ENDPOINT_IN != 0
1764
- dataIn = args.delete(:dataIn) || 0
1765
- dataOut = ''
1766
- else
1767
- dataOut = args.delete(:dataOut) || ''
1768
- end
1769
- raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1770
-
1771
- # reuse transfer struct to speed up transfer
1772
- @control_transfer ||= ControlTransfer.new :dev_handle => self
1773
- tr = @control_transfer
1774
- tr.timeout = timeout
1775
- if dataIn
1776
- setup_data = [bmRequestType, bRequest, wValue, wIndex, dataIn].pack('CCvvv')
1777
- tr.alloc_buffer( dataIn + CONTROL_SETUP_SIZE, setup_data )
1778
- else
1779
- tr.buffer = [bmRequestType, bRequest, wValue, wIndex, dataOut.bytesize, dataOut].pack('CCvvva*')
1780
- end
1781
-
1782
- tr.submit_and_wait!
1783
-
1784
- if dataIn
1785
- tr.actual_buffer(CONTROL_SETUP_SIZE)
1786
- else
1787
- tr.actual_length
1788
- end
1789
- end
1790
- end
1791
-
1792
52
  end