| #!/usr/bin/python | 
 | # Copyright 2014 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | """Code generator DeviceCapabilities literal.""" | 
 |  | 
 | import argparse | 
 | import ctypes | 
 | import evdev | 
 | import os | 
 | import sys | 
 |  | 
 |  | 
 | TEST_DATA_GROUP_SIZE = 64  # Aligns with sysfs on 64-bit devices. | 
 |  | 
 |  | 
 | def bits_to_groups(bits): | 
 |   return (bits + TEST_DATA_GROUP_SIZE - 1) / TEST_DATA_GROUP_SIZE | 
 |  | 
 |  | 
 | # As in /sys/class/input/input*/capabilities/* | 
 | def serialize_bitfield(bitfield, max_bit): | 
 |   result = "" | 
 |   group_count = bits_to_groups(max_bit) | 
 |   for group in xrange(group_count - 1, -1, -1): | 
 |     group_val = 0 | 
 |     for group_bit in xrange(TEST_DATA_GROUP_SIZE): | 
 |       code = group * TEST_DATA_GROUP_SIZE + group_bit | 
 |       if code in bitfield: | 
 |         group_val |= (1 << group_bit) | 
 |     if group_val or result: | 
 |       result += '%x' % group_val | 
 |       if group: | 
 |         result += ' ' | 
 |   if not result: | 
 |     return '0' | 
 |   return result | 
 |  | 
 |  | 
 | def dump_absinfo(out, capabilities, identifier): | 
 |   out.write('const DeviceAbsoluteAxis %s[] = {\n' % identifier) | 
 |  | 
 |   for code, absinfo in capabilities[evdev.ecodes.EV_ABS]: | 
 |     # Set value := 0 to make it deterministic. | 
 |     code_name = evdev.ecodes.bytype[evdev.ecodes.EV_ABS][code] | 
 |     absinfo_struct = (0, absinfo.min, absinfo.max, absinfo.fuzz, absinfo.flat, | 
 |                       absinfo.resolution) | 
 |     data = (code_name,) + absinfo_struct | 
 |     out.write('    {%s, {%d, %d, %d, %d, %d, %d}},\n' % data) | 
 |  | 
 |   out.write('};\n') | 
 |  | 
 |  | 
 | def dump_capabilities(out, dev, identifier): | 
 |   capabilities = dev.capabilities() | 
 |   has_abs = evdev.ecodes.EV_ABS in capabilities | 
 |  | 
 |   sysfs_path = '/sys/class/input/' + os.path.basename(dev.fn) | 
 |  | 
 |   # python-evdev is missing some features | 
 |   uniq = open(sysfs_path + '/device/uniq', 'r').read().strip() | 
 |   prop = open(sysfs_path + '/device/properties', 'r').read().strip() | 
 |   ff = open(sysfs_path + '/device/capabilities/ff', 'r').read().strip() | 
 |  | 
 |   # python-evdev parses the id wrong. | 
 |   bustype = open(sysfs_path + '/device/id/bustype', 'r').read().strip() | 
 |   vendor = open(sysfs_path + '/device/id/vendor', 'r').read().strip() | 
 |   product = open(sysfs_path + '/device/id/product', 'r').read().strip() | 
 |   version = open(sysfs_path + '/device/id/version', 'r').read().strip() | 
 |  | 
 |   # python-evdev drops EV_REP from the event set. | 
 |   ev = open(sysfs_path + '/device/capabilities/ev', 'r').read().strip() | 
 |  | 
 |   if ctypes.sizeof(ctypes.c_long()) != 8: | 
 |     # /sys/class/input/*/properties format is word size dependent. | 
 |     # Could be fixed by regrouping but for now, just raise an error. | 
 |     raise ValueError("Must be run on 64-bit machine") | 
 |  | 
 |   key_bits = capabilities.get(evdev.ecodes.EV_KEY, []) | 
 |   rel_bits = capabilities.get(evdev.ecodes.EV_REL, []) | 
 |   abs_bits = [abs[0] for abs in capabilities.get(evdev.ecodes.EV_ABS, [])] | 
 |   msc_bits = capabilities.get(evdev.ecodes.EV_MSC, []) | 
 |   sw_bits = capabilities.get(evdev.ecodes.EV_SW, []) | 
 |   led_bits = capabilities.get(evdev.ecodes.EV_LED, []) | 
 |  | 
 |   fields = [ | 
 |     ('path', os.path.realpath(sysfs_path)), | 
 |     ('name', dev.name), | 
 |     ('phys', dev.phys), | 
 |     ('uniq', uniq), | 
 |     ('bustype', bustype), | 
 |     ('vendor', vendor), | 
 |     ('product', product), | 
 |     ('version', version), | 
 |     ('prop', prop), | 
 |     ('ev', ev), | 
 |     ('key', serialize_bitfield(key_bits, evdev.ecodes.KEY_CNT)), | 
 |     ('rel', serialize_bitfield(rel_bits, evdev.ecodes.REL_CNT)), | 
 |     ('abs', serialize_bitfield(abs_bits, evdev.ecodes.ABS_CNT)), | 
 |     ('msc', serialize_bitfield(msc_bits, evdev.ecodes.MSC_CNT)), | 
 |     ('sw', serialize_bitfield(sw_bits, evdev.ecodes.SW_CNT)), | 
 |     ('led', serialize_bitfield(led_bits, evdev.ecodes.LED_CNT)), | 
 |     ('ff', ff), | 
 |   ] | 
 |  | 
 |   if has_abs: | 
 |     absinfo_identifier = identifier + 'AbsAxes' | 
 |     dump_absinfo(out, capabilities, absinfo_identifier) | 
 |  | 
 |   out.write('const DeviceCapabilities %s = {\n' % identifier) | 
 |   for name, val in fields: | 
 |     out.write('    /* %s */ "%s",\n' % (name, val)) | 
 |  | 
 |   if has_abs: | 
 |     out.write('    %s,\n' % absinfo_identifier) | 
 |     out.write('    arraysize(%s),\n' % absinfo_identifier) | 
 |  | 
 |   out.write('};\n') | 
 |  | 
 |  | 
 | def main(argv): | 
 |   parser = argparse.ArgumentParser() | 
 |   parser.add_argument('device') | 
 |   parser.add_argument('identifier') | 
 |   args = parser.parse_args(argv) | 
 |  | 
 |   dev = evdev.InputDevice(args.device) | 
 |   out = sys.stdout | 
 |  | 
 |   dump_capabilities(out, dev, args.identifier) | 
 |   return 0 | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |   sys.exit(main(sys.argv[1:])) |