1 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 7 from autotest_lib.client.common_lib import error 8 from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 9 10 11 class firmware_ECUsbPorts(FirmwareTest): 12 """ 13 Servo based EC USB port control test. 14 """ 15 version = 1 16 17 18 # Delay for remote shell command call to return 19 RPC_DELAY = 1 20 21 # Delay between turning off and on USB ports 22 REBOOT_DELAY = 6 23 24 # Timeout range for waiting system to shutdown 25 SHUTDOWN_TIMEOUT = 10 26 27 # USB charge modes, copied from ec/include/usb_charge.h 28 USB_CHARGE_MODE_DISABLED = 0 29 USB_CHARGE_MODE_SDP2 = 1 30 USB_CHARGE_MODE_CDP = 2 31 USB_CHARGE_MODE_DCP_SHORT = 3 32 USB_CHARGE_MODE_ENABLED = 4 33 34 def initialize(self, host, cmdline_args): 35 super(firmware_ECUsbPorts, self).initialize(host, cmdline_args) 36 # Only run in normal mode 37 self.switcher.setup_mode('normal') 38 self.ec.send_command("chan 0") 39 40 41 def cleanup(self): 42 try: 43 self.ec.send_command("chan 0xffffffff") 44 except Exception as e: 45 logging.error("Caught exception: %s", str(e)) 46 super(firmware_ECUsbPorts, self).cleanup() 47 48 49 def fake_reboot_by_usb_mode_change(self): 50 """ 51 Turn off USB ports and also kill FAFT client so that this acts like a 52 reboot. If USB ports cannot be turned off or on, reboot step would 53 fail. 54 """ 55 for_all_ports_cmd = ('id=0; while [ $id -lt %d ];' + 56 'do ectool usbchargemode "$id" %d;' + 57 'id=$((id+1)); sleep 0.5; done') 58 # Port disable - same for smart and dumb ports. 59 ports_off_cmd = for_all_ports_cmd % (self._port_count, 60 self.USB_CHARGE_MODE_DISABLED) 61 # Port enable - different command based on smart/dumb port. 62 port_enable_param = (self.USB_CHARGE_MODE_SDP2 63 if self._smart_usb_charge else self.USB_CHARGE_MODE_ENABLED) 64 ports_on_cmd = for_all_ports_cmd % (self._port_count, port_enable_param) 65 cmd = ("(sleep %d; %s; sleep %d; %s)&" % 66 (self.RPC_DELAY, ports_off_cmd, 67 self.REBOOT_DELAY, 68 ports_on_cmd)) 69 self.faft_client.system.run_shell_command(cmd) 70 self.faft_client.disconnect() 71 72 73 def get_port_count(self): 74 """ 75 Get the number of USB ports by checking the number of GPIO named 76 USB*_ENABLE. 77 """ 78 cnt = 0 79 limit = 10 80 while limit > 0: 81 try: 82 gpio_name = "USB%d_ENABLE" % (cnt + 1) 83 self.ec.send_command_get_output( 84 "gpioget %s" % gpio_name, 85 ["[01].\s*%s" % gpio_name]) 86 cnt = cnt + 1 87 limit = limit - 1 88 except error.TestFail: 89 logging.info("Found %d USB ports", cnt) 90 return cnt 91 92 # Limit reached. Probably something went wrong. 93 raise error.TestFail("Unexpected error while trying to determine " + 94 "number of USB ports") 95 96 97 def wait_port_disabled(self, port_count, timeout): 98 """ 99 Wait for all USB ports to be disabled. 100 101 Args: 102 @param port_count: Number of USB ports. 103 @param timeout: Timeout range. 104 """ 105 logging.info('Waiting for %d USB ports to be disabled.', port_count) 106 while timeout > 0: 107 try: 108 timeout = timeout - 1 109 for idx in xrange(1, port_count+1): 110 gpio_name = "USB%d_ENABLE" % idx 111 self.ec.send_command_get_output( 112 "gpioget %s" % gpio_name, 113 ["0.\s*%s" % gpio_name]) 114 return True 115 except error.TestFail: 116 # USB ports not disabled. Retry. 117 pass 118 return False 119 120 121 def check_power_off_mode(self): 122 """Shutdown the system and check USB ports are disabled.""" 123 self._failed = False 124 self.faft_client.system.run_shell_command("shutdown -P now") 125 self.switcher.wait_for_client_offline() 126 if not self.wait_port_disabled(self._port_count, self.SHUTDOWN_TIMEOUT): 127 logging.info("Fails to wait for USB port disabled") 128 self._failed = True 129 self.servo.power_short_press() 130 131 132 def check_failure(self): 133 """Returns true if failure has been encountered.""" 134 return not self._failed 135 136 137 def run_once(self): 138 if not self.check_ec_capability(['usb']): 139 raise error.TestNAError("Nothing needs to be tested on this device") 140 141 self._smart_usb_charge = ( 142 'smart_usb_charge' in self.faft_config.ec_capability) 143 self._port_count = self.get_port_count() 144 145 logging.info("Turn off all USB ports and then turn them on again.") 146 self.switcher.mode_aware_reboot( 147 'custom', self.fake_reboot_by_usb_mode_change) 148 149 logging.info("Check USB ports are disabled when powered off.") 150 self.switcher.mode_aware_reboot('custom', self.check_power_off_mode) 151 152 logging.info("Check if failure occurred.") 153 self.check_state(self.check_failure) 154