libusb 0.6.0-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +17 -0
  4. data/.yardopts +6 -0
  5. data/COPYING +165 -0
  6. data/Gemfile +11 -0
  7. data/History.md +124 -0
  8. data/README.md +159 -0
  9. data/Rakefile +145 -0
  10. data/appveyor.yml +23 -0
  11. data/lib/libusb.rb +58 -0
  12. data/lib/libusb/bos.rb +306 -0
  13. data/lib/libusb/call.rb +446 -0
  14. data/lib/libusb/compat.rb +376 -0
  15. data/lib/libusb/configuration.rb +155 -0
  16. data/lib/libusb/constants.rb +160 -0
  17. data/lib/libusb/context.rb +426 -0
  18. data/lib/libusb/dependencies.rb +7 -0
  19. data/lib/libusb/dev_handle.rb +564 -0
  20. data/lib/libusb/device.rb +365 -0
  21. data/lib/libusb/endpoint.rb +194 -0
  22. data/lib/libusb/eventmachine.rb +183 -0
  23. data/lib/libusb/interface.rb +60 -0
  24. data/lib/libusb/setting.rb +132 -0
  25. data/lib/libusb/ss_companion.rb +69 -0
  26. data/lib/libusb/stdio.rb +25 -0
  27. data/lib/libusb/transfer.rb +377 -0
  28. data/lib/libusb/version_gem.rb +19 -0
  29. data/lib/libusb/version_struct.rb +63 -0
  30. data/libusb.gemspec +30 -0
  31. data/test/test_libusb_bos.rb +118 -0
  32. data/test/test_libusb_bulk_stream_transfer.rb +50 -0
  33. data/test/test_libusb_capability.rb +23 -0
  34. data/test/test_libusb_compat.rb +78 -0
  35. data/test/test_libusb_compat_mass_storage.rb +81 -0
  36. data/test/test_libusb_descriptors.rb +212 -0
  37. data/test/test_libusb_event_machine.rb +118 -0
  38. data/test/test_libusb_gc.rb +37 -0
  39. data/test/test_libusb_hotplug.rb +127 -0
  40. data/test/test_libusb_iso_transfer.rb +50 -0
  41. data/test/test_libusb_mass_storage.rb +268 -0
  42. data/test/test_libusb_mass_storage2.rb +96 -0
  43. data/test/test_libusb_structs.rb +58 -0
  44. data/test/test_libusb_threads.rb +89 -0
  45. data/test/test_libusb_version.rb +40 -0
  46. data/wireshark-usb-sniffer.png +0 -0
  47. metadata +150 -0
@@ -0,0 +1,377 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ # Abstract base class for USB transfers. Use
20
+ # {ControlTransfer}, {BulkTransfer}, {InterruptTransfer}, {IsochronousTransfer}
21
+ # to do transfers.
22
+ #
23
+ # There are convenience methods for {DevHandle#bulk_transfer}, {DevHandle#control_transfer}
24
+ # and {DevHandle#interrupt_transfer}, that fit for most use cases.
25
+ # Using {Transfer} derived classes directly, however, is needed for isochronous transfers and
26
+ # allows a more advanced buffer management.
27
+ class Transfer
28
+ class ZeroCopyMemory < FFI::Pointer
29
+ attr_reader :size
30
+
31
+ def initialize(dev_handle, ptr, size)
32
+ @dev_handle = dev_handle
33
+ @size = size
34
+ super(ptr)
35
+ end
36
+
37
+ def free(id=nil)
38
+ return unless @size
39
+ # puts format("libusb_dev_mem_free(%#x, %d)%s", address, @size, id ? " by GC" : '')
40
+ res = Call.libusb_dev_mem_free( @dev_handle.pHandle, self, @size )
41
+ LIBUSB.raise_error res, "in libusb_dev_mem_free" if res!=0
42
+ @size = nil
43
+ end
44
+ end
45
+
46
+ def initialize(args={})
47
+ @buffer = nil
48
+ @completion_flag = Context::CompletionFlag.new
49
+ @allow_device_memory = false
50
+ args.each{|k,v| send("#{k}=", v) }
51
+ end
52
+ private :initialize
53
+
54
+ # Set the handle for the device to communicate with.
55
+ def dev_handle=(dev)
56
+ @dev_handle = dev
57
+ @transfer[:dev_handle] = @dev_handle.pHandle
58
+ end
59
+
60
+ # Timeout for this transfer in millseconds.
61
+ #
62
+ # A value of 0 indicates no timeout.
63
+ def timeout=(value)
64
+ @transfer[:timeout] = value
65
+ end
66
+
67
+ # Set the address of a valid endpoint to communicate with.
68
+ def endpoint=(endpoint)
69
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
70
+ @transfer[:endpoint] = endpoint
71
+ end
72
+
73
+ # Set output data that should be sent.
74
+ # @see #allow_device_memory
75
+ def buffer=(data)
76
+ ensure_enough_buffer(data.bytesize)
77
+ @buffer.put_bytes(0, data)
78
+ @transfer[:buffer] = @buffer
79
+ @transfer[:length] = data.bytesize
80
+ end
81
+
82
+ # Retrieve the current data buffer.
83
+ def buffer
84
+ @transfer[:buffer].read_string(@transfer[:length])
85
+ end
86
+
87
+ # Clear the current data buffer.
88
+ def free_buffer
89
+ if @buffer
90
+ @buffer.free
91
+ @buffer = nil
92
+ @transfer[:buffer] = nil
93
+ @transfer[:length] = 0
94
+ end
95
+ end
96
+
97
+ # Allocate +len+ bytes of data buffer for input transfer.
98
+ #
99
+ # @param [Fixnum] len Number of bytes to allocate
100
+ # @param [String, nil] data some data to initialize the buffer with
101
+ # @see #allow_device_memory
102
+ def alloc_buffer(len, data=nil)
103
+ ensure_enough_buffer(len)
104
+ @buffer.put_bytes(0, data) if data
105
+ @transfer[:buffer] = @buffer
106
+ @transfer[:length] = len
107
+ end
108
+
109
+ # The number of bytes actually transferred.
110
+ def actual_length
111
+ @transfer[:actual_length]
112
+ end
113
+
114
+ # Try to use persistent device memory.
115
+ #
116
+ # If enabled, attempts to allocate a block of persistent DMA memory suitable for transfers against the given device.
117
+ # The memory is allocated by {#alloc_buffer} or {#buffer=}.
118
+ # If unsuccessful, ordinary user space memory will be used.
119
+ #
120
+ # Using this memory instead of regular memory means that the host controller can use DMA directly into the buffer to increase performance, and also that transfers can no longer fail due to kernel memory fragmentation.
121
+ #
122
+ # It requires libusb-1.0.21 and Linux-4.6 to be effective, but it can safely be enabled on other systems.
123
+ #
124
+ # Note that this type of memory is bound to the {#dev_handle=}.
125
+ # So even if the {DevHandle} is closed, the memory is still accessable and the device is locked.
126
+ # It is free'd by the garbage collector eventually, but in order to close the device deterministic, it is required to call {#free_buffer} on all {Transfer}s which use persistent device memory.
127
+ #
128
+ # @see #free_buffer
129
+ # @see #memory_type
130
+ attr_accessor :allow_device_memory
131
+
132
+ # @return +:device_memory+ - If persistent device memory is allocated.
133
+ # @return +:user_space+ - If user space memory is allocated.
134
+ # @return +nil+ - If no memory is allocated.
135
+ def memory_type
136
+ case @buffer
137
+ when ZeroCopyMemory then :device_memory
138
+ when FFI::MemoryPointer then :user_space
139
+ else nil
140
+ end
141
+ end
142
+
143
+ def ensure_enough_buffer(len)
144
+ if !@buffer || len>@buffer.size
145
+ free_buffer
146
+ # Try to use zero-copy-memory and fallback to FFI-memory if not available
147
+ if @allow_device_memory && @dev_handle && Call.respond_to?(:libusb_dev_mem_alloc)
148
+ ptr = Call.libusb_dev_mem_alloc( @dev_handle.pHandle, len )
149
+ # puts format("libusb_dev_mem_alloc(%d) => %#x", len, ptr.address)
150
+ unless ptr.null?
151
+ buffer = ZeroCopyMemory.new(@dev_handle, ptr, len)
152
+ ObjectSpace.define_finalizer(self, buffer.method(:free))
153
+ end
154
+ end
155
+ @buffer = buffer || FFI::MemoryPointer.new(len, 1, false)
156
+ end
157
+ end
158
+ private :ensure_enough_buffer
159
+
160
+ # Retrieve the data actually transferred.
161
+ #
162
+ # @param [Fixnum] offset optional offset of the retrieved data in the buffer.
163
+ def actual_buffer(offset=0)
164
+ @transfer[:buffer].get_bytes(offset, @transfer[:actual_length])
165
+ end
166
+
167
+ # Set the block that will be invoked when the transfer completes,
168
+ # fails, or is cancelled.
169
+ #
170
+ # @param [Proc] proc The block that should be called
171
+ def callback=(proc)
172
+ # Save proc to instance variable so that GC doesn't free
173
+ # the proc object before the transfer.
174
+ @callback_proc = proc do |pTrans|
175
+ proc.call(self)
176
+ end
177
+ @transfer[:callback] = @callback_proc
178
+ end
179
+
180
+ # The status of the transfer.
181
+ #
182
+ # Only for use within transfer callback function or after the callback was called.
183
+ #
184
+ # If this is an isochronous transfer, this field may read :TRANSFER_COMPLETED even if there
185
+ # were errors in the frames. Use the status field in each packet to determine if
186
+ # errors occurred.
187
+ def status
188
+ @transfer[:status]
189
+ end
190
+
191
+ # Submit a transfer.
192
+ #
193
+ # This function will fire off the USB transfer and then return immediately.
194
+ # This method can be called with block. It is called when the transfer completes,
195
+ # fails, or is cancelled.
196
+ def submit!(&block)
197
+ self.callback = block if block_given?
198
+
199
+ # 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}"
200
+
201
+ res = Call.libusb_submit_transfer( @transfer )
202
+ LIBUSB.raise_error res, "in libusb_submit_transfer" if res!=0
203
+ end
204
+
205
+ # Asynchronously cancel a previously submitted transfer.
206
+ #
207
+ # This function returns immediately, but this does not indicate cancellation is
208
+ # complete. Your callback function will be invoked at some later time with a
209
+ # transfer status of :TRANSFER_CANCELLED.
210
+ def cancel!
211
+ res = Call.libusb_cancel_transfer( @transfer )
212
+ LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0
213
+ end
214
+
215
+ TransferStatusToError = {
216
+ :TRANSFER_ERROR => LIBUSB::ERROR_IO,
217
+ :TRANSFER_TIMED_OUT => LIBUSB::ERROR_TIMEOUT,
218
+ :TRANSFER_CANCELLED => LIBUSB::ERROR_INTERRUPTED,
219
+ :TRANSFER_STALL => LIBUSB::ERROR_PIPE,
220
+ :TRANSFER_NO_DEVICE => LIBUSB::ERROR_NO_DEVICE,
221
+ :TRANSFER_OVERFLOW => LIBUSB::ERROR_OVERFLOW,
222
+ }
223
+
224
+ # Submit the transfer and wait until the transfer completes or fails.
225
+ #
226
+ # Inspect {#status} to check for transfer errors.
227
+ def submit_and_wait
228
+ @completion_flag.completed = false
229
+ submit! do |tr2|
230
+ @completion_flag.completed = true
231
+ end
232
+
233
+ until @completion_flag.completed?
234
+ begin
235
+ @dev_handle.device.context.handle_events nil, @completion_flag
236
+ rescue ERROR_INTERRUPTED
237
+ next
238
+ rescue LIBUSB::Error
239
+ cancel!
240
+ until @completion_flag.completed?
241
+ @dev_handle.device.context.handle_events nil, @completion_flag
242
+ end
243
+ raise
244
+ end
245
+ end
246
+ end
247
+
248
+ # Submit the transfer and wait until the transfer completes or fails.
249
+ #
250
+ # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
251
+ def submit_and_wait!
252
+ submit_and_wait
253
+
254
+ raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
255
+ end
256
+ end
257
+
258
+ class BulkTransfer < Transfer
259
+ def initialize(args={})
260
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
261
+ @transfer[:type] = TRANSFER_TYPE_BULK
262
+ @transfer[:timeout] = 1000
263
+ super
264
+ end
265
+ end
266
+
267
+ if Call.respond_to?(:libusb_transfer_get_stream_id)
268
+
269
+ # Transfer class for USB bulk transfers using USB-3.0 streams.
270
+ #
271
+ # @see DevHandle#alloc_streams
272
+ #
273
+ # Available since libusb-1.0.19.
274
+ class BulkStreamTransfer < Transfer
275
+ def initialize(args={})
276
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
277
+ @transfer[:type] = TRANSFER_TYPE_BULK_STREAM
278
+ @transfer[:timeout] = 1000
279
+ super
280
+ end
281
+
282
+ # Set a transfers bulk stream id.
283
+ #
284
+ # @param [Fixnum] stream_id the stream id to set
285
+ def stream_id=(v)
286
+ Call.libusb_transfer_set_stream_id(@transfer, v)
287
+ v
288
+ end
289
+
290
+ # Get a transfers bulk stream id.
291
+ #
292
+ # Available since libusb-1.0.19.
293
+ #
294
+ # @return [Fixnum] the stream id for the transfer
295
+ def stream_id
296
+ Call.libusb_transfer_get_stream_id(@transfer)
297
+ end
298
+ end
299
+ end
300
+
301
+ class ControlTransfer < Transfer
302
+ def initialize(args={})
303
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
304
+ @transfer[:type] = TRANSFER_TYPE_CONTROL
305
+ @transfer[:timeout] = 1000
306
+ super
307
+ end
308
+ end
309
+
310
+ class InterruptTransfer < Transfer
311
+ def initialize(args={})
312
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
313
+ @transfer[:type] = TRANSFER_TYPE_INTERRUPT
314
+ @transfer[:timeout] = 1000
315
+ super
316
+ end
317
+ end
318
+
319
+ class IsoPacket
320
+ def initialize(ptr, pkg_nr)
321
+ @packet = Call::IsoPacketDescriptor.new ptr
322
+ @pkg_nr = pkg_nr
323
+ end
324
+
325
+ def status
326
+ @packet[:status]
327
+ end
328
+
329
+ def length
330
+ @packet[:length]
331
+ end
332
+ def length=(len)
333
+ @packet[:length] = len
334
+ end
335
+
336
+ def actual_length
337
+ @packet[:actual_length]
338
+ end
339
+ end
340
+
341
+ class IsochronousTransfer < Transfer
342
+ def initialize(num_packets, args={})
343
+ @ptr = Call.libusb_alloc_transfer(num_packets)
344
+ @transfer = Call::Transfer.new @ptr
345
+ @transfer[:type] = TRANSFER_TYPE_ISOCHRONOUS
346
+ @transfer[:timeout] = 1000
347
+ @transfer[:num_iso_packets] = num_packets
348
+ super(args)
349
+ end
350
+
351
+ def num_packets
352
+ @transfer[:num_iso_packets]
353
+ end
354
+ def num_packets=(number)
355
+ @transfer[:num_iso_packets] = number
356
+ end
357
+
358
+ def [](nr)
359
+ IsoPacket.new( @ptr + Call::Transfer.size + nr*Call::IsoPacketDescriptor.size, nr)
360
+ end
361
+
362
+ # Convenience function to set the length of all packets in an
363
+ # isochronous transfer, based on {IsochronousTransfer#num_packets}.
364
+ def packet_lengths=(len)
365
+ ptr = @ptr + Call::Transfer.size
366
+ num_packets.times do
367
+ ptr.write_uint(len)
368
+ ptr += Call::IsoPacketDescriptor.size
369
+ end
370
+ end
371
+
372
+ # The actual_length field of the transfer is meaningless and should not
373
+ # be examined; instead you must refer to the actual_length field of
374
+ # each individual packet.
375
+ private :actual_length, :actual_buffer
376
+ end
377
+ end
@@ -0,0 +1,19 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module LIBUSB
17
+ # Library version of libusb for Ruby
18
+ VERSION = "0.6.0"
19
+ end
@@ -0,0 +1,63 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'libusb/call'
17
+
18
+ module LIBUSB
19
+ class Version < FFI::Struct
20
+ layout :major, :uint16,
21
+ :minor, :uint16,
22
+ :micro, :uint16,
23
+ :nano, :uint16,
24
+ :rc, :pointer,
25
+ :describe, :pointer
26
+
27
+ # Library major version.
28
+ def major
29
+ self[:major]
30
+ end
31
+ # Library minor version.
32
+ def minor
33
+ self[:minor]
34
+ end
35
+ # Library micro version.
36
+ def micro
37
+ self[:micro]
38
+ end
39
+ # Library nano version.
40
+ def nano
41
+ self[:nano]
42
+ end
43
+
44
+ # Library release candidate suffix string, e.g. "-rc4".
45
+ def rc
46
+ self[:rc].read_string
47
+ end
48
+
49
+ # For ABI compatibility only.
50
+ def describe
51
+ self[:describe].read_string
52
+ end
53
+
54
+ # Version string, e.g. "1.2.3-rc4"
55
+ def to_s
56
+ "#{major}.#{minor}.#{micro}#{rc}"
57
+ end
58
+
59
+ def inspect
60
+ "\#<#{self.class} #{to_s}>"
61
+ end
62
+ end
63
+ end