Implemented new DS4_SUBMIT_REPORT_EX

This commit is contained in:
Benjamin Höglinger-Stelzer
2020-09-07 21:44:46 +02:00
parent 0c920602e7
commit 5611bbd3fa
3 changed files with 93 additions and 24 deletions

View File

@@ -424,6 +424,8 @@ VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT(
DS4_REPORT_INIT(&Report->Report);
}
#include <pshpack1.h>
typedef struct _DS4_SUBMIT_REPORT_EX
{
//

View File

@@ -1088,8 +1088,13 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbControlTransfer(PURB Urb)
NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SubmitReportImpl(PVOID NewReport)
{
NTSTATUS status;
WDFREQUEST usbRequest;
NTSTATUS status;
WDFREQUEST usbRequest;
/*
* The logic here is unusual to keep backwards compatibility with the
* original API that didn't allow submitting the full report.
*/
status = WdfIoQueueRetrieveNextRequest(this->_PendingUsbInRequests, &usbRequest);
@@ -1100,19 +1105,52 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SubmitReportImpl(PVOID NewRepo
PIRP pendingIrp = WdfRequestWdmGetIrp(usbRequest);
// Get USB request block
PURB urb = static_cast<PURB>(URB_FROM_IRP(pendingIrp));
const auto urb = static_cast<PURB>(URB_FROM_IRP(pendingIrp));
// Get transfer buffer
auto Buffer = static_cast<PUCHAR>(urb->UrbBulkOrInterruptTransfer.TransferBuffer);
const auto buffer = static_cast<PUCHAR>(urb->UrbBulkOrInterruptTransfer.TransferBuffer);
// Set correct buffer size
urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DS4_REPORT_SIZE;
/* Copy report to cache and transfer buffer
* Skip first byte as it contains the never changing report id */
RtlCopyBytes(this->_Report + 1, &(static_cast<PDS4_SUBMIT_REPORT>(NewReport))->Report, sizeof(DS4_REPORT));
// Cast to expected struct
const auto pSubmit = static_cast<PDS4_SUBMIT_REPORT>(NewReport);
if (Buffer)
RtlCopyBytes(Buffer, this->_Report, DS4_REPORT_SIZE);
/*
* Copy report to cache and transfer buffer
* Skip first byte as it contains the never changing report ID
*/
//
// "Old" API which only allows to update partial report
//
if (pSubmit->Size == sizeof(DS4_SUBMIT_REPORT))
{
TraceDbg(TRACE_DS4, "Received DS4_SUBMIT_REPORT update");
RtlCopyBytes(
&this->_Report[1],
&(static_cast<PDS4_SUBMIT_REPORT>(NewReport))->Report,
sizeof((static_cast<PDS4_SUBMIT_REPORT>(NewReport))->Report)
);
}
//
// "Extended" API allowing complete report update
//
if (pSubmit->Size == sizeof(DS4_SUBMIT_REPORT_EX))
{
TraceDbg(TRACE_DS4, "Received DS4_SUBMIT_REPORT_EX update");
RtlCopyBytes(
&this->_Report[1],
&(static_cast<PDS4_SUBMIT_REPORT_EX>(NewReport))->Report,
sizeof((static_cast<PDS4_SUBMIT_REPORT_EX>(NewReport))->Report)
);
}
if (buffer)
RtlCopyBytes(buffer, this->_Report, DS4_REPORT_SIZE);
// Complete pending request
WdfRequestComplete(usbRequest, status);

View File

@@ -300,25 +300,54 @@ VOID Bus_EvtIoDeviceControl(
break;
}
if ((sizeof(DS4_SUBMIT_REPORT) == ds4Submit->Size) && (length == InputBufferLength))
//
// Check if buffer is within expected bounds
//
if (length < sizeof(DS4_SUBMIT_REPORT) || length > sizeof(DS4_SUBMIT_REPORT_EX))
{
// This request only supports a single PDO at a time
if (ds4Submit->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
TraceDbg(
TRACE_QUEUE,
"Unexpected buffer size: %d",
static_cast<ULONG>(length)
);
status = STATUS_INVALID_PARAMETER;
break;
}
if (!EmulationTargetPDO::GetPdoByTypeAndSerial(Device, DualShock4Wired, ds4Submit->SerialNo, &pdo))
status = STATUS_DEVICE_DOES_NOT_EXIST;
else
status = pdo->SubmitReport(ds4Submit);
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
//
// Check if this makes sense before passing it on
//
if (length != ds4Submit->Size)
{
TraceDbg(
TRACE_QUEUE,
"Invalid buffer size: %d",
ds4Submit->Size
);
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
//
// This request only supports a single PDO at a time
//
if (ds4Submit->SerialNo == 0)
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_QUEUE,
"Invalid serial 0 submitted");
status = STATUS_INVALID_PARAMETER;
break;
}
if (!EmulationTargetPDO::GetPdoByTypeAndSerial(Device, DualShock4Wired, ds4Submit->SerialNo, &pdo))
status = STATUS_DEVICE_DOES_NOT_EXIST;
else
status = pdo->SubmitReport(ds4Submit);
break;
#pragma endregion