1cef7893435aa41160dd1255c43cb8498279738ccChris Craik#!/usr/bin/env python
2cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Copyright 2015 The Chromium Authors. All rights reserved.
3cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Use of this source code is governed by a BSD-style license that can be
4cef7893435aa41160dd1255c43cb8498279738ccChris Craik# found in the LICENSE file.
5cef7893435aa41160dd1255c43cb8498279738ccChris Craik
6cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport argparse
7cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport fcntl
8cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport logging
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport os
10cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport re
11cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport sys
12cef7893435aa41160dd1255c43cb8498279738ccChris Craik
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckif __name__ == '__main__':
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  sys.path.append(
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      os.path.abspath(os.path.join(os.path.dirname(__file__),
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck                                   '..', '..')))
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
18cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom devil.android import device_errors
19cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom devil.utils import lsusb
20cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom devil.utils import run_tests_helper
21cef7893435aa41160dd1255c43cb8498279738ccChris Craik
22ee838d1c4002134ff5af32da272140586c4d31deJohn Recklogger = logging.getLogger(__name__)
23ee838d1c4002134ff5af32da272140586c4d31deJohn Reck
24cef7893435aa41160dd1255c43cb8498279738ccChris Craik_INDENTATION_RE = re.compile(r'^( *)')
25cef7893435aa41160dd1255c43cb8498279738ccChris Craik_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
26cef7893435aa41160dd1255c43cb8498279738ccChris Craik_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
27cef7893435aa41160dd1255c43cb8498279738ccChris Craik_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
28cef7893435aa41160dd1255c43cb8498279738ccChris Craik
29cef7893435aa41160dd1255c43cb8498279738ccChris Craik_USBDEVFS_RESET = ord('U') << 8 | 20
30cef7893435aa41160dd1255c43cb8498279738ccChris Craik
31cef7893435aa41160dd1255c43cb8498279738ccChris Craik
32cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef reset_usb(bus, device):
33cef7893435aa41160dd1255c43cb8498279738ccChris Craik  """Reset the USB device with the given bus and device."""
34cef7893435aa41160dd1255c43cb8498279738ccChris Craik  usb_file_path = '/dev/bus/usb/%03d/%03d' % (bus, device)
35cef7893435aa41160dd1255c43cb8498279738ccChris Craik  with open(usb_file_path, 'w') as usb_file:
36ee838d1c4002134ff5af32da272140586c4d31deJohn Reck    logger.debug('fcntl.ioctl(%s, %d)', usb_file_path, _USBDEVFS_RESET)
37cef7893435aa41160dd1255c43cb8498279738ccChris Craik    fcntl.ioctl(usb_file, _USBDEVFS_RESET)
38cef7893435aa41160dd1255c43cb8498279738ccChris Craik
39cef7893435aa41160dd1255c43cb8498279738ccChris Craik
40cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef reset_android_usb(serial):
41cef7893435aa41160dd1255c43cb8498279738ccChris Craik  """Reset the USB device for the given Android device."""
42cef7893435aa41160dd1255c43cb8498279738ccChris Craik  lsusb_info = lsusb.lsusb()
43cef7893435aa41160dd1255c43cb8498279738ccChris Craik
44cef7893435aa41160dd1255c43cb8498279738ccChris Craik  bus = None
45cef7893435aa41160dd1255c43cb8498279738ccChris Craik  device = None
46cef7893435aa41160dd1255c43cb8498279738ccChris Craik  for device_info in lsusb_info:
47cef7893435aa41160dd1255c43cb8498279738ccChris Craik    device_serial = lsusb.get_lsusb_serial(device_info)
48cef7893435aa41160dd1255c43cb8498279738ccChris Craik    if device_serial == serial:
49cef7893435aa41160dd1255c43cb8498279738ccChris Craik      bus = int(device_info.get('bus'))
50cef7893435aa41160dd1255c43cb8498279738ccChris Craik      device = int(device_info.get('device'))
51cef7893435aa41160dd1255c43cb8498279738ccChris Craik
52cef7893435aa41160dd1255c43cb8498279738ccChris Craik  if bus and device:
53cef7893435aa41160dd1255c43cb8498279738ccChris Craik    reset_usb(bus, device)
54cef7893435aa41160dd1255c43cb8498279738ccChris Craik  else:
55cef7893435aa41160dd1255c43cb8498279738ccChris Craik    raise device_errors.DeviceUnreachableError(
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        'Unable to determine bus(%s) or device(%s) for device %s'
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck         % (bus, device, serial))
58cef7893435aa41160dd1255c43cb8498279738ccChris Craik
59cef7893435aa41160dd1255c43cb8498279738ccChris Craik
60cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef reset_all_android_devices():
61cef7893435aa41160dd1255c43cb8498279738ccChris Craik  """Reset all USB devices that look like an Android device."""
62cef7893435aa41160dd1255c43cb8498279738ccChris Craik  _reset_all_matching(lambda i: bool(lsusb.get_lsusb_serial(i)))
63cef7893435aa41160dd1255c43cb8498279738ccChris Craik
64cef7893435aa41160dd1255c43cb8498279738ccChris Craik
65cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef _reset_all_matching(condition):
66cef7893435aa41160dd1255c43cb8498279738ccChris Craik  lsusb_info = lsusb.lsusb()
67cef7893435aa41160dd1255c43cb8498279738ccChris Craik  for device_info in lsusb_info:
68cef7893435aa41160dd1255c43cb8498279738ccChris Craik    if int(device_info.get('device')) != 1 and condition(device_info):
69cef7893435aa41160dd1255c43cb8498279738ccChris Craik      bus = int(device_info.get('bus'))
70cef7893435aa41160dd1255c43cb8498279738ccChris Craik      device = int(device_info.get('device'))
71cef7893435aa41160dd1255c43cb8498279738ccChris Craik      try:
72cef7893435aa41160dd1255c43cb8498279738ccChris Craik        reset_usb(bus, device)
73cef7893435aa41160dd1255c43cb8498279738ccChris Craik        serial = lsusb.get_lsusb_serial(device_info)
74cef7893435aa41160dd1255c43cb8498279738ccChris Craik        if serial:
75ee838d1c4002134ff5af32da272140586c4d31deJohn Reck          logger.info(
76ee838d1c4002134ff5af32da272140586c4d31deJohn Reck              'Reset USB device (bus: %03d, device: %03d, serial: %s)',
77cef7893435aa41160dd1255c43cb8498279738ccChris Craik              bus, device, serial)
78cef7893435aa41160dd1255c43cb8498279738ccChris Craik        else:
79ee838d1c4002134ff5af32da272140586c4d31deJohn Reck          logger.info(
80ee838d1c4002134ff5af32da272140586c4d31deJohn Reck              'Reset USB device (bus: %03d, device: %03d)',
81cef7893435aa41160dd1255c43cb8498279738ccChris Craik              bus, device)
82cef7893435aa41160dd1255c43cb8498279738ccChris Craik      except IOError:
83ee838d1c4002134ff5af32da272140586c4d31deJohn Reck        logger.error(
84cef7893435aa41160dd1255c43cb8498279738ccChris Craik            'Failed to reset USB device (bus: %03d, device: %03d)',
85cef7893435aa41160dd1255c43cb8498279738ccChris Craik            bus, device)
86cef7893435aa41160dd1255c43cb8498279738ccChris Craik
87cef7893435aa41160dd1255c43cb8498279738ccChris Craik
88cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef main():
89cef7893435aa41160dd1255c43cb8498279738ccChris Craik  parser = argparse.ArgumentParser()
90cef7893435aa41160dd1255c43cb8498279738ccChris Craik  parser.add_argument('-v', '--verbose', action='count')
91cef7893435aa41160dd1255c43cb8498279738ccChris Craik  parser.add_argument('-s', '--serial')
92cef7893435aa41160dd1255c43cb8498279738ccChris Craik  parser.add_argument('--bus', type=int)
93cef7893435aa41160dd1255c43cb8498279738ccChris Craik  parser.add_argument('--device', type=int)
94cef7893435aa41160dd1255c43cb8498279738ccChris Craik  args = parser.parse_args()
95cef7893435aa41160dd1255c43cb8498279738ccChris Craik
96cef7893435aa41160dd1255c43cb8498279738ccChris Craik  run_tests_helper.SetLogLevel(args.verbose)
97cef7893435aa41160dd1255c43cb8498279738ccChris Craik
98cef7893435aa41160dd1255c43cb8498279738ccChris Craik  if args.serial:
99cef7893435aa41160dd1255c43cb8498279738ccChris Craik    reset_android_usb(args.serial)
100cef7893435aa41160dd1255c43cb8498279738ccChris Craik  elif args.bus and args.device:
101cef7893435aa41160dd1255c43cb8498279738ccChris Craik    reset_usb(args.bus, args.device)
102cef7893435aa41160dd1255c43cb8498279738ccChris Craik  else:
103cef7893435aa41160dd1255c43cb8498279738ccChris Craik    parser.error('Unable to determine target. '
104cef7893435aa41160dd1255c43cb8498279738ccChris Craik                 'Specify --serial or BOTH --bus and --device.')
105cef7893435aa41160dd1255c43cb8498279738ccChris Craik
106cef7893435aa41160dd1255c43cb8498279738ccChris Craik  return 0
107cef7893435aa41160dd1255c43cb8498279738ccChris Craik
108cef7893435aa41160dd1255c43cb8498279738ccChris Craik
109cef7893435aa41160dd1255c43cb8498279738ccChris Craikif __name__ == '__main__':
110cef7893435aa41160dd1255c43cb8498279738ccChris Craik  sys.exit(main())
111cef7893435aa41160dd1255c43cb8498279738ccChris Craik
112