1# Copyright (c) 2014 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 os
7
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.common_lib.cros import cros_config
11from autotest_lib.client.cros import touch_playback_test_base
12
13
14class touch_WakeupSource(touch_playback_test_base.touch_playback_test_base):
15    """Check that touchpad/touchscreen are set/not set as wake sources."""
16    version = 1
17
18    # Devices whose touchpads should not be a wake source.
19    #
20    # Note, starting with octopus platform, convertibles should enable touchpad
21    # wake.  If you  wish to enable on previous devices, see furquan@ doc
22    # go/cros-trackpad-wake and/or consult chromeos-platform-power@ for more
23    # details.
24    _NO_TOUCHPAD_WAKE = [
25            'caroline', 'clapper', 'elm', 'glimmer', 'hana', 'kevin', 'kukui',
26            'pyro', 'veyron_minnie'
27    ]
28    _TOUCHPAD_WAKE_SET_BY_CROS_CONFIG = ['coral', 'nami']
29
30    # Devices with Synaptics touchpads that do not report wake source,
31    # or reference platforms like Rambi which are broken but do not ship,
32    # or devices like Cyan which don't report this way: crosbug.com/p/46019.
33    _INVALID_TOUCHPADS = ['x86-alex', 'x86-alex_he', 'x86-zgb', 'x86-zgb_he',
34                          'x86-mario', 'stout', 'rambi', 'cyan']
35    _INVALID_TOUCHSCREENS = ['cyan', 'nocturne', 'sumo', 'ultima']
36
37    def _touchpad_should_be_wake_source(self):
38        base_platform = self._platform.replace('-kernelnext', '')
39        if base_platform in self._NO_TOUCHPAD_WAKE:
40            return False
41        if (base_platform in self._TOUCHPAD_WAKE_SET_BY_CROS_CONFIG
42                    and cros_config.call_cros_config_get_output(
43                            '/power touchpad-wakeup', utils.run) == '0'):
44            return False
45        return True
46
47    def _find_wakeup_file(self, input_type):
48        """Return path to wakeup file or None.
49
50        If the file does not exist, check the parent bus for wakeup rules
51        as well, as is the setup for some devices.
52
53        @param input_type: e.g. 'touchpad' or 'mouse'. See parent class for
54                all options.
55
56        @raises: TestError if input_type lacks required information.
57
58        """
59        device_dir = self.player.devices[input_type].device_dir
60        if not device_dir:
61            raise error.TestError('No device directory for %s!' % input_type)
62
63        filename = os.path.join(device_dir, 'power', 'wakeup')
64        if not os.path.isfile(filename):
65            logging.info('%s not found for %s', filename, input_type)
66
67            # Look for wakeup file on parent bus instead.
68            event = self.player.devices[input_type].node.split('/')[-1]
69
70            parent = None
71            i2c_devices_dir = os.path.join('/', 'sys', 'bus', 'i2c', 'devices')
72            for device_dir in os.listdir(i2c_devices_dir):
73                event_search = os.path.join(i2c_devices_dir, device_dir, '*',
74                                            'input', 'input*', event)
75                match_count = utils.run('ls %s 2>/dev/null | wc -l' % (
76                        event_search)).stdout.strip()
77                if int(match_count) > 0:
78                    parent = os.path.join(i2c_devices_dir, device_dir)
79                    break
80            if parent is None:
81                logging.info('Could not find parent bus for %s.', input_type)
82                return None
83
84            logging.info('Parent bus of %s is %s.', input_type, parent)
85            filename = os.path.join(parent, 'power', 'wakeup')
86            if not os.path.isfile(filename):
87                logging.info('%s not found either.', filename)
88                return None
89
90        return filename
91
92    def _is_wake_source(self, input_type):
93        """Return True if the given device is a wake source, else False.
94
95        If the file does not exist, return False.
96
97        @param input_type: e.g. 'touchpad' or 'mouse'. See parent class for
98                all options.
99
100        @raises: TestError if test cannot interpret the file contents.
101
102        """
103        filename = self._find_wakeup_file(input_type)
104        if filename is None:
105            return False
106
107        result = utils.run('cat %s' % filename).stdout.strip()
108        if result == 'enabled':
109            logging.info('Found that %s is a wake source.', input_type)
110            return True
111        elif result == 'disabled':
112            logging.info('Found that %s is not a wake source.', input_type)
113            return False
114        raise error.TestError('Wakeup file for %s said "%s".' %
115                              (input_type, result))
116
117    def run_once(self, source):
118        """Entry point of this test."""
119
120        # Check that touchpad is a wake source for all but the excepted boards.
121        if source == 'touchpad':
122            if (self._has_touchpad and
123                self._platform not in self._INVALID_TOUCHPADS):
124                if self._touchpad_should_be_wake_source():
125                    if not self._is_wake_source('touchpad'):
126                        raise error.TestFail('Touchpad is not a wake source!')
127                else:
128                    if self._is_wake_source('touchpad'):
129                        raise error.TestFail('Touchpad is a wake source!')
130
131        # Check that touchscreen is not a wake source (if present).
132        # Devices without a touchpad should have touchscreen as wake source.
133        if source == 'touchscreen':
134            if (self._has_touchscreen and
135                self._platform not in self._INVALID_TOUCHSCREENS):
136                touchscreen_wake = self._is_wake_source('touchscreen')
137                if self._has_touchpad and touchscreen_wake:
138                    raise error.TestFail('Touchscreen is a wake source!')
139                if not self._has_touchpad and not touchscreen_wake:
140                    raise error.TestFail('Touchscreen is not a wake source!')
141