libusb 0.1.0-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/lib/libusb.rb ADDED
@@ -0,0 +1,1523 @@
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 'rubygems'
17
+ require 'ffi'
18
+
19
+
20
+ module LIBUSB
21
+ VERSION = "0.1.0"
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
169
+ attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
170
+ attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int
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
175
+ attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int
176
+ attach_function 'libusb_reset_device', [:libusb_device_handle], :int
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
+ class Error < RuntimeError
239
+ end
240
+ ErrorClassForResult = {}
241
+
242
+ # define an exception class for each error code
243
+ Call::Errors.to_h.each do |k,v|
244
+ klass = Class.new(Error)
245
+ klass.send(:define_method, :code){ v }
246
+ const_set(k, klass)
247
+ ErrorClassForResult[v] = klass
248
+ end
249
+
250
+ def self.raise_error(res, text)
251
+ klass = ErrorClassForResult[res]
252
+ raise klass, "#{klass} #{text}"
253
+ end
254
+
255
+ CONTROL_SETUP_SIZE = 8
256
+ DT_DEVICE_SIZE = 18
257
+ DT_CONFIG_SIZE = 9
258
+ DT_INTERFACE_SIZE = 9
259
+ DT_ENDPOINT_SIZE = 7
260
+ DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
261
+ DT_HUB_NONVAR_SIZE = 7
262
+
263
+ ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
264
+ ENDPOINT_DIR_MASK = 0x80
265
+ TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
266
+ ISO_SYNC_TYPE_MASK = 0x0C
267
+ ISO_USAGE_TYPE_MASK = 0x30
268
+
269
+
270
+ # :stopdoc:
271
+ # http://www.usb.org/developers/defined_class
272
+ CLASS_CODES = [
273
+ [0x01, nil, nil, "Audio"],
274
+ [0x02, nil, nil, "Comm"],
275
+ [0x03, nil, nil, "HID"],
276
+ [0x05, nil, nil, "Physical"],
277
+ [0x06, 0x01, 0x01, "StillImaging"],
278
+ [0x06, nil, nil, "Image"],
279
+ [0x07, nil, nil, "Printer"],
280
+ [0x08, 0x01, nil, "MassStorage RBC Bluk-Only"],
281
+ [0x08, 0x02, 0x50, "MassStorage ATAPI Bluk-Only"],
282
+ [0x08, 0x03, 0x50, "MassStorage QIC-157 Bluk-Only"],
283
+ [0x08, 0x04, nil, "MassStorage UFI"],
284
+ [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bluk-Only"],
285
+ [0x08, 0x06, 0x50, "MassStorage SCSI Bluk-Only"],
286
+ [0x08, nil, nil, "MassStorage"],
287
+ [0x09, 0x00, 0x00, "Full speed Hub"],
288
+ [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
289
+ [0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
290
+ [0x09, nil, nil, "Hub"],
291
+ [0x0a, nil, nil, "CDC"],
292
+ [0x0b, nil, nil, "SmartCard"],
293
+ [0x0d, 0x00, 0x00, "ContentSecurity"],
294
+ [0x0e, nil, nil, "Video"],
295
+ [0xdc, 0x01, 0x01, "Diagnostic USB2"],
296
+ [0xdc, nil, nil, "Diagnostic"],
297
+ [0xe0, 0x01, 0x01, "Bluetooth"],
298
+ [0xe0, 0x01, 0x02, "UWB"],
299
+ [0xe0, 0x01, 0x03, "RemoteNDIS"],
300
+ [0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
301
+ [0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
302
+ [0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
303
+ [0xe0, nil, nil, "Wireless Controller"],
304
+ [0xef, 0x01, 0x01, "Active Sync"],
305
+ [0xef, 0x01, 0x02, "Palm Sync"],
306
+ [0xef, 0x02, 0x01, "Interface Association Descriptor"],
307
+ [0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
308
+ [0xef, 0x03, 0x01, "Cable Based Association Framework"],
309
+ [0xef, nil, nil, "Miscellaneous"],
310
+ [0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
311
+ [0xfe, 0x02, 0x00, "IRDA Bridge"],
312
+ [0xfe, 0x03, 0x00, "USB Test and Measurement"],
313
+ [0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
314
+ [0xfe, nil, nil, "Application Specific"],
315
+ [0xff, nil, nil, "Vendor specific"],
316
+ ]
317
+ CLASS_CODES_HASH1 = {}
318
+ CLASS_CODES_HASH2 = {}
319
+ CLASS_CODES_HASH3 = {}
320
+ CLASS_CODES.each {|base_class, sub_class, protocol, desc|
321
+ if protocol
322
+ CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
323
+ elsif sub_class
324
+ CLASS_CODES_HASH2[[base_class, sub_class]] = desc
325
+ else
326
+ CLASS_CODES_HASH1[base_class] = desc
327
+ end
328
+ }
329
+
330
+ def self.dev_string(base_class, sub_class, protocol)
331
+ if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
332
+ desc
333
+ elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
334
+ desc + " (%02x)" % [protocol]
335
+ elsif desc = CLASS_CODES_HASH1[base_class]
336
+ desc + " (%02x,%02x)" % [sub_class, protocol]
337
+ else
338
+ "Unkonwn(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
339
+ end
340
+ end
341
+ # :startdoc:
342
+
343
+
344
+ # Abstract base class for USB transfers. Use
345
+ # {ControlTransfer}, {BulkTransfer}, {InterruptTransfer}, {IsochronousTransfer}
346
+ # to do transfers.
347
+ class Transfer
348
+ def initialize(args={})
349
+ args.each{|k,v| send("#{k}=", v) }
350
+ @buffer = nil
351
+ end
352
+ private :initialize
353
+
354
+ # Set the handle for the device to communicate with.
355
+ def dev_handle=(dev)
356
+ @dev_handle = dev
357
+ @transfer[:dev_handle] = @dev_handle.pHandle
358
+ end
359
+
360
+ # Timeout for this transfer in millseconds.
361
+ #
362
+ # A value of 0 indicates no timeout.
363
+ def timeout=(value)
364
+ @transfer[:timeout] = value
365
+ end
366
+
367
+ # Set the address of a valid endpoint to communicate with.
368
+ def endpoint=(endpoint)
369
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
370
+ @transfer[:endpoint] = endpoint
371
+ end
372
+
373
+ # Set output data that should be sent.
374
+ def buffer=(data)
375
+ if !@buffer || data.bytesize>@buffer.size
376
+ free_buffer
377
+ @buffer = FFI::MemoryPointer.new(data.bytesize, 1, false)
378
+ end
379
+ @buffer.put_bytes(0, data)
380
+ @transfer[:buffer] = @buffer
381
+ @transfer[:length] = data.bytesize
382
+ end
383
+
384
+ # Retrieve the current data buffer.
385
+ def buffer
386
+ @transfer[:buffer].read_string(@transfer[:length])
387
+ end
388
+
389
+ # Clear the current data buffer.
390
+ def free_buffer
391
+ if @buffer
392
+ @buffer.free
393
+ @buffer = nil
394
+ @transfer[:buffer] = nil
395
+ @transfer[:length] = 0
396
+ end
397
+ end
398
+
399
+ # Allocate +len+ bytes of data buffer for input transfer.
400
+ #
401
+ # @param [Fixnum] len Number of bytes to allocate
402
+ # @param [String, nil] data some data to initialize the buffer with
403
+ def alloc_buffer(len, data=nil)
404
+ if !@buffer || len>@buffer.size
405
+ free_buffer
406
+ @buffer = FFI::MemoryPointer.new(len, 1, false)
407
+ end
408
+ @buffer.put_bytes(0, data) if data
409
+ @transfer[:buffer] = @buffer
410
+ @transfer[:length] = len
411
+ end
412
+
413
+ # The number of bytes actually transferred.
414
+ def actual_length
415
+ @transfer[:actual_length]
416
+ end
417
+
418
+ # Retrieve the data actually transferred.
419
+ #
420
+ # @param [Fixnum] offset optional offset of the retrieved data in the buffer.
421
+ def actual_buffer(offset=0)
422
+ @transfer[:buffer].get_bytes(offset, @transfer[:actual_length])
423
+ end
424
+
425
+ # Set the block that will be invoked when the transfer completes,
426
+ # fails, or is cancelled.
427
+ #
428
+ # @param [Proc] proc The block that should be called
429
+ def callback=(proc)
430
+ # Save proc to instance variable so that GC doesn't free
431
+ # the proc object before the transfer.
432
+ @callback_proc = proc do |pTrans|
433
+ proc.call(self)
434
+ end
435
+ @transfer[:callback] = @callback_proc
436
+ end
437
+
438
+ # The status of the transfer.
439
+ #
440
+ # Only for use within transfer callback function or after the callback was called.
441
+ #
442
+ # If this is an isochronous transfer, this field may read :TRANSFER_COMPLETED even if there
443
+ # were errors in the frames. Use the status field in each packet to determine if
444
+ # errors occurred.
445
+ def status
446
+ @transfer[:status]
447
+ end
448
+
449
+ # Submit a transfer.
450
+ #
451
+ # This function will fire off the USB transfer and then return immediately.
452
+ # This method can be called with block. It is called when the transfer completes,
453
+ # fails, or is cancelled.
454
+ def submit!(&block)
455
+ self.callback = block if block_given?
456
+
457
+ # 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}"
458
+
459
+ res = Call.libusb_submit_transfer( @transfer )
460
+ LIBUSB.raise_error res, "in libusb_submit_transfer" if res!=0
461
+ end
462
+
463
+ # Asynchronously cancel a previously submitted transfer.
464
+ #
465
+ # This function returns immediately, but this does not indicate cancellation is
466
+ # complete. Your callback function will be invoked at some later time with a
467
+ # transfer status of :TRANSFER_CANCELLED.
468
+ def cancel!
469
+ res = Call.libusb_cancel_transfer( @transfer )
470
+ LIBUSB.raise_error res, "in libusb_cancel_transfer" if res!=0
471
+ end
472
+
473
+ TransferStatusToError = {
474
+ :TRANSFER_ERROR => LIBUSB::ERROR_IO,
475
+ :TRANSFER_TIMED_OUT => LIBUSB::ERROR_TIMEOUT,
476
+ :TRANSFER_CANCELLED => LIBUSB::ERROR_INTERRUPTED,
477
+ :TRANSFER_STALL => LIBUSB::ERROR_PIPE,
478
+ :TRANSFER_NO_DEVICE => LIBUSB::ERROR_NO_DEVICE,
479
+ :TRANSFER_OVERFLOW => LIBUSB::ERROR_OVERFLOW,
480
+ }
481
+
482
+ # Submit the transfer and wait until the transfer completes or fails.
483
+ #
484
+ # A proper {LIBUSB::Error} is raised, in case the transfer did not complete.
485
+ def submit_and_wait!
486
+ completed = false
487
+ submit! do |tr2|
488
+ completed = true
489
+ end
490
+
491
+ until completed
492
+ begin
493
+ @dev_handle.device.context.handle_events
494
+ rescue ERROR_INTERRUPTED
495
+ next
496
+ rescue LIBUSB::Error
497
+ cancel!
498
+ until completed
499
+ @dev_handle.device.context.handle_events
500
+ end
501
+ raise
502
+ end
503
+ end
504
+
505
+ raise( TransferStatusToError[status] || ERROR_OTHER, "error #{status}") unless status==:TRANSFER_COMPLETED
506
+ end
507
+ end
508
+
509
+ class BulkTransfer < Transfer
510
+ def initialize(args={})
511
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
512
+ @transfer[:type] = TRANSFER_TYPE_BULK
513
+ @transfer[:timeout] = 1000
514
+ super
515
+ end
516
+ end
517
+
518
+ class ControlTransfer < Transfer
519
+ def initialize(args={})
520
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
521
+ @transfer[:type] = TRANSFER_TYPE_CONTROL
522
+ @transfer[:timeout] = 1000
523
+ super
524
+ end
525
+ end
526
+
527
+ class InterruptTransfer < Transfer
528
+ def initialize(args={})
529
+ @transfer = Call::Transfer.new Call.libusb_alloc_transfer(0)
530
+ @transfer[:type] = TRANSFER_TYPE_INTERRUPT
531
+ @transfer[:timeout] = 1000
532
+ super
533
+ end
534
+ end
535
+
536
+ class IsoPacket
537
+ def initialize(ptr, pkg_nr)
538
+ @packet = Call::IsoPacketDescriptor.new ptr
539
+ @pkg_nr = pkg_nr
540
+ end
541
+
542
+ def status
543
+ @packet[:status]
544
+ end
545
+
546
+ def length
547
+ @packet[:length]
548
+ end
549
+ def length=(len)
550
+ @packet[:length] = len
551
+ end
552
+
553
+ def actual_length
554
+ @packet[:actual_length]
555
+ end
556
+ end
557
+
558
+ class IsochronousTransfer < Transfer
559
+ def initialize(num_packets, args={})
560
+ @ptr = Call.libusb_alloc_transfer(num_packets)
561
+ @transfer = Call::Transfer.new @ptr
562
+ @transfer[:type] = TRANSFER_TYPE_ISOCHRONOUS
563
+ @transfer[:timeout] = 1000
564
+ @transfer[:num_iso_packets] = num_packets
565
+ super(args)
566
+ end
567
+
568
+ def num_packets
569
+ @transfer[:num_iso_packets]
570
+ end
571
+ def num_packets=(number)
572
+ @transfer[:num_iso_packets] = number
573
+ end
574
+
575
+ def [](nr)
576
+ IsoPacket.new( @ptr + Call::Transfer.size + nr*Call::IsoPacketDescriptor.size, nr)
577
+ end
578
+
579
+ # Convenience function to set the length of all packets in an
580
+ # isochronous transfer, based on {IsochronousTransfer#num_packets}.
581
+ def packet_lengths=(len)
582
+ ptr = @ptr + Call::Transfer.size
583
+ num_packets.times do
584
+ ptr.write_uint(len)
585
+ ptr += Call::IsoPacketDescriptor.size
586
+ end
587
+ end
588
+
589
+ # The actual_length field of the transfer is meaningless and should not
590
+ # be examined; instead you must refer to the actual_length field of
591
+ # each individual packet.
592
+ private :actual_length, :actual_buffer
593
+ end
594
+
595
+ class DeviceDescriptor < FFI::Struct
596
+ include Comparable
597
+
598
+ layout :bLength, :uint8,
599
+ :bDescriptorType, :uint8,
600
+ :bcdUSB, :uint16,
601
+ :bDeviceClass, :uint8,
602
+ :bDeviceSubClass, :uint8,
603
+ :bDeviceProtocol, :uint8,
604
+ :bMaxPacketSize0, :uint8,
605
+ :idVendor, :uint16,
606
+ :idProduct, :uint16,
607
+ :bcdDevice, :uint16,
608
+ :iManufacturer, :uint8,
609
+ :iProduct, :uint8,
610
+ :iSerialNumber, :uint8,
611
+ :bNumConfigurations, :uint8
612
+ end
613
+
614
+ class Configuration < FFI::ManagedStruct
615
+ include Comparable
616
+
617
+ layout :bLength, :uint8,
618
+ :bDescriptorType, :uint8,
619
+ :wTotalLength, :uint16,
620
+ :bNumInterfaces, :uint8,
621
+ :bConfigurationValue, :uint8,
622
+ :iConfiguration, :uint8,
623
+ :bmAttributes, :uint8,
624
+ :maxPower, :uint8,
625
+ :interface, :pointer,
626
+ :extra, :pointer,
627
+ :extra_length, :int
628
+
629
+ members.each do |member|
630
+ define_method(member) do
631
+ self[member]
632
+ end
633
+ end
634
+
635
+ def initialize(device, *args)
636
+ @device = device
637
+ super(*args)
638
+ end
639
+
640
+ def self.release(ptr)
641
+ Call.libusb_free_config_descriptor(ptr)
642
+ end
643
+
644
+ # @return [Device] the device this configuration belongs to.
645
+ attr_reader :device
646
+
647
+ def interfaces
648
+ ifs = []
649
+ self[:bNumInterfaces].times do |i|
650
+ ifs << Interface.new(self, self[:interface] + i*Interface.size)
651
+ end
652
+ return ifs
653
+ end
654
+
655
+ def inspect
656
+ attrs = []
657
+ attrs << self.bConfigurationValue.to_s
658
+ bits = self.bmAttributes
659
+ attrs << "SelfPowered" if (bits & 0b1000000) != 0
660
+ attrs << "RemoteWakeup" if (bits & 0b100000) != 0
661
+ desc = self.description
662
+ attrs << desc if desc != '?'
663
+ "\#<#{self.class} #{attrs.join(' ')}>"
664
+ end
665
+
666
+ # Return name of the configuration as String.
667
+ def description
668
+ return @description if defined? @description
669
+ @description = device.try_string_descriptor_ascii(self.iConfiguration)
670
+ end
671
+
672
+ # Return all interface decriptions of the configuration as Array of InterfaceDescriptor s.
673
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
674
+ # Return all endpoints of all interfaces of the configuration as Array of EndpointDescriptor s.
675
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
676
+
677
+ def <=>(o)
678
+ t = device<=>o.device
679
+ t = bConfigurationValue<=>o.bConfigurationValue if t==0
680
+ t
681
+ end
682
+ end
683
+
684
+ class Interface < FFI::Struct
685
+ include Comparable
686
+
687
+ layout :altsetting, :pointer,
688
+ :num_altsetting, :int
689
+
690
+ def initialize(configuration, *args)
691
+ @configuration = configuration
692
+ super(*args)
693
+ end
694
+
695
+ # @return [Configuration] the configuration this interface belongs to.
696
+ attr_reader :configuration
697
+
698
+ def alt_settings
699
+ ifs = []
700
+ self[:num_altsetting].times do |i|
701
+ ifs << Setting.new(self, self[:altsetting] + i*Setting.size)
702
+ end
703
+ return ifs
704
+ end
705
+ alias settings alt_settings
706
+
707
+ # The Device the Interface belongs to.
708
+ def device() self.configuration.device end
709
+ # Return all endpoints of all alternative settings as Array of EndpointDescriptor s.
710
+ def endpoints() self.alt_settings.map {|d| d.endpoints }.flatten end
711
+
712
+ def <=>(o)
713
+ configuration<=>o.configuration
714
+ end
715
+ end
716
+
717
+ class Setting < FFI::Struct
718
+ include Comparable
719
+
720
+ layout :bLength, :uint8,
721
+ :bDescriptorType, :uint8,
722
+ :bInterfaceNumber, :uint8,
723
+ :bAlternateSetting, :uint8,
724
+ :bNumEndpoints, :uint8,
725
+ :bInterfaceClass, :uint8,
726
+ :bInterfaceSubClass, :uint8,
727
+ :bInterfaceProtocol, :uint8,
728
+ :iInterface, :uint8,
729
+ :endpoint, :pointer,
730
+ :extra, :pointer,
731
+ :extra_length, :int
732
+
733
+ members.each do |member|
734
+ define_method(member) do
735
+ self[member]
736
+ end
737
+ end
738
+
739
+ def initialize(interface, *args)
740
+ @interface = interface
741
+ super(*args)
742
+ end
743
+
744
+ # @return [Interface] the interface this setting belongs to.
745
+ attr_reader :interface
746
+
747
+ def endpoints
748
+ ifs = []
749
+ self[:bNumEndpoints].times do |i|
750
+ ifs << Endpoint.new(self, self[:endpoint] + i*Endpoint.size)
751
+ end
752
+ return ifs
753
+ end
754
+
755
+ def inspect
756
+ attrs = []
757
+ attrs << self.bAlternateSetting.to_s
758
+ devclass = LIBUSB.dev_string(self.bInterfaceClass, self.bInterfaceSubClass, self.bInterfaceProtocol)
759
+ attrs << devclass
760
+ desc = self.description
761
+ attrs << desc if desc != '?'
762
+ "\#<#{self.class} #{attrs.join(' ')}>"
763
+ end
764
+
765
+ # Return name of the Interface as String.
766
+ def description
767
+ return @description if defined? @description
768
+ @description = device.try_string_descriptor_ascii(self.iInterface)
769
+ end
770
+
771
+ # The Device the InterfaceDescriptor belongs to.
772
+ def device() self.interface.configuration.device end
773
+ # The ConfigDescriptor the InterfaceDescriptor belongs to.
774
+ def configuration() self.interface.configuration end
775
+
776
+ def <=>(o)
777
+ t = interface<=>o.interface
778
+ t = bInterfaceNumber<=>o.bInterfaceNumber if t==0
779
+ t = bAlternateSetting<=>o.bAlternateSetting if t==0
780
+ t
781
+ end
782
+ end
783
+
784
+ class Endpoint < FFI::Struct
785
+ include Comparable
786
+
787
+ layout :bLength, :uint8,
788
+ :bDescriptorType, :uint8,
789
+ :bEndpointAddress, :uint8,
790
+ :bmAttributes, :uint8,
791
+ :wMaxPacketSize, :uint16,
792
+ :bInterval, :uint8,
793
+ :bRefresh, :uint8,
794
+ :bSynchAddress, :uint8,
795
+ :extra, :pointer,
796
+ :extra_length, :int
797
+
798
+ members.each do |member|
799
+ define_method(member) do
800
+ self[member]
801
+ end
802
+ end
803
+
804
+ def initialize(setting, *args)
805
+ @setting = setting
806
+ super(*args)
807
+ end
808
+
809
+ # @return [Setting] the setting this endpoint belongs to.
810
+ attr_reader :setting
811
+
812
+ def inspect
813
+ endpoint_address = self.bEndpointAddress
814
+ num = endpoint_address & 0b00001111
815
+ inout = (endpoint_address & 0b10000000) == 0 ? "OUT" : "IN "
816
+ bits = self.bmAttributes
817
+ transfer_type = %w[Control Isochronous Bulk Interrupt][0b11 & bits]
818
+ type = [transfer_type]
819
+ if transfer_type == 'Isochronous'
820
+ synchronization_type = %w[NoSynchronization Asynchronous Adaptive Synchronous][(0b1100 & bits) >> 2]
821
+ usage_type = %w[Data Feedback ImplicitFeedback ?][(0b110000 & bits) >> 4]
822
+ type << synchronization_type << usage_type
823
+ end
824
+ "\#<#{self.class} #{num} #{inout} #{type.join(" ")}>"
825
+ end
826
+
827
+ # The Device the EndpointDescriptor belongs to.
828
+ def device() self.setting.interface.configuration.device end
829
+ # The ConfigDescriptor the EndpointDescriptor belongs to.
830
+ def configuration() self.setting.interface.configuration end
831
+ # The Interface the EndpointDescriptor belongs to.
832
+ def interface() self.setting.interface end
833
+
834
+ def <=>(o)
835
+ t = setting<=>o.setting
836
+ t = bEndpointAddress<=>o.bEndpointAddress if t==0
837
+ t
838
+ end
839
+ end
840
+
841
+
842
+ # Class representing a libusb session.
843
+ class Context
844
+ # Initialize libusb context.
845
+ def initialize
846
+ m = FFI::MemoryPointer.new :pointer
847
+ Call.libusb_init(m)
848
+ @ctx = m.read_pointer
849
+ end
850
+
851
+ # Deinitialize libusb.
852
+ #
853
+ # Should be called after closing all open devices and before your application terminates.
854
+ def exit
855
+ Call.libusb_exit(@ctx)
856
+ end
857
+
858
+ # Set message verbosity.
859
+ #
860
+ # * Level 0: no messages ever printed by the library (default)
861
+ # * Level 1: error messages are printed to stderr
862
+ # * Level 2: warning and error messages are printed to stderr
863
+ # * Level 3: informational messages are printed to stdout, warning and
864
+ # error messages are printed to stderr
865
+ #
866
+ # The default level is 0, which means no messages are ever printed. If you
867
+ # choose to increase the message verbosity level, ensure that your
868
+ # application does not close the stdout/stderr file descriptors.
869
+ #
870
+ # You are advised to set level 3. libusb is conservative with its message
871
+ # logging and most of the time, will only log messages that explain error
872
+ # conditions and other oddities. This will help you debug your software.
873
+ #
874
+ # If the LIBUSB_DEBUG environment variable was set when libusb was
875
+ # initialized, this method does nothing: the message verbosity is
876
+ # fixed to the value in the environment variable.
877
+ #
878
+ # If libusb was compiled without any message logging, this method
879
+ # does nothing: you'll never get any messages.
880
+ #
881
+ # If libusb was compiled with verbose debug message logging, this
882
+ # method does nothing: you'll always get messages from all levels.
883
+ #
884
+ # @param [Fixnum] level debug level to set
885
+ def debug=(level)
886
+ Call.libusb_set_debug(@ctx, level)
887
+ end
888
+
889
+ def device_list
890
+ pppDevs = FFI::MemoryPointer.new :pointer
891
+ size = Call.libusb_get_device_list(@ctx, pppDevs)
892
+ ppDevs = pppDevs.read_pointer
893
+ pDevs = []
894
+ size.times do |devi|
895
+ pDev = ppDevs.get_pointer(devi*FFI.type_size(:pointer))
896
+ pDevs << Device.new(self, pDev)
897
+ end
898
+ Call.libusb_free_device_list(ppDevs, 1)
899
+ pDevs
900
+ end
901
+ private :device_list
902
+
903
+ # Handle any pending events in blocking mode.
904
+ #
905
+ # This method must be called when libusb is running asynchronous transfers.
906
+ # This gives libusb the opportunity to reap pending transfers,
907
+ # invoke callbacks, etc.
908
+ def handle_events
909
+ res = Call.libusb_handle_events(@ctx)
910
+ LIBUSB.raise_error res, "in libusb_handle_events" if res<0
911
+ end
912
+
913
+ # Obtain a list of devices currently attached to the USB system, optionally matching certain criteria.
914
+ #
915
+ # @param [Hash] filter_hash A number of criteria can be defined in key-value pairs.
916
+ # Only devices that equal all given criterions will be returned. If a criterion is
917
+ # not specified or its value is +nil+, any device will match that criterion.
918
+ # The following criteria can be filtered:
919
+ # * <tt>:idVendor</tt>, <tt>:idProduct</tt> (+FixNum+) for matching vendor/product ID,
920
+ # * <tt>:bClass</tt>, <tt>:bSubClass</tt>, <tt>:bProtocol</tt> (+FixNum+) for the device type -
921
+ # Devices using CLASS_PER_INTERFACE will match, if any of the interfaces match.
922
+ # * <tt>:bcdUSB</tt>, <tt>:bcdDevice</tt>, <tt>:bMaxPacketSize0</tt> (+FixNum+) for the
923
+ # USB and device release numbers.
924
+ # Criteria can also specified as Array of several alternative values.
925
+ #
926
+ # @example
927
+ # # Return all devices of vendor 0x0ab1 where idProduct is 3 or 4:
928
+ # context.device :idVendor=>0x0ab1, :idProduct=>[0x0003, 0x0004]
929
+ #
930
+ # @return [Array<LIBUSB::Device>]
931
+ def devices(filter_hash={})
932
+ device_list.select do |dev|
933
+ ( !filter_hash[:bClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
934
+ dev.settings.map(&:bInterfaceClass).&([filter_hash[:bClass]].flatten).any? :
935
+ [filter_hash[:bClass]].flatten.include?(dev.bDeviceClass))) &&
936
+ ( !filter_hash[:bSubClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
937
+ dev.settings.map(&:bInterfaceSubClass).&([filter_hash[:bSubClass]].flatten).any? :
938
+ [filter_hash[:bSubClass]].flatten.include?(dev.bDeviceSubClass))) &&
939
+ ( !filter_hash[:bProtocol] || (dev.bDeviceClass==CLASS_PER_INTERFACE ?
940
+ dev.settings.map(&:bInterfaceProtocol).&([filter_hash[:bProtocol]].flatten).any? :
941
+ [filter_hash[:bProtocol]].flatten.include?(dev.bDeviceProtocol))) &&
942
+ ( !filter_hash[:bMaxPacketSize0] || [filter_hash[:bMaxPacketSize0]].flatten.include?(dev.bMaxPacketSize0) ) &&
943
+ ( !filter_hash[:idVendor] || [filter_hash[:idVendor]].flatten.include?(dev.idVendor) ) &&
944
+ ( !filter_hash[:idProduct] || [filter_hash[:idProduct]].flatten.include?(dev.idProduct) ) &&
945
+ ( !filter_hash[:bcdUSB] || [filter_hash[:bcdUSB]].flatten.include?(dev.bcdUSB) ) &&
946
+ ( !filter_hash[:bcdDevice] || [filter_hash[:bcdDevice]].flatten.include?(dev.bcdDevice) )
947
+ end
948
+ end
949
+ end
950
+
951
+ # Class representing a USB device detected on the system.
952
+ #
953
+ # Devices of the system can be obtained with {Context#devices} .
954
+ class Device
955
+ include Comparable
956
+
957
+ # @return [Context] the context this device belongs to.
958
+ attr_reader :context
959
+
960
+ def initialize context, pDev
961
+ @context = context
962
+ class << pDev
963
+ def unref_device(id)
964
+ Call.libusb_unref_device(self)
965
+ end
966
+ end
967
+ ObjectSpace.define_finalizer(self, pDev.method(:unref_device))
968
+ Call.libusb_ref_device(pDev)
969
+ @pDev = pDev
970
+
971
+ @pDevDesc = DeviceDescriptor.new
972
+ res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
973
+ LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
974
+ end
975
+
976
+ # Open a device and obtain a device handle.
977
+ #
978
+ # A handle allows you to perform I/O on the device in question.
979
+ # This is a non-blocking function; no requests are sent over the bus.
980
+ #
981
+ # If called with a block, the handle is passed to the block
982
+ # and is closed when the block has finished.
983
+ #
984
+ # You need proper access permissions on:
985
+ # * Linux: <tt>/dev/bus/usb/<bus>/<dev></tt>
986
+ #
987
+ # @return [DevHandle] Handle to the device.
988
+ def open
989
+ ppHandle = FFI::MemoryPointer.new :pointer
990
+ res = Call.libusb_open(@pDev, ppHandle)
991
+ LIBUSB.raise_error res, "in libusb_open" if res!=0
992
+ handle = DevHandle.new self, ppHandle.read_pointer
993
+ return handle unless block_given?
994
+ begin
995
+ yield handle
996
+ ensure
997
+ handle.close
998
+ end
999
+ end
1000
+
1001
+ # Get the number of the bus that a device is connected to.
1002
+ def bus_number
1003
+ Call.libusb_get_bus_number(@pDev)
1004
+ end
1005
+
1006
+ # Get the address of the device on the bus it is connected to.
1007
+ def device_address
1008
+ Call.libusb_get_device_address(@pDev)
1009
+ end
1010
+
1011
+ # Convenience function to retrieve the wMaxPacketSize value for a
1012
+ # particular endpoint in the active device configuration.
1013
+ #
1014
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
1015
+ # @return [Fixnum] the wMaxPacketSize value
1016
+ def max_packet_size(endpoint)
1017
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1018
+ res = Call.libusb_get_max_packet_size(@pDev, endpoint)
1019
+ LIBUSB.raise_error res, "in libusb_get_max_packet_size" unless res>=0
1020
+ res
1021
+ end
1022
+
1023
+ # Calculate the maximum packet size which a specific endpoint is capable is
1024
+ # sending or receiving in the duration of 1 microframe.
1025
+ #
1026
+ # Only the active configution is examined. The calculation is based on the
1027
+ # wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6
1028
+ # in the USB 2.0 specifications.
1029
+ #
1030
+ # If acting on an isochronous or interrupt endpoint, this function will
1031
+ # multiply the value found in bits 0:10 by the number of transactions per
1032
+ # microframe (determined by bits 11:12). Otherwise, this function just returns
1033
+ # the numeric value found in bits 0:10.
1034
+ #
1035
+ # This function is useful for setting up isochronous transfers, for example
1036
+ # you might use the return value from this function to call
1037
+ # IsoPacket#alloc_buffer in order to set the length field
1038
+ # of an isochronous packet in a transfer.
1039
+ #
1040
+ # @param [Endpoint, Fixnum] endpoint (address of) the endpoint in question
1041
+ # @return [Fixnum] the maximum packet size which can be sent/received on this endpoint
1042
+ def max_iso_packet_size(endpoint)
1043
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1044
+ res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
1045
+ LIBUSB.raise_error res, "in libusb_get_max_iso_packet_size" unless res>=0
1046
+ res
1047
+ end
1048
+
1049
+ # Obtain a config descriptor of the device.
1050
+ #
1051
+ # @param [Fixnum] index number of the config descriptor
1052
+ # @return Configuration
1053
+ def config_descriptor(index)
1054
+ ppConfig = FFI::MemoryPointer.new :pointer
1055
+ res = Call.libusb_get_config_descriptor(@pDev, index, ppConfig)
1056
+ LIBUSB.raise_error res, "in libusb_get_config_descriptor" if res!=0
1057
+ pConfig = ppConfig.read_pointer
1058
+ config = Configuration.new(self, pConfig)
1059
+ config
1060
+ end
1061
+
1062
+ # allow access to Descriptor members on Device
1063
+ DeviceDescriptor.members.each do |member|
1064
+ define_method(member) do
1065
+ @pDevDesc[member]
1066
+ end
1067
+ end
1068
+
1069
+ def inspect
1070
+ attrs = []
1071
+ attrs << "#{self.bus_number}/#{self.device_address}"
1072
+ attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
1073
+ attrs << self.manufacturer
1074
+ attrs << self.product
1075
+ attrs << self.serial_number
1076
+ if self.bDeviceClass == LIBUSB::CLASS_PER_INTERFACE
1077
+ devclass = self.settings.map {|i|
1078
+ LIBUSB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
1079
+ }.join(", ")
1080
+ else
1081
+ devclass = LIBUSB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
1082
+ end
1083
+ attrs << "(#{devclass})"
1084
+ attrs.compact!
1085
+ "\#<#{self.class} #{attrs.join(' ')}>"
1086
+ end
1087
+
1088
+ def try_string_descriptor_ascii(i)
1089
+ begin
1090
+ open{|h| h.string_descriptor_ascii(i) }
1091
+ rescue
1092
+ "?"
1093
+ end
1094
+ end
1095
+
1096
+ # Return manufacturer of the device
1097
+ # @return String
1098
+ def manufacturer
1099
+ return @manufacturer if defined? @manufacturer
1100
+ @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
1101
+ @manufacturer.strip! if @manufacturer
1102
+ @manufacturer
1103
+ end
1104
+
1105
+ # Return product name of the device.
1106
+ # @return String
1107
+ def product
1108
+ return @product if defined? @product
1109
+ @product = try_string_descriptor_ascii(self.iProduct)
1110
+ @product.strip! if @product
1111
+ @product
1112
+ end
1113
+
1114
+ # Return serial number of the device.
1115
+ # @return String
1116
+ def serial_number
1117
+ return @serial_number if defined? @serial_number
1118
+ @serial_number = try_string_descriptor_ascii(self.iSerialNumber)
1119
+ @serial_number.strip! if @serial_number
1120
+ @serial_number
1121
+ end
1122
+
1123
+ # Return configurations of the device.
1124
+ # @return [Array<Configuration>]
1125
+ def configurations
1126
+ configs = []
1127
+ bNumConfigurations.times do |config_index|
1128
+ begin
1129
+ configs << config_descriptor(config_index)
1130
+ rescue RuntimeError
1131
+ # On Windows some devices don't return it's configuration.
1132
+ end
1133
+ end
1134
+ configs
1135
+ end
1136
+
1137
+ # Return all interfaces of the device.
1138
+ # @return [Array<Interface>]
1139
+ def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
1140
+ # Return all interface decriptions of the device.
1141
+ # @return [Array<Setting>]
1142
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
1143
+ # Return all endpoints of all interfaces of the device.
1144
+ # @return [Array<Endpoint>]
1145
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
1146
+
1147
+ def <=>(o)
1148
+ t = bus_number<=>o.bus_number
1149
+ t = device_address<=>o.device_address if t==0
1150
+ t
1151
+ end
1152
+ end
1153
+
1154
+ # Class representing a handle on a USB device.
1155
+ #
1156
+ # A device handle is used to perform I/O and other operations. When finished
1157
+ # with a device handle, you should call DevHandle#close .
1158
+ class DevHandle
1159
+ # @private
1160
+ attr_reader :pHandle
1161
+ # @return [Device] the device this handle belongs to.
1162
+ attr_reader :device
1163
+
1164
+ def initialize device, pHandle
1165
+ @device = device
1166
+ @pHandle = pHandle
1167
+ @bulk_transfer = @control_transfer = @interrupt_transfer = nil
1168
+ end
1169
+
1170
+ # Close a device handle.
1171
+ #
1172
+ # Should be called on all open handles before your application exits.
1173
+ #
1174
+ # Internally, this function destroys the reference that was added by {Device#open}
1175
+ # on the given device.
1176
+ #
1177
+ # This is a non-blocking function; no requests are sent over the bus.
1178
+ def close
1179
+ Call.libusb_close(@pHandle)
1180
+ end
1181
+
1182
+ def string_descriptor_ascii(index)
1183
+ pString = FFI::MemoryPointer.new 0x100
1184
+ res = Call.libusb_get_string_descriptor_ascii(@pHandle, index, pString, pString.size)
1185
+ LIBUSB.raise_error res, "in libusb_get_string_descriptor_ascii" unless res>=0
1186
+ pString.read_string(res)
1187
+ end
1188
+
1189
+ # Claim an interface on a given device handle.
1190
+ #
1191
+ # You must claim the interface you wish to use before you can perform I/O on any
1192
+ # of its endpoints.
1193
+ #
1194
+ # It is legal to attempt to claim an already-claimed interface, in which case
1195
+ # libusb just returns without doing anything.
1196
+ #
1197
+ # Claiming of interfaces is a purely logical operation; it does not cause any
1198
+ # requests to be sent over the bus. Interface claiming is used to instruct the
1199
+ # underlying operating system that your application wishes to take ownership of
1200
+ # the interface.
1201
+ #
1202
+ # This is a non-blocking function.
1203
+ #
1204
+ # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
1205
+ def claim_interface(interface)
1206
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1207
+ res = Call.libusb_claim_interface(@pHandle, interface)
1208
+ LIBUSB.raise_error res, "in libusb_claim_interface" if res!=0
1209
+ end
1210
+
1211
+ # Release an interface previously claimed with {DevHandle#claim_interface}.
1212
+ #
1213
+ # You should release all claimed interfaces before closing a device handle.
1214
+ #
1215
+ # This is a blocking function. A SET_INTERFACE control request will be sent to the
1216
+ # device, resetting interface state to the first alternate setting.
1217
+ #
1218
+ # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you
1219
+ # claimed previously
1220
+ def release_interface(interface)
1221
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1222
+ res = Call.libusb_release_interface(@pHandle, interface)
1223
+ LIBUSB.raise_error res, "in libusb_release_interface" if res!=0
1224
+ end
1225
+
1226
+ # Set the active configuration for a device.
1227
+ #
1228
+ # The operating system may or may not have already set an active configuration on
1229
+ # the device. It is up to your application to ensure the correct configuration is
1230
+ # selected before you attempt to claim interfaces and perform other operations.
1231
+ #
1232
+ # If you call this function on a device already configured with the selected
1233
+ # configuration, then this function will act as a lightweight device reset: it
1234
+ # will issue a SET_CONFIGURATION request using the current configuration, causing
1235
+ # most USB-related device state to be reset (altsetting reset to zero, endpoint
1236
+ # halts cleared, toggles reset).
1237
+ #
1238
+ # You cannot change/reset configuration if your application has claimed interfaces -
1239
+ # you should free them with {DevHandle#release_interface} first. You cannot
1240
+ # change/reset configuration if other applications or drivers have claimed
1241
+ # interfaces.
1242
+ #
1243
+ # A configuration value of +nil+ will put the device in unconfigured state. The USB
1244
+ # specifications state that a configuration value of 0 does this, however buggy
1245
+ # devices exist which actually have a configuration 0.
1246
+ #
1247
+ # You should always use this function rather than formulating your own
1248
+ # SET_CONFIGURATION control request. This is because the underlying operating
1249
+ # system needs to know when such changes happen.
1250
+ #
1251
+ # This is a blocking function.
1252
+ #
1253
+ # @param [Configuration, Fixnum] configuration the configuration or it's
1254
+ # bConfigurationValue you wish to activate, or +nil+ if you wish to put
1255
+ # the device in unconfigured state
1256
+ def set_configuration(configuration)
1257
+ configuration = configuration.bConfigurationValue if configuration.respond_to? :bConfigurationValue
1258
+ res = Call.libusb_set_configuration(@pHandle, configuration || -1)
1259
+ LIBUSB.raise_error res, "in libusb_set_configuration" if res!=0
1260
+ end
1261
+ alias configuration= set_configuration
1262
+
1263
+ # Activate an alternate setting for an interface.
1264
+ #
1265
+ # The interface must have been previously claimed with {DevHandle#claim_interface}.
1266
+ #
1267
+ # You should always use this function rather than formulating your own
1268
+ # SET_INTERFACE control request. This is because the underlying operating system
1269
+ # needs to know when such changes happen.
1270
+ #
1271
+ # This is a blocking function.
1272
+ #
1273
+ # @param [Setting, Fixnum] setting_or_interface_number the alternate setting
1274
+ # to activate or the bInterfaceNumber of the previously-claimed interface
1275
+ # @param [Fixnum, nil] alternate_setting the bAlternateSetting of the alternate setting to activate
1276
+ # (only if first param is a Fixnum)
1277
+ def set_interface_alt_setting(setting_or_interface_number,
1278
+ alternate_setting=nil)
1279
+ alternate_setting ||= setting_or_interface_number.bAlternateSetting if setting_or_interface_number.respond_to? :bAlternateSetting
1280
+ setting_or_interface_number = setting_or_interface_number.bInterfaceNumber if setting_or_interface_number.respond_to? :bInterfaceNumber
1281
+ res = Call.libusb_set_interface_alt_setting(@pHandle, setting_or_interface_number, alternate_setting)
1282
+ LIBUSB.raise_error res, "in libusb_set_interface_alt_setting" if res!=0
1283
+ end
1284
+
1285
+ # Clear the halt/stall condition for an endpoint.
1286
+ #
1287
+ # Endpoints with halt status are unable to receive or transmit
1288
+ # data until the halt condition is stalled.
1289
+ #
1290
+ # You should cancel all pending transfers before attempting to
1291
+ # clear the halt condition.
1292
+ #
1293
+ # This is a blocking function.
1294
+ #
1295
+ # @param [Endpoint, Fixnum] endpoint the endpoint in question or it's bEndpointAddress
1296
+ def clear_halt(endpoint)
1297
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1298
+ res = Call.libusb_clear_halt(@pHandle, endpoint)
1299
+ LIBUSB.raise_error res, "in libusb_clear_halt" if res!=0
1300
+ end
1301
+
1302
+ # Perform a USB port reset to reinitialize a device.
1303
+ #
1304
+ # The system will attempt to restore the previous configuration and
1305
+ # alternate settings after the reset has completed.
1306
+ #
1307
+ # If the reset fails, the descriptors change, or the previous
1308
+ # state cannot be restored, the device will appear to be disconnected
1309
+ # and reconnected. This means that the device handle is no longer
1310
+ # valid (you should close it) and rediscover the device. A Exception
1311
+ # of LIBUSB::ERROR_NOT_FOUND indicates when this is the case.
1312
+ #
1313
+ # This is a blocking function which usually incurs a noticeable delay.
1314
+ def reset_device
1315
+ res = Call.libusb_reset_device(@pHandle)
1316
+ LIBUSB.raise_error res, "in libusb_reset_device" if res!=0
1317
+ end
1318
+
1319
+ # Determine if a kernel driver is active on an interface.
1320
+ #
1321
+ # If a kernel driver is active, you cannot claim the interface,
1322
+ # and libusb will be unable to perform I/O.
1323
+ #
1324
+ # @param [Interface, Fixnum] interface the interface to check or it's bInterfaceNumber
1325
+ # @return [Boolean]
1326
+ def kernel_driver_active?(interface)
1327
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1328
+ res = Call.libusb_kernel_driver_active(@pHandle, interface)
1329
+ LIBUSB.raise_error res, "in libusb_kernel_driver_active" unless res>=0
1330
+ return res==1
1331
+ end
1332
+
1333
+ # Detach a kernel driver from an interface.
1334
+ #
1335
+ # If successful, you will then be able to claim the interface and perform I/O.
1336
+ #
1337
+ # @param [Interface, Fixnum] interface the interface to detach the driver
1338
+ # from or it's bInterfaceNumber
1339
+ def detach_kernel_driver(interface)
1340
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1341
+ res = Call.libusb_detach_kernel_driver(@pHandle, interface)
1342
+ LIBUSB.raise_error res, "in libusb_detach_kernel_driver" if res!=0
1343
+ end
1344
+
1345
+ # Re-attach an interface's kernel driver, which was previously detached
1346
+ # using {DevHandle#detach_kernel_driver}.
1347
+ #
1348
+ # @param [Interface, Fixnum] interface the interface to attach the driver to
1349
+ def attach_kernel_driver(interface)
1350
+ interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1351
+ res = Call.libusb_attach_kernel_driver(@pHandle, interface)
1352
+ LIBUSB.raise_error res, "in libusb_attach_kernel_driver" if res!=0
1353
+ end
1354
+
1355
+
1356
+ # Perform a USB bulk transfer.
1357
+ #
1358
+ # The direction of the transfer is inferred from the direction bits of the
1359
+ # endpoint address.
1360
+ #
1361
+ # For bulk reads, the :dataIn param indicates the maximum length of data you are
1362
+ # expecting to receive. If less data arrives than expected, this function will
1363
+ # return that data.
1364
+ #
1365
+ # You should also check the returned number of bytes for bulk writes. Not all of the
1366
+ # data may have been written.
1367
+ #
1368
+ # Also check transferred bytes when dealing with a timeout error code. libusb may have
1369
+ # to split your transfer into a number of chunks to satisfy underlying O/S
1370
+ # requirements, meaning that the timeout may expire after the first few chunks
1371
+ # have completed. libusb is careful not to lose any data that may have been
1372
+ # transferred; do not assume that timeout conditions indicate a complete lack of
1373
+ # I/O.
1374
+ #
1375
+ # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1376
+ # @param [String] :dataOut the data to send with an outgoing transfer
1377
+ # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1378
+ #
1379
+ # @return [Fixnum] Number of bytes sent for an outgoing transfer
1380
+ # @return [String] Received data for an ingoing transfer
1381
+ def bulk_transfer(args={})
1382
+ timeout = args.delete(:timeout) || 1000
1383
+ endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
1384
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1385
+ if endpoint&ENDPOINT_IN != 0
1386
+ dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for bulk read")
1387
+ else
1388
+ dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for bulk write")
1389
+ end
1390
+ raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1391
+
1392
+ # reuse transfer struct to speed up transfer
1393
+ @bulk_transfer ||= BulkTransfer.new :dev_handle => self
1394
+ tr = @bulk_transfer
1395
+ tr.endpoint = endpoint
1396
+ tr.timeout = timeout
1397
+ if dataOut
1398
+ tr.buffer = dataOut
1399
+ else
1400
+ tr.alloc_buffer(dataIn)
1401
+ end
1402
+
1403
+ tr.submit_and_wait!
1404
+
1405
+ if dataOut
1406
+ tr.actual_length
1407
+ else
1408
+ tr.actual_buffer
1409
+ end
1410
+ end
1411
+
1412
+ # Perform a USB interrupt transfer.
1413
+ #
1414
+ # The direction of the transfer is inferred from the direction bits of the
1415
+ # endpoint address.
1416
+ #
1417
+ # For interrupt reads, the :dataIn param indicates the maximum length of data you
1418
+ # are expecting to receive. If less data arrives than expected, this function will
1419
+ # return that data.
1420
+ #
1421
+ # You should also check the returned number of bytes for interrupt writes. Not all of
1422
+ # the data may have been written.
1423
+ #
1424
+ # Also check transferred when dealing with a timeout error code. libusb may have
1425
+ # to split your transfer into a number of chunks to satisfy underlying O/S
1426
+ # requirements, meaning that the timeout may expire after the first few chunks
1427
+ # have completed. libusb is careful not to lose any data that may have been
1428
+ # transferred; do not assume that timeout conditions indicate a complete lack of
1429
+ # I/O.
1430
+ #
1431
+ # The default endpoint bInterval value is used as the polling interval.
1432
+ #
1433
+ # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1434
+ # @param [String] :dataOut the data to send with an outgoing transfer
1435
+ # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1436
+ #
1437
+ # @return [Fixnum] Number of bytes sent for an outgoing transfer
1438
+ # @return [String] Received data for an ingoing transfer
1439
+ def interrupt_transfer(args={})
1440
+ timeout = args.delete(:timeout) || 1000
1441
+ endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
1442
+ endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
1443
+ if endpoint&ENDPOINT_IN != 0
1444
+ dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for interrupt read")
1445
+ else
1446
+ dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for interrupt write")
1447
+ end
1448
+ raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1449
+
1450
+ # reuse transfer struct to speed up transfer
1451
+ @interrupt_transfer ||= InterruptTransfer.new :dev_handle => self
1452
+ tr = @interrupt_transfer
1453
+ tr.endpoint = endpoint
1454
+ tr.timeout = timeout
1455
+ if dataOut
1456
+ tr.buffer = dataOut
1457
+ else
1458
+ tr.alloc_buffer(dataIn)
1459
+ end
1460
+
1461
+ tr.submit_and_wait!
1462
+
1463
+ if dataOut
1464
+ tr.actual_length
1465
+ else
1466
+ tr.actual_buffer
1467
+ end
1468
+ end
1469
+
1470
+ # Perform a USB control transfer.
1471
+ #
1472
+ # The direction of the transfer is inferred from the bmRequestType field of the
1473
+ # setup packet.
1474
+ #
1475
+ # @param [Fixnum] :bmRequestType the request type field for the setup packet
1476
+ # @param [Fixnum] :bRequest the request field for the setup packet
1477
+ # @param [Fixnum] :wValue the value field for the setup packet
1478
+ # @param [Fixnum] :wIndex the index field for the setup packet
1479
+ # @param [String] :dataOut the data to send with an outgoing transfer, it
1480
+ # is appended to the setup packet
1481
+ # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1482
+ # (excluding setup packet)
1483
+ # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1484
+ # up due to no response being received. For an unlimited timeout, use value 0.
1485
+ #
1486
+ # @return [Fixnum] Number of bytes sent (excluding setup packet) for outgoing transfer
1487
+ # @return [String] Received data (without setup packet) for ingoing transfer
1488
+ def control_transfer(args={})
1489
+ bmRequestType = args.delete(:bmRequestType) || raise(ArgumentError, "param :bmRequestType not given")
1490
+ bRequest = args.delete(:bRequest) || raise(ArgumentError, "param :bRequest not given")
1491
+ wValue = args.delete(:wValue) || raise(ArgumentError, "param :wValue not given")
1492
+ wIndex = args.delete(:wIndex) || raise(ArgumentError, "param :wIndex not given")
1493
+ timeout = args.delete(:timeout) || 1000
1494
+ if bmRequestType&ENDPOINT_IN != 0
1495
+ dataIn = args.delete(:dataIn) || 0
1496
+ dataOut = ''
1497
+ else
1498
+ dataOut = args.delete(:dataOut) || ''
1499
+ end
1500
+ raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?
1501
+
1502
+ # reuse transfer struct to speed up transfer
1503
+ @control_transfer ||= ControlTransfer.new :dev_handle => self
1504
+ tr = @control_transfer
1505
+ tr.timeout = timeout
1506
+ if dataIn
1507
+ setup_data = [bmRequestType, bRequest, wValue, wIndex, dataIn].pack('CCvvv')
1508
+ tr.alloc_buffer( dataIn + CONTROL_SETUP_SIZE, setup_data )
1509
+ else
1510
+ tr.buffer = [bmRequestType, bRequest, wValue, wIndex, dataOut.bytesize, dataOut].pack('CCvvva*')
1511
+ end
1512
+
1513
+ tr.submit_and_wait!
1514
+
1515
+ if dataIn
1516
+ tr.actual_buffer(CONTROL_SETUP_SIZE)
1517
+ else
1518
+ tr.actual_length
1519
+ end
1520
+ end
1521
+ end
1522
+
1523
+ end