1# Copyright (c) 2015 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
5import logging
6import time
7
8from autotest_lib.client.common_lib import error
9from autotest_lib.server.cros import vboot_constants as vboot
10from autotest_lib.server.cros.faft.firmware_test import ConnectionError
11from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
12from autotest_lib.server.cros.faft.utils import mode_switcher
13
14class firmware_ECLidShutdown(FirmwareTest):
15    """
16    Testing GBB_FLAG_DISABLE_LID_SHUTDOWN flag
17    """
18    version = 1
19
20    # Delay between closing and opening the lid
21    LID_DELAY = 2
22    # time to wait before checking if DUT booted into OS mode
23    BOOTUP_TIME = 30
24    # # times to check if DUT in expected power state
25    # This accomodates if DUT needs to transition into certain states.
26    PWR_RETRIES = 13
27
28    def initialize(self, host, cmdline_args):
29        super(firmware_ECLidShutdown, self).initialize(host, cmdline_args)
30        self.setup_usbkey(usbkey=False)
31
32    def cleanup(self):
33        """If DUT not pingable, may be still stuck in recovery mode.
34        Reboot it.  Also, reset GBB_FLAGS and make sure that lid set
35        to open (in case of error).
36        """
37        # reset ec_uart_regexp to prevent timeouts in case there was
38        # an error before we could reset it
39        try:
40            self._reset_ec_regexp()
41            if self.servo.get('lid_open') == 'no':
42                self.servo.set('lid_open', 'yes')
43            self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN, 0)
44            self.switcher.wait_for_client()
45        except ConnectionError:
46            logging.error("ERROR: client not in OS mode.  Rebooting ...")
47            # reboot back to OS mode
48            self.switcher.mode_aware_reboot(reboot_type='cold',
49                                            sync_before_boot=False)
50        except Exception as e:
51            logging.error("Caught exception: %s", str(e))
52        super(firmware_ECLidShutdown, self).cleanup()
53
54    def _reset_ec_regexp(self):
55        """Reset ec_uart_regexp field
56
57        Needs to be done for the ec_uart_regexp otherwise
58        dut-control command will time out due to no match.
59        """
60        self.servo.set('ec_uart_regexp', 'None')
61
62    def verify_lid_shutdown(self):
63        """
64        Make sure that firmware boots into OS with lid closed
65        """
66        self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN,
67                                 0)
68        # reboot into recovery mode and wait a bit for it to actually get there
69        self.faft_client.system.request_recovery_boot()
70        self.switcher.simple_reboot()
71        time.sleep(self.faft_config.firmware_screen)
72
73        # close/open lid
74        self.servo.set('lid_open', 'no')
75        time.sleep(self.LID_DELAY)
76        if not self.wait_power_state("G3", self.PWR_RETRIES):
77            logging.error("ERROR: EC does not shut down")
78            return False
79        self.servo.set('lid_open', 'yes')
80
81        # ping DUT - should boot into OS now
82        self._reset_ec_regexp()
83        self.switcher.wait_for_client()
84
85        return True
86
87    def check_disable_lid_shutdown(self):
88        """
89        Set flag to disable shutdown of DUT when lid closed.  Then check
90        if DUT shuts down during recovery mode screen.
91        """
92        # enable shutdown flag
93        self.clear_set_gbb_flags(0,
94                                 vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN)
95        # reboot into recovery mode and wait a bit for it to get there
96        self.faft_client.system.request_recovery_boot()
97        self.switcher.simple_reboot()
98        time.sleep(self.faft_config.firmware_screen)
99
100        # close/open the lid
101        self.servo.set('lid_open', 'no')
102        time.sleep(self.LID_DELAY)
103        if not self.wait_power_state("S0", self.PWR_RETRIES):
104            logging.error("ERROR: EC shuts down")
105            return False
106        self.servo.set('lid_open', 'yes')
107
108        # this should be more than enough time for system to boot up
109        # if it was going to.
110        time.sleep(self.BOOTUP_TIME)
111
112        # should still be offline
113        self.switcher.wait_for_client_offline()
114
115        # reboot back to OS mode
116        self.switcher.mode_aware_reboot(reboot_type='cold',
117                                        sync_before_boot=False)
118
119        # disable flag
120        self._reset_ec_regexp()
121        return True
122
123
124    def run_once(self):
125        if not self.check_ec_capability(['lid']):
126            raise error.TestNAError("This device needs a lid to run this test")
127
128        logging.info("Verify DUT with DISABLE_LID_SHUTDOWN disabled")
129        self.check_state(self.verify_lid_shutdown)
130
131        logging.info("Verify DUT with DISABLE_LID_SHUTDOWN enabled")
132        self.check_state(self.check_disable_lid_shutdown)
133
134