#include "drv_common.h"
extern volatile LONG DeviceInstanceNumber;
#if (defined(ALLOC_PRAGMA) && defined(PAGING_ENABLED))
#pragma alloc_text(PAGE, Device_OnAdd)
#pragma alloc_text(PAGE, Device_OnPrepareHardware)
#pragma alloc_text(PAGE, Device_OnFileCreate)
#pragma alloc_text(PAGE, Device_OnFileClose)
#pragma alloc_text(PAGE, Device_Create)
#pragma alloc_text(PAGE, Device_FetchConfigDescriptor)
#pragma alloc_text(PAGE, Device_Configure)
#pragma alloc_text(PAGE, Device_Reset)
#endif
NTSTATUS
Device_OnAdd(
__in WDFDRIVER Driver,
__in PWDFDEVICE_INIT DeviceInit)
{
WDF_FILEOBJECT_CONFIG fileConfig;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES fdoAttributes;
WDF_OBJECT_ATTRIBUTES fileObjectAttributes;
WDF_OBJECT_ATTRIBUTES requestAttributes;
NTSTATUS status;
WDFDEVICE device;
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
PDEVICE_CONTEXT deviceContext;
WDFQUEUE queue;
UNICODE_STRING symbolicLinkName;
WCHAR tmpName[128];
INT i;
UNREFERENCED_PARAMETER(Driver);
PAGED_CODE();
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = Device_OnPrepareHardware;
pnpPowerCallbacks.EvtDeviceD0Entry = Device_OnD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = Device_OnD0Exit;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
WDF_OBJECT_ATTRIBUTES_INIT(&requestAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&requestAttributes, REQUEST_CONTEXT);
WdfDeviceInitSetRequestAttributes(DeviceInit, &requestAttributes);
WDF_FILEOBJECT_CONFIG_INIT(
&fileConfig,
Device_OnFileCreate,
Device_OnFileClose,
WDF_NO_EVENT_CALLBACK
);
WDF_OBJECT_ATTRIBUTES_INIT(&fileObjectAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fileObjectAttributes, FILE_CONTEXT);
WdfDeviceInitSetFileObjectConfig(DeviceInit,
&fileConfig,
&fileObjectAttributes);
#if !defined(BUFFERED_READ_WRITE)
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
#endif
WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, Request_PreIoInitialize);
WDF_OBJECT_ATTRIBUTES_INIT(&fdoAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdoAttributes, DEVICE_CONTEXT);
status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device);
if (!NT_SUCCESS(status))
{
USBERR("WdfDeviceCreate failed. status=%Xh\n", status);
return status;
}
deviceContext = GetDeviceContext(device);
deviceContext->WdfDevice = device;
deviceContext->InstanceNumber = InterlockedIncrement(&DeviceInstanceNumber);
status = Registry_ReadAllDeviceKeys(deviceContext);
if (!NT_SUCCESS(status))
{
USBERR("Registry_ReadAllDeviceKeys failed. status=%Xh\n", status);
goto Error;
}
for (i = LIBUSB_MAX_NUMBER_OF_DEVICES - 1; i > 1; i--)
{
RtlZeroMemory(tmpName, sizeof(tmpName));
_snwprintf(tmpName,
sizeof(tmpName) / sizeof(WCHAR),
L"%s%04d", LIBUSB_SYMBOLIC_LINK_NAME, i);
RtlInitUnicodeString(&symbolicLinkName, tmpName);
status = WdfDeviceCreateSymbolicLink(device, &symbolicLinkName);
if (NT_SUCCESS(status))
{
USBMSG("[dev-id=#%d] SymbolicLink=%s%04d\n",
deviceContext->InstanceNumber, LIBUSB_SYMBOLIC_LINK_NAMEA, i);
break;
}
}
if (!NT_SUCCESS(status))
{
USBERR("[dev-id=#%d] creating symbolic link failed. status=%Xh\n", deviceContext->InstanceNumber, status);
goto Error;
}
WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
pnpCaps.SurpriseRemovalOK = WdfTrue;
WdfDeviceSetPnpCapabilities(device, &pnpCaps);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel);
ioQueueConfig.EvtIoRead = DefaultQueue_OnRead;
ioQueueConfig.EvtIoWrite = DefaultQueue_OnWrite;
ioQueueConfig.EvtIoDeviceControl = DefaultQueue_OnIoControl;
status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue); if (!NT_SUCCESS(status))
{
USBERR("WdfIoQueueCreate failed for Default Queue. status=%Xh\n", status);
goto Error;
}
USBD_GetUSBDIVersion(&deviceContext->UsbVersionInfo);
if (deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs != WDF_NO_HANDLE)
{
WDFCOLLECTION collection = deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs;
ULONG count = WdfCollectionGetCount(collection);
ULONG index;
for (index = 0; index < count; index++)
{
WDFSTRING guidString = WdfCollectionGetItem(collection, index);
if (guidString != WDF_NO_HANDLE)
{
GUID guid = {0};
if (NT_SUCCESS(GUIDFromWdfString(guidString, &guid)))
{
status = WdfDeviceCreateDeviceInterface(device,
(LPGUID) &guid,
NULL); if (!NT_SUCCESS(status))
{
USBERR("WdfDeviceCreateDeviceInterface failed. status=%Xh\n", status);
goto Error;
}
else
{
USBMSG("[dev-id=#%d] assigned DeviceInterfaceGUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}.\n",
deviceContext->InstanceNumber,
guid.Data1,
guid.Data2,
guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
}
}
}
}
return status;
Error:
if (DeviceInit)
{
WdfDeviceInitFree(DeviceInit);
DeviceInit = NULL;
}
return status;
}
NTSTATUS
Device_OnPrepareHardware(
__in WDFDEVICE Device,
__in WDFCMRESLIST ResourceList,
__in WDFCMRESLIST ResourceListTranslated)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT deviceContext;
UNREFERENCED_PARAMETER(ResourceList);
UNREFERENCED_PARAMETER(ResourceListTranslated);
deviceContext = GetDeviceContext(Device);
if (deviceContext->WdfUsbTargetDevice)
{
USBMSGN("Hardware is already prepared. Skipping..");
return STATUS_SUCCESS;
}
status = Device_Create(Device);
if (!NT_SUCCESS(status))
{
USBERRN("Device_Create Failed. Status=%08Xh", status);
return status;
}
status = Device_FetchConfigDescriptor(Device);
if (!NT_SUCCESS(status))
{
USBERRN("Device_FetchConfigDescriptor Failed. Status=%08Xh", status);
return status;
}
status = Device_Configure(Device);
if (!NT_SUCCESS(status))
{
USBERRN("Device_Configure Failed. Status=%08Xh", status);
return status;
}
status = Policy_InitPower(deviceContext);
if (!NT_SUCCESS(status))
{
USBWRNN("Policy_InitPower Failed. Status=%08Xh", status);
status = STATUS_SUCCESS;
}
return status;
}
NTSTATUS Device_OnD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE WdfPowerDeviceState)
{
UNREFERENCED_PARAMETER(Device);
UNREFERENCED_PARAMETER(WdfPowerDeviceState);
USBMSGN("Active. D%u -> D0", WdfPowerDeviceState - 1);
return STATUS_SUCCESS;
}
NTSTATUS Device_OnD0Exit(WDFDEVICE Device, WDF_POWER_DEVICE_STATE WdfPowerDeviceState)
{
PDEVICE_CONTEXT deviceContext;
PQUEUE_CONTEXT queueContext;
PPIPE_CONTEXT pipeContext;
int i;
UNREFERENCED_PARAMETER(WdfPowerDeviceState);
USBMSGN("Idle. D0 -> D%u", WdfPowerDeviceState - 1);
deviceContext = GetDeviceContext(Device);
for (i = 1; i < LIBUSB_MAX_ENDPOINT_COUNT; i++)
{
pipeContext = &deviceContext->PipeContextByID[i];
if (pipeContext->IsValid && pipeContext->Pipe && pipeContext->Queue && pipeContext->Policies.ResetPipeOnResume && (pipeContext->PipeInformation.EndpointAddress & 0xF))
{
queueContext = GetQueueContext(pipeContext->Queue);
if (!queueContext)
{
USBERRN("Invalid queue context. pipeID=%02Xh queue=%p",
pipeContext->PipeInformation.EndpointAddress, pipeContext->Queue);
continue;
}
if (!queueContext->ResetPipeForResume)
{
USBMSGN("Marking pipe for reset on next request. pipeID=%02Xh queue=%p",
pipeContext->PipeInformation.EndpointAddress, pipeContext->Queue);
queueContext->ResetPipeForResume = TRUE;
}
}
}
return STATUS_SUCCESS;
}
VOID Device_OnFileCreate(__in WDFDEVICE Device,
__in WDFREQUEST Request,
__in WDFFILEOBJECT FileObject)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PUNICODE_STRING fileName;
PFILE_CONTEXT pFileContext;
PDEVICE_CONTEXT deviceContext;
PPIPE_CONTEXT pipeContext;
PEPROCESS pProcess;
PAGED_CODE();
USBMSG("begins\n");
deviceContext = GetDeviceContext(Device);
pFileContext = GetFileContext(FileObject);
pFileContext->DeviceContext = deviceContext;
fileName = WdfFileObjectGetFileName(FileObject);
pProcess = PsGetCurrentProcess();
if (pProcess != NULL)
{
USBMSG("Process ID=%u\n", PsGetProcessId(pProcess));
}
if (0 == fileName->Length)
{
status = STATUS_SUCCESS;
}
else
{
pipeContext = Pipe_GetContextFromName(deviceContext, fileName);
if (pipeContext != NULL)
{
pFileContext->PipeID = pipeContext->PipeInformation.EndpointAddress;
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipeContext->Pipe);
status = STATUS_SUCCESS;
}
else
{
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
InterlockedIncrement(&deviceContext->OpenedFileHandleCount);
WdfRequestComplete(Request, status);
USBMSG("ends\n");
return;
}
VOID Device_OnFileClose(__in WDFFILEOBJECT FileObject)
{
PFILE_CONTEXT pFileContext;
PAGED_CODE();
pFileContext = GetFileContext(FileObject);
if (pFileContext && pFileContext->DeviceContext)
{
Interface_ReleaseAll(pFileContext->DeviceContext, WdfFileObjectWdmGetFileObject(FileObject));
InterlockedDecrement(&pFileContext->DeviceContext->OpenedFileHandleCount);
USBDBGN("OpenedFileHandleCount=%u", pFileContext->DeviceContext->OpenedFileHandleCount);
}
}
NTSTATUS Device_Create(__in WDFDEVICE Device)
{
NTSTATUS status;
PDEVICE_CONTEXT deviceContext;
WDF_USB_DEVICE_INFORMATION info;
PAGED_CODE();
deviceContext = GetDeviceContext(Device);
if (deviceContext->WdfUsbTargetDevice == NULL)
{
status = WdfUsbTargetDeviceCreate(Device,
WDF_NO_OBJECT_ATTRIBUTES,
&deviceContext->WdfUsbTargetDevice);
if (!NT_SUCCESS(status))
{
USBERR("WdfUsbTargetDeviceCreate failed. status=%08Xh\n", status);
return status;
}
}
WdfUsbTargetDeviceGetDeviceDescriptor(deviceContext->WdfUsbTargetDevice,
&deviceContext->UsbDeviceDescriptor);
ASSERT(deviceContext->UsbDeviceDescriptor.bNumConfigurations);
WDF_USB_DEVICE_INFORMATION_INIT(&info);
deviceContext->DeviceSpeed = UsbLowSpeed;
deviceContext->RemoteWakeCapable = FALSE;
deviceContext->SelfPowered = FALSE;
status = WdfUsbTargetDeviceRetrieveInformation(deviceContext->WdfUsbTargetDevice, &info);
if (NT_SUCCESS(status))
{
if ((info.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED))
{
deviceContext->DeviceSpeed = UsbHighSpeed;
}
if ((info.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE))
{
deviceContext->RemoteWakeCapable = TRUE;
}
if ((info.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED))
{
deviceContext->SelfPowered = TRUE;
}
}
else
{
USBWRN("WdfUsbTargetDeviceRetrieveInformation failed, status=%Xh. Cannot properly determine device speed.\n", status);
}
GetPolicyValue(DEVICE_SPEED, deviceContext->DevicePolicy) = deviceContext->DeviceSpeed + 1;
USBMSG("DeviceSpeed=%s RemoteWakeCapable=%s SelfPowered=%s\n",
GetDeviceSpeedString(deviceContext->DeviceSpeed),
GetBoolString(deviceContext->RemoteWakeCapable),
GetBoolString(deviceContext->SelfPowered));
return status;
}
NTSTATUS Device_FetchConfigDescriptor(__in WDFDEVICE Device)
{
USHORT size = 0;
NTSTATUS status;
PDEVICE_CONTEXT deviceContext;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
WDF_OBJECT_ATTRIBUTES attributes;
WDFMEMORY memory;
PAGED_CODE();
configurationDescriptor = NULL;
deviceContext = GetDeviceContext(Device);
status = WdfUsbTargetDeviceRetrieveConfigDescriptor(deviceContext->WdfUsbTargetDevice,
NULL,
&size);
if (status != STATUS_BUFFER_TOO_SMALL || size == 0)
{
USBERR("WdfUsbTargetDeviceRetrieveConfigDescriptor failed. status=%08Xh\n", status);
return status;
}
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = deviceContext->WdfDevice;
deviceContext->ConfigurationDescriptorSize = 0;
status = WdfMemoryCreate(&attributes,
NonPagedPool,
POOL_TAG,
size,
&memory,
&configurationDescriptor);
if (!NT_SUCCESS(status))
{
USBERR("WdfMemoryCreate failed. size=%u status=%08Xh\n", size, status);
return status;
}
status = WdfUsbTargetDeviceRetrieveConfigDescriptor(deviceContext->WdfUsbTargetDevice,
configurationDescriptor,
&size);
if (!NT_SUCCESS(status))
{
USBERR("WdfUsbTargetDeviceRetrieveConfigDescriptor failed. status=%08Xh\n", status);
return status;
}
deviceContext->ConfigurationDescriptorSize = size;
deviceContext->UsbConfigurationDescriptor = configurationDescriptor;
deviceContext->ConfigDescriptorIndex = 0;
return status;
}
NTSTATUS Device_Configure(WDFDEVICE Device)
{
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS params;
PWDF_USB_INTERFACE_SETTING_PAIR settingPairs = NULL;
NTSTATUS status;
PDEVICE_CONTEXT deviceContext;
PINTERFACE_CONTEXT interfaceContext;
UCHAR interfaceIndex;
PAGED_CODE();
deviceContext = GetDeviceContext(Device);
deviceContext->InterfaceCount = WdfUsbTargetDeviceGetNumInterfaces(deviceContext->WdfUsbTargetDevice);
if (deviceContext->InterfaceCount == 1)
{
USBDBG("Using single interface configuration..\n");
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(¶ms);
}
else
{
USBDBG("Using multiple interface configuration..\n");
settingPairs = ExAllocatePoolWithTag(
PagedPool,
sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * deviceContext->InterfaceCount,
POOL_TAG);
if (settingPairs == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
USBERR("ExAllocatePoolWithTag failed. size=%u status=%08Xh\n",
sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * deviceContext->InterfaceCount,
status);
return status;
}
for (interfaceIndex = 0; interfaceIndex < deviceContext->InterfaceCount; interfaceIndex++)
{
settingPairs[interfaceIndex].UsbInterface =
WdfUsbTargetDeviceGetInterface(deviceContext->WdfUsbTargetDevice, interfaceIndex);
if (settingPairs[interfaceIndex].UsbInterface == WDF_NO_HANDLE)
{
USBDBG("WdfUsbTargetDeviceGetInterface failed. interfaceIndex=%u\n", interfaceIndex);
}
settingPairs[interfaceIndex].SettingIndex = 0;
}
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(¶ms, deviceContext->InterfaceCount, settingPairs);
}
status = WdfUsbTargetDeviceSelectConfig(deviceContext->WdfUsbTargetDevice, NULL, ¶ms);
if (!NT_SUCCESS(status))
{
USBERR("WdfUsbTargetDeviceSelectConfig failed. status=%Xh", status);
goto Error;
}
else
{
deviceContext->InterfaceCount = WdfUsbTargetDeviceGetNumInterfaces(deviceContext->WdfUsbTargetDevice);
status = Pipe_InitDefaultContext(deviceContext);
if (!NT_SUCCESS(status))
{
USBERR("failed initializing default pipe! status=%Xh", status);
goto Error;
}
for (interfaceIndex = 0; interfaceIndex < deviceContext->InterfaceCount; interfaceIndex++)
{
interfaceContext = &deviceContext->InterfaceContext[interfaceIndex];
interfaceContext->InterfaceIndex = interfaceIndex;
interfaceContext->Interface = WdfUsbTargetDeviceGetInterface(deviceContext->WdfUsbTargetDevice, interfaceContext->InterfaceIndex);
status = Interface_InitContext(deviceContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("Interface_InitContext failed. status=%Xh", status);
deviceContext->InterfaceCount = interfaceIndex;
goto Error;
}
status = Interface_Start(deviceContext, interfaceContext);
if (!NT_SUCCESS(status))
{
USBERR("Interface_Start failed. status=%Xh", status);
deviceContext->InterfaceCount = interfaceIndex;
goto Error;
}
}
}
Error:
if (settingPairs)
{
ExFreePoolWithTag(settingPairs, POOL_TAG);
settingPairs = NULL;
}
return status;
}
NTSTATUS Device_Reset(__in WDFDEVICE Device)
{
PDEVICE_CONTEXT deviceContext;
NTSTATUS status;
PAGED_CODE();
deviceContext = GetDeviceContext(Device);
Pipe_StopAll(deviceContext, TRUE);
status = WdfUsbTargetDeviceIsConnectedSynchronous(deviceContext->WdfUsbTargetDevice);
if(NT_SUCCESS(status))
{
status = WdfUsbTargetDeviceResetPortSynchronously(deviceContext->WdfUsbTargetDevice);
USBMSG("WdfUsbTargetDeviceResetPortSynchronously status=%Xh\n", status);
}
else
{
USBMSG("WdfUsbTargetDeviceIsConnectedSynchronous status=%Xh\n", status);
}
Pipe_StartAll(deviceContext, TRUE);
return status;
}