#include "drv_common.h"
PINTERFACE_CONTEXT Interface_GetContextByNumber(__in PDEVICE_CONTEXT deviceContext,
__in UCHAR interfaceNumber)
{
UCHAR interfaceIndex;
UCHAR interfaceCount;
interfaceCount = deviceContext->InterfaceCount;
for (interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++)
{
if (deviceContext->InterfaceContext[interfaceIndex].InterfaceDescriptor.bInterfaceNumber == interfaceNumber)
{
return &deviceContext->InterfaceContext[interfaceIndex];
}
}
return NULL;
}
PINTERFACE_CONTEXT Interface_GetContextByIndex(__in PDEVICE_CONTEXT deviceContext,
__in UCHAR interfaceIndex)
{
if (interfaceIndex >= deviceContext->InterfaceCount) return NULL;
return &deviceContext->InterfaceContext[interfaceIndex];
}
NTSTATUS Interface_Stop(__in PDEVICE_CONTEXT deviceContext, __in PINTERFACE_CONTEXT interfaceContext)
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR pipeIndex;
PPIPE_CONTEXT pipeContext;
UNREFERENCED_PARAMETER(deviceContext);
for (pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++)
{
pipeContext = interfaceContext->PipeContextByIndex[pipeIndex];
if (pipeContext)
{
Pipe_Stop(pipeContext, WdfIoTargetCancelSentIo, TRUE, FALSE);
}
}
return status;
}
NTSTATUS Interface_Start(__in PDEVICE_CONTEXT deviceContext,
__in PINTERFACE_CONTEXT interfaceContext)
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR pipeIndex;
PPIPE_CONTEXT pipeContext;
for (pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++)
{
pipeContext = interfaceContext->PipeContextByIndex[pipeIndex];
if (pipeContext)
{
Pipe_Start(deviceContext, pipeContext, FALSE);
}
}
return status;
}
VOID Interface_DeletePipesAndQueues(__in PINTERFACE_CONTEXT interfaceContext)
{
UCHAR pipeIndex;
for (pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++)
{
PPIPE_CONTEXT pipeContext = interfaceContext->PipeContextByIndex[pipeIndex];
interfaceContext->PipeContextByIndex[pipeIndex] = NULL;
if (!pipeContext)
{
USBERRN("NULL pipeContext at index %u. Memory may be corrupt!", pipeIndex);
continue;
}
if (pipeContext->IsValid == FALSE &&
pipeContext->Queue != WDF_NO_HANDLE &&
(pipeContext->PipeInformation.EndpointAddress & 0xF))
{
USBDBGN("pipeID=%02Xh Destroying pipe queue.", pipeContext->PipeInformation.EndpointAddress);
WdfObjectDelete(pipeContext->Queue);
pipeContext->Queue = WDF_NO_HANDLE;
}
pipeContext->Pipe = WDF_NO_HANDLE;
}
interfaceContext->PipeCount = 0;
}
NTSTATUS Interface_InitContext(__in PDEVICE_CONTEXT deviceContext,
__in PINTERFACE_CONTEXT interfaceContext)
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR pipeIndex;
if (interfaceContext->Interface == WDF_NO_HANDLE)
{
USBERR("WdfUsbTargetDeviceGetInterface returned a null interface handle at index %u\n", interfaceContext->InterfaceIndex);
return STATUS_FILE_CORRUPT_ERROR;
}
interfaceContext->SettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(interfaceContext->Interface);
WdfUsbInterfaceGetDescriptor(
interfaceContext->Interface,
interfaceContext->SettingIndex,
&interfaceContext->InterfaceDescriptor);
interfaceContext->PipeCount = WdfUsbInterfaceGetNumConfiguredPipes(interfaceContext->Interface);
for(pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++)
{
WDF_USB_PIPE_INFORMATION pipeInfo;
WDFUSBPIPE pipe;
PPIPE_CONTEXT pipeContext;
WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
pipe = WdfUsbInterfaceGetConfiguredPipe(interfaceContext->Interface, pipeIndex, &pipeInfo);
if (!pipe)
{
USBERR("WdfUsbInterfaceGetConfiguredPipe returned a null pipe handle at index %u\n", pipeIndex);
interfaceContext->PipeCount = pipeIndex;
status = STATUS_INSUFFICIENT_RESOURCES;
return status;
}
pipeContext = GetPipeContextByID(deviceContext, pipeInfo.EndpointAddress);
interfaceContext->PipeContextByIndex[pipeIndex] = pipeContext;
RtlCopyMemory(&pipeContext->PipeInformation, &pipeInfo, sizeof(WDF_USB_PIPE_INFORMATION));
Policy_InitPipe(deviceContext, pipeContext);
pipeContext->Pipe = pipe;
pipeInfo.MaximumTransferSize = Pipe_CalcMaxTransferSize(IsHighSpeedDevice(deviceContext), pipeInfo.PipeType, pipeInfo.MaximumPacketSize, pipeInfo.MaximumTransferSize);
pipeContext->PipeInformation.MaximumTransferSize = pipeInfo.MaximumTransferSize;
USBDBG("configured %s pipe: PipeID=%02Xh MaximumPacketSize=%u MaximumTransferSize=%u PipeType=%s\n",
GetEndpointDirString(pipeInfo.EndpointAddress), pipeInfo.EndpointAddress, pipeInfo.MaximumPacketSize, pipeInfo.MaximumTransferSize, GetPipeTypeString(pipeInfo.PipeType));
}
return status;
}
NTSTATUS Interface_SetAltSetting(__in PDEVICE_CONTEXT deviceContext,
__in PREQUEST_CONTEXT requestContext,
__out PINTERFACE_CONTEXT* interfaceContext)
{
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES pipesAttributes;
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams;
USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
UCHAR altSettingCount;
UCHAR altsetting_index = BYTE_MAX;
status = GetInterfaceContextFromRequest(deviceContext, requestContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("GetInterfaceContextFromRequest failed. status=%Xh\n", status);
goto Done;
}
if ((*interfaceContext)->Interface == WDF_NO_HANDLE)
{
status = STATUS_NO_MORE_ENTRIES;
USBERR("Interface handle is NULL. status=%Xh\n", status);
goto Done;
}
status = GetInterfaceAltSettingIndexFromRequest(requestContext, (*interfaceContext), &altsetting_index, &altSettingCount, &interfaceDescriptor);
if (!NT_SUCCESS(status))
{
USBERR("GetInterfaceAltSettingIndexFromRequest failed. status=%Xh\n", status);
goto Done;
}
if ((*interfaceContext)->SettingIndex == altsetting_index)
{
USBMSG("alternate interface index %u already selected\n",
requestContext->IoControlRequest.intf.altsetting_number);
status = STATUS_SUCCESS;
goto Done;
}
WDF_OBJECT_ATTRIBUTES_INIT(&pipesAttributes);
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams, altsetting_index);
status = Interface_Stop(deviceContext, (*interfaceContext));
if (!NT_SUCCESS(status))
{
USBERR("Interface_Stop failed. status=%Xh", status);
goto Done;
}
status = WdfUsbInterfaceSelectSetting((*interfaceContext)->Interface, &pipesAttributes, &selectSettingParams);
if (!NT_SUCCESS(status))
{
USBERR("unable to set alt setting index %u on interface number %u\n", altsetting_index,
(*interfaceContext)->InterfaceDescriptor.bInterfaceNumber);
if (!NT_SUCCESS(Interface_Start(deviceContext, (*interfaceContext))))
{
USBERR("Interface_Start failed. status=%Xh", status);
}
}
else
{
USBMSG("selected alt setting index %u on interface number %u\n", altsetting_index,
(*interfaceContext)->InterfaceDescriptor.bInterfaceNumber);
(*interfaceContext)->SettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex((*interfaceContext)->Interface);
Interface_DeletePipesAndQueues((*interfaceContext));
status = Interface_InitContext(deviceContext, (*interfaceContext));
if (!NT_SUCCESS(status))
{
USBERR("Interface_InitContext failed. status=%Xh", status);
goto Done;
}
status = Interface_Start(deviceContext, (*interfaceContext));
if (!NT_SUCCESS(status))
{
USBERR("Interface_Start failed. status=%Xh", status);
goto Done;
}
}
Done:
return status;
}
NTSTATUS Interface_GetAltSetting(
__in PDEVICE_CONTEXT deviceContext,
__in PREQUEST_CONTEXT requestContext,
__out PINTERFACE_CONTEXT* interfaceContext)
{
NTSTATUS status = STATUS_SUCCESS;
status = GetInterfaceContextFromRequest(deviceContext, requestContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("GetInterfaceContextFromRequest failed. status=%Xh%d\n", status);
goto Error;
}
Error:
return status;
}
NTSTATUS Interface_Claim(__in PDEVICE_CONTEXT deviceContext,
__in PREQUEST_CONTEXT requestContext,
__in PFILE_OBJECT fileObject,
__out PINTERFACE_CONTEXT* interfaceContext)
{
NTSTATUS status = GetInterfaceContextFromRequest(deviceContext, requestContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("GetInterfaceContextFromRequest failed. status=%Xh\n", status);
return status;
}
if ((*interfaceContext)->ClaimedByFileObject == fileObject)
return STATUS_SUCCESS;
if ((*interfaceContext)->ClaimedByFileObject)
{
USBERR("interface number %u is already claimed\n", (*interfaceContext)->InterfaceDescriptor.bInterfaceNumber);
return STATUS_OBJECT_NAME_COLLISION;
}
(*interfaceContext)->ClaimedByFileObject = fileObject;
return STATUS_SUCCESS;
}
NTSTATUS Interface_Release(
__in PDEVICE_CONTEXT deviceContext,
__in PREQUEST_CONTEXT requestContext,
__in PFILE_OBJECT fileObject,
__out PINTERFACE_CONTEXT* interfaceContext)
{
NTSTATUS status = GetInterfaceContextFromRequest(deviceContext, requestContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("GetInterfaceContextFromRequest failed. status=%Xh\n", status);
return status;
}
if (!(*interfaceContext)->ClaimedByFileObject)
{
return STATUS_SUCCESS;
}
if ((*interfaceContext)->ClaimedByFileObject != fileObject)
{
USBERR("interface number %u is not bound to this file object\n",
(*interfaceContext)->InterfaceDescriptor.bInterfaceNumber);
return STATUS_OBJECT_NAME_COLLISION;
}
(*interfaceContext)->ClaimedByFileObject = NULL;
return STATUS_SUCCESS;
}
NTSTATUS Interface_ReleaseAll(__in PDEVICE_CONTEXT deviceContext,
__in PFILE_OBJECT fileObject)
{
INT i;
USBMSG("releasing all interfaces bound to file object 0x%x\n", fileObject);
for (i = 0; i < deviceContext->InterfaceCount; i++)
{
if (deviceContext->InterfaceContext[i].ClaimedByFileObject == fileObject)
{
deviceContext->InterfaceContext[i].ClaimedByFileObject = NULL;
}
}
return STATUS_SUCCESS;
}