1# Lint as: python2, python3 2# Copyright 2017 The Chromium OS 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"""Power cycle a usb port on DUT(device under test).""" 7 8from __future__ import absolute_import 9from __future__ import division 10from __future__ import print_function 11 12import logging 13import os 14from six.moves import zip 15import time 16 17from autotest_lib.client.common_lib.cros.cfm.usb import usb_port_manager 18 19 20TOKEN_NEW_BUS = '/: ' 21TOKEN_ROOT_DEVICE = '\n |__ ' 22 23# On board guado, there are three gpios that control usb port power: 24# Front left usb port: 218, port number: 2 25# Front right usb port: 219, port number: 3 26# Rear dual usb ports: 209, port number: 5,6 27# 28# On board fizz, there are 5 usb ports and usb port power is controlled by EC 29# with user space command: ectool goioset USBx_ENABLE 0/1 (x from 1 to 5). 30PORT_NUM_DICT = { 31 'guado': { 32 # USB 2.0. 33 'bus1': { 34 2: 'front_left', 35 3: 'front_right', 36 5: 'back_dual', 37 6: 'back_dual' 38 }, 39 # USB 3.0. 40 'bus2': { 41 1: 'front_left', 42 2: 'front_right', 43 3: 'back_dual', 44 4: 'back_dual' 45 } 46 }, 47 'fizz': { 48 # USB 2.0. 49 'bus1': { 50 2: 'rear_right', 51 3: 'front_right', 52 4: 'front_left', 53 5: 'rear_left', 54 6: 'rear_middle' 55 }, 56 # USB 3.0. 57 'bus2': { 58 2: 'rear_right', 59 3: 'front_right', 60 4: 'front_left', 61 5: 'rear_left', 62 6: 'rear_middle' 63 } 64 } 65} 66PORT_GPIO_DICT = { 67 'guado': { 68 'bus1': { 69 'front_left': 218, 70 'front_right': 219, 71 'back_dual': 209 72 }, 73 'bus2': { 74 'front_left': 218, 75 'front_right': 219, 76 'back_dual': 209 77 } 78 }, 79 'fizz': { 80 'bus1': { 81 'rear_left': 1, 82 'rear_middle': 2, 83 'rear_right': 3, 84 'front_right': 4, 85 'front_left': 5 86 }, 87 'bus2': { 88 'rear_left': 1, 89 'rear_middle': 2, 90 'rear_right': 3, 91 'front_right': 4, 92 'front_left': 5 93 } 94 } 95} 96 97 98def power_cycle_usb_vidpid(dut, board, vid, pid, pause=1): 99 """ 100 Power cycle a usb port on DUT via peripharel's VID and PID. 101 102 When only the VID and PID of the peripharel is known, a search is needed 103 to decide which port it connects to by its VID and PID and look up the gpio 104 index according to the board and port number in the dictionary. Then the 105 USB port is power cycled using the gpio number. 106 107 @param dut: The handle of the device under test. 108 @param board: Board name ('guado', etc.) 109 @param vid: Vendor ID of the peripharel device. 110 @param pid: Product ID of the peripharel device. 111 @param pause: Time interval between power off and power on, unit is second. 112 113 @raise KeyError if the target device wasn't found by given VID and PID. 114 115 """ 116 bus_idx, port_idx = get_port_number_from_vidpid(dut, vid, pid) 117 if port_idx is None: 118 raise KeyError('Couldn\'t find target device, {}:{}.'.format(vid, pid)) 119 logging.info('found device bus {} port {}'.format(bus_idx, port_idx)) 120 121 usb_manager = usb_port_manager.UsbPortManager(dut) 122 port_id = [usb_port_manager.PortId(bus=bus_idx, port_number=port_idx)] 123 usb_manager.set_port_power(port_id, 0) 124 time.sleep(pause) 125 usb_manager.set_port_power(port_id, 1) 126 127 128def get_port_number_from_vidpid(dut, vid, pid): 129 """ 130 Get bus number and port number a device is connected to on DUT. 131 132 Get the bus number and port number of the usb port the target perpipharel 133 device is connected to. 134 135 @param dut: The handle of the device under test. 136 @param vid: Vendor ID of the peripharel device. 137 @param pid: Product ID of the peripharel device. 138 139 @returns the target bus number and port number, if device not found, returns 140 (None, None). 141 142 """ 143 cmd = 'lsusb -d {}:{}'.format(vid, pid) 144 lsusb_output = dut.run(cmd, ignore_status=True).stdout 145 logging.info('lsusb output {}'.format(lsusb_output)) 146 target_bus_idx, target_dev_idx = get_bus_dev_id(lsusb_output, vid, pid) 147 if target_bus_idx is None: 148 return None, None 149 cmd = 'lsusb -t' 150 lsusb_output = dut.run(cmd, ignore_status=True).stdout 151 target_port_number = get_port_number( 152 lsusb_output, target_bus_idx, target_dev_idx) 153 return target_bus_idx, target_port_number 154 155 156def get_bus_dev_id(lsusb_output, vid, pid): 157 """ 158 Get bus number and device index a device is connected to on DUT. 159 160 Get the bus number and port number of the usb port the target perpipharel 161 device is connected to based on the output of command 'lsusb -d VID:PID'. 162 163 @param lsusb_output: output of command 'lsusb -d VID:PID' running on DUT. 164 @param vid: Vendor ID of the peripharel device. 165 @param pid: Product ID of the peripharel device. 166 167 @returns the target bus number and device index, if device not found, 168 returns (None, None). 169 170 """ 171 if lsusb_output == '': 172 return None, None 173 lsusb_device_info = lsusb_output.strip().split('\n') 174 if len(lsusb_device_info) > 1: 175 logging.info('find more than one device with VID:PID: %s:%s', vid, pid) 176 return None, None 177 # An example of the info line is 'Bus 001 Device 006: ID 266e:0110 ...' 178 fields = lsusb_device_info[0].split(' ') 179 assert len(fields) >= 6, 'Wrong info format: {}'.format(lsusb_device_info) 180 target_bus_idx = int(fields[1]) 181 target_device_idx = int(fields[3][:-1]) 182 logging.info('found target device %s:%s, bus: %d, dev: %d', 183 vid, pid, target_bus_idx, target_device_idx) 184 return target_bus_idx, target_device_idx 185 186def get_port_number(lsusb_tree_output, bus, dev): 187 """ 188 Get port number that certain device is connected to on DUT. 189 190 Get the port number of the usb port that the target peripharel device is 191 connected to based on the output of command 'lsusb -t', its bus number and 192 device index. 193 An example of lsusb_tree_output could be: 194 /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M 195 |__ Port 2: Dev 2, If 0, Class=Hub, Driver=hub/4p, 5000M 196 /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/11p, 480M 197 |__ Port 2: Dev 52, If 0, Class=Hub, Driver=hub/4p, 480M 198 |__ Port 1: Dev 55, If 0, Class=Human Interface Device, 199 Driver=usbhid, 12M 200 |__ Port 3: Dev 54, If 0, Class=Vendor Specific Class, 201 Driver=udl, 480M 202 |__ Port 3: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M 203 |__ Port 4: Dev 4, If 0, Class=Wireless, Driver=btusb, 12M 204 |__ Port 4: Dev 4, If 1, Class=Wireless, Driver=btusb, 12M 205 206 @param lsusb_tree_output: The output of command 'lsusb -t' on DUT. 207 @param bus: The bus number the peripharel device is connected to. 208 @param dev: The device index of the peripharel device on DUT. 209 210 @returns the target port number, if device not found, returns None. 211 212 """ 213 lsusb_device_buses = lsusb_tree_output.strip().split(TOKEN_NEW_BUS) 214 target_bus_token = 'Bus {:02d}.'.format(bus) 215 for bus_info in lsusb_device_buses: 216 if bus_info.find(target_bus_token) != 0: 217 continue 218 target_dev_token = 'Dev {}'.format(dev) 219 device_info = bus_info.strip(target_bus_token).split(TOKEN_ROOT_DEVICE) 220 for device in device_info: 221 if target_dev_token not in device: 222 continue 223 target_port_number = int(device.split(':')[0].split(' ')[1]) 224 return target_port_number 225 return None 226 227 228def get_all_port_number_from_vidpid(dut, vid, pid): 229 """ 230 Get the list of bus number and port number devices are connected to DUT. 231 232 Get the the list of bus number and port number of the usb ports the target 233 perpipharel devices are connected to. 234 235 @param dut: The handle of the device under test. 236 @param vid: Vendor ID of the peripharel device. 237 @param pid: Product ID of the peripharel device. 238 239 @returns the list of target bus number and port number, if device not found, 240 returns empty list. 241 242 """ 243 port_number = [] 244 cmd = 'lsusb -d {}:{}'.format(vid, pid) 245 lsusb_output = dut.run(cmd, ignore_status=True).stdout 246 (target_bus_idx, target_dev_idx) = get_all_bus_dev_id(lsusb_output, vid, pid) 247 if target_bus_idx is None: 248 return None, None 249 cmd = 'lsusb -t' 250 lsusb_output = dut.run(cmd, ignore_status=True).stdout 251 for bus, dev in zip(target_bus_idx, target_dev_idx): 252 port_number.append(get_port_number( 253 lsusb_output, bus, dev)) 254 return (target_bus_idx, port_number) 255 256 257def get_all_bus_dev_id(lsusb_output, vid, pid): 258 """ 259 Get the list of bus number and device index devices are connected to DUT. 260 261 Get the bus number and port number of the usb ports the target perpipharel 262 devices are connected to based on the output of command 'lsusb -d VID:PID'. 263 264 @param lsusb_output: output of command 'lsusb -d VID:PID' running on DUT. 265 @param vid: Vendor ID of the peripharel device. 266 @param pid: Product ID of the peripharel device. 267 268 @returns the list of target bus number and device index, if device not found, 269 returns empty list. 270 271 """ 272 bus_idx = [] 273 device_idx =[] 274 if lsusb_output == '': 275 return None, None 276 lsusb_device_info = lsusb_output.strip().split('\n') 277 for lsusb_device in lsusb_device_info: 278 fields = lsusb_device.split(' ') 279 assert len(fields) >= 6, 'Wrong info format: {}'.format(lsusb_device_info) 280 target_bus_idx = int(fields[1]) 281 target_device_idx = int(fields[3][:-1]) 282 bus_idx.append(target_bus_idx) 283 device_idx.append( target_device_idx) 284 return (bus_idx, device_idx) 285 286 287def get_target_all_gpio(dut, board, vid, pid): 288 """ 289 Get GPIO for all devices with vid, pid connected to on DUT. 290 291 Get gpio of usb port the target perpipharel devices are 292 connected to based on the output of command 'lsusb -d VID:PID'. 293 294 @param dut: The handle of the device under test. 295 @param board: Board name ('guado', etc.) 296 @param vid: Vendor ID of the peripharel device. 297 @param pid: Product ID of the peripharel device. 298 299 @returns the list of gpio, if no device found return [] 300 301 """ 302 gpio_list = [] 303 (bus_idx, port_idx) = get_all_port_number_from_vidpid(dut, vid, pid) 304 if port_idx is None: 305 raise KeyError('Couldn\'t find target device, {}:{}.'.format(vid, pid)) 306 307 for bus, port in zip(bus_idx, port_idx): 308 logging.info('found device bus {} port {}'.format(bus, port)) 309 token_bus = 'bus{}'.format(bus) 310 target_gpio_pos = (PORT_NUM_DICT.get(board, {}) 311 .get(token_bus, {}).get(port, '')) 312 target_gpio = (PORT_GPIO_DICT.get(board, {}) 313 .get(token_bus, {}).get(target_gpio_pos, None)) 314 logging.info('Target gpio num {}'.format(target_gpio)) 315 gpio_list.append(target_gpio) 316 return gpio_list 317