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