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