Files
ViGEmBus/sys/buspdo.c
Benjamin Höglinger-Stelzer b5a2450b95 Updated license snippets in source files
Updated .gitignore
Updated client library submodule
2019-12-20 09:58:38 +01:00

913 lines
25 KiB
C

/*
* Virtual Gamepad Emulation Framework - Windows kernel-mode bus driver
*
* MIT License
*
* Copyright (c) 2016-2019 Nefarius Software Solutions e.U. and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "busenum.h"
#include <wdmsec.h>
#include <usbioctl.h>
#include "buspdo.tmh"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Bus_CreatePdo)
#pragma alloc_text(PAGE, Bus_EvtDeviceListCreatePdo)
#pragma alloc_text(PAGE, Pdo_EvtDevicePrepareHardware)
#endif
NTSTATUS Bus_EvtDeviceListCreatePdo(
WDFCHILDLIST DeviceList,
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription,
PWDFDEVICE_INIT ChildInit)
{
PPDO_IDENTIFICATION_DESCRIPTION pDesc;
PAGED_CODE();
pDesc = CONTAINING_RECORD(IdentificationDescription, PDO_IDENTIFICATION_DESCRIPTION, Header);
return Bus_CreatePdo(WdfChildListGetDevice(DeviceList), ChildInit, pDesc);
}
//
// Compares two children on the bus based on their serial numbers.
//
BOOLEAN Bus_EvtChildListIdentificationDescriptionCompare(
WDFCHILDLIST DeviceList,
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER FirstIdentificationDescription,
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER SecondIdentificationDescription)
{
PPDO_IDENTIFICATION_DESCRIPTION lhs, rhs;
UNREFERENCED_PARAMETER(DeviceList);
lhs = CONTAINING_RECORD(FirstIdentificationDescription,
PDO_IDENTIFICATION_DESCRIPTION,
Header);
rhs = CONTAINING_RECORD(SecondIdentificationDescription,
PDO_IDENTIFICATION_DESCRIPTION,
Header);
return (lhs->SerialNo == rhs->SerialNo) ? TRUE : FALSE;
}
//
// Creates and initializes a PDO (child).
//
NTSTATUS Bus_CreatePdo(
_In_ WDFDEVICE Device,
_In_ PWDFDEVICE_INIT DeviceInit,
_In_ PPDO_IDENTIFICATION_DESCRIPTION Description)
{
NTSTATUS status;
PPDO_DEVICE_DATA pdoData;
WDFDEVICE hChild = NULL;
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
WDF_DEVICE_POWER_CAPABILITIES powerCaps;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES pdoAttributes;
WDF_IO_QUEUE_CONFIG defaultPdoQueueConfig;
WDFQUEUE defaultPdoQueue;
UNICODE_STRING deviceDescription;
VIGEM_BUS_INTERFACE busInterface;
WDF_OBJECT_ATTRIBUTES attributes;
WDF_IO_QUEUE_CONFIG usbInQueueConfig;
WDF_IO_QUEUE_CONFIG notificationsQueueConfig;
DECLARE_CONST_UNICODE_STRING(deviceLocation, L"Virtual Gamepad Emulation Bus");
DECLARE_UNICODE_STRING_SIZE(buffer, MAX_INSTANCE_ID_LEN);
// reserve space for device id
DECLARE_UNICODE_STRING_SIZE(deviceId, MAX_INSTANCE_ID_LEN);
PAGED_CODE();
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
//
// Get the FDO interface ASAP to report progress to bus
//
status = WdfFdoQueryForInterface(Device,
&GUID_VIGEM_INTERFACE_PDO,
(PINTERFACE)&busInterface,
sizeof(VIGEM_BUS_INTERFACE),
VIGEM_BUS_INTERFACE_VERSION,
NULL);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfFdoQueryForInterface failed with status %!STATUS!",
status);
return status;
}
// set device type
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
// Bus is power policy owner
WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE);
#pragma region Enter RAW device mode
status = WdfPdoInitAssignRawDevice(DeviceInit, &GUID_DEVCLASS_VIGEM_RAWPDO);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfPdoInitAssignRawDevice failed with status %!STATUS!",
status);
goto endCreatePdo;
}
WdfDeviceInitSetCharacteristics(DeviceInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
status = WdfDeviceInitAssignSDDLString(DeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfDeviceInitAssignSDDLString failed with status %!STATUS!",
status);
goto endCreatePdo;
}
#pragma endregion
#pragma region Prepare PDO
// set parameters matching desired target device
switch (Description->TargetType)
{
//
// A Xbox 360 device was requested
//
case Xbox360Wired:
status = Xusb_PreparePdo(
DeviceInit,
Description->VendorId,
Description->ProductId,
&deviceId,
&deviceDescription);
if (!NT_SUCCESS(status))
goto endCreatePdo;
break;
//
// A Sony DualShock 4 device was requested
//
case DualShock4Wired:
status = Ds4_PreparePdo(DeviceInit, &deviceId, &deviceDescription);
if (!NT_SUCCESS(status))
goto endCreatePdo;
break;
//
// A Xbox One device was requested
//
case XboxOneWired:
status = Xgip_PreparePdo(DeviceInit, &deviceId, &deviceDescription);
if (!NT_SUCCESS(status))
goto endCreatePdo;
break;
default:
status = STATUS_INVALID_PARAMETER;
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"Unknown target type: %d (%!STATUS!)",
Description->TargetType,
status);
goto endCreatePdo;
}
// set device id
status = WdfPdoInitAssignDeviceID(DeviceInit, &deviceId);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfPdoInitAssignDeviceID failed with status %!STATUS!",
status);
goto endCreatePdo;
}
// prepare instance id
status = RtlUnicodeStringPrintf(&buffer, L"%02d", Description->SerialNo);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"RtlUnicodeStringPrintf failed with status %!STATUS!",
status);
goto endCreatePdo;
}
// set instance id
status = WdfPdoInitAssignInstanceID(DeviceInit, &buffer);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfPdoInitAssignInstanceID failed with status %!STATUS!",
status);
goto endCreatePdo;
}
// set device description (for English operating systems)
status = WdfPdoInitAddDeviceText(DeviceInit, &deviceDescription, &deviceLocation, 0x409);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfPdoInitAddDeviceText failed with status %!STATUS!",
status);
goto endCreatePdo;
}
// default locale is English
// TODO: add more locales
WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);
#pragma endregion
#pragma region PNP/Power event callbacks
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = Pdo_EvtDevicePrepareHardware;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
#pragma endregion
// NOTE: not utilized at the moment
WdfPdoInitAllowForwardingRequestToParent(DeviceInit);
#pragma region Create PDO
// Add common device data context
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_DEVICE_DATA);
status = WdfDeviceCreate(&DeviceInit, &pdoAttributes, &hChild);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfDeviceCreate failed with status %!STATUS!",
status);
goto endCreatePdo;
}
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
"Created PDO 0x%p",
hChild);
switch (Description->TargetType)
{
// Add XUSB-specific device data context
case Xbox360Wired:
{
PXUSB_DEVICE_DATA xusbData = NULL;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, XUSB_DEVICE_DATA);
status = WdfObjectAllocateContext(hChild, &pdoAttributes, (PVOID)&xusbData);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfObjectAllocateContext failed with status %!STATUS!",
status);
goto endCreatePdo;
}
break;
}
case DualShock4Wired:
{
PDS4_DEVICE_DATA ds4Data = NULL;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, DS4_DEVICE_DATA);
status = WdfObjectAllocateContext(hChild, &pdoAttributes, (PVOID)&ds4Data);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfObjectAllocateContext failed with status %!STATUS!",
status);
goto endCreatePdo;
}
break;
}
case XboxOneWired:
{
PXGIP_DEVICE_DATA xgipData = NULL;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, XGIP_DEVICE_DATA);
status = WdfObjectAllocateContext(hChild, &pdoAttributes, (PVOID)&xgipData);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfObjectAllocateContext failed with status %!STATUS!",
status);
goto endCreatePdo;
}
break;
}
default:
break;
}
#pragma endregion
#pragma region Expose USB Interface
status = WdfDeviceCreateDeviceInterface(Device, (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE, NULL);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfDeviceCreateDeviceInterface failed with status %!STATUS!",
status);
goto endCreatePdo;
}
#pragma endregion
#pragma region Set PDO contexts
pdoData = PdoGetData(hChild);
pdoData->BusInterface = busInterface;
pdoData->SerialNo = Description->SerialNo;
pdoData->TargetType = Description->TargetType;
pdoData->OwnerProcessId = Description->OwnerProcessId;
pdoData->VendorId = Description->VendorId;
pdoData->ProductId = Description->ProductId;
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
"PDO Context properties: serial = %d, type = %d, pid = %d, vid = 0x%04X, pid = 0x%04X",
pdoData->SerialNo,
pdoData->TargetType,
pdoData->OwnerProcessId,
pdoData->VendorId,
pdoData->ProductId);
// Initialize additional contexts (if available)
switch (Description->TargetType)
{
case Xbox360Wired:
status = Xusb_AssignPdoContext(hChild);
break;
case DualShock4Wired:
status = Ds4_AssignPdoContext(hChild, Description);
break;
case XboxOneWired:
status = Xgip_AssignPdoContext(hChild);
break;
default:
break;
}
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"Couldn't initialize additional contexts: %!STATUS!",
status);
goto endCreatePdo;
}
#pragma endregion
#pragma region Create Queues & Locks
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = hChild;
// Create and assign queue for incoming interrupt transfer
WDF_IO_QUEUE_CONFIG_INIT(&usbInQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(hChild, &usbInQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pdoData->PendingUsbInRequests);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfIoQueueCreate (PendingUsbInRequests) failed with status %!STATUS!",
status);
goto endCreatePdo;
}
// Create and assign queue for user-land notification requests
WDF_IO_QUEUE_CONFIG_INIT(&notificationsQueueConfig, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(Device, &notificationsQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pdoData->PendingNotificationRequests);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfIoQueueCreate (PendingNotificationRequests) failed with status %!STATUS!",
status);
goto endCreatePdo;
}
#pragma endregion
#pragma region Default I/O queue setup
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&defaultPdoQueueConfig, WdfIoQueueDispatchParallel);
defaultPdoQueueConfig.EvtIoInternalDeviceControl = Pdo_EvtIoInternalDeviceControl;
status = WdfIoQueueCreate(hChild, &defaultPdoQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &defaultPdoQueue);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_BUSPDO,
"WdfIoQueueCreate (Default) failed with status %!STATUS!",
status);
goto endCreatePdo;
}
#pragma endregion
#pragma region PNP capabilities
WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
pnpCaps.Removable = WdfTrue;
pnpCaps.EjectSupported = WdfTrue;
pnpCaps.SurpriseRemovalOK = WdfTrue;
pnpCaps.Address = Description->SerialNo;
pnpCaps.UINumber = Description->SerialNo;
WdfDeviceSetPnpCapabilities(hChild, &pnpCaps);
#pragma endregion
#pragma region Power capabilities
WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
powerCaps.DeviceD1 = WdfTrue;
powerCaps.WakeFromD1 = WdfTrue;
powerCaps.DeviceWake = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
powerCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
WdfDeviceSetPowerCapabilities(hChild, &powerCaps);
#pragma endregion
endCreatePdo:
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_BUSPDO,
"BUS_PDO_REPORT_STAGE_RESULT Stage: ViGEmPdoCreate [serial: %d, status: %!STATUS!]",
Description->SerialNo, status);
BUS_PDO_REPORT_STAGE_RESULT(busInterface, ViGEmPdoCreate, Description->SerialNo, status);
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
return status;
}
//
// PDO power-up.
//
NTSTATUS Pdo_EvtDevicePrepareHardware(
_In_ WDFDEVICE Device,
_In_ WDFCMRESLIST ResourcesRaw,
_In_ WDFCMRESLIST ResourcesTranslated
)
{
PPDO_DEVICE_DATA pdoData;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAGED_CODE();
UNREFERENCED_PARAMETER(ResourcesRaw);
UNREFERENCED_PARAMETER(ResourcesTranslated);
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSENUM, "%!FUNC! Entry");
pdoData = PdoGetData(Device);
switch (pdoData->TargetType)
{
// Expose XUSB interfaces
case Xbox360Wired:
status = Xusb_PrepareHardware(Device);
break;
case DualShock4Wired:
status = Ds4_PrepareHardware(Device);
break;
case XboxOneWired:
status = Xgip_PrepareHardware(Device);
break;
default:
break;
}
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_BUSPDO,
"BUS_PDO_REPORT_STAGE_RESULT Stage: ViGEmPdoCreate [serial: %d, status: %!STATUS!]",
pdoData->SerialNo, status);
BUS_PDO_REPORT_STAGE_RESULT(pdoData->BusInterface, ViGEmPdoPrepareHardware, pdoData->SerialNo, status);
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
return status;
}
//
// Responds to IRP_MJ_INTERNAL_DEVICE_CONTROL requests sent to PDO.
//
VOID Pdo_EvtIoInternalDeviceControl(
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ size_t OutputBufferLength,
_In_ size_t InputBufferLength,
_In_ ULONG IoControlCode
)
{
// Regular buffers not used in USB communication
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);
NTSTATUS status = STATUS_INVALID_PARAMETER;
WDFDEVICE hDevice;
PIRP irp;
PURB urb;
PPDO_DEVICE_DATA pdoData;
PIO_STACK_LOCATION irpStack;
PXUSB_DEVICE_DATA pXusbData;
PUCHAR blobBuffer;
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_BUSPDO, "%!FUNC! Entry");
hDevice = WdfIoQueueGetDevice(Queue);
pdoData = PdoGetData(hDevice);
// No help from the framework available from here on
irp = WdfRequestWdmGetIrp(Request);
irpStack = IoGetCurrentIrpStackLocation(irp);
switch (IoControlCode)
{
case IOCTL_INTERNAL_USB_SUBMIT_URB:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> IOCTL_INTERNAL_USB_SUBMIT_URB");
urb = (PURB)URB_FROM_IRP(irp);
switch (urb->UrbHeader.Function)
{
case URB_FUNCTION_CONTROL_TRANSFER:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_CONTROL_TRANSFER");
switch (urb->UrbControlTransfer.SetupPacket[6])
{
case 0x04:
if (pdoData->TargetType == Xbox360Wired)
{
pXusbData = XusbGetData(hDevice);
blobBuffer = WdfMemoryGetBuffer(pXusbData->InterruptBlobStorage, NULL);
//
// Xenon magic
//
RtlCopyMemory(
urb->UrbControlTransfer.TransferBuffer,
&blobBuffer[XUSB_BLOB_07_OFFSET],
0x04
);
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;
case URB_FUNCTION_CONTROL_TRANSFER_EX:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_CONTROL_TRANSFER_EX");
status = STATUS_UNSUCCESSFUL;
break;
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER");
status = UsbPdo_BulkOrInterruptTransfer(urb, hDevice, Request);
break;
case URB_FUNCTION_SELECT_CONFIGURATION:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_SELECT_CONFIGURATION");
status = UsbPdo_SelectConfiguration(urb, pdoData);
break;
case URB_FUNCTION_SELECT_INTERFACE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_SELECT_INTERFACE");
status = UsbPdo_SelectInterface(urb, pdoData);
break;
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE");
switch (urb->UrbControlDescriptorRequest.DescriptorType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> USB_DEVICE_DESCRIPTOR_TYPE");
status = UsbPdo_GetDeviceDescriptorType(urb, pdoData);
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> USB_CONFIGURATION_DESCRIPTOR_TYPE");
status = UsbPdo_GetConfigurationDescriptorType(urb, pdoData);
break;
case USB_STRING_DESCRIPTOR_TYPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> USB_STRING_DESCRIPTOR_TYPE");
status = UsbPdo_GetStringDescriptorType(urb, pdoData);
break;
case USB_INTERFACE_DESCRIPTOR_TYPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> USB_INTERFACE_DESCRIPTOR_TYPE");
break;
case USB_ENDPOINT_DESCRIPTOR_TYPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> USB_ENDPOINT_DESCRIPTOR_TYPE");
break;
default:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> >> Unknown descriptor type");
break;
}
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
"<< <<");
break;
case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_GET_STATUS_FROM_DEVICE");
// Defaults always succeed
status = STATUS_SUCCESS;
break;
case URB_FUNCTION_ABORT_PIPE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_ABORT_PIPE");
status = UsbPdo_AbortPipe(hDevice);
break;
case URB_FUNCTION_CLASS_INTERFACE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_CLASS_INTERFACE");
status = UsbPdo_ClassInterface(urb, hDevice, pdoData);
break;
case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE");
status = UsbPdo_GetDescriptorFromInterface(urb, pdoData);
//
// 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;
default:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> >> Unknown function: 0x%X",
urb->UrbHeader.Function);
break;
}
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
"<<");
break;
case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> IOCTL_INTERNAL_USB_GET_PORT_STATUS");
// We report the (virtual) port as always active
*(unsigned long *)irpStack->Parameters.Others.Argument1 = USBD_PORT_ENABLED | USBD_PORT_CONNECTED;
status = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_USB_RESET_PORT:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> IOCTL_INTERNAL_USB_RESET_PORT");
// Sure, why not ;)
status = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION");
// TODO: implement
// This happens if the I/O latency is too high so HIDUSB aborts communication.
status = STATUS_SUCCESS;
break;
default:
TraceEvents(TRACE_LEVEL_VERBOSE,
TRACE_BUSPDO,
">> Unknown I/O control code 0x%X",
IoControlCode);
break;
}
if (status != STATUS_PENDING)
{
WdfRequestComplete(Request, status);
}
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_BUSPDO, "%!FUNC! Exit with status %!STATUS!", status);
}