1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#!/usr/bin/python
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Reset a USB device (presumbly android phone) by serial number.
Given a serial number, inspects connected USB devices and issues USB
reset to the one that matches. Python version written by Than
McIntosh, based on a perl version from Chris Ferris. Intended for use
on linux.
"""
import fcntl
import getopt
import locale
import os
import re
import shlex
import subprocess
import sys
# Serial number of device that we want to reset
flag_serial = None
# Debugging verbosity level (0 -> no output)
flag_debug = 0
USBDEVFS_RESET = ord("U") << (4*2) | 20
def verbose(level, msg):
"""Print debug trace output of verbosity level is >= value in 'level'."""
if level <= flag_debug:
sys.stderr.write(msg + "\n")
def increment_verbosity():
"""Increment debug trace level by 1."""
global flag_debug
flag_debug += 1
def issue_ioctl_to_device(device):
"""Issue USB reset ioctl to device."""
try:
fd = open(device, "wb")
except IOError as e:
error("unable to open device %s: "
"%s" % (device, e.strerror))
verbose(1, "issuing USBDEVFS_RESET ioctl() to %s" % device)
fcntl.ioctl(fd, USBDEVFS_RESET, 0)
fd.close()
# perform default locale setup if needed
def set_default_lang_locale():
if "LANG" not in os.environ:
warning("no env setting for LANG -- using default values")
os.environ["LANG"] = "en_US.UTF-8"
os.environ["LANGUAGE"] = "en_US:"
def warning(msg):
"""Issue a warning to stderr."""
sys.stderr.write("warning: " + msg + "\n")
def error(msg):
"""Issue an error to stderr, then exit."""
sys.stderr.write("error: " + msg + "\n")
exit(1)
# invoke command, returning array of lines read from it
def docmdlines(cmd, nf=None):
"""Run a command via subprocess, returning output as an array of lines."""
verbose(2, "+ docmdlines executing: %s" % cmd)
args = shlex.split(cmd)
mypipe = subprocess.Popen(args, stdout=subprocess.PIPE)
encoding = locale.getdefaultlocale()[1]
pout, perr = mypipe.communicate()
if mypipe.returncode != 0:
if perr:
decoded_err = perr.decode(encoding)
warning(decoded_err)
if nf:
return None
error("command failed (rc=%d): cmd was %s" % (mypipe.returncode, args))
decoded = pout.decode(encoding)
lines = decoded.strip().split("\n")
return lines
def perform():
"""Main driver routine."""
lines = docmdlines("usb-devices")
dmatch = re.compile(r"^\s*T:\s*Bus\s*=\s*(\d+)\s+.*\s+Dev#=\s*(\d+).*$")
smatch = re.compile(r"^\s*S:\s*SerialNumber=(.*)$")
device = None
found = False
for line in lines:
m = dmatch.match(line)
if m:
p1 = int(m.group(1))
p2 = int(m.group(2))
device = "/dev/bus/usb/%03d/%03d" % (p1, p2)
verbose(1, "setting device: %s" % device)
continue
m = smatch.match(line)
if m:
ser = m.group(1)
if ser == flag_serial:
verbose(0, "matched serial %s to device "
"%s, invoking reset" % (ser, device))
issue_ioctl_to_device(device)
found = True
break
if not found:
error("unable to locate device with serial number %s" % flag_serial)
def usage(msgarg):
"""Print usage and exit."""
if msgarg:
sys.stderr.write("error: %s\n" % msgarg)
print """\
usage: %s [options] XXYYZZ
where XXYYZZ is the serial number of a connected Android device.
options:
-d increase debug msg verbosity level
""" % os.path.basename(sys.argv[0])
sys.exit(1)
def parse_args():
"""Command line argument parsing."""
global flag_serial
try:
optlist, args = getopt.getopt(sys.argv[1:], "d")
except getopt.GetoptError as err:
# unrecognized option
usage(str(err))
if not args or len(args) != 1:
usage("supply a single device serial number as argument")
flag_serial = args[0]
for opt, _ in optlist:
if opt == "-d":
increment_verbosity()
set_default_lang_locale()
parse_args()
perform()
|