Пример #1
0
NTSTATUS Registry_ReadAllDeviceKeys(__in PDEVICE_CONTEXT deviceContext)
{
	WDFKEY					hKey = NULL;
	NTSTATUS				status = STATUS_INVALID_DEVICE_STATE;
	UNICODE_STRING			valueName;
	WDF_OBJECT_ATTRIBUTES	collectionAttributes;
	WDF_OBJECT_ATTRIBUTES	stringAttributes;
	GUID					guidTest = {0};

	PAGED_CODE();

	if (!deviceContext->WdfDevice)
	{
		USBERR("deviceContext->WdfDevice is NULL.\n");
		return status;
	}

	// The driver sets the PLUGPLAY_REGKEY_DEVICE flag to open the Device
	// Parameters subkey under the device's hardware key, or it sets the
	// PLUGPLAY_REGKEY_DRIVER flag to open the driver's software key. If the
	// PLUGPLAY_REGKEY_CURRENT_HWPROFILE flag is also set,
	// WdfDeviceOpenRegistryKey opens the copy of the hardware or software key
	// that is in the current hardware profile.
	status = WdfDeviceOpenRegistryKey(deviceContext->WdfDevice,
	                                  PLUGPLAY_REGKEY_DEVICE,
	                                  KEY_READ,
	                                  WDF_NO_OBJECT_ATTRIBUTES,
	                                  &hKey);

	if (!NT_SUCCESS (status))
	{
		USBERR("WdfDeviceOpenRegistryKey failed.\n");
		hKey = NULL;
		return status;
	}

	//////////////////////////////////////////////////////////////////////////
	// Read the device interface guids from the registry.
	// These are set in the inf files [Device_AddReg] group.
	//
	WDF_OBJECT_ATTRIBUTES_INIT(&collectionAttributes);
	collectionAttributes.ParentObject = deviceContext->WdfDevice;

	status = WdfCollectionCreate(&collectionAttributes,
	                             &deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs);
	if (!NT_SUCCESS(status))
	{
		USBERR("collection object could not be allocated. status=%Xh", status);
		goto Done;
	}

	WDF_OBJECT_ATTRIBUTES_INIT(&stringAttributes);
	stringAttributes.ParentObject = deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs;
	RtlInitUnicodeString(&valueName, L"DeviceInterfaceGUIDs");

	status = WdfRegistryQueryMultiString(hKey, &valueName, &stringAttributes, deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs);
	if (NT_SUCCESS(status))
	{
		ULONG guidCount = WdfCollectionGetCount(deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs);
		ULONG guidIndex;
		WDFSTRING wdfGuidString;
		BOOLEAN removeGuidFromCollection;

		USBMSG("Found %u DeviceInterfaceGUIDs strings.", guidCount);

		for (guidIndex = 0; guidIndex < guidCount; guidIndex++)
		{
			removeGuidFromCollection = TRUE;

			wdfGuidString = (WDFSTRING)WdfCollectionGetItem(deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs, guidIndex);
			status = GUIDFromWdfString(wdfGuidString, &guidTest);
			if (!NT_SUCCESS(status))
			{
				USBERR("removing invalid DeviceInterfaceGUID string at index %u\n", guidIndex);
			}
			else
			{
				if (IsEqualGUID(&guidTest, &Libusb0DeviceGuid))
				{
					USBWRN("libusb0 device DeviceInterfaceGUID found. skippng..\n");
				}
				else if (IsEqualGUID(&guidTest, &Libusb0FilterGuid))
				{
					USBWRN("libusb0 filter DeviceInterfaceGUID found. skippng..\n");
				}
				else if (IsEqualGUID(&guidTest, &LibusbKDeviceGuid))
				{
					USBWRN("libusbK default device DeviceInterfaceGUID found. skippng..\n");
				}
				else
				{
					removeGuidFromCollection = FALSE;
				}
			}

			if (removeGuidFromCollection)
			{
				WdfCollectionRemoveItem(deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs, guidIndex);
				guidIndex--;
				guidCount--;
			}
		}
	}
	else
	{
		USBWRN("DeviceInterfaceGUIDs registry key does not exist.\n"
		       "    Ensure the DeviceInterfaceGUIDs key has been properly set in the .inf and re-install the device.\n\n");
	}

	if (WdfCollectionGetCount(deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs) == 0)
	{
		status = AddDefaultDeviceInterfaceGUID(deviceContext);
		if (!NT_SUCCESS(status))
		{
			goto Done;
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Read the device power policy settings (if any).
	// These are set in the inf files [Device_AddReg] group.
	//
	GetDeviceRegSettingKey(DeviceIdleEnabled, FALSE);
	GetDeviceRegSettingKey(DeviceIdleIgnoreWakeEnable, FALSE);
	GetDeviceRegSettingKey(UserSetDeviceIdleEnabled, FALSE);
	GetDeviceRegSettingKey(DefaultIdleState, FALSE);
	GetDeviceRegSettingKey(DefaultIdleTimeout, 5000);
	GetDeviceRegSettingKey(SystemWakeEnabled, FALSE);

	status = STATUS_SUCCESS;

Done:
	if (hKey)
	{
		WdfRegistryClose(hKey);
		hKey = NULL;
	}
	return status;
}
Пример #2
0
NTSTATUS
ToastMon_EvtDeviceAdd(
    IN WDFDRIVER Driver,
    IN PWDFDEVICE_INIT DeviceInit
    )
/*++
Routine Description:

    ToastMon_EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent a new instance of toaster device.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    WDF_OBJECT_ATTRIBUTES           attributes;
    NTSTATUS                        status = STATUS_SUCCESS;
    WDFDEVICE                       device;
    PDEVICE_EXTENSION               deviceExtension;

    KdPrint( ("ToastMon_EvtDeviceAdd routine\n"));

    UNREFERENCED_PARAMETER(Driver);

    PAGED_CODE();

    //
    // Specify the size of device extension where we track per device
    // context.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION);

    attributes.EvtCleanupCallback = ToastMon_EvtDeviceContextCleanup;

    //
    // Create a framework device object.This call will inturn create
    // a WDM deviceobject, attach to the lower stack and set the
    // appropriate flags and attributes.
    //
    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDeviceCreate failed with Status 0x%x\n", status));
        return status;
    }

    //
    // Get the DeviceExtension and initialize it.
    //
    deviceExtension = GetDeviceExtension(device);

    deviceExtension->WdfDevice = device;

    //
    // Create a collection to store information about target devices.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;

    status = WdfCollectionCreate(&attributes,
                                &deviceExtension->TargetDeviceCollection);
    if (!NT_SUCCESS(status))
    {
        KdPrint( ("WdfCollectionCreate failed with status 0x%x\n", status));
        return status;
    }

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;

    status = WdfWaitLockCreate(&attributes,
                               &deviceExtension->TargetDeviceCollectionLock);
    if (!NT_SUCCESS(status))
    {
        KdPrint( ("WdfWaitLockCreate failed with status 0x%x\n", status));
        return status;
    }

    //
    // Register for TOASTER device interface change notification.
    // We will get GUID_DEVICE_INTERFACE_ARRIVAL and
    // GUID_DEVICE_INTERFACE_REMOVAL notification when the toaster
    // device is started and removed.
    // Framework doesn't provide a WDF interface to register for interface change
    // notification. However if the target device is opened by symboliclink using
    // IoTarget, framework registers itself EventCategoryTargetDeviceChange
    // notification on the handle and responds to the pnp notifications.
    //
    // Note that as soon as you register, arrival notification will be sent
    // about all existing toaster devices even before this device is started. So if
    // you cannot handle these notification before start then you should register this in
    // PrepareHardware or SelfManagedIoInit callback.
    // You must unregister this notification when the device is removed in the
    // DeviceContextCleanup callback. This call takes a reference on the driverobject.
    // So if you don't unregister it will prevent the driver from unloading.
    //
    status = IoRegisterPlugPlayNotification (
                EventCategoryDeviceInterfaceChange,
                PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
                (PVOID)&GUID_DEVINTERFACE_TOASTER,
                WdfDriverWdmGetDriverObject(WdfDeviceGetDriver(device)),
                (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)
                    ToastMon_PnpNotifyInterfaceChange,
                (PVOID)deviceExtension,
                &deviceExtension->NotificationHandle);

    if (!NT_SUCCESS(status)) {
        KdPrint(("RegisterPnPNotifiction failed: 0x%x\n", status));
        return status;
    }

    RegisterForWMINotification(deviceExtension);

    return status;
}
Пример #3
0
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    Installable driver initialization entry point.
    This entry point is called directly by the I/O system.

Arguments:

    DriverObject - pointer to the driver object

    RegistryPath - pointer to a unicode string representing the path,
                   to driver-specific key in the registry.

Return Value:

    STATUS_SUCCESS if successful,
    STATUS_UNSUCCESSFUL otherwise.

--*/
{
    WDF_DRIVER_CONFIG   config;
    NTSTATUS            status;
    WDFDRIVER   hDriver;

    KdPrint(("Toaster SideBand Filter Driver Sample - Driver Framework Edition.\n"));
    KdPrint(("Built %s %s\n", __DATE__, __TIME__));

    //
    // Initiialize driver config to control the attributes that
    // are global to the driver. Note that framework by default
    // provides a driver unload routine. If you create any resources
    // in the DriverEntry and want to be cleaned in driver unload,
    // you can override that by manually setting the EvtDriverUnload in the
    // config structure. In general xxx_CONFIG_INIT macros are provided to
    // initialize most commonly used members.
    //

    WDF_DRIVER_CONFIG_INIT(
        &config,
        FilterEvtDeviceAdd
    );

    //
    // Create a framework driver object to represent our driver.
    //
    status = WdfDriverCreate(DriverObject,
                            RegistryPath,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &config,
                            &hDriver);
    if (!NT_SUCCESS(status)) {
        KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status));
    }

    //
    // Since there is only one control-device for all the instances
    // of the physical device, we need an ability to get to particular instance
    // of the device in our FilterEvtIoDeviceControlForControl. For that we
    // will create a collection object and store filter device objects.        
    // The collection object has the driver object as a default parent.
    //

    status = WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES,
                                &FilterDeviceCollection);
    if (!NT_SUCCESS(status))
    {
        KdPrint( ("WdfCollectionCreate failed with status 0x%x\n", status));
        return status;
    }

    //
    // The wait-lock object has the driver object as a default parent.
    //

    status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES,
                                &FilterDeviceCollectionLock);
    if (!NT_SUCCESS(status))
    {
        KdPrint( ("WdfWaitLockCreate failed with status 0x%x\n", status));
        return status;
    }

    return status;
}
Пример #4
0
/**
 * @brief Called by the framework when a new PDO has arrived that this driver manages.
 * The device in question is not operational at this point in time.
 * 
 * @param[in] Driver handle to WDFDRIVER object created by DriverEntry()
 * @param[in,out] DeviceInit device init object provided by framework.
 * 
 * @returns NTSTATUS value indicating success or failure.
 * 
 */
NTSTATUS
FdoEvtDeviceAdd(
    _In_    WDFDRIVER       Driver,    
    _Inout_ PWDFDEVICE_INIT DeviceInit 
    )
{
    UNREFERENCED_PARAMETER(Driver);
    WDF_OBJECT_ATTRIBUTES   attributes;
    NTSTATUS status;

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE,
        __FUNCTION__"\n");
    
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
    WdfDeviceInitSetExclusive(DeviceInit, FALSE);
    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, USB_FDO_CONTEXT);
    attributes.EvtCleanupCallback = FdoEvtDeviceContextCleanup;
    
    //
    // Device state callbacks.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS    pnpPowerCallbacks;
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
    pnpPowerCallbacks.EvtDevicePrepareHardware = FdoEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = FdoEvtDeviceReleaseHardware;
    pnpPowerCallbacks.EvtDeviceD0Entry = FdoEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = FdoEvtDeviceD0EntryPostInterruptsEnabled;
    pnpPowerCallbacks.EvtDeviceD0Exit  = FdoEvtDeviceD0Exit;
    pnpPowerCallbacks.EvtDeviceSurpriseRemoval = FdoEvtDeviceSurpriseRemoval;
    
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
    //
    // establish a request context
    //
    WDF_OBJECT_ATTRIBUTES   requestAttributes;
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&requestAttributes, FDO_REQUEST_CONTEXT);
    WdfDeviceInitSetRequestAttributes(DeviceInit, &requestAttributes);

    //
    // static verifier seems to have a rule that the FDO must call 
    // WdfFdoInitSetDefaultChildListConfig if any component in the driver has
    // dynamic child devices, and the roothub has one if it is not operating in 
    // connect usb hub mode.
    //
    WDF_CHILD_LIST_CONFIG  config;
    WDF_CHILD_LIST_CONFIG_INIT(&config,
        sizeof(PDO_INDENTIFICATION_DESCRIPTION),
        FdoEvtChildListCreateDevice);

    WdfFdoInitSetDefaultChildListConfig(DeviceInit,
        &config,
        WDF_NO_OBJECT_ATTRIBUTES);
    //
    // add a preprocess callback for QueryInterface to support multi-version USBDI intefaces
    //
    UCHAR MinorFunctionTable[1] = {IRP_MN_QUERY_INTERFACE};

    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
        DeviceInit,
        FdoPreProcessQueryInterface,
        IRP_MJ_PNP,
        MinorFunctionTable,
        1);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            __FUNCTION__": WdfDeviceInitAssignWdmIrpPreprocessCallback failed error %x\n",
            status);
        return status;
    }

    //
    // Add create/close handlers
    //
    WDF_OBJECT_ATTRIBUTES   fileAttributes;
    WDF_OBJECT_ATTRIBUTES_INIT(&fileAttributes);
    fileAttributes.SynchronizationScope = WdfSynchronizationScopeNone;
    WDF_FILEOBJECT_CONFIG FileObjectConfig;
    WDF_FILEOBJECT_CONFIG_INIT(
        &FileObjectConfig,
        FdoEvtDeviceFileCreate,
        FdoEvtFileClose,
        WDF_NO_EVENT_CALLBACK);

    WdfDeviceInitSetFileObjectConfig(
        DeviceInit,
        &FileObjectConfig,
        &fileAttributes);
        
    WDFDEVICE device;
    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            __FUNCTION__": WdfDeviceCreate failed error %x\n",
            status);
        return status;
    }

    PUSB_FDO_CONTEXT fdoContext = DeviceGetFdoContext(device);
    RtlZeroMemory(fdoContext, sizeof(USB_FDO_CONTEXT));
    fdoContext->WdfDevice = device;
    KeInitializeEvent(&fdoContext->resetCompleteEvent, SynchronizationEvent, FALSE);
    //
    // allocate the dpc request collection.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;
    status = WdfCollectionCreate(&attributes,
        &fdoContext->RequestCollection);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
        __FUNCTION__": WdfCollectionCreate failed\n");
        return status;
    };
    //
    // The FDO is the USB Controller, create a device interface for that.
    //
    status = WdfDeviceCreateDeviceInterface(
        device,
        &GUID_DEVINTERFACE_USB_HOST_CONTROLLER,
        NULL);

    if (!NT_SUCCESS(status)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            __FUNCTION__": WdfDeviceCreateDeviceInterface for device %p error %x\n",
            device,
            status);
        return status;
    }

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);    
    attributes.ParentObject = device;
    status = WdfStringCreate(NULL, &attributes, &fdoContext->hcdsymlink);
    if (!NT_SUCCESS(status)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            __FUNCTION__": WdfStringCreate for device %p error %x\n",
            device,
            status);
        return status;
    }

    status = WdfDeviceRetrieveDeviceInterfaceString(device,
        &GUID_DEVINTERFACE_USB_HOST_CONTROLLER,
        NULL,
        fdoContext->hcdsymlink);
    if (!NT_SUCCESS(status)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            __FUNCTION__": WdfStringCreate for device %p error %x\n",
            device,
            status);
        return status;
    }
    //
    // Some of our resources are independent of the device state and 
    // can be allocated/initialized here.
    //
    status = InitScratchpad(fdoContext);

    if (!NT_SUCCESS(status)) 
    {
        return status;
    }
    //
    // Initialize the I/O Package and any Queues
    //
    status = FdoQueueInitialize(device);
    if (!NT_SUCCESS(status)) 
    {
        return status;
    }

    //
    // --XT-- All of the WDF ISR and DPC setup code was removed
    // here. The DPC is now setup through the Xen interface in the
    // previous call. Note the event channel is setup but not active
    // until the backend is connected.
    //

    //
    // Allocate a watchdog timer for our Xen interface.
    //
    WDF_TIMER_CONFIG  timerConfig;
    WDF_OBJECT_ATTRIBUTES  timerAttributes;

    WDF_TIMER_CONFIG_INIT(
        &timerConfig,
        FdoEvtTimerFunc); 

    WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
    timerAttributes.ParentObject = device;
    timerAttributes.ExecutionLevel = WdfExecutionLevelPassive;

    status = WdfTimerCreate(
        &timerConfig,
        &timerAttributes,
        &fdoContext->WatchdogTimer);

    if (!NT_SUCCESS(status)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
        __FUNCTION__": WdfTimerCreate error %x\n",
        status);
        return status;
    }

    //
    // Create a collection of work items.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;
    status = WdfCollectionCreate(&attributes,
        &fdoContext->FreeWorkItems);
    if (!NT_SUCCESS(status)) 
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
        __FUNCTION__": WdfCollectionCreate error %x\n",
        status);
        return status;
    }

    for (ULONG index = 0; index < INIT_WORK_ITEM_COUNT; index++)
    {
        WDFWORKITEM workitem = NewWorkItem(fdoContext,
            NULL,
            0,0,0,0);
        if (workitem)
        {
            status = WdfCollectionAdd(fdoContext->FreeWorkItems, workitem);
            if (!NT_SUCCESS(status))
            {
                TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
                    __FUNCTION__": WdfCollectionAdd for workitem index %d error %x\n",
                    index,
                    status);
                
                WdfObjectDelete(workitem);
                return status;
            }
        }
    }

    PNP_BUS_INFORMATION  busInformation;
    busInformation.BusNumber = 0;
    busInformation.BusTypeGuid = GUID_BUS_TYPE_USB;
    busInformation.LegacyBusType = PNPBus;

    WdfDeviceSetBusInformationForChildren(
        device,
        &busInformation);

    if (NT_SUCCESS(status)) {
        status = LateSetup(device);
    }

    return status;
}
Пример #5
0
NTSTATUS
UfxDevice_DeviceCreate (
    _In_ WDFDEVICE WdfDevice
    )
/*++

Routine Description:

    Routine that registers with UFX and creates the UFX device object.

Arguments:

    WdfDevice - Wdf object representing the device.

Return Value:

    NTSTATUS.

--*/
{
    NTSTATUS Status;
    PCONTROLLER_CONTEXT ControllerContext;
    UFX_DEVICE_CALLBACKS UfxDeviceCallbacks;
    UFX_DEVICE_CAPABILITIES UfxDeviceCapabilities;
    PUFXDEVICE_CONTEXT UfxDeviceContext;
    UFXDEVICE UfxDevice;
    WDF_OBJECT_ATTRIBUTES Attributes;

    PAGED_CODE();

    TraceEntry();

    ControllerContext = DeviceGetControllerContext(WdfDevice);

    UFX_DEVICE_CAPABILITIES_INIT(&UfxDeviceCapabilities);
    UfxDeviceCapabilities.MaxSpeed = UsbSuperSpeed;
    UfxDeviceCapabilities.RemoteWakeSignalDelay = REMOTE_WAKEUP_TIMEOUT_INTERVAL_MS;
    
    //
    // Set bitmasks that define the IN and OUT endpoint numbers that are available on the controller
    //
    
    //
    // #### TODO: Set the IN endpoint mask here if not all endpoint addresses are supported ####
    //
    // For illustration purposes sample will set default control endpoint 0, 1-4, 8
    UfxDeviceCapabilities.InEndpointBitmap = 0x011F;
    
    //
    // #### TODO: Set the OUT endpoint mask here if not all endpoint addresses are supported ####
    //
    // For illustration purposes sample will set default control endpoint 0, 2-7
    //
    UfxDeviceCapabilities.OutEndpointBitmap = 0x00FD;

    //
    // Set the event callbacks for the ufxdevice
    //
    UFX_DEVICE_CALLBACKS_INIT(&UfxDeviceCallbacks);
    UfxDeviceCallbacks.EvtDeviceHostConnect = UfxDevice_EvtDeviceHostConnect;
    UfxDeviceCallbacks.EvtDeviceHostDisconnect = UfxDevice_EvtDeviceHostDisconnect;
    UfxDeviceCallbacks.EvtDeviceAddressed = UfxDevice_EvtDeviceAddressed;
    UfxDeviceCallbacks.EvtDeviceEndpointAdd = UfxDevice_EvtDeviceEndpointAdd;
    UfxDeviceCallbacks.EvtDeviceDefaultEndpointAdd = UfxDevice_EvtDeviceDefaultEndpointAdd;
    UfxDeviceCallbacks.EvtDeviceUsbStateChange = UfxDevice_EvtDeviceUsbStateChange;
    UfxDeviceCallbacks.EvtDevicePortChange = UfxDevice_EvtDevicePortChange;
    UfxDeviceCallbacks.EvtDevicePortDetect = UfxDevice_EvtDevicePortDetect;
    UfxDeviceCallbacks.EvtDeviceRemoteWakeupSignal = UfxDevice_EvtDeviceRemoteWakeupSignal;
    UfxDeviceCallbacks.EvtDeviceTestModeSet = UfxDevice_EvtDeviceTestModeSet;
    UfxDeviceCallbacks.EvtDeviceSuperSpeedPowerFeature = UfxDevice_EvtDeviceSuperSpeedPowerFeature;

    // Context associated with UFXDEVICE object
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, UFXDEVICE_CONTEXT);
    Attributes.EvtCleanupCallback = UfxDevice_EvtCleanupCallback;

    // Create the UFXDEVICE object
    Status = UfxDeviceCreate(WdfDevice,
                             &UfxDeviceCallbacks,
                             &UfxDeviceCapabilities,
                             &Attributes,
                             &UfxDevice);
    CHK_NT_MSG(Status, "Failed to create UFXDEVICE object");

    // Initialize the client context space in UFXDEVICE object
    UfxDeviceContext = UfxDeviceGetContext(UfxDevice);
    UfxDeviceContext->FdoWdfDevice = WdfDevice;
    UfxDeviceContext->UsbState = UsbfnDeviceStateDetached;
    UfxDeviceContext->UsbPort = UsbfnUnknownPort;
    UfxDeviceContext->IsIdle = TRUE;

    ControllerContext->UfxDevice = UfxDevice;

    //
    // Create endpoints collection
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
    Attributes.ParentObject = UfxDevice;
    Status = WdfCollectionCreate(&Attributes, &UfxDeviceContext->Endpoints);
    CHK_NT_MSG(Status, "Failed to create endpoint collection object");

End:
    TraceExit();
    return Status;
}