libusb 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,271 @@
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
+ module LIBUSB
20
+ # C level interface
21
+ module Call
22
+ extend FFI::Library
23
+
24
+ if FFI::Platform.windows?
25
+ bundled_dll = File.join(File.dirname(__FILE__), '..', 'libusb-1.0.dll')
26
+ ffi_lib(['libusb-1.0', bundled_dll])
27
+ else
28
+ ffi_lib 'libusb-1.0'
29
+ end
30
+
31
+ ClassCodes = enum :libusb_class_code, [
32
+ :CLASS_PER_INTERFACE, 0,
33
+ :CLASS_AUDIO, 1,
34
+ :CLASS_COMM, 2,
35
+ :CLASS_HID, 3,
36
+ :CLASS_PRINTER, 7,
37
+ :CLASS_PTP, 6,
38
+ :CLASS_MASS_STORAGE, 8,
39
+ :CLASS_HUB, 9,
40
+ :CLASS_DATA, 10,
41
+ :CLASS_WIRELESS, 0xe0,
42
+ :CLASS_APPLICATION, 0xfe,
43
+ :CLASS_VENDOR_SPEC, 0xff
44
+ ]
45
+
46
+ Errors = enum :libusb_error, [
47
+ :SUCCESS, 0,
48
+ :ERROR_IO, -1,
49
+ :ERROR_INVALID_PARAM, -2,
50
+ :ERROR_ACCESS, -3,
51
+ :ERROR_NO_DEVICE, -4,
52
+ :ERROR_NOT_FOUND, -5,
53
+ :ERROR_BUSY, -6,
54
+ :ERROR_TIMEOUT, -7,
55
+ :ERROR_OVERFLOW, -8,
56
+ :ERROR_PIPE, -9,
57
+ :ERROR_INTERRUPTED, -10,
58
+ :ERROR_NO_MEM, -11,
59
+ :ERROR_NOT_SUPPORTED, -12,
60
+ :ERROR_OTHER, -99,
61
+ ]
62
+
63
+ # Transfer status codes
64
+ TransferStatus = enum :libusb_transfer_status, [
65
+ :TRANSFER_COMPLETED,
66
+ :TRANSFER_ERROR,
67
+ :TRANSFER_TIMED_OUT,
68
+ :TRANSFER_CANCELLED,
69
+ :TRANSFER_STALL,
70
+ :TRANSFER_NO_DEVICE,
71
+ :TRANSFER_OVERFLOW,
72
+ ]
73
+
74
+ # libusb_transfer.flags values
75
+ TransferFlags = enum :libusb_transfer_flags, [
76
+ :TRANSFER_SHORT_NOT_OK, 1 << 0,
77
+ :TRANSFER_FREE_BUFFER, 1 << 1,
78
+ :TRANSFER_FREE_TRANSFER, 1 << 2,
79
+ :TRANSFER_ADD_ZERO_PACKET, 1 << 3,
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
+ Speeds = enum :libusb_speed, [
142
+ :SPEED_UNKNOWN, 0,
143
+ :SPEED_LOW, 1,
144
+ :SPEED_FULL, 2,
145
+ :SPEED_HIGH, 3,
146
+ :SPEED_SUPER, 4,
147
+ ]
148
+
149
+ Capabilities = enum :libusb_capability, [
150
+ :CAP_HAS_CAPABILITY, 0,
151
+ ]
152
+
153
+ typedef :pointer, :libusb_context
154
+ typedef :pointer, :libusb_device_handle
155
+
156
+ def self.try_attach_function(method, *args)
157
+ if ffi_libraries.find{|lib| lib.find_function(method) }
158
+ attach_function method, *args
159
+ end
160
+ end
161
+
162
+ try_attach_function 'libusb_get_version', [], :pointer
163
+
164
+ attach_function 'libusb_init', [ :pointer ], :int
165
+ attach_function 'libusb_exit', [ :pointer ], :void
166
+ attach_function 'libusb_set_debug', [:pointer, :int], :void
167
+ try_attach_function 'libusb_has_capability', [:libusb_capability], :int
168
+
169
+ attach_function 'libusb_get_device_list', [:pointer, :pointer], :size_t
170
+ attach_function 'libusb_free_device_list', [:pointer, :int], :void
171
+ attach_function 'libusb_ref_device', [:pointer], :pointer
172
+ attach_function 'libusb_unref_device', [:pointer], :void
173
+
174
+ attach_function 'libusb_get_device_descriptor', [:pointer, :pointer], :int
175
+ attach_function 'libusb_get_active_config_descriptor', [:pointer, :pointer], :int
176
+ attach_function 'libusb_get_config_descriptor', [:pointer, :uint8, :pointer], :int
177
+ attach_function 'libusb_get_config_descriptor_by_value', [:pointer, :uint8, :pointer], :int
178
+ attach_function 'libusb_free_config_descriptor', [:pointer], :void
179
+ attach_function 'libusb_get_bus_number', [:pointer], :uint8
180
+ try_attach_function 'libusb_get_port_number', [:pointer], :uint8
181
+ try_attach_function 'libusb_get_parent', [:pointer], :pointer
182
+ try_attach_function 'libusb_get_port_path', [:pointer, :pointer, :pointer, :uint8], :uint8
183
+ attach_function 'libusb_get_device_address', [:pointer], :uint8
184
+ try_attach_function 'libusb_get_device_speed', [:pointer], :libusb_speed
185
+ attach_function 'libusb_get_max_packet_size', [:pointer, :uint8], :int
186
+ attach_function 'libusb_get_max_iso_packet_size', [:pointer, :uint8], :int
187
+
188
+ attach_function 'libusb_open', [:pointer, :pointer], :int
189
+ attach_function 'libusb_close', [:pointer], :void
190
+ attach_function 'libusb_get_device', [:libusb_device_handle], :pointer
191
+
192
+ attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int, :blocking=>true
193
+ attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
194
+ attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int, :blocking=>true
195
+
196
+ attach_function 'libusb_open_device_with_vid_pid', [:pointer, :int, :int], :pointer
197
+
198
+ attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int, :blocking=>true
199
+ attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int, :blocking=>true
200
+ attach_function 'libusb_reset_device', [:libusb_device_handle], :int, :blocking=>true
201
+
202
+ attach_function 'libusb_kernel_driver_active', [:libusb_device_handle, :int], :int
203
+ attach_function 'libusb_detach_kernel_driver', [:libusb_device_handle, :int], :int
204
+ attach_function 'libusb_attach_kernel_driver', [:libusb_device_handle, :int], :int
205
+
206
+ attach_function 'libusb_get_string_descriptor_ascii', [:pointer, :uint8, :pointer, :int], :int
207
+
208
+ attach_function 'libusb_alloc_transfer', [:int], :pointer
209
+ attach_function 'libusb_submit_transfer', [:pointer], :int
210
+ attach_function 'libusb_cancel_transfer', [:pointer], :int
211
+ attach_function 'libusb_free_transfer', [:pointer], :void
212
+
213
+ attach_function 'libusb_handle_events', [:libusb_context], :int, :blocking=>true
214
+
215
+
216
+ callback :libusb_transfer_cb_fn, [:pointer], :void
217
+
218
+ class IsoPacketDescriptor < FFI::Struct
219
+ layout :length, :uint,
220
+ :actual_length, :uint,
221
+ :status, :libusb_transfer_status
222
+ end
223
+
224
+ # Setup packet for control transfers.
225
+ class ControlSetup < FFI::Struct
226
+ layout :bmRequestType, :uint8,
227
+ :bRequest, :uint8,
228
+ :wValue, :uint16,
229
+ :wIndex, :uint16,
230
+ :wLength, :uint16
231
+ end
232
+
233
+ class Transfer < FFI::ManagedStruct
234
+ layout :dev_handle, :libusb_device_handle,
235
+ :flags, :uint8,
236
+ :endpoint, :uchar,
237
+ :type, :uchar,
238
+ :timeout, :uint,
239
+ :status, :libusb_transfer_status,
240
+ :length, :int,
241
+ :actual_length, :int,
242
+ :callback, :libusb_transfer_cb_fn,
243
+ :user_data, :pointer,
244
+ :buffer, :pointer,
245
+ :num_iso_packets, :int
246
+
247
+ def self.release(ptr)
248
+ Call.libusb_free_transfer(ptr)
249
+ end
250
+ end
251
+
252
+ class DeviceDescriptor < FFI::Struct
253
+ include Comparable
254
+
255
+ layout :bLength, :uint8,
256
+ :bDescriptorType, :uint8,
257
+ :bcdUSB, :uint16,
258
+ :bDeviceClass, :uint8,
259
+ :bDeviceSubClass, :uint8,
260
+ :bDeviceProtocol, :uint8,
261
+ :bMaxPacketSize0, :uint8,
262
+ :idVendor, :uint16,
263
+ :idProduct, :uint16,
264
+ :bcdDevice, :uint16,
265
+ :iManufacturer, :uint8,
266
+ :iProduct, :uint8,
267
+ :iSerialNumber, :uint8,
268
+ :bNumConfigurations, :uint8
269
+ end
270
+ end
271
+ end
@@ -97,8 +97,8 @@ module USB
97
97
  USB_RECIP_ENDPOINT = LIBUSB::RECIPIENT_ENDPOINT
98
98
  USB_RECIP_OTHER = LIBUSB::RECIPIENT_OTHER
99
99
 
100
- HAS_GET_DRIVER_NP = RUBY_PLATFORM=~/mswin|mingw/ ? false : true
101
- HAS_DETACH_KERNEL_DRIVER_NP = RUBY_PLATFORM=~/mswin|mingw/ ? false : true
100
+ HAS_GET_DRIVER_NP = !FFI::Platform.windows?
101
+ HAS_DETACH_KERNEL_DRIVER_NP = !FFI::Platform.windows?
102
102
 
103
103
  # not defined by libusb-1.0, but typical values are:
104
104
  USB_MAXENDPOINTS = 32
@@ -0,0 +1,139 @@
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 Configuration < FFI::ManagedStruct
20
+ include Comparable
21
+
22
+ layout :bLength, :uint8,
23
+ :bDescriptorType, :uint8,
24
+ :wTotalLength, :uint16,
25
+ :bNumInterfaces, :uint8,
26
+ :bConfigurationValue, :uint8,
27
+ :iConfiguration, :uint8,
28
+ :bmAttributes, :uint8,
29
+ :maxPower, :uint8,
30
+ :interface, :pointer,
31
+ :extra, :pointer,
32
+ :extra_length, :int
33
+
34
+ # Size of this descriptor (in bytes).
35
+ def bLength
36
+ self[:bLength]
37
+ end
38
+
39
+ # Descriptor type (0x02)
40
+ def bDescriptorType
41
+ self[:bDescriptorType]
42
+ end
43
+
44
+ # Total length of data returned for this configuration.
45
+ def wTotalLength
46
+ self[:wTotalLength]
47
+ end
48
+
49
+ # Number of interfaces supported by this configuration.
50
+ def bNumInterfaces
51
+ self[:bNumInterfaces]
52
+ end
53
+
54
+ # Identifier value for this configuration.
55
+ def bConfigurationValue
56
+ self[:bConfigurationValue]
57
+ end
58
+
59
+ # Index of string descriptor describing this configuration.
60
+ def iConfiguration
61
+ self[:iConfiguration]
62
+ end
63
+
64
+ # Configuration characteristics.
65
+ #
66
+ # * Bit 7: Reserved, set to 1. (USB 1.0 Bus Powered)
67
+ # * Bit 6: Self Powered
68
+ # * Bit 5: Remote Wakeup
69
+ # * Bit 4..0: Reserved, set to 0.
70
+ #
71
+ # @return [Integer]
72
+ def bmAttributes
73
+ self[:bmAttributes]
74
+ end
75
+
76
+ # Maximum power consumption of the USB device from this bus in this configuration when the device is fully opreation.
77
+ #
78
+ # @return [Integer] Maximum Power Consumption in 2mA units
79
+ def maxPower
80
+ self[:maxPower]
81
+ end
82
+
83
+ # Extra descriptors.
84
+ #
85
+ # @return [String]
86
+ def extra
87
+ return if self[:extra].null?
88
+ self[:extra].read_string(self[:extra_length])
89
+ end
90
+
91
+ def initialize(device, *args)
92
+ @device = device
93
+ super(*args)
94
+ end
95
+
96
+ def self.release(ptr)
97
+ Call.libusb_free_config_descriptor(ptr)
98
+ end
99
+
100
+ # @return [Device] the device this configuration belongs to.
101
+ attr_reader :device
102
+
103
+ def interfaces
104
+ ifs = []
105
+ self[:bNumInterfaces].times do |i|
106
+ ifs << Interface.new(self, self[:interface] + i*Interface.size)
107
+ end
108
+ return ifs
109
+ end
110
+
111
+ def inspect
112
+ attrs = []
113
+ attrs << self.bConfigurationValue.to_s
114
+ bits = self.bmAttributes
115
+ attrs << "SelfPowered" if (bits & 0b1000000) != 0
116
+ attrs << "RemoteWakeup" if (bits & 0b100000) != 0
117
+ desc = self.description
118
+ attrs << desc if desc != '?'
119
+ "\#<#{self.class} #{attrs.join(' ')}>"
120
+ end
121
+
122
+ # Return name of this configuration as String.
123
+ def description
124
+ return @description if defined? @description
125
+ @description = device.try_string_descriptor_ascii(self.iConfiguration)
126
+ end
127
+
128
+ # Return all interface decriptions of the configuration as Array of {Setting}s.
129
+ def settings() self.interfaces.map {|d| d.settings }.flatten end
130
+ # Return all endpoints of all interfaces of the configuration as Array of {Endpoint}s.
131
+ def endpoints() self.settings.map {|d| d.endpoints }.flatten end
132
+
133
+ def <=>(o)
134
+ t = device<=>o.device
135
+ t = bConfigurationValue<=>o.bConfigurationValue if t==0
136
+ t
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,138 @@
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
+ Call::ClassCodes.to_h.each{|k,v| const_set(k,v) }
20
+ Call::TransferTypes.to_h.each{|k,v| const_set(k,v) }
21
+ Call::StandardRequests.to_h.each{|k,v| const_set(k,v) }
22
+ Call::RequestTypes.to_h.each{|k,v| const_set(k,v) }
23
+ Call::DescriptorTypes.to_h.each{|k,v| const_set(k,v) }
24
+ Call::EndpointDirections.to_h.each{|k,v| const_set(k,v) }
25
+ Call::RequestRecipients.to_h.each{|k,v| const_set(k,v) }
26
+ Call::IsoSyncTypes.to_h.each{|k,v| const_set(k,v) }
27
+ Call::Speeds.to_h.each{|k,v| const_set(k,v) }
28
+ Call::Capabilities.to_h.each{|k,v| const_set(k,v) }
29
+
30
+ # Base class of libusb errors
31
+ class Error < RuntimeError
32
+ end
33
+ # @private
34
+ ErrorClassForResult = {}
35
+
36
+ # define an exception class for each error code
37
+ Call::Errors.to_h.each do |k,v|
38
+ klass = Class.new(Error)
39
+ klass.send(:define_method, :code){ v }
40
+ const_set(k, klass)
41
+ ErrorClassForResult[v] = klass
42
+ end
43
+
44
+ def self.raise_error(res, text)
45
+ klass = ErrorClassForResult[res]
46
+ raise klass, "#{klass} #{text}"
47
+ end
48
+
49
+ CONTROL_SETUP_SIZE = 8
50
+ DT_DEVICE_SIZE = 18
51
+ DT_CONFIG_SIZE = 9
52
+ DT_INTERFACE_SIZE = 9
53
+ DT_ENDPOINT_SIZE = 7
54
+ DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
55
+ DT_HUB_NONVAR_SIZE = 7
56
+
57
+ ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
58
+ ENDPOINT_DIR_MASK = 0x80
59
+ TRANSFER_TYPE_MASK = 0x03 # in bmAttributes
60
+ ISO_SYNC_TYPE_MASK = 0x0C
61
+ ISO_USAGE_TYPE_MASK = 0x30
62
+
63
+
64
+ # http://www.usb.org/developers/defined_class
65
+ # @private
66
+ CLASS_CODES = [
67
+ [0x01, nil, nil, "Audio"],
68
+ [0x02, nil, nil, "Comm"],
69
+ [0x03, nil, nil, "HID"],
70
+ [0x05, nil, nil, "Physical"],
71
+ [0x06, 0x01, 0x01, "StillImaging"],
72
+ [0x06, nil, nil, "Image"],
73
+ [0x07, nil, nil, "Printer"],
74
+ [0x08, 0x01, nil, "MassStorage RBC Bluk-Only"],
75
+ [0x08, 0x02, 0x50, "MassStorage ATAPI Bluk-Only"],
76
+ [0x08, 0x03, 0x50, "MassStorage QIC-157 Bluk-Only"],
77
+ [0x08, 0x04, nil, "MassStorage UFI"],
78
+ [0x08, 0x05, 0x50, "MassStorage SFF-8070i Bluk-Only"],
79
+ [0x08, 0x06, 0x50, "MassStorage SCSI Bluk-Only"],
80
+ [0x08, nil, nil, "MassStorage"],
81
+ [0x09, 0x00, 0x00, "Full speed Hub"],
82
+ [0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
83
+ [0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
84
+ [0x09, nil, nil, "Hub"],
85
+ [0x0a, nil, nil, "CDC"],
86
+ [0x0b, nil, nil, "SmartCard"],
87
+ [0x0d, 0x00, 0x00, "ContentSecurity"],
88
+ [0x0e, nil, nil, "Video"],
89
+ [0xdc, 0x01, 0x01, "Diagnostic USB2"],
90
+ [0xdc, nil, nil, "Diagnostic"],
91
+ [0xe0, 0x01, 0x01, "Bluetooth"],
92
+ [0xe0, 0x01, 0x02, "UWB"],
93
+ [0xe0, 0x01, 0x03, "RemoteNDIS"],
94
+ [0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
95
+ [0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
96
+ [0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
97
+ [0xe0, nil, nil, "Wireless Controller"],
98
+ [0xef, 0x01, 0x01, "Active Sync"],
99
+ [0xef, 0x01, 0x02, "Palm Sync"],
100
+ [0xef, 0x02, 0x01, "Interface Association Descriptor"],
101
+ [0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
102
+ [0xef, 0x03, 0x01, "Cable Based Association Framework"],
103
+ [0xef, nil, nil, "Miscellaneous"],
104
+ [0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
105
+ [0xfe, 0x02, 0x00, "IRDA Bridge"],
106
+ [0xfe, 0x03, 0x00, "USB Test and Measurement"],
107
+ [0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
108
+ [0xfe, nil, nil, "Application Specific"],
109
+ [0xff, nil, nil, "Vendor specific"],
110
+ ]
111
+ # @private
112
+ CLASS_CODES_HASH1 = {}
113
+ # @private
114
+ CLASS_CODES_HASH2 = {}
115
+ # @private
116
+ CLASS_CODES_HASH3 = {}
117
+ CLASS_CODES.each {|base_class, sub_class, protocol, desc|
118
+ if protocol
119
+ CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
120
+ elsif sub_class
121
+ CLASS_CODES_HASH2[[base_class, sub_class]] = desc
122
+ else
123
+ CLASS_CODES_HASH1[base_class] = desc
124
+ end
125
+ }
126
+
127
+ def self.dev_string(base_class, sub_class, protocol)
128
+ if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
129
+ desc
130
+ elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
131
+ desc + " (%02x)" % [protocol]
132
+ elsif desc = CLASS_CODES_HASH1[base_class]
133
+ desc + " (%02x,%02x)" % [sub_class, protocol]
134
+ else
135
+ "Unkonwn(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
136
+ end
137
+ end
138
+ end