# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import time from autotest_lib.client.common_lib import error from autotest_lib.server import autotest from autotest_lib.server.cros.faft.firmware_test import FirmwareTest from autotest_lib.server.cros.faft.firmware_test import ConnectionError from autotest_lib.server.cros.servo import servo class firmware_ECWakeSource(FirmwareTest): """ Servo based EC wake source test. """ version = 1 # After suspending the device, wait this long before waking it again. SUSPEND_WAIT_TIME_SECONDS = 5 # Retries allowed for reaching S0ix|S3 after suspend and S0 after wake. POWER_STATE_RETRY_COUNT = 10 # The timeout (in seconds) to confirm the device is woken up from # suspend mode. RESUME_TIMEOUT = 60 # Delay before the USB keyboard is seen by DUT after initialization USB_PRESENT_DELAY = 1 def initialize(self, host, cmdline_args): super(firmware_ECWakeSource, self).initialize(host, cmdline_args) # Only run in normal mode self.switcher.setup_mode('normal') self.has_internal_display = host.has_internal_display() def cleanup(self): # Restore the lid_open switch in case the test failed in the middle. if self.check_ec_capability(['lid']): self.servo.set('lid_open', 'yes') super(firmware_ECWakeSource, self).cleanup() def is_ec_console_responsive(self): """Test if EC console is responsive.""" try: self.ec.send_command_get_output('help', ['.*>']) return True except servo.UnresponsiveConsoleError: return False def wake_by_lid_switch(self): """Wake up the device by lid switch.""" self.servo.set('lid_open', 'no') time.sleep(self.LID_DELAY) self.servo.set('lid_open', 'yes') def suspend_and_wake(self, suspend_func, wake_func): """Suspend and then wake up the device. Args: suspend_func: The method used to suspend the device wake_func: The method used to resume the device """ suspend_func() self.switcher.wait_for_client_offline() if not self.wait_power_state(self.POWER_STATE_SUSPEND, self.POWER_STATE_RETRY_COUNT): raise error.TestFail('Platform failed to reach S0ix or S3 state.') time.sleep(self.SUSPEND_WAIT_TIME_SECONDS) wake_func() if not self.wait_power_state(self.POWER_STATE_S0, self.POWER_STATE_RETRY_COUNT): raise error.TestFail('Platform failed to reach S0 state.') self.switcher.wait_for_client(timeout=self.RESUME_TIMEOUT) def suspend_and_dont_wake(self, suspend_func, wake_func): """Suspend and then check the the device doesn't wake up. Args: suspend_func: The method used to suspend the device wake_func: The method used to wake the device """ suspend_func() self.switcher.wait_for_client_offline() if not self.wait_power_state(self.POWER_STATE_SUSPEND, self.POWER_STATE_RETRY_COUNT): raise error.TestFail('Platform failed to reach S0ix or S3 state.') time.sleep(self.SUSPEND_WAIT_TIME_SECONDS) wake_func() if self.wait_power_state(self.POWER_STATE_S0, self.POWER_STATE_RETRY_COUNT): raise error.TestFail('Platform woke up unexpectedly.') else: self.servo.power_normal_press() if not self.wait_power_state(self.POWER_STATE_S0, self.POWER_STATE_RETRY_COUNT): raise error.TestFail('Platform failed to reach S0 state.') self.switcher.wait_for_client(timeout=self.RESUME_TIMEOUT) def check_boot_id(self, host, orig_boot_id, wake_method): """Check current boot id matches original boot id. Args: host: test host object orig_boot_id: original boot_id to compare against wake_method: string indicating the method used to wake the device """ boot_id = host.get_boot_id() if boot_id != orig_boot_id: raise error.TestFail('Unexpected reboot by suspend and wake: ' + wake_method) def run_once(self, host): """Runs a single iteration of the test.""" if not self.check_ec_capability(): raise error.TestNAError( "Nothing needs to be tested on this device") # Login as a normal user and stay there, such that closing lid triggers # suspend, instead of shutdown. autotest_client = autotest.Autotest(host) autotest_client.run_test('desktopui_SimpleLogin', exit_without_logout=True) original_boot_id = host.get_boot_id() # Test suspend and wake by power button wake_src = 'power button' if not self.has_internal_display: # With no display connected, pressing the power button in suspend mode # would lead to shutdown. logging.info( 'The device has no internal display. ' 'Skip testing suspend/resume by %s.', wake_src) else: logging.info('Suspend and wake by %s.', wake_src) self.suspend_and_wake(self.suspend, self.servo.power_normal_press) self.check_boot_id(host, original_boot_id, wake_src) # Test suspend and wake by internal key press wake_src = 'internal key press' if not self.check_ec_capability(['keyboard']): logging.info( 'The device has no internal keyboard. ' 'Skip testing suspend/resume by %s.', wake_src) elif not self.ec.has_command('ksstate'): logging.info( 'The device does not support the ksstate command. ' 'Skip testing suspend/resume by %s.', wake_src) else: result = self.ec.send_command_get_output( 'ksstate', ['Keyboard scan disable mask: 0x([0-9a-fA-F]{8})']) kb_scan_disable_mask = int(result[0][1], 16) if kb_scan_disable_mask == 0: logging.info('Suspend and wake by %s.', wake_src) self.suspend_and_wake(self.suspend, lambda: self.ec.key_press('')) else: logging.info( 'Tablet mode enabled; suspend and check device ' 'does not wake by %s.', wake_src) self.suspend_and_dont_wake( self.suspend, lambda: self.ec.key_press('')) self.check_boot_id(host, original_boot_id, wake_src) # Test suspend and wake by USB HID key press wake_src = 'USB HID key press' if not self.faft_config.usb_hid_wake_enabled: logging.info( 'Device does not support wake by USB HID. ' 'Skip suspend and wake by %s.', wake_src) else: logging.info('Suspend and wake by %s.', wake_src) logging.debug('Initializing HID keyboard emulator.') self.servo.set_nocheck('init_usb_keyboard', 'on') time.sleep(self.USB_PRESENT_DELAY) try: self.suspend_and_wake(self.suspend, lambda:self.servo.set_nocheck('usb_keyboard_enter_key', 'press')) except ConnectionError: raise error.TestFail( 'USB HID suspend/resume fails. Maybe try to ' 'update firmware for Atmel USB KB emulator by running ' 'firmware_FlashServoKeyboardMap test and then try again?' ) self.check_boot_id(host, original_boot_id, wake_src) logging.debug('Turning off HID keyboard emulator.') self.servo.set_nocheck('init_usb_keyboard', 'off') # Test suspend and wake by lid switch wake_src = 'lid switch' if not self.check_ec_capability(['lid']): logging.info( 'The device has no lid. ' 'Skip testing suspend/resume by %s.', wake_src) else: logging.info('Suspend and wake by %s.', wake_src) self.suspend_and_wake(self.suspend, self.wake_by_lid_switch) logging.info('Close lid to suspend and wake by %s.', wake_src) self.suspend_and_wake(lambda:self.servo.set('lid_open', 'no'), self.wake_by_lid_switch) self.check_boot_id(host, original_boot_id, wake_src)