VOID
OsrFxInitChildList(
    IN PWDFDEVICE_INIT  DeviceInit
    )
/*++

Routine Description:

    This routine is called from the EvtDeviceAdd routine to initialize
    the default child list.

Arguments:


Return Value:

    NT status value

--*/
{
    WDF_CHILD_LIST_CONFIG      config;

    //
    // Init the default child list so that we can enumerate a raw PDO
    //
    WDF_CHILD_LIST_CONFIG_INIT(&config,
                                sizeof(PDO_IDENTIFICATION_DESCRIPTION),
                                OsrEvtDeviceListCreatePdo // callback to create a child device.
                                );
    //
    // Tell the framework to use the built-in devicelist to track the state
    // of the device based on the configuration we just created.
    //
    WdfFdoInitSetDefaultChildListConfig(DeviceInit,
                                         &config,
                                         WDF_NO_OBJECT_ATTRIBUTES);

    return;

}
Example #2
0
NTSTATUS
Bus_EvtDeviceAdd(
    IN WDFDRIVER        Driver,
    IN PWDFDEVICE_INIT  DeviceInit
    )
/*++
Routine Description:

    Bus_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 bus.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    WDF_CHILD_LIST_CONFIG      config;
    WDF_OBJECT_ATTRIBUTES      fdoAttributes;
    NTSTATUS                   status;
    WDFDEVICE                  device;
    WDF_IO_QUEUE_CONFIG        queueConfig;
    PNP_BUS_INFORMATION        busInfo;
    //PFDO_DEVICE_DATA           deviceData;
    WDFQUEUE                   queue;

    UNREFERENCED_PARAMETER(Driver);

    PAGED_CODE ();

    KdPrint(("Bus_EvtDeviceAdd: 0x%p\n", Driver));

    //
    // Initialize all the properties specific to the device.
    // Framework has default values for the one that are not
    // set explicitly here. So please read the doc and make sure
    // you are okay with the defaults.
    //
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);
    WdfDeviceInitSetExclusive(DeviceInit, TRUE);

    //
    // Since this is pure software bus enumerator, we don't have to register for
    // any PNP/Power callbacks. Framework will take the default action for
    // all the PNP and Power IRPs.
    //


    //
    // WDF_ DEVICE_LIST_CONFIG describes how the framework should handle
    // dynamic child enumeration on behalf of the driver writer.
    // Since we are a bus driver, we need to specify identification description
    // for our child devices. This description will serve as the identity of our
    // child device. Since the description is opaque to the framework, we
    // have to provide bunch of callbacks to compare, copy, or free
    // any other resources associated with the description.
    //
    WDF_CHILD_LIST_CONFIG_INIT(&config,
                                sizeof(PDO_IDENTIFICATION_DESCRIPTION),
                                Bus_EvtDeviceListCreatePdo // callback to create a child device.
                                );
    //
    // This function pointer will be called when the framework needs to copy a
    // identification description from one location to another.  An implementation
    // of this function is only necessary if the description contains description
    // relative pointer values (like  LIST_ENTRY for instance) .
    // If set to NULL, the framework will use RtlCopyMemory to copy an identification .
    // description. In this sample, it's not required to provide these callbacks.
    // they are added just for illustration.
    //
    config.EvtChildListIdentificationDescriptionDuplicate =
                                Bus_EvtChildListIdentificationDescriptionDuplicate;

    //
    // This function pointer will be called when the framework needs to compare
    // two identificaiton descriptions.  If left NULL a call to RtlCompareMemory
    // will be used to compare two identificaiton descriptions.
    //
    config.EvtChildListIdentificationDescriptionCompare =
                                Bus_EvtChildListIdentificationDescriptionCompare;
    //
    // This function pointer will be called when the framework needs to free a
    // identification description.  An implementation of this function is only
    // necessary if the description contains dynamically allocated memory
    // (by the driver writer) that needs to be freed. The actual identification
    // description pointer itself will be freed by the framework.
    //
    config.EvtChildListIdentificationDescriptionCleanup =
                                Bus_EvtChildListIdentificationDescriptionCleanup;

    //
    // Tell the framework to use the built-in childlist to track the state
    // of the device based on the configuration we just created.
    //
    WdfFdoInitSetDefaultChildListConfig(DeviceInit,
                                         &config,
                                         WDF_NO_OBJECT_ATTRIBUTES);

    //
    // Initialize attributes structure to specify size and accessor function
    // for storing device context.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DEVICE_DATA);

    //
    // Create a framework device object. In response to this call, framework
    // creates a WDM deviceobject and attach to the PDO.
    //
    status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device);

    if (!NT_SUCCESS(status)) {
        KdPrint(("Error creating device 0x%x\n", status));
        return status;
    }

    //
    // Configure a default queue so that requests that are not
    // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
    // other queues get dispatched here.
    //
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
        &queueConfig,
        WdfIoQueueDispatchParallel
    );

    queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl;

    //
    // By default, Static Driver Verifier (SDV) displays a warning if it 
    // doesn't find the EvtIoStop callback on a power-managed queue. 
    // The 'assume' below causes SDV to suppress this warning. If the driver 
    // has not explicitly set PowerManaged to WdfFalse, the framework creates
    // power-managed queues when the device is not a filter driver.  Normally 
    // the EvtIoStop is required for power-managed queues, but for this driver
    // it is not needed b/c the driver doesn't hold on to the requests or 
    // forward them to other drivers. This driver completes the requests 
    // directly in the queue's handlers. If the EvtIoStop callback is not 
    // implemented, the framework waits for all driver-owned requests to be
    // done before moving in the Dx/sleep states or before removing the 
    // device, which is the correct behavior for this type of driver.
    // If the requests were taking an indeterminate amount of time to complete,
    // or if the driver forwarded the requests to a lower driver/another stack,
    // the queue should have an EvtIoStop/EvtIoResume.
    //
    __analysis_assume(queueConfig.EvtIoStop != 0);
    status = WdfIoQueueCreate( device,
                               &queueConfig,
                               WDF_NO_OBJECT_ATTRIBUTES,
                               &queue );
    __analysis_assume(queueConfig.EvtIoStop == 0);

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

    //
    // Get the device context.
    //
    //deviceData = FdoGetData(device);

    //
    // Create device interface for this device. The interface will be
    // enabled by the framework when we return from StartDevice successfully.
    // Clients of this driver will open this interface and send ioctls.
    //
    status = WdfDeviceCreateDeviceInterface(
        device,
        &GUID_DEVINTERFACE_BUSENUM_TOASTER,
        NULL // No Reference String. If you provide one it will appended to the
        );   // symbolic link. Some drivers register multiple interfaces for the same device
             // and use the reference string to distinguish between them
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION
    // for the child devices. This is an optional information provided to
    // uniquely idenitfy the bus the device is connected.
    //
    busInfo.BusTypeGuid = GUID_DEVCLASS_TOASTER;
    busInfo.LegacyBusType = PNPBus;
    busInfo.BusNumber = 0;

    WdfDeviceSetBusInformationForChildren(device, &busInfo);

    status = Bus_WmiRegistration(device);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Check the registry to see if we need to enumerate child devices during
    // start.
    //
    status = Bus_DoStaticEnumeration(device);

    return status;
}
_Must_inspect_result_
NTSTATUS
FxPkgFdo::Initialize(
    __in PWDFDEVICE_INIT DeviceInit
    )
/*++ 








Routine Description:

    After creating a FxPkgFdo, the driver writer will initialize it by passing
    a set of driver callbacks that allow the driver writer to customize the
    behavior when handling certain IRPs.

    This is the place to do any initialization that might fail.

Arguments:

    Device - a pointer to the FxDevice

    DispatchTable - a driver supplied table of callbacks

Returns:

    NTSTATUS

--*/
{
    PFX_DRIVER_GLOBALS pGlobals;
    WDF_CHILD_LIST_CONFIG config;
    size_t totalDescriptionSize = 0;
    WDFCHILDLIST hList;
    NTSTATUS status;

    pGlobals = GetDriverGlobals();

    status = FxPkgPnp::Initialize(DeviceInit);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = AllocateEnumInfo();
    if (!NT_SUCCESS(status)) {
        return status;
    }

    #pragma prefast(suppress: __WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "Static child lists do not use the EvtChildListCreateDevice callback")
    WDF_CHILD_LIST_CONFIG_INIT(&config,
                               sizeof(FxStaticChildDescription),
                               NULL);

    status = FxChildList::_ComputeTotalDescriptionSize(pGlobals,
                                                       &config,
                                                       &totalDescriptionSize);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = FxChildList::_CreateAndInit(&m_StaticDeviceList,
                                         pGlobals,
                                         WDF_NO_OBJECT_ATTRIBUTES,
                                         totalDescriptionSize, 
                                         m_Device,
                                         &config,
                                         TRUE);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = m_StaticDeviceList->Commit(WDF_NO_OBJECT_ATTRIBUTES,
                                        (WDFOBJECT*) &hList,
                                        m_Device);

    if (!NT_SUCCESS(status)) {
        m_StaticDeviceList->DeleteFromFailedCreate();
        m_StaticDeviceList = NULL;

        return status;
    }

    //
    // This will be released in the destructor
    //
    m_StaticDeviceList->ADDREF(this);

    return status;
}
NTSTATUS
XenUsb_EvtDriverDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init)
{
  NTSTATUS status;
  WDF_CHILD_LIST_CONFIG child_list_config;
  WDFDEVICE device;
  PXENUSB_DEVICE_DATA xudd;
  //UNICODE_STRING reference;
  WDF_OBJECT_ATTRIBUTES device_attributes;
  PNP_BUS_INFORMATION pbi;
  WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
  WDF_DEVICE_POWER_CAPABILITIES power_capabilities;
  WDF_IO_QUEUE_CONFIG queue_config;
  UCHAR pnp_minor_functions[] = { IRP_MN_QUERY_INTERFACE };
  DECLARE_CONST_UNICODE_STRING(symbolicname_name, L"SymbolicName");
  WDFSTRING symbolicname_value_wdfstring;
  WDFKEY device_key;
  UNICODE_STRING symbolicname_value;

  UNREFERENCED_PARAMETER(driver);

  FUNCTION_ENTER();

  WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
  pnp_power_callbacks.EvtDeviceD0Entry = XenUsb_EvtDeviceD0Entry;
  pnp_power_callbacks.EvtDeviceD0Exit = XenUsb_EvtDeviceD0Exit;

  WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);

  status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenUsb_EvtDeviceWdmIrpPreprocessQUERY_INTERFACE,
    IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
  if (!NT_SUCCESS(status))
  {
    return status;
  }

  WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER);
  WdfDeviceInitSetExclusive(device_init, FALSE);

  WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENUSB_PDO_IDENTIFICATION_DESCRIPTION), XenUsb_EvtChildListCreateDevice);
  child_list_config.EvtChildListScanForChildren = XenUsb_EvtChildListScanForChildren;
  WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES);

  WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered);

  WdfDeviceInitSetPowerNotPageable(device_init);
  
  WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENUSB_DEVICE_DATA);
  status = WdfDeviceCreate(&device_init, &device_attributes, &device);
  if (!NT_SUCCESS(status))
  {
    FUNCTION_MSG("Error creating device %08x\n", status);
    return status;
  }

  xudd = GetXudd(device);
  xudd->pdo = WdfDeviceWdmGetPhysicalDevice(device);
  xudd->child_list = WdfFdoGetDefaultChildList(device);
  KeInitializeEvent(&xudd->backend_event, SynchronizationEvent, FALSE);
  InitializeListHead(&xudd->partial_pvurb_queue);
  InitializeListHead(&xudd->partial_pvurb_ring);
  KeInitializeDpc(&xudd->event_dpc, XenUsb_HandleEventDpc, xudd);

  KeInitializeSpinLock(&xudd->urb_ring_lock);
  
  WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel);
  queue_config.PowerManaged = FALSE; /* ? */
  queue_config.EvtIoDeviceControl = XenUsb_EvtIoDeviceControl;
  queue_config.EvtIoInternalDeviceControl = XenUsb_EvtIoInternalDeviceControl;
  queue_config.EvtIoDefault = XenUsb_EvtIoDefault;
  status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xudd->io_queue);
  if (!NT_SUCCESS(status)) {
      FUNCTION_MSG("Error creating io_queue 0x%x\n", status);
      return status;
  }

  WDF_IO_QUEUE_CONFIG_INIT(&queue_config, WdfIoQueueDispatchParallel);
  queue_config.PowerManaged = FALSE; /* ? */
  //queue_config.EvtIoDeviceControl = XenUsb_EvtIoDeviceControl;
  queue_config.EvtIoInternalDeviceControl = XenUsb_EvtIoInternalDeviceControl_PVURB;
  //queue_config.EvtIoDefault = XenUsb_EvtIoDefault;
  queue_config.Settings.Parallel.NumberOfPresentedRequests = USB_URB_RING_SIZE; /* the queue controls if the ring is full */
  status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xudd->pvurb_queue);
  if (!NT_SUCCESS(status)) {
      FUNCTION_MSG("Error creating urb_queue 0x%x\n", status);
      return status;
  }

  WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities);
  power_capabilities.DeviceD1 = WdfTrue;
  power_capabilities.WakeFromD1 = WdfTrue;
  power_capabilities.DeviceWake = PowerDeviceD1;
  power_capabilities.DeviceState[PowerSystemWorking]   = PowerDeviceD0;
  power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
  power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
  power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
  power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  power_capabilities.DeviceState[PowerSystemShutdown]  = PowerDeviceD3;
  WdfDeviceSetPowerCapabilities(device, &power_capabilities);  

  WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
  WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
  WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
  
  pbi.BusTypeGuid = GUID_BUS_TYPE_XEN;
  pbi.LegacyBusType = PNPBus;
  pbi.BusNumber = 0;
  WdfDeviceSetBusInformationForChildren(device, &pbi);

  status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL);
  if (!NT_SUCCESS(status)) {
    FUNCTION_MSG("WdfDeviceCreateDeviceInterface returned %08x\n");
    return status;
  }

  /* USB likes to have a registry key with the symbolic link name in it */
  status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &symbolicname_value_wdfstring);
  if (!NT_SUCCESS(status)) {
    FUNCTION_MSG("WdfStringCreate returned %08x\n");
    return status;
  }
  status = WdfDeviceRetrieveDeviceInterfaceString(device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, symbolicname_value_wdfstring);
  if (!NT_SUCCESS(status)) {
    FUNCTION_MSG("WdfDeviceRetrieveDeviceInterfaceString returned %08x\n");
    return status;
  }
  WdfStringGetUnicodeString(symbolicname_value_wdfstring, &symbolicname_value);
  status = WdfDeviceOpenRegistryKey(device, PLUGPLAY_REGKEY_DEVICE, KEY_SET_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &device_key);
  if (!NT_SUCCESS(status)) {
    FUNCTION_MSG("WdfDeviceOpenRegistryKey returned %08x\n");
    return status;
  }
  WdfRegistryAssignUnicodeString(device_key, &symbolicname_name, &symbolicname_value);

  FUNCTION_EXIT();
  return status;
}
Example #5
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;
}
NTSTATUS
VIOSerialEvtDeviceAdd(
    IN WDFDRIVER Driver,
    IN PWDFDEVICE_INIT DeviceInit)
{
    NTSTATUS                     status = STATUS_SUCCESS;
    WDF_OBJECT_ATTRIBUTES        Attributes;
    WDFDEVICE                    hDevice;
    WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
    WDF_CHILD_LIST_CONFIG        ChildListConfig;
    PNP_BUS_INFORMATION          busInfo;
    PPORTS_DEVICE                pContext = NULL;

    UNREFERENCED_PARAMETER(Driver);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__);

    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
    PnpPowerCallbacks.EvtDevicePrepareHardware = VIOSerialEvtDevicePrepareHardware;
    PnpPowerCallbacks.EvtDeviceReleaseHardware = VIOSerialEvtDeviceReleaseHardware;
    PnpPowerCallbacks.EvtDeviceD0Entry         = VIOSerialEvtDeviceD0Entry;
    PnpPowerCallbacks.EvtDeviceD0Exit          = VIOSerialEvtDeviceD0Exit;
    PnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = VIOSerialEvtDeviceD0EntryPostInterruptsEnabled;
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks);

    WDF_CHILD_LIST_CONFIG_INIT(
                                 &ChildListConfig,
                                 sizeof(VIOSERIAL_PORT),
                                 VIOSerialDeviceListCreatePdo
                                 );

    ChildListConfig.EvtChildListIdentificationDescriptionDuplicate =
                                 VIOSerialEvtChildListIdentificationDescriptionDuplicate;

    ChildListConfig.EvtChildListIdentificationDescriptionCompare =
                                 VIOSerialEvtChildListIdentificationDescriptionCompare;

    ChildListConfig.EvtChildListIdentificationDescriptionCleanup =
                                 VIOSerialEvtChildListIdentificationDescriptionCleanup;

    WdfFdoInitSetDefaultChildListConfig(
                                 DeviceInit,
                                 &ChildListConfig,
                                 WDF_NO_OBJECT_ATTRIBUTES
                                 );

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, PORTS_DEVICE);
    Attributes.SynchronizationScope = WdfSynchronizationScopeDevice;
    Attributes.ExecutionLevel = WdfExecutionLevelPassive;
    status = WdfDeviceCreate(&DeviceInit, &Attributes, &hDevice);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed - 0x%x\n", status);
        return status;
    }

    status = VIOSerialInitInterruptHandling(hDevice);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIOSerialInitInterruptHandling failed - 0x%x\n", status);
    }

    status = WdfDeviceCreateDeviceInterface(
                                 hDevice,
                                 &GUID_VIOSERIAL_CONTROLLER,
                                 NULL
                                 );
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed - 0x%x\n", status);
        return status;
    }

    pContext = GetPortsDevice(hDevice);
    pContext->DeviceId = gDeviceCount++;

    busInfo.BusTypeGuid = GUID_DEVCLASS_PORT_DEVICE;
    busInfo.LegacyBusType = PNPBus;
    busInfo.BusNumber = pContext->DeviceId;

    WdfDeviceSetBusInformationForChildren(hDevice, &busInfo);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
    return status;
}