#include "drv_common.h"
extern WDFDRIVER gWdfDriver;
#pragma warning(disable: 4127)
#if (defined(ALLOC_PRAGMA) && defined(PAGING_ENABLED))
#pragma alloc_text(PAGE, Pipe_AbortAll)
#pragma alloc_text(PAGE, Pipe_Reset)
#pragma alloc_text(PAGE, Pipe_Abort)
#pragma alloc_text(PAGE, Pipe_Start)
#pragma alloc_text(PAGE, Pipe_Stop)
#pragma alloc_text(PAGE, Pipe_StartAll)
#pragma alloc_text(PAGE, Pipe_StopAll)
#pragma alloc_text(PAGE, Pipe_GetContextFromName)
#endif
#define PIPENAME_PREFIX PIPE_
#define _DEF_PIPENAME_MAP(Name,PipeID) {#Name #PipeID,0x##PipeID,L#Name L#PipeID}
#define DEF_PIPENAME_MAP(Name,PipeID) _DEF_PIPENAME_MAP(Name,PipeID)
typedef struct _PIPENAME_MAP
{
LPCSTR Name; CCHAR PipeID; LPCWSTR NameW; } PIPENAME_MAP, *PPIPENAME_MAP;
CONST PIPENAME_MAP PipeNameToPipeID[] =
{
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 01), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 81),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 02), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 82),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 03), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 83),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 04), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 84),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 05), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 85),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 06), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 86),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 07), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 87),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 08), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 88),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 09), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 89),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0A), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8A),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0B), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8B),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0C), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8C),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0D), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8D),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0E), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8E),
DEF_PIPENAME_MAP(PIPENAME_PREFIX, 0F), DEF_PIPENAME_MAP(PIPENAME_PREFIX, 8F),
};
NTSTATUS Pipe_Reset(__in PDEVICE_CONTEXT deviceContext,
__in UCHAR pipeID)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
PPIPE_CONTEXT pipeContext;
PAGED_CODE();
pipeContext = GetPipeContextByID(deviceContext, pipeID);
if (pipeContext->Pipe)
{
USBMSG("pipeID=%02Xh\n", pipeID);
status = WdfUsbTargetPipeResetSynchronously(pipeContext->Pipe, WDF_NO_HANDLE, NULL);
if (!NT_SUCCESS(status))
{
USBERR("WdfUsbTargetPipeResetSynchronously failed pipeID=%02Xh status=%Xh\n", pipeID, status);
}
else
{
if (pipeContext->Queue)
{
PQUEUE_CONTEXT queueContext = GetQueueContext(pipeContext->Queue);
queueContext->IsFreshPipeReset = TRUE;
}
}
}
else
{
USBERR("pipeID=%02Xh not found\n", pipeID);
}
return status;
}
NTSTATUS Pipe_Abort(__in PDEVICE_CONTEXT deviceContext,
__in UCHAR pipeID)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
PPIPE_CONTEXT pipeContext;
PAGED_CODE();
pipeContext = GetPipeContextByID(deviceContext, pipeID);
if (pipeContext->Pipe)
{
USBMSG("pipeID=%02Xh\n", pipeID);
status = WdfUsbTargetPipeAbortSynchronously(pipeContext->Pipe, WDF_NO_HANDLE, NULL);
if (!NT_SUCCESS(status))
{
USBERR("WdfUsbTargetPipeResetSynchronously failed pipeID=%02Xh status=%Xh\n", pipeID, status);
}
}
else
{
USBERR("pipeID=%02Xh not found\n", pipeID);
}
return status;
}
NTSTATUS Pipe_RefreshQueue(__in PDEVICE_CONTEXT deviceContext, __in PPIPE_CONTEXT pipeContext)
{
NTSTATUS status;
status = Pipe_Stop(pipeContext, WdfIoTargetCancelSentIo, TRUE, FALSE);
if (!NT_SUCCESS(status))
{
USBERRN("Pipe_Stop failed. PipeID=%02Xh Status=%08Xh", pipeContext->PipeInformation.EndpointAddress, status);
goto Done;
}
status = Pipe_Start(deviceContext, pipeContext, FALSE);
if (!NT_SUCCESS(status))
{
USBERRN("Pipe_Start failed. PipeID=%02Xh Status=%08Xh", pipeContext->PipeInformation.EndpointAddress, status);
goto Done;
}
Done:
return status;
}
NTSTATUS Pipe_Stop(__in PPIPE_CONTEXT pipeContext,
__in WDF_IO_TARGET_SENT_IO_ACTION WdfIoTargetSentIoAction,
__in BOOLEAN purgeQueue,
__in BOOLEAN stopIoTarget)
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
if (pipeContext->IsValid == TRUE)
{
pipeContext->IsValid = FALSE;
if (pipeContext->Queue && purgeQueue) WdfIoQueuePurgeSynchronously(pipeContext->Queue);
if (pipeContext->Pipe && stopIoTarget)
PipeStop(pipeContext, WdfIoTargetSentIoAction); }
else
{
USBERRN("Invalid pipeContext");
status = STATUS_INVALID_PIPE_STATE;
}
return status;
}
NTSTATUS Pipe_AbortAll(__in PDEVICE_CONTEXT deviceContext)
{
UCHAR interfaceIndex, pipeIndex;
UCHAR interfaceCount, pipeCount;
NTSTATUS status;
PAGED_CODE();
interfaceCount = deviceContext->InterfaceCount;
for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++)
{
pipeCount = deviceContext->InterfaceContext[interfaceIndex].PipeCount;
for (pipeIndex = 0; pipeIndex < pipeCount; pipeIndex++)
{
USBMSG("interface-number=%u pipe-id=%2Xh",
deviceContext->InterfaceContext[interfaceIndex].InterfaceDescriptor.bInterfaceNumber,
deviceContext->InterfaceContext[interfaceIndex].PipeContextByIndex[pipeIndex]->PipeInformation.EndpointAddress);
status = WdfUsbTargetPipeAbortSynchronously(
deviceContext->InterfaceContext[interfaceIndex].PipeContextByIndex[pipeIndex]->Pipe,
WDF_NO_HANDLE, NULL);
if (!NT_SUCCESS(status))
{
USBMSG("WdfUsbTargetPipeAbortSynchronously failed %Xh\n", status);
break;
}
}
}
return STATUS_SUCCESS;
}
VOID Pipe_StopAll(__in PDEVICE_CONTEXT deviceContext, __in BOOLEAN stopIoTarget)
{
PPIPE_CONTEXT pipeContext = NULL;
UCHAR interfaceIndex, pipeIndex;
UCHAR interfaceCount, pipeCount;
PAGED_CODE();
interfaceCount = deviceContext->InterfaceCount;
for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++)
{
pipeCount = deviceContext->InterfaceContext[interfaceIndex].PipeCount;
for (pipeIndex = 0; pipeIndex < pipeCount; pipeIndex++)
{
pipeContext = deviceContext->InterfaceContext[interfaceIndex].PipeContextByIndex[pipeIndex];
Pipe_Stop(pipeContext, WdfIoTargetCancelSentIo, TRUE, stopIoTarget);
}
}
}
VOID Pipe_InitQueueConfig(
__in PPIPE_CONTEXT pipeContext,
__out WDF_IO_QUEUE_CONFIG* queueConfig)
{
WDF_DRIVER_VERSION_AVAILABLE_PARAMS verParams;
if (!pipeContext->Pipe)
{
WDF_IO_QUEUE_CONFIG_INIT(queueConfig, WdfIoQueueDispatchSequential);
queueConfig->EvtIoDeviceControl = PipeQueue_OnIoControl;
return;
}
if (pipeContext->PipeInformation.PipeType == WdfUsbPipeTypeIsochronous || pipeContext->Policies.RawIO)
{
USBDBGN("Configuring parallel queue..");
WDF_IO_QUEUE_CONFIG_INIT(queueConfig, WdfIoQueueDispatchParallel);
WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&verParams, KMDF_MAJOR_VERSION, KMDF_MINOR_VERSION);
if (WdfDriverIsVersionAvailable(gWdfDriver, &verParams))
{
# if ((KMDF_MAJOR_VERSION==1 && KMDF_MINOR_VERSION >= 9) || (KMDF_MAJOR_VERSION > 1))
if (pipeContext->SimulParallelRequests)
queueConfig->Settings.Parallel.NumberOfPresentedRequests = pipeContext->SimulParallelRequests;
# endif
}
else
{
DbgPrint("Expected library version %u.%u!\n",KMDF_MAJOR_VERSION, KMDF_MINOR_VERSION);
}
}
else
{
USBDBGN("Configuring sequential queue..");
WDF_IO_QUEUE_CONFIG_INIT(queueConfig, WdfIoQueueDispatchSequential);
queueConfig->EvtIoStop = Queue_OnStop;
queueConfig->EvtIoResume = Queue_OnResume;
}
queueConfig->EvtIoDeviceControl = PipeQueue_OnIoControl;
if (USB_ENDPOINT_DIRECTION_IN(pipeContext->PipeInformation.EndpointAddress))
{
queueConfig->EvtIoRead = PipeQueue_OnRead;
}
else
{
queueConfig->EvtIoWrite = PipeQueue_OnWrite;
queueConfig->AllowZeroLengthRequests = TRUE;
}
}
NTSTATUS Pipe_InitQueue(
__in PDEVICE_CONTEXT deviceContext,
__in PPIPE_CONTEXT pipeContext,
__out WDFQUEUE* queueRef)
{
WDF_IO_QUEUE_CONFIG queueConfig;
WDF_OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS status = STATUS_INVALID_HANDLE;
WDFQUEUE queue = NULL;
PQUEUE_CONTEXT queueContext;
WDF_OBJECT_ATTRIBUTES memAttributes;
WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
objectAttributes.SynchronizationScope = WdfSynchronizationScopeQueue;
*queueRef = NULL;
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objectAttributes, QUEUE_CONTEXT);
queueConfig.DispatchType = WdfIoQueueDispatchInvalid;
Pipe_InitQueueConfig(pipeContext, &queueConfig);
if (queueConfig.DispatchType != WdfIoQueueDispatchInvalid)
{
status = WdfIoQueueCreate(deviceContext->WdfDevice,
&queueConfig,
&objectAttributes,
&queue);
if (!NT_SUCCESS(status))
{
USBERR("WdfIoQueueCreate failed. pipeID=%02Xh status=%Xh\n", pipeContext->PipeInformation.EndpointAddress, status);
goto Exit;
}
queueContext = GetQueueContext(queue);
queueContext->IsFreshPipeReset = TRUE;
RtlZeroMemory(&queueContext->OverOfs, sizeof(queueContext->OverOfs));
queueContext->PipeHandle = pipeContext->Pipe;
RtlCopyMemory(&queueContext->Info, &pipeContext->PipeInformation, sizeof(queueContext->Info));
WDF_OBJECT_ATTRIBUTES_INIT(&memAttributes);
memAttributes.ParentObject = queue;
if ((queueContext->Info.MaximumPacketSize) &&
(queueContext->Info.PipeType == WdfUsbPipeTypeBulk || queueContext->Info.PipeType == WdfUsbPipeTypeInterrupt))
{
status = WdfMemoryCreate(&memAttributes, NonPagedPool, POOL_TAG, queueContext->Info.MaximumPacketSize, &queueContext->OverMem, &queueContext->OverBuf);
if (!NT_SUCCESS(status))
{
USBERRN("WdfMemoryCreate failed. status=%08Xh", status);
WdfObjectDelete(queue);
goto Exit;
}
}
}
*queueRef = queue;
Exit:
return status;
}
NTSTATUS Pipe_InitContext(__in PDEVICE_CONTEXT deviceContext,
__in PPIPE_CONTEXT pipeContext,
__in BOOLEAN startIoTarget)
{
NTSTATUS status = STATUS_INVALID_HANDLE;
WDFQUEUE queueOld = pipeContext->Queue;
WDFQUEUE queueNew = NULL;
if (!pipeContext->Pipe && pipeContext->PipeInformation.PipeType != WdfUsbPipeTypeControl)
{
USBERR("pipeID=%02Xh invalid pipe handle\n", pipeContext->PipeInformation.EndpointAddress);
goto Done;
}
if (queueOld == NULL || ((pipeContext->PipeInformation.EndpointAddress & 0xF) && pipeContext->IsQueueDirty))
{
pipeContext->IsQueueDirty = FALSE;
if (queueOld != NULL)
{
USBDBGN("pipeID=%02Xh Destroying old pipe queue.", pipeContext->PipeInformation.EndpointAddress);
WdfObjectDelete(queueOld);
queueOld = NULL;
}
USBDBGN("pipeID=%02Xh Creating pipe queue.", pipeContext->PipeInformation.EndpointAddress);
status = Pipe_InitQueue(deviceContext, pipeContext, &queueNew);
if (!NT_SUCCESS(status))
{
pipeContext->Queue = NULL;
pipeContext->IsValid = FALSE;
USBERRN("Pipe_InitQueue failed. pipeID=%02Xh status=%08Xh", pipeContext->PipeInformation.EndpointAddress, status);
goto Done;
}
pipeContext->Queue = queueNew;
}
else
{
status = STATUS_SUCCESS;
queueNew = queueOld;
}
if (!queueNew && NT_SUCCESS(status))
status = STATUS_INVALID_PIPE_STATE;
if (NT_SUCCESS(status))
{
if (pipeContext->PipeInformation.PipeType != WdfUsbPipeTypeControl)
{
if (startIoTarget)
{
USBDBG("pipeID=%02Xh starting..\n", pipeContext->PipeInformation.EndpointAddress);
status = PipeStart(pipeContext);
if (!NT_SUCCESS(status))
{
pipeContext->IsValid = FALSE;
USBERR("WdfIoTargetStart failed. status=%Xh\n", status);
goto Done;
}
}
}
USBDBG("pipeID=%02Xh queue starting..\n", pipeContext->PipeInformation.EndpointAddress);
WdfIoQueueStart(queueNew);
pipeContext->IsValid = TRUE;
}
else
{
USBERR("WdfIoQueueCreate failed. status=%Xh\n", status);
pipeContext->IsValid = FALSE;
goto Done;
}
Done:
return status;
}
NTSTATUS Pipe_Start(__in PDEVICE_CONTEXT deviceContext,
__in PPIPE_CONTEXT pipeContext,
__in BOOLEAN startIoTarget)
{
NTSTATUS status = STATUS_INVALID_PIPE_STATE;
PAGED_CODE();
if (!pipeContext)
return status;
if (pipeContext->IsValid == FALSE)
{
status = Pipe_InitContext(deviceContext, pipeContext, startIoTarget);
if (!NT_SUCCESS(status))
{
USBERR("pipeID=%02Xh failed initializing pipe\n",
pipeContext->PipeInformation.EndpointAddress);
}
}
else
{
USBERRN("pipeContext already valid!");
}
return status;
}
VOID Pipe_StartAll(__in PDEVICE_CONTEXT deviceContext, __in BOOLEAN startIoTarget)
{
PPIPE_CONTEXT pipeContext = NULL;
UCHAR interfaceIndex, pipeIndex;
UCHAR interfaceCount, pipeCount;
NTSTATUS status;
PAGED_CODE();
interfaceCount = deviceContext->InterfaceCount;
for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++)
{
pipeCount = deviceContext->InterfaceContext[interfaceIndex].PipeCount;
for (pipeIndex = 0; pipeIndex < pipeCount; pipeIndex++)
{
pipeContext = deviceContext->InterfaceContext[interfaceIndex].PipeContextByIndex[pipeIndex];
status = Pipe_Start(deviceContext, pipeContext, startIoTarget);
}
}
}
PPIPE_CONTEXT Pipe_GetContextFromName(
__in PDEVICE_CONTEXT DeviceContext,
__in PUNICODE_STRING FileName)
{
INT nameLength, index;
PPIPE_CONTEXT pipeContext = NULL;
PAGED_CODE();
nameLength = (INT)(FileName->Length / sizeof(WCHAR));
for (index = 0; index < sizeof(PipeNameToPipeID) / sizeof(PipeNameToPipeID[0]); index++)
{
INT checkLength = (INT)wcslen(PipeNameToPipeID[index].NameW);
if (checkLength == nameLength &&
wmemcmp(FileName->Buffer, PipeNameToPipeID[index].NameW, nameLength) == 0)
{
pipeContext = GetPipeContextByID(DeviceContext, PipeNameToPipeID[index].PipeID);
if (pipeContext == NULL || !pipeContext->IsValid || !pipeContext->Pipe || !pipeContext->Queue)
{
USBERR("pipe filename %s is valid but the pipe does not exist\n", PipeNameToPipeID[index].Name);
return NULL;
}
return pipeContext; }
}
USBERR("invalid pipe filename=%wZ\n", FileName->Buffer);
return NULL;
}
NTSTATUS Pipe_InitDefaultContext(__in PDEVICE_CONTEXT deviceContext)
{
PPIPE_CONTEXT pipeContext = GetPipeContextByID(deviceContext, 0);
Policy_InitPipe(deviceContext, pipeContext);
pipeContext->Pipe = WDF_NO_HANDLE;
pipeContext->Queue = WDF_NO_HANDLE;
pipeContext->PipeInformation.MaximumPacketSize = deviceContext->UsbDeviceDescriptor.bMaxPacketSize0;
pipeContext->PipeInformation.MaximumTransferSize = MAX_CONTROL_TRANSFER_SIZE;
pipeContext->PipeInformation.EndpointAddress = 0x00;
pipeContext->PipeInformation.PipeType = WdfUsbPipeTypeControl;
pipeContext->TimeoutPolicy = 5000;
return Pipe_InitContext(deviceContext, pipeContext, FALSE);
}
ULONG Pipe_CalcMaxTransferSize(
__in BOOLEAN IsHS,
__in WDF_USB_PIPE_TYPE pipeType,
__in ULONG maxPacketSize,
__in ULONG originalMaxTransferSize)
{
ULONG maxTransferSize;
switch (pipeType)
{
case WdfUsbPipeTypeIsochronous:
maxTransferSize = IsHS ? (1024 * maxPacketSize) : (255 * maxPacketSize);
break;
case WdfUsbPipeTypeBulk:
case WdfUsbPipeTypeInterrupt:
maxTransferSize = maxPacketSize * 4096;
break;
default:
return originalMaxTransferSize;
}
return maxTransferSize > originalMaxTransferSize ? originalMaxTransferSize : maxTransferSize;
}