1#!/usr/bin/env python
2#
3# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import logging
8import re
9
10from subprocess import Popen, PIPE
11
12from autotest_lib.client.bin import test
13from autotest_lib.client.bin import utils
14from autotest_lib.client.common_lib import error
15
16# Keys for udev db
17KEY_NAME = 'NAME'
18KEY_DEVPATH = 'DEVPATH'
19KEY_ID_INPUT_TOUCHPAD = 'ID_INPUT_TOUCHPAD'
20
21# True equivalences
22TRUE_EQ = ['1', 'on', 'true', 'yes']
23
24# Regular expressions for cmt module related log
25UNLOAD_CMT_RE = r'UnloadModule.*cmt'
26USE_CMT_STRING = "Using input driver 'cmt' for '%s'"
27
28# Path to xorg log
29XORG_LOG_PATH = '/var/log/Xorg.0.log'
30
31
32class hardware_TrackpadFunction(test.test):
33    '''Test to make sure trackpad functions correctly'''
34    version = 1
35
36    def _udev_from_string(self, device_string):
37        # Sample lines:
38        # P: /devices/LNXSYSTM:00/LNXPWRBN:00
39        # E: UDEV_LOG=3
40        # E: DEVPATH=/devices/LNXSYSTM:00/LNXPWRBN:00
41        properties = {}
42        for line in device_string.split('\n'):
43            _, _, val = line.partition(': ')
44            args = val.partition('=')
45            if args[1] != '':
46                properties[args[0]] = args[2]
47        return properties
48
49    def _udevadm_export_db(self):
50        p = Popen('udevadm info --export-db', shell=True, stdout=PIPE)
51        output = p.communicate()[0]
52        devs = output.split('\n\n')
53        return [self._udev_from_string(dev) for dev in devs]
54
55    def run_once(self):
56        """Test if cmt driver is loaded correctly.
57        """
58        # TODO(ihf): Delete this test once all boards run freon.
59        if utils.is_freon():
60            return
61
62        devices = self._udevadm_export_db()
63        named_devices = [dev for dev in devices if KEY_NAME in dev]
64
65        touchpad_devices = []
66        for named_device in named_devices:
67            dev_path = named_device.get(KEY_DEVPATH)
68            for dev in devices:
69                # Use device path prefix match to examine if a named device is
70                # touchpad or not.
71                #
72                # Example of named device data:
73                #
74                # P: /devices/platform/i8042/serio4/input/input6
75                # E: UDEV_LOG=3
76                # E: DEVPATH=/devices/platform/i8042/serio4/input/input6
77                # E: PRODUCT=11/2/7/1b1
78                # E: NAME="SynPS/2 Synaptics TouchPad"
79                # E: PHYS="isa0060/serio4/input0"
80                #
81                # Example of the data whose DEVPATH prefix matches the DEVPATH
82                # above and ID_INPUT_TOUCHPAD is true.
83                #
84                # P: /devices/platform/i8042/serio4/input/input6/event6
85                # N: input/event6
86                # S: input/by-path/platform-i8042-serio-4-event-mouse
87                # E: UDEV_LOG=3
88                # E: DEVPATH=/devices/platform/i8042/serio4/input/input6/event6
89                # E: MAJOR=13
90                # E: MINOR=70
91                # E: DEVNAME=/dev/input/event6
92                # E: SUBSYSTEM=input
93                # E: ID_INPUT=1
94                # E: ID_INPUT_TOUCHPAD=1
95                if (dev.get(KEY_DEVPATH, '').find(dev_path) == 0 and
96                        dev.get(KEY_ID_INPUT_TOUCHPAD, '') in TRUE_EQ):
97                    touchpad_devices.append(named_device)
98        if touchpad_devices:
99            loaded = False
100            for touchpad_device in touchpad_devices:
101                name = touchpad_device.get(KEY_NAME).strip('"')
102                with open(XORG_LOG_PATH, 'r') as f:
103                    for line in f.readlines():
104                        if USE_CMT_STRING % name in line:
105                            logging.info('cmt loaded: %s', line)
106                            loaded = True
107                        if re.search(UNLOAD_CMT_RE, line, re.I):
108                            loaded = False
109                            break
110
111                if not loaded:
112                    raise error.TestFail('cmt did not load for %s' % name)
113        else:
114            # TODO: when touchpad_devices is empty we should check the board
115            # to see if it's expected.
116            logging.info('no trackpad found')
117