• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
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.
5
6import sys
7if sys.platform == 'win32':
8  raise ImportError('devil.utils.reset_usb only supported on unix systems.')
9
10import argparse
11import fcntl
12import logging
13import os
14import re
15
16if __name__ == '__main__':
17  sys.path.append(
18      os.path.abspath(os.path.join(os.path.dirname(__file__),
19                                   '..', '..')))
20
21from devil.android import device_errors
22from devil.utils import lsusb
23from devil.utils import run_tests_helper
24
25logger = logging.getLogger(__name__)
26
27_INDENTATION_RE = re.compile(r'^( *)')
28_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
29_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
30_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
31
32_USBDEVFS_RESET = ord('U') << 8 | 20
33
34
35def reset_usb(bus, device):
36  """Reset the USB device with the given bus and device."""
37  usb_file_path = '/dev/bus/usb/%03d/%03d' % (bus, device)
38  with open(usb_file_path, 'w') as usb_file:
39    logger.debug('fcntl.ioctl(%s, %d)', usb_file_path, _USBDEVFS_RESET)
40    fcntl.ioctl(usb_file, _USBDEVFS_RESET)
41
42
43def reset_android_usb(serial):
44  """Reset the USB device for the given Android device."""
45  lsusb_info = lsusb.lsusb()
46
47  bus = None
48  device = None
49  for device_info in lsusb_info:
50    device_serial = lsusb.get_lsusb_serial(device_info)
51    if device_serial == serial:
52      bus = int(device_info.get('bus'))
53      device = int(device_info.get('device'))
54
55  if bus and device:
56    reset_usb(bus, device)
57  else:
58    raise device_errors.DeviceUnreachableError(
59        'Unable to determine bus(%s) or device(%s) for device %s'
60         % (bus, device, serial))
61
62
63def reset_all_android_devices():
64  """Reset all USB devices that look like an Android device."""
65  _reset_all_matching(lambda i: bool(lsusb.get_lsusb_serial(i)))
66
67
68def _reset_all_matching(condition):
69  lsusb_info = lsusb.lsusb()
70  for device_info in lsusb_info:
71    if int(device_info.get('device')) != 1 and condition(device_info):
72      bus = int(device_info.get('bus'))
73      device = int(device_info.get('device'))
74      try:
75        reset_usb(bus, device)
76        serial = lsusb.get_lsusb_serial(device_info)
77        if serial:
78          logger.info(
79              'Reset USB device (bus: %03d, device: %03d, serial: %s)',
80              bus, device, serial)
81        else:
82          logger.info(
83              'Reset USB device (bus: %03d, device: %03d)',
84              bus, device)
85      except IOError:
86        logger.error(
87            'Failed to reset USB device (bus: %03d, device: %03d)',
88            bus, device)
89
90
91def main():
92  parser = argparse.ArgumentParser()
93  parser.add_argument('-v', '--verbose', action='count')
94  parser.add_argument('-s', '--serial')
95  parser.add_argument('--bus', type=int)
96  parser.add_argument('--device', type=int)
97  args = parser.parse_args()
98
99  run_tests_helper.SetLogLevel(args.verbose)
100
101  if args.serial:
102    reset_android_usb(args.serial)
103  elif args.bus and args.device:
104    reset_usb(args.bus, args.device)
105  else:
106    parser.error('Unable to determine target. '
107                 'Specify --serial or BOTH --bus and --device.')
108
109  return 0
110
111
112if __name__ == '__main__':
113  sys.exit(main())
114
115