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