diff --git a/app/src/main/java/com/limelight/binding/input/driver/UsbDriverService.java b/app/src/main/java/com/limelight/binding/input/driver/UsbDriverService.java index b6602be9..254af937 100644 --- a/app/src/main/java/com/limelight/binding/input/driver/UsbDriverService.java +++ b/app/src/main/java/com/limelight/binding/input/driver/UsbDriverService.java @@ -20,6 +20,7 @@ import com.limelight.LimeLog; import com.limelight.R; import com.limelight.preferences.PreferenceConfiguration; +import java.io.File; import java.util.ArrayList; public class UsbDriverService extends Service implements UsbDriverListener { @@ -183,6 +184,9 @@ public class UsbDriverService extends Service implements UsbDriverListener { else if (Xbox360Controller.canClaimDevice(device)) { controller = new Xbox360Controller(device, connection, nextDeviceId++, this); } + else if (Xbox360WirelessController.canClaimDevice(device)) { + controller = new Xbox360WirelessController(device, connection, nextDeviceId++, this); + } else { // Unreachable return; @@ -248,9 +252,32 @@ public class UsbDriverService extends Service implements UsbDriverListener { } } + public static boolean kernelSupportsXbox360W() { + File systemDir = new File("/sys/class/leds"); + File[] files = systemDir.listFiles(); + if (files != null) { + for (File f : files) { + if (f.getName().equals("xpad0") || + f.getName().equals("xpad1") || + f.getName().equals("xpad2") || + f.getName().equals("xpad3") || + f.getName().equals("xpad4") || + f.getName().equals("xpad5") || + f.getName().equals("xpad6") || + f.getName().equals("xpad7") || + f.getName().equals("xpad8") || + f.getName().equals("xpad9")) { + return true; + } + } + } + return false; + } + public static boolean shouldClaimDevice(UsbDevice device, boolean claimAllAvailable) { return ((!kernelSupportsXboxOne() || !isRecognizedInputDevice(device) || claimAllAvailable) && XboxOneController.canClaimDevice(device)) || - ((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)); + ((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)) || + ((!kernelSupportsXbox360W() || !isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360WirelessController.canClaimDevice(device)); } private void start() { diff --git a/app/src/main/java/com/limelight/binding/input/driver/Xbox360WirelessController.java b/app/src/main/java/com/limelight/binding/input/driver/Xbox360WirelessController.java new file mode 100644 index 00000000..fdcda540 --- /dev/null +++ b/app/src/main/java/com/limelight/binding/input/driver/Xbox360WirelessController.java @@ -0,0 +1,82 @@ +package com.limelight.binding.input.driver; + +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; + +import com.limelight.LimeLog; +import com.limelight.nvstream.input.ControllerPacket; + +import java.nio.ByteBuffer; + +public class Xbox360WirelessController extends AbstractXboxController { + private static final int XB360W_IFACE_SUBCLASS = 93; + private static final int XB360W_IFACE_PROTOCOL = 129; // Wireless only + + private static final int[] SUPPORTED_VENDORS = { + 0x045e, // Microsoft + }; + + public static boolean canClaimDevice(UsbDevice device) { + for (int supportedVid : SUPPORTED_VENDORS) { + if (device.getVendorId() == supportedVid && + device.getInterfaceCount() >= 1 && + device.getInterface(0).getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC && + device.getInterface(0).getInterfaceSubclass() == XB360W_IFACE_SUBCLASS && + device.getInterface(0).getInterfaceProtocol() == XB360W_IFACE_PROTOCOL) { + return true; + } + } + + return false; + } + + public Xbox360WirelessController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) { + super(device, connection, deviceId, listener); + } + + @Override + protected boolean handleRead(ByteBuffer buffer) { + // Unreachable + return true; + } + + private boolean sendLedCommand(byte command) { + byte[] commandBuffer = { + 0x00, + 0x00, + 0x08, + (byte) (0x40 + command), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + + int res = connection.bulkTransfer(outEndpt, commandBuffer, commandBuffer.length, 3000); + if (res != commandBuffer.length) { + LimeLog.warning("LED set transfer failed: "+res); + return false; + } + + return true; + } + + @Override + protected boolean doInit() { + // Turn the LED on corresponding to our device ID + sendLedCommand((byte)(2 + (getControllerId() % 4))); + + // Close the interface and return false to give control back to the kernel. + connection.releaseInterface(device.getInterface(0)); + return false; + } + + @Override + public void rumble(short lowFreqMotor, short highFreqMotor) { + // Unreachable. + } +}