83 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			83 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
import usb
 | 
						|
 | 
						|
USB_INTERFACE_CLASS_HID = 0x03
 | 
						|
 | 
						|
def usb_device_spec(spec):
 | 
						|
    major = spec >> 8
 | 
						|
    minor = (spec >> 4) & 0xF
 | 
						|
    return f"{major}.{minor}"
 | 
						|
 | 
						|
def usb_device_speed(speed):
 | 
						|
    if speed == 1:
 | 
						|
        return "Low-speed"
 | 
						|
    elif speed == 2:
 | 
						|
        return "Full-speed"
 | 
						|
    elif speed == 3:
 | 
						|
        return "High-speed"
 | 
						|
    elif speed == 4:
 | 
						|
        return "SuperSpeed"
 | 
						|
    elif speed == 5:
 | 
						|
        return "SuperSpeed+"
 | 
						|
 | 
						|
    return "Speed unknown"
 | 
						|
 | 
						|
def usb_hid_interface_subclass(subclass):
 | 
						|
    if subclass == 0x00:
 | 
						|
        return "None"
 | 
						|
    elif subclass == 0x01:
 | 
						|
        return "Boot"
 | 
						|
    else:
 | 
						|
        return f"Unknown (0x{subclass:02X})"
 | 
						|
 | 
						|
def usb_hid_interface_protocol(subclass, protocol):
 | 
						|
    if subclass == 0x00 and protocol == 0x00:
 | 
						|
        return "None"
 | 
						|
    elif subclass == 0x01:
 | 
						|
        if protocol == 0x00:
 | 
						|
            return "None"
 | 
						|
        elif protocol == 0x01:
 | 
						|
            return "Keyboard"
 | 
						|
        elif protocol == 0x02:
 | 
						|
            return "Mouse"
 | 
						|
 | 
						|
    return f"Unknown (0x{protocol:02X})"
 | 
						|
 | 
						|
def usb_interface_polling_rate(speed, interval):
 | 
						|
    if speed >= 3:
 | 
						|
        return f"{interval * 125} μs ({8000 // interval} Hz)"
 | 
						|
    else:
 | 
						|
        return f"{interval} ms ({1000 // interval} Hz)"
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    devices = usb.core.find(find_all=True)
 | 
						|
 | 
						|
    for device in devices:
 | 
						|
        try:
 | 
						|
            configuration = device.get_active_configuration()
 | 
						|
        except NotImplementedError:
 | 
						|
            continue
 | 
						|
 | 
						|
        hid_interfaces = []
 | 
						|
        for interface in configuration.interfaces():
 | 
						|
            if interface.bInterfaceClass == USB_INTERFACE_CLASS_HID:
 | 
						|
                hid_interfaces.append(interface)
 | 
						|
 | 
						|
        if len(hid_interfaces) > 0:
 | 
						|
            print(f"{device.manufacturer} {device.product} ({device.idVendor:04X}:{device.idProduct:04X}:{device.bcdDevice:04X}), {usb_device_spec(device.bcdUSB)} {usb_device_speed(device.speed)}")
 | 
						|
 | 
						|
            for interface in hid_interfaces:
 | 
						|
                print(f"└─ HID Interface {interface.bInterfaceNumber}")
 | 
						|
                subclass = interface.bInterfaceSubClass
 | 
						|
                protocol = interface.bInterfaceProtocol
 | 
						|
                print(f"   ├─ Subclass: {usb_hid_interface_subclass(subclass)}")
 | 
						|
                print(f"   ├─ Protocol: {usb_hid_interface_protocol(subclass, protocol)}")
 | 
						|
 | 
						|
                for endpoint in interface.endpoints():
 | 
						|
                    endpoint_address = endpoint.bEndpointAddress & 0xF
 | 
						|
                    endpoint_direction = "IN" if endpoint.bEndpointAddress & 0x80 else "OUT"
 | 
						|
                    print(f"   └─ Endpoint {endpoint_address} {endpoint_direction}")
 | 
						|
                    print(f"      ├─ Endpoint Size: {endpoint.wMaxPacketSize} bytes")
 | 
						|
                    print(f"      └─ Polling Rate: {usb_interface_polling_rate(device.speed, endpoint.bInterval)}")
 |