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