ruby-usb 0.1.3-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +504 -0
- data/History.txt +19 -0
- data/Manifest.txt +11 -0
- data/README.txt +55 -0
- data/README.win32 +61 -0
- data/Rakefile +30 -0
- data/ext/constants.h +86 -0
- data/ext/extconf.rb +28 -0
- data/ext/usb.c +931 -0
- data/ext/usb.so +0 -0
- data/lib/usb.rb +420 -0
- data/sample/usb-power +46 -0
- metadata +71 -0
data/ext/usb.so
ADDED
Binary file
|
data/lib/usb.rb
ADDED
@@ -0,0 +1,420 @@
|
|
1
|
+
# usb.rb - utility methods for libusb binding for Ruby.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2007 Tanaka Akira
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require 'usb.so'
|
20
|
+
|
21
|
+
# USB module is a binding for libusb.
|
22
|
+
#
|
23
|
+
# It needs appropriate privilege to access USB.
|
24
|
+
# For example, the process should be an member of plugdev group on Debin GNU/Linux (etch).
|
25
|
+
#
|
26
|
+
# = Example
|
27
|
+
#
|
28
|
+
# 1. list up USB devices
|
29
|
+
#
|
30
|
+
# require 'usb'
|
31
|
+
# require 'pp'
|
32
|
+
# pp USB.devices
|
33
|
+
# #=>
|
34
|
+
# [#<USB::Device 001/001 0000:0000 Linux 2.6.17-2-486 uhci_hcd UHCI Host Controller 0000:00:1d.0 (Full speed Hub)>,
|
35
|
+
# #<USB::Device 002/001 0000:0000 Linux 2.6.17-2-486 uhci_hcd UHCI Host Controller 0000:00:1d.1 (Full speed Hub)>,
|
36
|
+
# #<USB::Device 003/001 0000:0000 Linux 2.6.17-2-486 uhci_hcd UHCI Host Controller 0000:00:1d.2 (Full speed Hub)>,
|
37
|
+
# #<USB::Device 004/001 0000:0000 Linux 2.6.17-2-486 ehci_hcd EHCI Host Controller 0000:00:1d.7 (Hi-speed Hub with single TT)>]
|
38
|
+
#
|
39
|
+
# 2. find a device by bus id and device id
|
40
|
+
#
|
41
|
+
# # find the device "004/001" in the above list.
|
42
|
+
# dev = USB.find_bus(4).find_device(1)
|
43
|
+
# p dev
|
44
|
+
# #=>
|
45
|
+
# #<USB::Device 004/001 0000:0000 Linux 2.6.17-2-486 ehci_hcd EHCI Host Controller 0000:00:1d.7 (Hi-speed Hub with single TT)>
|
46
|
+
#
|
47
|
+
# 3. open a device
|
48
|
+
#
|
49
|
+
# dev.open {|handle| p handle }
|
50
|
+
# #=>
|
51
|
+
# #<USB::DevHandle:0xa7d94688>
|
52
|
+
#
|
53
|
+
# = USB overview
|
54
|
+
#
|
55
|
+
# * A host has busses.
|
56
|
+
# * A bus has devices.
|
57
|
+
# * A device has configurations.
|
58
|
+
# * A configuration has interfaces.
|
59
|
+
# * A interface has settings.
|
60
|
+
# * A setting has endpoints.
|
61
|
+
#
|
62
|
+
|
63
|
+
module USB
|
64
|
+
def USB.busses
|
65
|
+
result = []
|
66
|
+
bus = USB.first_bus
|
67
|
+
while bus
|
68
|
+
result << bus
|
69
|
+
bus = bus.next
|
70
|
+
end
|
71
|
+
result.sort_by {|b| b.dirname }
|
72
|
+
end
|
73
|
+
|
74
|
+
def USB.devices() USB.busses.map {|b| b.devices }.flatten end
|
75
|
+
def USB.configurations() USB.devices.map {|d| d.configurations }.flatten end
|
76
|
+
def USB.interfaces() USB.configurations.map {|d| d.interfaces }.flatten end
|
77
|
+
def USB.settings() USB.interfaces.map {|d| d.settings }.flatten end
|
78
|
+
def USB.endpoints() USB.settings.map {|d| d.endpoints }.flatten end
|
79
|
+
|
80
|
+
def USB.find_bus(n)
|
81
|
+
bus = USB.first_bus
|
82
|
+
while bus
|
83
|
+
return bus if n == bus.dirname.to_i
|
84
|
+
bus = bus.next
|
85
|
+
end
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# searches devices by USB device class, subclass and protocol.
|
90
|
+
#
|
91
|
+
# # find hubs.
|
92
|
+
# USB.each_device_by_class(USB::USB_CLASS_HUB) {|d| p d }'
|
93
|
+
#
|
94
|
+
# # find Full speed Hubs
|
95
|
+
# USB.each_device_by_class(USB::USB_CLASS_HUB, 0, 0) {|d| p d }'
|
96
|
+
#
|
97
|
+
# # find Hi-speed Hubs with single TT
|
98
|
+
# USB.each_device_by_class(USB::USB_CLASS_HUB, 0, 1) {|d| p d }'
|
99
|
+
#
|
100
|
+
# # find Hi-speed Hubs with multiple TT
|
101
|
+
# USB.each_device_by_class(USB::USB_CLASS_HUB, 0, 2) {|d| p d }'
|
102
|
+
#
|
103
|
+
def USB.each_device_by_class(devclass, subclass=nil, protocol=nil)
|
104
|
+
USB.devices.each {|dev|
|
105
|
+
if dev.bDeviceClass == USB::USB_CLASS_PER_INTERFACE
|
106
|
+
found = dev.settings.any? {|s|
|
107
|
+
s.bInterfaceClass == devclass &&
|
108
|
+
(!subclass || s.bInterfaceSubClass == subclass) &&
|
109
|
+
(!protocol || s.bInterfaceProtocol == protocol) }
|
110
|
+
else
|
111
|
+
found = dev.bDeviceClass == devclass &&
|
112
|
+
(!subclass || dev.bDeviceSubClass == subclass) &&
|
113
|
+
(!protocol || dev.bDeviceProtocol == protocol)
|
114
|
+
end
|
115
|
+
yield dev if found
|
116
|
+
}
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
class Bus
|
121
|
+
def inspect
|
122
|
+
if self.revoked?
|
123
|
+
"\#<#{self.class} revoked>"
|
124
|
+
else
|
125
|
+
"\#<#{self.class} #{self.dirname}>"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def devices
|
130
|
+
result = []
|
131
|
+
device = self.first_device
|
132
|
+
while device
|
133
|
+
result << device
|
134
|
+
device = device.next
|
135
|
+
end
|
136
|
+
result.sort_by {|d| d.filename }
|
137
|
+
end
|
138
|
+
|
139
|
+
def configurations() self.devices.map {|d| d.configurations }.flatten end
|
140
|
+
def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
|
141
|
+
def settings() self.interfaces.map {|d| d.settings }.flatten end
|
142
|
+
def endpoints() self.settings.map {|d| d.endpoints }.flatten end
|
143
|
+
|
144
|
+
def find_device(n)
|
145
|
+
device = self.first_device
|
146
|
+
while device
|
147
|
+
return device if n == device.filename.to_i
|
148
|
+
device = device.next
|
149
|
+
end
|
150
|
+
return nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# :stopdoc:
|
155
|
+
# http://www.usb.org/developers/defined_class
|
156
|
+
CLASS_CODES = [
|
157
|
+
[0x01, nil, nil, "Audio"],
|
158
|
+
[0x02, nil, nil, "Comm"],
|
159
|
+
[0x03, nil, nil, "HID"],
|
160
|
+
[0x05, nil, nil, "Physical"],
|
161
|
+
[0x06, 0x01, 0x01, "StillImaging"],
|
162
|
+
[0x06, nil, nil, "Image"],
|
163
|
+
[0x07, nil, nil, "Printer"],
|
164
|
+
[0x08, 0x01, nil, "MassStorage RBC Bluk-Only"],
|
165
|
+
[0x08, 0x02, 0x50, "MassStorage ATAPI Bluk-Only"],
|
166
|
+
[0x08, 0x03, 0x50, "MassStorage QIC-157 Bluk-Only"],
|
167
|
+
[0x08, 0x04, nil, "MassStorage UFI"],
|
168
|
+
[0x08, 0x05, 0x50, "MassStorage SFF-8070i Bluk-Only"],
|
169
|
+
[0x08, 0x06, 0x50, "MassStorage SCSI Bluk-Only"],
|
170
|
+
[0x08, nil, nil, "MassStorage"],
|
171
|
+
[0x09, 0x00, 0x00, "Full speed Hub"],
|
172
|
+
[0x09, 0x00, 0x01, "Hi-speed Hub with single TT"],
|
173
|
+
[0x09, 0x00, 0x02, "Hi-speed Hub with multiple TTs"],
|
174
|
+
[0x09, nil, nil, "Hub"],
|
175
|
+
[0x0a, nil, nil, "CDC"],
|
176
|
+
[0x0b, nil, nil, "SmartCard"],
|
177
|
+
[0x0d, 0x00, 0x00, "ContentSecurity"],
|
178
|
+
[0x0e, nil, nil, "Video"],
|
179
|
+
[0xdc, 0x01, 0x01, "Diagnostic USB2"],
|
180
|
+
[0xdc, nil, nil, "Diagnostic"],
|
181
|
+
[0xe0, 0x01, 0x01, "Bluetooth"],
|
182
|
+
[0xe0, 0x01, 0x02, "UWB"],
|
183
|
+
[0xe0, 0x01, 0x03, "RemoteNDIS"],
|
184
|
+
[0xe0, 0x02, 0x01, "Host Wire Adapter Control/Data"],
|
185
|
+
[0xe0, 0x02, 0x02, "Device Wire Adapter Control/Data"],
|
186
|
+
[0xe0, 0x02, 0x03, "Device Wire Adapter Isochronous"],
|
187
|
+
[0xe0, nil, nil, "Wireless Controller"],
|
188
|
+
[0xef, 0x01, 0x01, "Active Sync"],
|
189
|
+
[0xef, 0x01, 0x02, "Palm Sync"],
|
190
|
+
[0xef, 0x02, 0x01, "Interface Association Descriptor"],
|
191
|
+
[0xef, 0x02, 0x02, "Wire Adapter Multifunction Peripheral"],
|
192
|
+
[0xef, 0x03, 0x01, "Cable Based Association Framework"],
|
193
|
+
[0xef, nil, nil, "Miscellaneous"],
|
194
|
+
[0xfe, 0x01, 0x01, "Device Firmware Upgrade"],
|
195
|
+
[0xfe, 0x02, 0x00, "IRDA Bridge"],
|
196
|
+
[0xfe, 0x03, 0x00, "USB Test and Measurement"],
|
197
|
+
[0xfe, 0x03, 0x01, "USB Test and Measurement (USBTMC USB488)"],
|
198
|
+
[0xfe, nil, nil, "Application Specific"],
|
199
|
+
[0xff, nil, nil, "Vendor specific"],
|
200
|
+
]
|
201
|
+
CLASS_CODES_HASH1 = {}
|
202
|
+
CLASS_CODES_HASH2 = {}
|
203
|
+
CLASS_CODES_HASH3 = {}
|
204
|
+
CLASS_CODES.each {|base_class, sub_class, protocol, desc|
|
205
|
+
if protocol
|
206
|
+
CLASS_CODES_HASH3[[base_class, sub_class, protocol]] = desc
|
207
|
+
elsif sub_class
|
208
|
+
CLASS_CODES_HASH2[[base_class, sub_class]] = desc
|
209
|
+
else
|
210
|
+
CLASS_CODES_HASH1[base_class] = desc
|
211
|
+
end
|
212
|
+
}
|
213
|
+
|
214
|
+
def USB.dev_string(base_class, sub_class, protocol)
|
215
|
+
if desc = CLASS_CODES_HASH3[[base_class, sub_class, protocol]]
|
216
|
+
desc
|
217
|
+
elsif desc = CLASS_CODES_HASH2[[base_class, sub_class]]
|
218
|
+
desc + " (%02x)" % [protocol]
|
219
|
+
elsif desc = CLASS_CODES_HASH1[base_class]
|
220
|
+
desc + " (%02x,%02x)" % [sub_class, protocol]
|
221
|
+
else
|
222
|
+
"Unkonwn(%02x,%02x,%02x)" % [base_class, sub_class, protocol]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
# :startdoc:
|
226
|
+
|
227
|
+
class Device
|
228
|
+
def inspect
|
229
|
+
if self.revoked?
|
230
|
+
"\#<#{self.class} revoked>"
|
231
|
+
else
|
232
|
+
attrs = []
|
233
|
+
attrs << "#{self.bus.dirname}/#{self.filename}"
|
234
|
+
attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
|
235
|
+
attrs << self.manufacturer
|
236
|
+
attrs << self.product
|
237
|
+
attrs << self.serial_number
|
238
|
+
if self.bDeviceClass == USB::USB_CLASS_PER_INTERFACE
|
239
|
+
devclass = self.settings.map {|i|
|
240
|
+
USB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
|
241
|
+
}.join(", ")
|
242
|
+
else
|
243
|
+
devclass = USB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
|
244
|
+
end
|
245
|
+
attrs << "(#{devclass})"
|
246
|
+
attrs.compact!
|
247
|
+
"\#<#{self.class} #{attrs.join(' ')}>"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def manufacturer
|
252
|
+
return @manufacturer if defined? @manufacturer
|
253
|
+
@manufacturer = self.open {|h| h.get_string_simple(self.iManufacturer) }
|
254
|
+
@manufacturer.strip! if @manufacturer
|
255
|
+
@manufacturer
|
256
|
+
end
|
257
|
+
|
258
|
+
def product
|
259
|
+
return @product if defined? @product
|
260
|
+
@product = self.open {|h| h.get_string_simple(self.iProduct) }
|
261
|
+
@product.strip! if @product
|
262
|
+
@product
|
263
|
+
end
|
264
|
+
|
265
|
+
def serial_number
|
266
|
+
return @serial_number if defined? @serial_number
|
267
|
+
@serial_number = self.open {|h| h.get_string_simple(self.iSerialNumber) }
|
268
|
+
@serial_number.strip! if @serial_number
|
269
|
+
@serial_number
|
270
|
+
end
|
271
|
+
|
272
|
+
def open
|
273
|
+
h = self.usb_open
|
274
|
+
if block_given?
|
275
|
+
begin
|
276
|
+
r = yield h
|
277
|
+
ensure
|
278
|
+
h.usb_close
|
279
|
+
end
|
280
|
+
else
|
281
|
+
h
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def interfaces() self.configurations.map {|d| d.interfaces }.flatten end
|
286
|
+
def settings() self.interfaces.map {|d| d.settings }.flatten end
|
287
|
+
def endpoints() self.settings.map {|d| d.endpoints }.flatten end
|
288
|
+
end
|
289
|
+
|
290
|
+
class Configuration
|
291
|
+
def inspect
|
292
|
+
if self.revoked?
|
293
|
+
"\#<#{self.class} revoked>"
|
294
|
+
else
|
295
|
+
attrs = []
|
296
|
+
attrs << self.bConfigurationValue.to_s
|
297
|
+
bits = self.bmAttributes
|
298
|
+
attrs << "SelfPowered" if (bits & 0b1000000) != 0
|
299
|
+
attrs << "RemoteWakeup" if (bits & 0b100000) != 0
|
300
|
+
desc = self.description
|
301
|
+
attrs << desc if desc != '?'
|
302
|
+
"\#<#{self.class} #{attrs.join(' ')}>"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def description
|
307
|
+
return @description if defined? @description
|
308
|
+
@description = self.device.open {|h| h.get_string_simple(self.iConfiguration) }
|
309
|
+
end
|
310
|
+
|
311
|
+
def bus() self.device.bus end
|
312
|
+
|
313
|
+
def settings() self.interfaces.map {|d| d.settings }.flatten end
|
314
|
+
def endpoints() self.settings.map {|d| d.endpoints }.flatten end
|
315
|
+
end
|
316
|
+
|
317
|
+
class Interface
|
318
|
+
def inspect
|
319
|
+
if self.revoked?
|
320
|
+
"\#<#{self.class} revoked>"
|
321
|
+
else
|
322
|
+
"\#<#{self.class}>"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def bus() self.configuration.device.bus end
|
327
|
+
def device() self.configuration.device end
|
328
|
+
|
329
|
+
def endpoints() self.settings.map {|d| d.endpoints }.flatten end
|
330
|
+
end
|
331
|
+
|
332
|
+
class Setting
|
333
|
+
def inspect
|
334
|
+
if self.revoked?
|
335
|
+
"\#<#{self.class} revoked>"
|
336
|
+
else
|
337
|
+
attrs = []
|
338
|
+
attrs << self.bAlternateSetting.to_s
|
339
|
+
devclass = USB.dev_string(self.bInterfaceClass, self.bInterfaceSubClass, self.bInterfaceProtocol)
|
340
|
+
attrs << devclass
|
341
|
+
desc = self.description
|
342
|
+
attrs << desc if desc != '?'
|
343
|
+
"\#<#{self.class} #{attrs.join(' ')}>"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def description
|
348
|
+
return @description if defined? @description
|
349
|
+
@description = self.device.open {|h| h.get_string_simple(self.iInterface) }
|
350
|
+
end
|
351
|
+
|
352
|
+
def bus() self.interface.configuration.device.bus end
|
353
|
+
def device() self.interface.configuration.device end
|
354
|
+
def configuration() self.interface.configuration end
|
355
|
+
end
|
356
|
+
|
357
|
+
class Endpoint
|
358
|
+
def inspect
|
359
|
+
if self.revoked?
|
360
|
+
"\#<#{self.class} revoked>"
|
361
|
+
else
|
362
|
+
endpoint_address = self.bEndpointAddress
|
363
|
+
num = endpoint_address & 0b00001111
|
364
|
+
inout = (endpoint_address & 0b10000000) == 0 ? "OUT" : "IN "
|
365
|
+
bits = self.bmAttributes
|
366
|
+
transfer_type = %w[Control Isochronous Bulk Interrupt][0b11 & bits]
|
367
|
+
type = [transfer_type]
|
368
|
+
if transfer_type == 'Isochronous'
|
369
|
+
synchronization_type = %w[NoSynchronization Asynchronous Adaptive Synchronous][(0b1100 & bits) >> 2]
|
370
|
+
usage_type = %w[Data Feedback ImplicitFeedback ?][(0b110000 & bits) >> 4]
|
371
|
+
type << synchronization_type << usage_type
|
372
|
+
end
|
373
|
+
"\#<#{self.class} #{num} #{inout} #{type.join(" ")}>"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def bus() self.setting.interface.configuration.device.bus end
|
378
|
+
def device() self.setting.interface.configuration.device end
|
379
|
+
def configuration() self.setting.interface.configuration end
|
380
|
+
def interface() self.setting.interface end
|
381
|
+
end
|
382
|
+
|
383
|
+
class DevHandle
|
384
|
+
def set_configuration(configuration)
|
385
|
+
configuration = configuration.bConfigurationValue if configuration.respond_to? :bConfigurationValue
|
386
|
+
self.usb_set_configuration(configuration)
|
387
|
+
end
|
388
|
+
|
389
|
+
def set_altinterface(alternate)
|
390
|
+
alternate = alternate.bAlternateSetting if alternate.respond_to? :bAlternateSetting
|
391
|
+
self.usb_set_altinterface(alternate)
|
392
|
+
end
|
393
|
+
|
394
|
+
def clear_halt(ep)
|
395
|
+
ep = ep.bEndpointAddress if ep.respond_to? :bEndpointAddress
|
396
|
+
self.usb_clear_halt(ep)
|
397
|
+
end
|
398
|
+
|
399
|
+
def claim_interface(interface)
|
400
|
+
interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
|
401
|
+
self.usb_claim_interface(interface)
|
402
|
+
end
|
403
|
+
|
404
|
+
def release_interface(interface)
|
405
|
+
interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
|
406
|
+
self.usb_release_interface(interface)
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_string_simple(index)
|
410
|
+
result = "\0" * 1024
|
411
|
+
begin
|
412
|
+
self.usb_get_string_simple(index, result)
|
413
|
+
rescue Errno::EPIPE, Errno::EFBIG, Errno::EPERM
|
414
|
+
return nil
|
415
|
+
end
|
416
|
+
result.delete!("\0")
|
417
|
+
result
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
data/sample/usb-power
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# usage: usb-power bus/device port on|off
|
4
|
+
#
|
5
|
+
# example:
|
6
|
+
# usb-power 004/006 2 on
|
7
|
+
# usb-power 004/006 2 off
|
8
|
+
|
9
|
+
require 'usb'
|
10
|
+
require 'optparse'
|
11
|
+
|
12
|
+
USB_RT_PORT = USB::USB_TYPE_CLASS | USB::USB_RECIP_OTHER
|
13
|
+
USB_PORT_FEAT_POWER = 8
|
14
|
+
|
15
|
+
def list_usb2_hub
|
16
|
+
USB.devices.find_all {|d|
|
17
|
+
0x200 <= d.bcdDevice &&
|
18
|
+
d.bDeviceClass == USB::USB_CLASS_HUB
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'pp'
|
23
|
+
|
24
|
+
def power_on(h, port)
|
25
|
+
h.usb_control_msg(USB_RT_PORT, USB::USB_REQ_SET_FEATURE, USB_PORT_FEAT_POWER, port, "", 0)
|
26
|
+
end
|
27
|
+
|
28
|
+
def power_off(h, port)
|
29
|
+
h.usb_control_msg(USB_RT_PORT, USB::USB_REQ_CLEAR_FEATURE, USB_PORT_FEAT_POWER, port, "", 0)
|
30
|
+
end
|
31
|
+
|
32
|
+
bus_device = ARGV.shift
|
33
|
+
port = ARGV.shift.to_i
|
34
|
+
on_off = ARGV.shift
|
35
|
+
|
36
|
+
%r{/} =~ bus_device
|
37
|
+
bus = $`.to_i
|
38
|
+
device = $'.to_i
|
39
|
+
|
40
|
+
USB.find_bus(bus).find_device(device).open {|h|
|
41
|
+
if on_off == 'off'
|
42
|
+
power_off(h, port)
|
43
|
+
else
|
44
|
+
power_on(h, port)
|
45
|
+
end
|
46
|
+
}
|