1#!/usr/bin/env python3 2# vim: set expandtab shiftwidth=4: 3# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ 4# 5# Copyright © 2018 Red Hat, Inc. 6# 7# Permission is hereby granted, free of charge, to any person obtaining a 8# copy of this software and associated documentation files (the 'Software'), 9# to deal in the Software without restriction, including without limitation 10# the rights to use, copy, modify, merge, publish, distribute, sublicense, 11# and/or sell copies of the Software, and to permit persons to whom the 12# Software is furnished to do so, subject to the following conditions: 13# 14# The above copyright notice and this permission notice (including the next 15# paragraph) shall be included in all copies or substantial portions of the 16# Software. 17# 18# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24# DEALINGS IN THE SOFTWARE. 25 26import argparse 27import sys 28 29try: 30 import pyudev 31except ModuleNotFoundError as e: 32 print("Error: {}".format(str(e)), file=sys.stderr) 33 print( 34 "One or more python modules are missing. Please install those " 35 "modules and re-run this tool." 36 ) 37 sys.exit(1) 38 39 40def list_devices(): 41 devices = {} 42 context = pyudev.Context() 43 for device in context.list_devices(subsystem="input"): 44 if (device.device_node or "").startswith("/dev/input/event"): 45 parent = device.parent 46 if parent is not None: 47 name = parent.properties["NAME"] or "" 48 # The udev name includes enclosing quotes 49 devices[device.device_node] = name[1:-1] 50 51 def versionsort(key): 52 return int(key[len("/dev/input/event") :]) 53 54 for k in sorted(devices, key=versionsort): 55 print(f"{k}:\t{devices[k]}") 56 57 58class HidDevice: 59 def __init__(self, name, driver, vendor, product, devpath): 60 self.name = name 61 self.driver = driver 62 self.vendor = vendor 63 self.product = product 64 self.devpath = devpath 65 self.hidraws = [] 66 self.evdevs = [] 67 68 69def list_hid_devices(): 70 devices = [] 71 context = pyudev.Context() 72 for device in context.list_devices(subsystem="hid"): 73 name = device.properties.get("HID_NAME") 74 driver = device.properties.get("DRIVER") 75 devpath = device.properties.get("DEVPATH") 76 id = device.properties.get("HID_ID") or "0:0:0" 77 _, vendor, product = (int(x, 16) for x in id.split(":")) 78 devices.append(HidDevice(name, driver, vendor, product, devpath)) 79 80 for device in context.list_devices(subsystem="hidraw"): 81 devpath = device.properties["DEVPATH"] 82 83 for hid in devices: 84 if devpath.startswith(hid.devpath): 85 hid.hidraws.append(f"'{device.device_node}'") 86 87 for device in context.list_devices(subsystem="input"): 88 if (device.device_node or "").startswith("/dev/input/event"): 89 devpath = device.properties["DEVPATH"] 90 91 for hid in devices: 92 if devpath.startswith(hid.devpath): 93 hid.evdevs.append(f"'{device.device_node}'") 94 95 print("hid:") 96 for d in devices: 97 print(f"- name: '{d.name}'") 98 print(f" id: '{d.vendor:04x}:{d.product:04x}'") 99 print(f" driver: '{d.driver}'") 100 print(f" hidraw: [{', '.join(h for h in d.hidraws)}]") 101 print(f" evdev: [{', '.join(h for h in d.evdevs)}]") 102 print("") 103 104 105def main(): 106 parser = argparse.ArgumentParser(description="List kernel devices") 107 parser.add_argument("--hid", action="store_true", default=False) 108 args = parser.parse_args() 109 110 if args.hid: 111 list_hid_devices() 112 else: 113 list_devices() 114 115 116if __name__ == "__main__": 117 try: 118 main() 119 except KeyboardInterrupt: 120 print("Exited on user request") 121