diff --git a/Xusb.h b/Xusb.h index 76b8536..384903c 100644 --- a/Xusb.h +++ b/Xusb.h @@ -52,6 +52,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_XUSB_UNKNOWN_2, #define XUSB_RUMBLE_SIZE 0x08 #define XUSB_LEDSET_SIZE 0x03 #define XUSB_LEDNUM_SIZE 0x01 +#define XUSB_INIT_STAGE_SIZE 0x03 #define XUSB_IS_DATA_PIPE(_x_) ((BOOLEAN)(_x_->PipeHandle == (USBD_PIPE_HANDLE)0xFFFF0081)) #define XUSB_IS_CONTROL_PIPE(_x_) ((BOOLEAN)(_x_->PipeHandle == (USBD_PIPE_HANDLE)0xFFFF0083)) @@ -91,6 +92,16 @@ typedef struct _XUSB_DEVICE_DATA // WDFQUEUE HoldingUsbInRequests; + // + // Required for XInputGetCapabilities to work + // + BOOLEAN ReportedCapabilities; + + // + // Required for XInputGetCapabilities to work + // + ULONG InterruptInitStage; + } XUSB_DEVICE_DATA, *PXUSB_DEVICE_DATA; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(XUSB_DEVICE_DATA, XusbGetData) diff --git a/busenum.h b/busenum.h index 52a009d..5c5b813 100644 --- a/busenum.h +++ b/busenum.h @@ -71,6 +71,13 @@ SOFTWARE. // #define HID_GET_REPORT_TYPE(_req_) ((_req_->Value >> 8) & 0xFF) +// +// Some insane macro-magic =3 +// +#define P99_PROTECT(...) __VA_ARGS__ +#define COPY_BYTE_ARRAY(_dst_, _bytes_) do {BYTE b[] = _bytes_; \ + RtlCopyMemory(_dst_, b, RTL_NUMBER_OF_V1(b)); } while (0) + #pragma endregion diff --git a/buspdo.c b/buspdo.c index 94bc057..108245d 100644 --- a/buspdo.c +++ b/buspdo.c @@ -530,8 +530,35 @@ VOID Pdo_EvtIoInternalDeviceControl( KdPrint((DRIVERNAME ">> >> URB_FUNCTION_CONTROL_TRANSFER\n")); - // Control transfer can safely be ignored - status = STATUS_SUCCESS; + switch (urb->UrbControlTransfer.SetupPacket[6]) + { + case 0x04: + // + // Xenon magic + // + COPY_BYTE_ARRAY(urb->UrbControlTransfer.TransferBuffer, P99_PROTECT({ + 0x31, 0x3F, 0xCF, 0xDC + })); + status = STATUS_SUCCESS; + break; + case 0x14: + // + // This is some weird USB 1.0 condition and _must fail_ + // + urb->UrbControlTransfer.Hdr.Status = USBD_STATUS_STALL_PID; + status = STATUS_UNSUCCESSFUL; + break; + case 0x08: + // + // This is some weird USB 1.0 condition and _must fail_ + // + urb->UrbControlTransfer.Hdr.Status = USBD_STATUS_STALL_PID; + status = STATUS_UNSUCCESSFUL; + break; + default: + status = STATUS_SUCCESS; + break; + } break; diff --git a/usbpdo.c b/usbpdo.c index 469912b..7311007 100644 --- a/usbpdo.c +++ b/usbpdo.c @@ -504,16 +504,79 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R if (XUSB_IS_DATA_PIPE(pTransfer)) { - /* This request is sent periodically and relies on data the "feeder" - * has to supply, so we queue this request and return with STATUS_PENDING. - * The request gets completed as soon as the "feeder" sent an update. */ - status = WdfRequestForwardToIoQueue(Request, pdoData->PendingUsbInRequests); + // + // Send "boot sequence" first, then the actual inputs + // + switch (xusb->InterruptInitStage) + { + case 0: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x01, 0x03, 0x0E + })); + return STATUS_SUCCESS; + case 1: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x02, 0x03, 0x00 + })); + return STATUS_SUCCESS; + case 2: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x03, 0x03, 0x03 + })); + return STATUS_SUCCESS; + case 3: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x08, 0x03, 0x00 + })); + return STATUS_SUCCESS; + case 4: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = sizeof(XUSB_INTERRUPT_IN_PACKET); + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf2, + 0xb3, 0xf8, 0x49, 0xf3, 0xb0, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + })); + return STATUS_SUCCESS; + case 5: + xusb->InterruptInitStage++; + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x01, 0x03, 0x03 + })); + return STATUS_SUCCESS; + default: + /* This request is sent periodically and relies on data the "feeder" + * has to supply, so we queue this request and return with STATUS_PENDING. + * The request gets completed as soon as the "feeder" sent an update. */ + status = WdfRequestForwardToIoQueue(Request, pdoData->PendingUsbInRequests); - return (NT_SUCCESS(status)) ? STATUS_PENDING : status; + return (NT_SUCCESS(status)) ? STATUS_PENDING : status; + } } if (XUSB_IS_CONTROL_PIPE(pTransfer)) { + if (!xusb->ReportedCapabilities && pTransfer->TransferBufferLength >= XUSB_INIT_STAGE_SIZE) + { + pTransfer->TransferBufferLength = XUSB_INIT_STAGE_SIZE; + COPY_BYTE_ARRAY(pTransfer->TransferBuffer, P99_PROTECT({ + 0x05, 0x03, 0x00 + })); + + xusb->ReportedCapabilities = TRUE; + + return STATUS_SUCCESS; + } + status = WdfRequestForwardToIoQueue(Request, xusb->HoldingUsbInRequests); return (NT_SUCCESS(status)) ? STATUS_PENDING : status;