• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import logging
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
9
10
11class 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        self.ec.send_command("chan 0xffffffff")
43        super(firmware_ECUsbPorts, self).cleanup()
44
45
46    def fake_reboot_by_usb_mode_change(self):
47        """
48        Turn off USB ports and also kill FAFT client so that this acts like a
49        reboot. If USB ports cannot be turned off or on, reboot step would
50        fail.
51        """
52        for_all_ports_cmd = ('id=0; while [ $id -lt %d ];' +
53                             'do ectool usbchargemode "$id" %d;' +
54                             'id=$((id+1)); sleep 0.5; done')
55        # Port disable - same for smart and dumb ports.
56        ports_off_cmd = for_all_ports_cmd % (self._port_count,
57                                             self.USB_CHARGE_MODE_DISABLED)
58        # Port enable - different command based on smart/dumb port.
59        port_enable_param = (self.USB_CHARGE_MODE_SDP2
60            if self._smart_usb_charge else self.USB_CHARGE_MODE_ENABLED)
61        ports_on_cmd = for_all_ports_cmd % (self._port_count, port_enable_param)
62        cmd = ("(sleep %d; %s; sleep %d; %s)&" %
63                (self.RPC_DELAY, ports_off_cmd,
64                 self.REBOOT_DELAY,
65                 ports_on_cmd))
66        self.faft_client.system.run_shell_command(cmd)
67        self.faft_client.disconnect()
68
69
70    def get_port_count(self):
71        """
72        Get the number of USB ports by checking the number of GPIO named
73        USB*_ENABLE.
74        """
75        cnt = 0
76        limit = 10
77        while limit > 0:
78            try:
79                gpio_name = "USB%d_ENABLE" % (cnt + 1)
80                self.ec.send_command_get_output(
81                        "gpioget %s" % gpio_name,
82                        ["[01].\s*%s" % gpio_name])
83                cnt = cnt + 1
84                limit = limit - 1
85            except error.TestFail:
86                logging.info("Found %d USB ports", cnt)
87                return cnt
88
89        # Limit reached. Probably something went wrong.
90        raise error.TestFail("Unexpected error while trying to determine " +
91                             "number of USB ports")
92
93
94    def wait_port_disabled(self, port_count, timeout):
95        """
96        Wait for all USB ports to be disabled.
97
98        Args:
99          @param port_count: Number of USB ports.
100          @param timeout: Timeout range.
101        """
102        logging.info('Waiting for %d USB ports to be disabled.', port_count)
103        while timeout > 0:
104            try:
105                timeout = timeout - 1
106                for idx in xrange(1, port_count+1):
107                    gpio_name = "USB%d_ENABLE" % idx
108                    self.ec.send_command_get_output(
109                            "gpioget %s" % gpio_name,
110                            ["0.\s*%s" % gpio_name])
111                return True
112            except error.TestFail:
113                # USB ports not disabled. Retry.
114                pass
115        return False
116
117
118    def check_power_off_mode(self):
119        """Shutdown the system and check USB ports are disabled."""
120        self._failed = False
121        self.faft_client.system.run_shell_command("shutdown -P now")
122        self.switcher.wait_for_client_offline()
123        if not self.wait_port_disabled(self._port_count, self.SHUTDOWN_TIMEOUT):
124            logging.info("Fails to wait for USB port disabled")
125            self._failed = True
126        self.servo.power_short_press()
127
128
129    def check_failure(self):
130        """Returns true if failure has been encountered."""
131        return not self._failed
132
133
134    def run_once(self):
135        if not self.check_ec_capability(['usb']):
136            raise error.TestNAError("Nothing needs to be tested on this device")
137
138        self._smart_usb_charge = (
139            'smart_usb_charge' in self.faft_config.ec_capability)
140        self._port_count = self.get_port_count()
141
142        logging.info("Turn off all USB ports and then turn them on again.")
143        self.switcher.mode_aware_reboot(
144                'custom', self.fake_reboot_by_usb_mode_change)
145
146        logging.info("Check USB ports are disabled when powered off.")
147        self.switcher.mode_aware_reboot('custom', self.check_power_off_mode)
148
149        logging.info("Check if failure occurred.")
150        self.check_state(self.check_failure)
151