Implemented vigem_target_x360_get_user_index in library and driver

This commit is contained in:
Benjamin Höglinger
2018-05-10 20:42:38 +02:00
parent f254c03b3d
commit 08729f1cde
11 changed files with 189 additions and 7 deletions

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@
/sys/RCb21300
/sys/RCa21300
*.user
/.vs/config

View File

@@ -42,7 +42,8 @@ typedef enum _VIGEM_PDO_STAGE
{
ViGEmPdoCreate,
ViGEmPdoPrepareHardware,
ViGEmPdoInternalIoControl
ViGEmPdoInternalIoControl,
ViGEmPdoInitFinished
} VIGEM_PDO_STAGE, *PVIGEM_PDO_STAGE;

View File

@@ -265,6 +265,39 @@ VOID FORCEINLINE XUSB_SUBMIT_REPORT_INIT(
Report->SerialNo = SerialNo;
}
typedef struct _XUSB_GET_USER_INDEX
{
//
// sizeof(struct _XUSB_GET_USER_INDEX)
//
ULONG Size;
//
// Serial number of target device.
//
ULONG SerialNo;
//
// User index of target device.
//
OUT ULONG UserIndex;
} XUSB_GET_USER_INDEX, *PXUSB_GET_USER_INDEX;
//
// Initializes XUSB_GET_USER_INDEX structure.
//
VOID FORCEINLINE XUSB_GET_USER_INDEX_INIT(
_Out_ PXUSB_GET_USER_INDEX GetRequest,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(GetRequest, sizeof(XUSB_GET_USER_INDEX));
GetRequest->Size = sizeof(XUSB_GET_USER_INDEX);
GetRequest->SerialNo = SerialNo;
}
#pragma endregion
#pragma region DualShock 4 section

View File

@@ -451,7 +451,7 @@ VIGEM_API VIGEM_TARGET_TYPE vigem_target_get_type(PVIGEM_TARGET target);
VIGEM_API BOOL vigem_target_is_attached(PVIGEM_TARGET target);
/**
* \fn VIGEM_API ULONG vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
* \fn VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index);
*
* \brief Returns the user index of the emulated Xenon device. This value correspondents to the
* (zero-based) index number representing the player number via LED present on a
@@ -462,10 +462,11 @@ VIGEM_API BOOL vigem_target_is_attached(PVIGEM_TARGET target);
*
* \param vigem The driver connection object.
* \param target The target device object.
* \param index The (zero-based) user index of the Xenon device.
*
* \return The user index of the Xenon device.
* \return A VIGEM_ERROR.
*/
VIGEM_API ULONG vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target);
VIGEM_API VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index);
#ifdef __cplusplus
}

View File

@@ -635,7 +635,48 @@ BOOL vigem_target_is_attached(PVIGEM_TARGET target)
return (target->State == VIGEM_TARGET_CONNECTED);
}
ULONG vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
VIGEM_ERROR vigem_target_x360_get_user_index(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, PULONG index)
{
return VIGEM_API ULONG();
if (vigem->hBusDevice == nullptr)
{
return VIGEM_ERROR_BUS_NOT_FOUND;
}
if (target->SerialNo == 0 || target->Type != Xbox360Wired)
{
return VIGEM_ERROR_INVALID_TARGET;
}
DWORD transfered = 0;
OVERLAPPED lOverlapped = { 0 };
lOverlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
XUSB_GET_USER_INDEX gui;
XUSB_GET_USER_INDEX_INIT(&gui, target->SerialNo);
DeviceIoControl(
vigem->hBusDevice,
IOCTL_XUSB_GET_USER_INDEX,
&gui,
gui.Size,
&gui,
gui.Size,
&transfered,
&lOverlapped
);
if (GetOverlappedResult(vigem->hBusDevice, &lOverlapped, &transfered, TRUE) == 0)
{
if (GetLastError() == ERROR_ACCESS_DENIED)
{
CloseHandle(lOverlapped.hEvent);
return VIGEM_ERROR_INVALID_TARGET;
}
}
CloseHandle(lOverlapped.hEvent);
*index = gui.UserIndex;
return VIGEM_ERROR_NONE;
}

View File

@@ -411,7 +411,7 @@ Bus_PdoStageResult(
//
// If any stage fails or is last stage, get associated request and complete it
//
if (!NT_SUCCESS(Status) || Stage == ViGEmPdoInternalIoControl)
if (!NT_SUCCESS(Status) || Stage == ViGEmPdoInitFinished)
{
WdfSpinLockAcquire(pFdoData->PendingPluginRequestsLock);

View File

@@ -50,6 +50,7 @@ VOID Bus_EvtIoDeviceControl(
PXGIP_SUBMIT_REPORT xgipSubmit = NULL;
PXGIP_SUBMIT_INTERRUPT xgipInterrupt = NULL;
PVIGEM_CHECK_VERSION pCheckVersion = NULL;
PXUSB_GET_USER_INDEX pXusbGetUserIndex = NULL;
Device = WdfIoQueueGetDevice(Queue);
@@ -277,6 +278,45 @@ VOID Bus_EvtIoDeviceControl(
break;
#pragma endregion
#pragma region IOCTL_XUSB_GET_USER_INDEX
case IOCTL_XUSB_GET_USER_INDEX:
KdPrint((DRIVERNAME "IOCTL_XUSB_GET_USER_INDEX"));
// Don't accept the request if the output buffer can't hold the results
if (OutputBufferLength < sizeof(XUSB_GET_USER_INDEX))
{
KdPrint((DRIVERNAME "IOCTL_XUSB_GET_USER_INDEX: output buffer too small: %ul\n", OutputBufferLength));
break;
}
status = WdfRequestRetrieveInputBuffer(
Request,
sizeof(XUSB_GET_USER_INDEX),
(PVOID)&pXusbGetUserIndex,
&length);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME "WdfRequestRetrieveInputBuffer failed 0x%x\n", status));
break;
}
if ((sizeof(XUSB_GET_USER_INDEX) == pXusbGetUserIndex->Size) && (length == InputBufferLength))
{
// This request only supports a single PDO at a time
if (pXusbGetUserIndex->SerialNo == 0)
{
status = STATUS_INVALID_PARAMETER;
break;
}
status = Xusb_GetUserIndex(Device, pXusbGetUserIndex);
}
break;
#pragma endregion
default:
KdPrint((DRIVERNAME "UNKNOWN IOCTL CODE 0x%x\n", IoControlCode));
break; // default status is STATUS_INVALID_PARAMETER

View File

@@ -124,3 +124,4 @@ NTSTATUS Xusb_AssignPdoContext(WDFDEVICE Device, PPDO_IDENTIFICATION_DESCRIPTION
VOID Xusb_GetConfigurationDescriptorType(PUCHAR Buffer, ULONG Length);
VOID Xusb_GetDeviceDescriptorType(PUSB_DEVICE_DESCRIPTOR pDescriptor, PPDO_DEVICE_DATA pCommon);
VOID Xusb_SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo);
NTSTATUS Xusb_GetUserIndex(WDFDEVICE Device, PXUSB_GET_USER_INDEX Request);

View File

@@ -700,6 +700,22 @@ VOID Pdo_EvtIoInternalDeviceControl(
// success to the parent bus.
//
BUS_PDO_REPORT_STAGE_RESULT(pdoData->BusInterface, ViGEmPdoInternalIoControl, pdoData->SerialNo, status);
//
// The DS4 is basically ready to operate at this stage
//
if (pdoData->TargetType == DualShock4Wired)
{
//
// Report back to FDO that we are ready to operate
//
BUS_PDO_REPORT_STAGE_RESULT(
pdoData->BusInterface,
ViGEmPdoInitFinished,
pdoData->SerialNo,
STATUS_SUCCESS
);
}
break;

View File

@@ -604,6 +604,16 @@ NTSTATUS UsbPdo_BulkOrInterruptTransfer(PURB urb, WDFDEVICE Device, WDFREQUEST R
if (Buffer[2] == 0x05) xusb->LedNumber = 3;
KdPrint((DRIVERNAME "-- LED Number: %d\n", xusb->LedNumber));
//
// Report back to FDO that we are ready to operate
//
BUS_PDO_REPORT_STAGE_RESULT(
pdoData->BusInterface,
ViGEmPdoInitFinished,
pdoData->SerialNo,
STATUS_SUCCESS
);
}
}

View File

@@ -504,3 +504,41 @@ VOID Xusb_SelectConfiguration(PUSBD_INTERFACE_INFORMATION pInfo)
pInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)0xFFFF0000;
}
NTSTATUS Xusb_GetUserIndex(WDFDEVICE Device, PXUSB_GET_USER_INDEX Request)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
WDFDEVICE hChild;
PPDO_DEVICE_DATA pdoData;
PXUSB_DEVICE_DATA xusbData;
KdPrint((DRIVERNAME "Entered Bus_QueueNotification\n"));
hChild = Bus_GetPdo(Device, Request->SerialNo);
// Validate child
if (hChild == NULL)
{
KdPrint((DRIVERNAME "Bus_QueueNotification: PDO with serial %d not found\n", Request->SerialNo));
return STATUS_NO_SUCH_DEVICE;
}
// Check common context
pdoData = PdoGetData(hChild);
if (pdoData == NULL)
{
KdPrint((DRIVERNAME "Bus_QueueNotification: PDO context not found\n"));
return STATUS_INVALID_PARAMETER;
}
// Check if caller owns this PDO
if (!IS_OWNER(pdoData))
{
KdPrint((DRIVERNAME "Bus_QueueNotification: PID mismatch: %d != %d\n", pdoData->OwnerProcessId, CURRENT_PROCESS_ID()));
return STATUS_ACCESS_DENIED;
}
Request->UserIndex = (ULONG)XusbGetData(hChild)->LedNumber;
return status;
}