2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
12 from pylib
import cmd_helper
13 from pylib
.device
import adb_wrapper
14 from pylib
.device
import device_errors
15 from pylib
.utils
import run_tests_helper
17 _INDENTATION_RE
= re
.compile(r
'^( *)')
18 _LSUSB_BUS_DEVICE_RE
= re
.compile(r
'^Bus (\d{3}) Device (\d{3}):')
19 _LSUSB_ENTRY_RE
= re
.compile(r
'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
20 _LSUSB_GROUP_RE
= re
.compile(r
'^ *([^ ]+.*):$')
22 _USBDEVFS_RESET
= ord('U') << 8 |
20
25 def reset_usb(bus
, device
):
26 """Reset the USB device with the given bus and device."""
27 usb_file_path
= '/dev/bus/usb/%03d/%03d' % (bus
, device
)
28 with
open(usb_file_path
, 'w') as usb_file
:
29 logging
.debug('fcntl.ioctl(%s, %d)', usb_file_path
, _USBDEVFS_RESET
)
30 fcntl
.ioctl(usb_file
, _USBDEVFS_RESET
)
33 def reset_android_usb(serial
):
34 """Reset the USB device for the given Android device."""
39 for device_info
in lsusb_info
:
40 device_serial
= _get_lsusb_serial(device
)
41 if device_serial
== serial
:
42 bus
= int(device_info
.get('bus'))
43 device
= int(device_info
.get('device'))
46 reset_usb(bus
, device
)
48 raise device_errors
.DeviceUnreachableError(
49 'Unable to determine bus or device for device %s' % serial
)
52 def reset_all_android_devices():
53 """Reset all USB devices that look like an Android device."""
54 _reset_all_matching(lambda i
: bool(_get_lsusb_serial(i
)))
57 def _reset_all_matching(condition
):
59 for device_info
in lsusb_info
:
60 if int(device_info
.get('device')) != 1 and condition(device_info
):
61 bus
= int(device_info
.get('bus'))
62 device
= int(device_info
.get('device'))
64 reset_usb(bus
, device
)
65 serial
= _get_lsusb_serial(device_info
)
67 logging
.info('Reset USB device (bus: %03d, device: %03d, serial: %s)',
70 logging
.info('Reset USB device (bus: %03d, device: %03d)',
74 'Failed to reset USB device (bus: %03d, device: %03d)',
79 """Call lsusb and return the parsed output."""
80 lsusb_raw_output
= cmd_helper
.GetCmdOutput(['lsusb', '-v'])
84 for line
in lsusb_raw_output
.splitlines():
87 devices
.append(device
)
92 m
= _LSUSB_BUS_DEVICE_RE
.match(line
)
98 depth_stack
= [device
]
101 indent_match
= _INDENTATION_RE
.match(line
)
105 depth
= 1 + len(indent_match
.group(1)) / 2
106 if depth
> len(depth_stack
):
107 logging
.error('lsusb parsing error: unexpected indentation: "%s"', line
)
110 while depth
< len(depth_stack
):
113 cur
= depth_stack
[-1]
115 m
= _LSUSB_GROUP_RE
.match(line
)
118 cur
[m
.group(1)] = new_group
119 depth_stack
.append(new_group
)
122 m
= _LSUSB_ENTRY_RE
.match(line
)
125 '_value': m
.group(2),
128 cur
[m
.group(1)] = new_entry
129 depth_stack
.append(new_entry
)
132 logging
.error('lsusb parsing error: unrecognized line: "%s"', line
)
135 devices
.append(device
)
140 def _get_lsusb_serial(device
):
141 return device
.get('Device Descriptor', {}).get('iSerial', {}).get('_desc')
145 parser
= argparse
.ArgumentParser()
146 parser
.add_argument('-v', '--verbose', action
='count')
147 parser
.add_argument('-s', '--serial')
148 parser
.add_argument('--bus', type=int)
149 parser
.add_argument('--device', type=int)
150 args
= parser
.parse_args()
152 run_tests_helper
.SetLogLevel(args
.verbose
)
155 reset_android_usb(args
.serial
)
156 elif args
.bus
and args
.device
:
157 reset_usb(args
.bus
, args
.device
)
159 parser
.error('Unable to determine target. '
160 'Specify --serial or BOTH --bus and --device.')
165 if __name__
== '__main__':