def init(daemon, config): """ Registers hotplug callback for controller dongle """ def cb(device, handle): return SCByCable(device, handle, daemon) register_hotplug_device(cb, VENDOR_ID, PRODUCT_ID) return True
def init(daemon, config): """ Registers hotplug callback for controller dongle """ def cb(device, handle): return SCByCable(device, handle, daemon) register_hotplug_device(cb, VENDOR_ID, PRODUCT_ID) return True
def init(daemon, config): """ Registers hotplug callback for ds4 device """ def hid_callback(device, handle): return DS4Controller(device, daemon, handle, None, None) def evdev_make_device_callback(daemon, evdevdevices): # With kernel 4.10 or later, PS4 controller pretends to be 3 different devices. # 1st, determining which one is actual controller is needed controllerdevice = None for device in evdevdevices: count = len(get_axes(device)) if count == 8: # 8 axes - Controller controllerdevice = device if not controllerdevice: log.warning("Failed to determine controller device") return # 2nd, find motion sensor and touchpad with physical address matching # controllerdevice gyro, touchpad = None, None phys = device.phys.split("/")[0] for device in evdevdevices: if device.phys.startswith(phys): count = len(get_axes(device)) if count == 6: # 6 axes - gyro sensor gyro = device elif count == 4: # 4 axes - Touchpad touchpad = device # 3rd, do a magic return DS4EvdevController(daemon, controllerdevice, gyro, touchpad) def fail_cb(vid, pid): if HAVE_EVDEV: log.warning( "Failed to acquire USB device, falling back to evdev driver. This is far from optimal." ) make_new_device(vid, pid, evdev_make_device_callback) else: log.error( "Failed to acquire USB device and evdev is not available. Everything is lost and DS4 support disabled." ) # TODO: Maybe add_error here, but error reporting needs little rework so it's not threated as fatal # daemon.add_error("ds4", "No access to DS4 device") if config["drivers"].get("hiddrv") or (HAVE_EVDEV and config["drivers"].get("evdevdrv")): register_hotplug_device(hid_callback, VENDOR_ID, PRODUCT_ID, on_failure=fail_cb) return True else: log.warning( "Neither HID nor Evdev driver is enabled, DS4 support cannot be enabled." ) return False
class HIDDrv(object): def __init__(self, daemon): self.registered = set() self.config_files = {} self.configs = {} self.scan_files() self.daemon = daemon def hotplug_cb(self, device, handle): vid, pid = device.getVendorID(), device.getProductID() if (vid, pid) in self.configs: controller = HIDController(device, self.daemon, handle, self.config_files[vid, pid], self.configs[vid, pid]) return controller return None def scan_files(self): """ Goes through ~/.config/scc/devices and enables hotplug callback for every known HID device """ path = os.path.join(get_config_path(), "devices") if not os.path.exists(path): # Nothing to do return known = set() for name in os.listdir(path): if name.startswith("hid-") and name.endswith(".json"): vid, pid = name.split("-", 2)[1].split(":")[0:2] vid = int(vid, 16) pid = int(pid, 16) config_file = os.path.join(path, name) try: config = json.loads(open(config_file, "r").read()) except Exception, e: log.warning("Ignoring file that cannot be parsed: %s", name) continue self.config_files[vid, pid] = config_file self.configs[vid, pid] = config known.add((vid, pid)) for new in known - self.registered: vid, pid = new register_hotplug_device(self.hotplug_cb, vid, pid) self.registered.add(new) for removed in self.registered - known: vid, pid = removed unregister_hotplug_device(self.hotplug_cb, vid, pid) self.registered.remove(removed) if (vid, pid) in self.config_files: del self.config_files[vid, pid] if (vid, pid) in self.configs: del self.configs[vid, pid]
def scan_files(self): """ Goes through ~/.config/scc/devices and enables hotplug callback for every known HID device """ path = os.path.join(get_config_path(), "devices") if not os.path.exists(path): # Nothing to do return known = set() for name in os.listdir(path): if name.startswith("hid-") and name.endswith(".json"): vid, pid = name.split("-", 2)[1].split(":")[0:2] vid = int(vid, 16) pid = int(pid, 16) config_file = os.path.join(path, name) try: config = json.loads(open(config_file, "r").read()) except Exception: log.warning("Ignoring file that cannot be parsed: %s", name) continue self.config_files[vid, pid] = config_file.decode("utf-8") self.configs[vid, pid] = config known.add((vid, pid)) for new in known - self.registered: vid, pid = new register_hotplug_device(self.hotplug_cb, vid, pid) self.registered.add(new) for removed in self.registered - known: vid, pid = removed unregister_hotplug_device(self.hotplug_cb, vid, pid) self.registered.remove(removed) if (vid, pid) in self.config_files: del self.config_files[vid, pid] if (vid, pid) in self.configs: del self.configs[vid, pid]
def scan_files(self): """ Goes through ~/.config/scc/devices and enables hotplug callback for every known HID device """ path = os.path.join(get_config_path(), "devices") if not os.path.exists(path): # Nothing to do return known = set() for name in os.listdir(path): if name.startswith("hid-") and name.endswith(".json"): vid, pid = name.split("-", 2)[1].split(":")[0:2] vid = int(vid, 16) pid = int(pid, 16) config_file = os.path.join(path, name) try: config = json.loads(open(config_file, "r").read()) except Exception: log.warning("Ignoring file that cannot be parsed: %s", name) continue self.config_files[vid, pid] = config_file self.configs[vid, pid] = config known.add((vid, pid)) for new in known - self.registered: vid, pid = new register_hotplug_device(self.hotplug_cb, vid, pid) self.registered.add(new) for removed in self.registered - known: vid, pid = removed unregister_hotplug_device(self.hotplug_cb, vid, pid) self.registered.remove(removed) if (vid, pid) in self.config_files: del self.config_files[vid, pid] if (vid, pid) in self.configs: del self.configs[vid, pid]
def cb(device, handle): try: return cls(device, None, handle, None, None, test_mode=True) except NotHIDDevice: print >>sys.stderr, "%.4x:%.4x is not a HID device" % (vid, pid) fake_daemon.exitcode = 3 except UnparsableDescriptor, e: print >>sys.stderr, "Invalid or unparsable HID descriptor", str(e) fake_daemon.exitcode = 4 except Exception, e: print >>sys.stderr, "Failed to open device:", str(e) fake_daemon.exitcode = 2 _usb.set_daemon(fake_daemon) register_hotplug_device(cb, vid, pid) fake_daemon.dev_monitor.start() _usb.start() fake_daemon.dev_monitor.rescan() if fake_daemon.exitcode < 0: print "Ready" sys.stdout.flush() while fake_daemon.exitcode < 0: fake_daemon.poller.poll() _usb.mainloop() return fake_daemon.exitcode def init(daemon, config): """ Called from scc-daemon """
fake_daemon = FakeDaemon() def cb(device, handle): try: return cls(device, None, handle, None, None, test_mode=True) except NotHIDDevice: print >>sys.stderr, "%.4x:%.4x is not a HID device" % (vid, pid) fake_daemon.exitcode = 3 except UnparsableDescriptor, e: print >>sys.stderr, "Invalid or unparsable HID descriptor", str(e) fake_daemon.exitcode = 4 except Exception, e: print >>sys.stderr, "Failed to open device:", str(e) fake_daemon.exitcode = 2 register_hotplug_device(cb, vid, pid) _usb._daemon = fake_daemon _usb.start() if fake_daemon.exitcode < 0: print "Ready" sys.stdout.flush() while fake_daemon.exitcode < 0: fake_daemon.poller.poll() _usb.mainloop() return fake_daemon.exitcode def init(daemon, config): """ Called from scc-daemon """
def init(daemon, config): """ Registers hotplug callback for ds4 device """ def hid_callback(device, handle): return DS4Controller(device, daemon, handle, None, None) def make_evdev_device(syspath, *whatever): devices = get_evdev_devices_from_syspath(syspath) # With kernel 4.10 or later, PS4 controller pretends to be 3 different devices. # 1st, determining which one is actual controller is needed controllerdevice = None for device in devices: count = len(get_axes(device)) if count == 8: # 8 axes - Controller controllerdevice = device if not controllerdevice: log.warning("Failed to determine controller device") return None # 2nd, find motion sensor and touchpad with physical address matching controllerdevice gyro, touchpad = None, None phys = device.phys.split("/")[0] for device in devices: if device.phys.startswith(phys): axes = get_axes(device) count = len(axes) if count == 6: # 6 axes if EvdevController.ECODES.ABS_MT_POSITION_X in axes: # kernel 4.17+ - touchpad touchpad = device else: # gyro sensor gyro = device pass elif count == 4: # 4 axes - Touchpad touchpad = device # 3rd, do a magic if controllerdevice and gyro and touchpad: return make_new_device(DS4EvdevController, controllerdevice, gyro, touchpad) def fail_cb(syspath, vid, pid): if HAVE_EVDEV: log.warning("Failed to acquire USB device, falling back to evdev driver. This is far from optimal.") make_evdev_device(syspath) else: log.error("Failed to acquire USB device and evdev is not available. Everything is lost and DS4 support disabled.") # TODO: Maybe add_error here, but error reporting needs little rework so it's not threated as fatal # daemon.add_error("ds4", "No access to DS4 device") if config["drivers"].get("hiddrv") or (HAVE_EVDEV and config["drivers"].get("evdevdrv")): register_hotplug_device(hid_callback, VENDOR_ID, PRODUCT_ID, on_failure=fail_cb) if HAVE_EVDEV and config["drivers"].get("evdevdrv"): daemon.get_device_monitor().add_callback("bluetooth", VENDOR_ID, PRODUCT_ID, make_evdev_device, None) return True else: log.warning("Neither HID nor Evdev driver is enabled, DS4 support cannot be enabled.") return False