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

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