Sample Code

Windows Driver Samples/ Bluetooth Serial HCI Bus Driver/ C++/ pdo.c/

/*++

Copyright (c) Microsoft Corporation All Rights Reserved

Module Name:

    Pdo.c

Abstract:

    This module create a PDO and handles plug & play calls for the child device (PDO).

Environment:

    kernel mode only

--*/

#include "driver.h"
#include "pdo.tmh"


#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PdoCreate)
#pragma alloc_text(PAGE, PdoDevD0Exit)
#pragma alloc_text(PAGE, PdoDevD0Entry)
#pragma alloc_text(PAGE, PdoDevPrepareHardware)
#pragma alloc_text(PAGE, PdoDevReleaseHardware)
#endif

#define MAX_ID_LEN 80



#ifdef DYNAMIC_ENUM


NTSTATUS
PdoCreateDynamic(
    _In_ WDFDEVICE       _Device,
    _In_ PWDFDEVICE_INIT _DeviceInit,
    _In_ PWCHAR          _HardwareIds,
    _In_ ULONG           _SerialNo
    )
/*++

Routine Description:

    This routine creates and initialize a PDO.

Arguments:

Return Value:

    NT Status code.

--*/
{
    NTSTATUS                    Status;
    PPDO_EXTENSION              PdoExtension = NULL;
    WDFDEVICE                   ChildDevice = NULL;
    WDF_OBJECT_ATTRIBUTES       pdoAttributes;
    WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
    WDF_DEVICE_POWER_CAPABILITIES powerCaps;
    DECLARE_CONST_UNICODE_STRING(compatId, BT_PDO_COMPATIBLE_IDS);
    DECLARE_CONST_UNICODE_STRING(deviceLocation, L"Serial HCI Bus - Bluetooth Function");
    DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN);
    DECLARE_UNICODE_STRING_SIZE(deviceId, MAX_ID_LEN);

    WDF_IO_QUEUE_CONFIG         QueueConfig;
    WDFQUEUE                    Queue;      
    

    PAGED_CODE();

    UNREFERENCED_PARAMETER(_Device);

    KdPrint(("Entered PdoCreateDynamic\n"));

    //
    // Set DeviceType
    //
    WdfDeviceInitSetDeviceType(_DeviceInit, FILE_DEVICE_BUS_EXTENDER);

    //
    // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId
    //
    RtlInitUnicodeString(&deviceId, _HardwareIds);

    Status = WdfPdoInitAssignDeviceID(_DeviceInit, &deviceId);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // NOTE: same string  is used to initialize hardware id too
    //
    Status = WdfPdoInitAddHardwareID(_DeviceInit, &deviceId);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = WdfPdoInitAddCompatibleID(_DeviceInit, &compatId );
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status =  RtlUnicodeStringPrintf(&buffer, L"%02d", _SerialNo);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = WdfPdoInitAssignInstanceID(_DeviceInit, &buffer);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Provide a description about the device. This text is usually read from
    // the device. In the case of USB device, this text comes from the string
    // descriptor. This text is displayed momentarily by the PnP manager while
    // it's looking for a matching INF. If it finds one, it uses the Device
    // Description from the INF file or the friendly name created by
    // coinstallers to display in the device manager. FriendlyName takes
    // precedence over the DeviceDesc from the INF file.
    //
    Status = RtlUnicodeStringPrintf( &buffer,
                                     L"SerialHciBus_%02d",
                                     _SerialNo );
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // You can call WdfPdoInitAddDeviceText multiple times, adding device
    // text for multiple locales. When the system displays the text, it
    // chooses the text that matches the current locale, if available.
    // Otherwise it will use the string for the default locale.
    // The driver can specify the driver's default locale by calling
    // WdfPdoInitSetDefaultLocale.
    //
    Status = WdfPdoInitAddDeviceText(_DeviceInit,
                                    &buffer,
                                    &deviceLocation,
                                     0x409 );
    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    WdfPdoInitSetDefaultLocale(_DeviceInit, 0x409);

    //
    // Initialize the attributes to specify the size of PDO device extension.
    // All the state information private to the PDO will be tracked here.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, PDO_EXTENSION);

    //
    // Allow to forward requests to its FDO of this bus driver by using 
    // WdfRequestForwardToParentDeviceIoQueue()in the DeviceIoControl callback.
    //    
    WdfPdoInitAllowForwardingRequestToParent(_DeviceInit);
    
    //
    // Create a framework device object to represent PDO of this bus driver. In response 
    // to this call, framework creates a WDM deviceobject.
    //
    Status = WdfDeviceCreate(&_DeviceInit, 
                             &pdoAttributes, 
                             &ChildDevice);
    
    if (!NT_SUCCESS(Status)) {
        return Status;
    }


    //
    // Note: Once the device is created successfully, framework frees the
    // _DeviceInit memory and sets the _DeviceInit to NULL. So don't
    // call any WdfDeviceInit functions after that.
    //

    //
    // Initalize the PDO extension
    //
    PdoExtension = PdoGetExtension(ChildDevice);

    RtlZeroMemory(PdoExtension, sizeof(PDO_EXTENSION));

    PdoExtension->FdoExtension = FdoGetExtension(_Device);

    PdoExtension->SerialNo = _SerialNo;

    

    //
    // Set some properties for the child device.
    //
    WDF_DEVICE_PNP_CAPABILITIES_INIT(&PnpCaps);  // Zeros this structure (note: WdfFalse is 0)

    //
    // Bus driver sets this value to WdfFalse for this embedded device, which cannot 
    // be physically removed; its FDO must not set/override this.
    //
    PnpCaps.Removable         = WdfFalse;      

    //
    // Bus driver sets this value to WdfTrue.  FDO can override this value (when this irp is on its 
    // way up) if it determines that this device cannot be safely surprise (not orderly) removed 
    // without data loss.
    //
    PnpCaps.SurpriseRemovalOK = WdfTrue;  
    
    pnpCaps.Address  = _SerialNo;
    pnpCaps.UINumber = _SerialNo;

    WdfDeviceSetPnpCapabilities(ChildDevice, &pnpCaps);

    WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);

    powerCaps.DeviceD1 = WdfFalse;
    powerCaps.DeviceD2 = WdfTrue;

    powerCaps.WakeFromD0 = WdfFalse;    
    powerCaps.WakeFromD1 = WdfFalse;
    powerCaps.WakeFromD2 = WdfTrue;    
    powerCaps.WakeFromD3 = WdfTrue;    
    
    powerCaps.DeviceWake = PowerDeviceD2;

    powerCaps.DeviceState[PowerSystemWorking]   = PowerDeviceD0;
    powerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD2;
    powerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
    powerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
    powerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
    powerCaps.DeviceState[PowerSystemShutdown]  = PowerDeviceD3;

    WdfDeviceSetPowerCapabilities(ChildDevice, &powerCaps);


    //
    // Configure a default queue so that requests that are not
    // configure-forwarded using WdfDeviceConfigureRequestDispatching to goto
    // other queues get dispatched here.
    //

    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, WdfIoQueueDispatchParallel);

    //
    // Cannot be power managed queue (dispatch only at D0) as
    // BthMini issues BthX DDI to get version and capabilities 
    // before enter D0.  A deadlock occurs if this is power managed.
    //
    QueueConfig.PowerManaged = WdfFalse;
    
    QueueConfig.EvtIoDeviceControl = PdoIoQuDeviceControl;

    Status = WdfIoQueueCreate(ChildDevice, 
                              &QueueConfig, 
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &Queue);
    DoTrace(LEVEL_INFO, TFLAG_PNP, (" WdfIoQueueCreate (%!STATUS!)", Status));    
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }       
   
Cleanup:


    //
    // Call WdfDeviceInitFree if you encounter an error before the
    // device is created. Once the device is created, framework
    // NULLs the DeviceInit value.
    //
    if (!NT_SUCCESS(Status)) {
        
        DoTrace(LEVEL_ERROR, TFLAG_PNP, (" -PdoCreateDynamic: exit %!STATUS!", Status));        

        if(ChildDevice) {
            WdfObjectDelete(ChildDevice);
        }
    }
    else
    {
        DoTrace(LEVEL_INFO, TFLAG_PNP, (" -PdoCreateDynamic: exit %!STATUS!", Status));          
    }


    return Status;
}

#endif



NTSTATUS
PdoCreate(
    _In_ WDFDEVICE  _Device,
    _In_ PWSTR      _HardwareIds,
    _In_ ULONG      _SerialNo
)
/*++

Routine Description:

    This routine creates and initialize a PDO to service a Bluetooth function.

Arguments:

    _Device - A framework device object
    
    _HardwareIds - a hardware ID for this device

    -SerialNo - serial number of the child DO
    
Return Value:

    NT Status code.

--*/
{
    NTSTATUS                    Status;
    PWDFDEVICE_INIT             DeviceInit = NULL;
    WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;   
    PPDO_EXTENSION              PdoExtension = NULL;
    WDFDEVICE                   ChildDevice = NULL;
    WDF_OBJECT_ATTRIBUTES       Attributes;
    WDF_DEVICE_PNP_CAPABILITIES PnpCaps;
    WDF_DEVICE_POWER_CAPABILITIES PowerCaps;
    UNICODE_STRING              StaticString = {0};
    UNICODE_STRING DeviceId;
    DECLARE_UNICODE_STRING_SIZE(Buffer, MAX_ID_LEN);
    UNICODE_STRING ContainerID = {0};
    WDF_PDO_EVENT_CALLBACKS     Callbacks;
    WDF_IO_QUEUE_CONFIG         QueueConfig;
    WDFQUEUE                    Queue;      

    DoTrace(LEVEL_INFO, TFLAG_PNP, (" +PdoCreate: HWID(%S), compatID(%S)", _HardwareIds, BT_PDO_COMPATIBLE_IDS));

    PAGED_CODE();

    //
    // Allocate a WDFDEVICE_INIT structure and set the properties
    // so that we can create a device object for the child.
    //
    DeviceInit = WdfPdoInitAllocate(_Device);
    if (DeviceInit == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Cleanup;
    }

    //
    // Set DeviceType
    //
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);

    //
    // Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId
    //
    RtlInitUnicodeString(&DeviceId, _HardwareIds);
    Status = WdfPdoInitAssignDeviceID(DeviceInit, &DeviceId);
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    //
    // Note: same string is used to initialize hardware id
    //
    Status = WdfPdoInitAddHardwareID(DeviceInit, &DeviceId);
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    RtlInitUnicodeString(&StaticString, BT_PDO_COMPATIBLE_IDS);
    Status = WdfPdoInitAddCompatibleID(DeviceInit, &StaticString);
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    Status =  RtlUnicodeStringPrintf(&Buffer, L"%02d", _SerialNo);
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }
    Status = WdfPdoInitAssignInstanceID(DeviceInit, &Buffer);
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    //
    // Assign the containerID for an internally connected device
    //
    Status = RtlStringFromGUID(&GUID_CONTAINERID_INTERNALLY_CONNECTED_DEVICE, &ContainerID);
    if (!NT_SUCCESS(Status)) {
        DoTrace(LEVEL_ERROR, TFLAG_PNP, ("Failed to generate the ContainerID, %!STATUS!", Status));;
        goto Cleanup;
    }

    Status = WdfPdoInitAssignContainerID(DeviceInit, &ContainerID);
    if (!NT_SUCCESS(Status)) {
        DoTrace(LEVEL_ERROR, TFLAG_PNP, ("Failed to assign the ContainerID, %!STATUS!", Status));
        goto Cleanup;
    }
    
    //
    // Provide a description about the device. This text is usually read from
    // the device. This text is displayed momentarily by the PnP manager while
    // it's looking for a matching INF. If it finds one, it uses the Device
    // Description from the INF file or the friendly name created by
    // coinstallers to display in the device manager. FriendlyName takes
    // precedence over the DeviceDesc from the INF file.
    //
    Status = RtlUnicodeStringPrintf(&Buffer, L"SerialHciBus_%02d", _SerialNo );
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    //
    // You can call WdfPdoInitAddDeviceText multiple times, adding device
    // text for multiple locales. When the system displays the text, it
    // chooses the text that matches the current locale, if available.
    // Otherwise it will use the string for the default locale.
    // The driver can specify the driver's default locale by calling
    // WdfPdoInitSetDefaultLocale.
    //
    RtlInitUnicodeString(&StaticString, BT_PDO_DEVICE_LOCATION);
    Status = WdfPdoInitAddDeviceText(DeviceInit,
                                     &Buffer,
                                     &StaticString,
                                     0x409);
    if (!NT_SUCCESS(Status)) {        
        goto Cleanup;
    }

    WdfPdoInitSetDefaultLocale(DeviceInit, 0x409);

    //
    // Initialize the attributes to specify the size of PDO device extension.
    // All the state information private to the PDO will be tracked here.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, PDO_EXTENSION);

    //
    // Set power callbacks to handle idle/active transition of the Bluetooth function
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);  

    //
    // Register PnP callback
    //
    PnpPowerCallbacks.EvtDevicePrepareHardware = PdoDevPrepareHardware;
    PnpPowerCallbacks.EvtDeviceReleaseHardware = PdoDevReleaseHardware; 

    //
    // Register for Power callback
    //
    PnpPowerCallbacks.EvtDeviceD0Entry = PdoDevD0Entry;
    PnpPowerCallbacks.EvtDeviceD0Exit  = PdoDevD0Exit; 
    
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, 
                                           &PnpPowerCallbacks); 

    //
    // Allow to forward requests to its FDO of this bus driver by using 
    // WdfRequestForwardToParentDeviceIoQueue()in the DeviceIoControl callback.
    //    
    WdfPdoInitAllowForwardingRequestToParent(DeviceInit);

    //
    // Register to handle bus level power management (arm for wake?)
    //
    WDF_PDO_EVENT_CALLBACKS_INIT(&Callbacks);
        
    //
    // Arm the device for wake:    
    //
    // When the device is powered down, the framework calls the bus driver's 
    // EvtDeviceEnableWakeAtBus callback function at the beginning of the shutdown 
    // sequence, while the child device is still in the D0 state. In this callback 
    // function, the bus driver must do whatever is required at the bus level to 
    // enable the wake signal.
    //    
    Callbacks.EvtDeviceEnableWakeAtBus  = PdoDevEnableWakeAtBus; 

    //
    // Disarm the device for wake:        
    //
    // If the child device triggered a wake signal, the system and the framework 
    // return the device to D0. The framework calls the bus driver's 
    // EvtDeviceDisableWakeAtBus callback function during startup of the child 
    // device. In this callback function, the bus driver should do whatever is 
    // required at the bus level to disable the wake signal, so that the device 
    // can no longer trigger it. Thus, EvtDeviceDisableWakeAtBus reverses the 
    // actions of EvtDeviceEnableWakeAtBus.
    //
    Callbacks.EvtDeviceDisableWakeAtBus = PdoDevDisableWakeAtBus;

    WdfPdoInitSetEventCallbacks(DeviceInit, &Callbacks);
    
    //
    // Create a framework device object to represent PDO of this bus driver. In response 
    // to this call, framework creates a WDM deviceobject.
    //
    Status = WdfDeviceCreate(&DeviceInit, 
                             &Attributes, 
                             &ChildDevice);    
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

    //
    // Note: Once the device is created successfully, framework frees the
    // DeviceInit memory and sets the DeviceInit to NULL. So don't
    // call any WdfDeviceInit functions after that.
    //

    //
    // Initalize the PDO extension
    //
    PdoExtension = PdoGetExtension(ChildDevice);

    RtlZeroMemory(PdoExtension, sizeof(PDO_EXTENSION));

    PdoExtension->FdoExtension = FdoGetExtension(_Device);

    PdoExtension->SerialNo = _SerialNo;


    //
    // Set PnP and Power capabilities for this child device.
    //    
    WDF_DEVICE_PNP_CAPABILITIES_INIT(&PnpCaps);  // Zeros this structure (note: WdfFalse is 0)

    //
    // Bus driver sets this value to WdfFalse for this embedded device, which cannot 
    // be physically removed; its FDO must not set/override this.
    //
    PnpCaps.Removable         = WdfFalse;      

    //
    // Bus driver sets this value to WdfTrue.  FDO can override this value (when this irp is on its 
    // way up) if it determines that this device cannot be safely surprise (not orderly) removed 
    // without data loss.
    //
    PnpCaps.SurpriseRemovalOK = WdfTrue;    

    PnpCaps.Address  = _SerialNo;
    PnpCaps.UINumber = _SerialNo;

    WdfDeviceSetPnpCapabilities(ChildDevice, &PnpCaps);

    WDF_DEVICE_POWER_CAPABILITIES_INIT(&PowerCaps);

    PowerCaps.DeviceD1 = WdfFalse;
    PowerCaps.DeviceD2 = WdfTrue;    

    PowerCaps.WakeFromD0 = WdfFalse;    
    PowerCaps.WakeFromD1 = WdfFalse;    
    PowerCaps.WakeFromD2 = WdfTrue;
    PowerCaps.WakeFromD3 = WdfTrue;    
    
    PowerCaps.DeviceState[PowerSystemWorking]   = PowerDeviceD0;
    PowerCaps.DeviceState[PowerSystemSleeping1] = PowerDeviceD2;
    PowerCaps.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
    PowerCaps.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
    PowerCaps.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
    PowerCaps.DeviceState[PowerSystemShutdown]  = PowerDeviceD3;

    PowerCaps.DeviceWake = PowerDeviceD2;   // Lowest-powered Dx state to send wake signal to system

    WdfDeviceSetPowerCapabilities(ChildDevice, &PowerCaps);       

    //
    // 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);

    //
    // Cannot be power managed queue (dispatch only at D0) as
    // BthMini issues BthX DDI to get version and capabilities 
    // before enter D0.  A deadlock occurs if this is power managed.
    //
    QueueConfig.PowerManaged = WdfFalse;
    
    QueueConfig.EvtIoDeviceControl = PdoIoQuDeviceControl;

    Status = WdfIoQueueCreate(ChildDevice, 
                              &QueueConfig, 
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &Queue);
    DoTrace(LEVEL_INFO, TFLAG_PNP, (" WdfIoQueueCreate (%!STATUS!)", Status));    
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }       

    //
    // Add this device to the FDO's collection of children.
    // After the child device is added to the static collection successfully,
    // driver must call WdfPdoMarkMissing to get the device deleted. It
    // shouldn't delete the child device directly by calling WdfObjectDelete.
    //
    Status = WdfFdoAddStaticChild(_Device, ChildDevice);
    DoTrace(LEVEL_INFO, TFLAG_PNP, (" WdfFdoAddStaticChild (%!STATUS!)", Status));
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }

Cleanup:
    
    //
    // Call WdfDeviceInitFree if you encounter an error before the
    // device is created. Once the device is created, framework
    // NULLs the DeviceInit value.
    //
    if (!NT_SUCCESS(Status)) {
        
        DoTrace(LEVEL_ERROR, TFLAG_PNP, (" -PdoCreate: exit %!STATUS!", Status));
        
        if (DeviceInit != NULL) {
            WdfDeviceInitFree(DeviceInit);
        }

        if(ChildDevice) {
            WdfObjectDelete(ChildDevice);
        }
    }
    else
    {
        DoTrace(LEVEL_INFO, TFLAG_PNP, (" -PdoCreate: exit %!STATUS!", Status));          
    }

    if (NULL != ContainerID.Buffer) {
        RtlFreeUnicodeString(&ContainerID);
    }

    return Status;
}

NTSTATUS
PdoDevPrepareHardware(
    _In_  WDFDEVICE     _Device,
    _In_  WDFCMRESLIST  _ResourcesRaw,
    _In_  WDFCMRESLIST  _ResourcesTranslated     
    )
/*++
Routine Description:

    This PnP CB function take a refernce of its parent so it will not enter DxState while in S0Idle.

Arguments:

    _Device - WDF Device object

    _ResourcesRaw - (Not referenced)
    
    _ResourcesTranslated - (Not referenced)

Return Value:

    NTSTATUS

--*/     
{
    NTSTATUS Status = STATUS_SUCCESS;
    WDFDEVICE ParentDevice;    
    
    PAGED_CODE();

    UNREFERENCED_PARAMETER(_ResourcesRaw);   
    UNREFERENCED_PARAMETER(_ResourcesTranslated);     

    DoTrace(LEVEL_INFO, TFLAG_PNP,("+PdoDevPrepareHardware"));  

    ParentDevice = WdfPdoGetParent(_Device);

    //
    // Take a reference to avoid FDO to enter DxState in IdleS0
    //
    Status = WdfDeviceStopIdle(ParentDevice, FALSE);
    DoTrace(LEVEL_INFO, TFLAG_PNP, ("WdfDeviceStopIdle %!STATUS!", Status));  
    
    //
    // Any failure Status code should be invesigated to ensure that the reference count is balanced. 
    //
    NT_ASSERT(NT_SUCCESS(Status));

    DoTrace(LEVEL_INFO, TFLAG_PNP, ("-PdoDevPrepareHardware"));   

    return Status;
}


NTSTATUS
PdoDevReleaseHardware(
    _In_  WDFDEVICE     _Device,
    _In_  WDFCMRESLIST  _ResourcesTranslated
    )
/*++
Routine Description:

    This PnP CB function release a refcount of its parent so it can enter DxState in S0Idle.

Arguments:

    _Device - WDF Device object
    
    _ResourcesTranslated - (Not referenced)

Return Value:

    NTSTATUS

--*/    
{
    WDFDEVICE ParentDevice;       
    
    PAGED_CODE();
   
    UNREFERENCED_PARAMETER(_ResourcesTranslated);   

    DoTrace(LEVEL_INFO, TFLAG_PNP,("+PdoDevReleaseHardware")); 

    ParentDevice = WdfPdoGetParent(_Device);

    //
    // Release a reference to allow FDO to enter DxState in IdleS0
    //
    WdfDeviceResumeIdle(ParentDevice);    
        
    return STATUS_SUCCESS;
}



NTSTATUS
PdoDevD0Entry(
    _In_   WDFDEVICE              _Device,
    _In_   WDF_POWER_DEVICE_STATE _PreviousState
    )
/*++
Routine Description:

    This PnPPower CB function is invoked after device has entered D0 (working) state. 

Arguments:

    _Device - WDF Device object
    
    PreviousState - Previous device power state

Return Value:

    NTSTATUS

--*/    
{
    NTSTATUS       Status = STATUS_SUCCESS;    

    PAGED_CODE();   

    UNREFERENCED_PARAMETER(_Device);
    UNREFERENCED_PARAMETER(_PreviousState);    
    
    DoTrace(LEVEL_INFO, TFLAG_UART, ("+PdoDevD0Entry")); 

    // 
    // Can bring the Bluetooth function back to active state
    //


    DoTrace(LEVEL_INFO, TFLAG_UART, ("-PdoDevD0Entry %!STATUS!", Status));
    
    return Status;
}


NTSTATUS
PdoDevD0Exit(
    _In_   WDFDEVICE              _Device,
    _In_   WDF_POWER_DEVICE_STATE _TargetState
    )
/*++
Routine Description:

    This PnP CB function is invoked when device has exited D0 (working) state.

Arguments:

    _Device - WDF Device object
    
    _TargetState - Next device power state that it is about to enter

Return Value:

    NTSTATUS

--*/    
{
    PAGED_CODE();  

    UNREFERENCED_PARAMETER(_Device);
    UNREFERENCED_PARAMETER(_TargetState);
    
    DoTrace(LEVEL_INFO, TFLAG_UART, ("+PdoDevD0Exit: D0 -> D%d", _TargetState-WdfPowerDeviceD0));

    //
    // Can prepare the Bluetooth function to enter lower power device state
    //

   
    DoTrace(LEVEL_INFO, TFLAG_UART, ("-PdoDevD0Exit"));

    return STATUS_SUCCESS;
}


VOID
PdoDevDisableWakeAtBus(
    _In_  WDFDEVICE _Device
    )
/*++

Routine Description:

    This framework callback routine performs bus-level operations that disable 
    the ability of one of the bus's devices to trigger a wake-up signal.
    
Arguments:

    _Device - Framework device object

Return Value:

   VOID

--*/    
{   
    //
    // Do not mark this function pageable to potentially reduce power up time.
    //
    
    DoTrace(LEVEL_INFO, TFLAG_POWER,("<==(D)== PdoDevDisableWakeAtBus"));  

    //
    // Device specific implementation to disarm for wake
    //
    DeviceDisableWakeControl(_Device);    
}

NTSTATUS
PdoDevEnableWakeAtBus(
    _In_  WDFDEVICE          _Device,
    _In_  SYSTEM_POWER_STATE _PowerState
    ) 
/*++

Routine Description:

    This framework callback routine performs bus-level operations that enable 
    one of the bus's devices to trigger a wake-up signal.
    
Arguments:

    _Device - Framework device object

    _PowerState - identifies the system power state that the system or device will wake from. 

Return Value:

   NTSTATUS

--*/
{
    //
    // Do not mark this function pageable to potentially reduce power up time.
    //
    
    DoTrace(LEVEL_INFO, TFLAG_POWER,("==(E)==> PdoDevEnableWakeAtBus from %S", 
            _PowerState == PowerSystemWorking ? L"S0" : L"Sx"));

    //
    // Device specific implementation to arm for wake
    //
    return DeviceEnableWakeControl(_Device, _PowerState);  
}

VOID
PdoIoQuDeviceControl(
    _In_  WDFQUEUE     _Queue,
    _In_  WDFREQUEST   _Request,
    _In_  size_t       _OutputBufferLength,
    _In_  size_t       _InputBufferLength,
    _In_  ULONG        _IoControlCode
    )
/*++

Routine Description:

    This routine is the dispatch routine for device control requests.  This routine can be invoke
    at the DISPATCH level from BthPort/mini.
    
Arguments:

    _Queue - Handle to the framework queue object that is associated
            with the I/O request.
    _Request - Handle to a framework request object.

    _OutputBufferLength - length of the request's output buffer,
                        if an output buffer is available.
    _InputBufferLength - length of the request's input buffer,
                        if an input buffer is available.

    _IoControlCode - the driver-defined or system-defined I/O control code
                    (IOCTL) that is associated with the request.

Return Value:

   VOID

--*/
{
    WDFDEVICE Device = NULL;
    NTSTATUS Status = STATUS_INVALID_PARAMETER;
    WDF_REQUEST_FORWARD_OPTIONS ForwardOptions;
    WDFDEVICE ParentDevice;
    ULONG ControlCode = (_IoControlCode & 0x00003ffc) >> 2;    

    UNREFERENCED_PARAMETER(_OutputBufferLength);
    UNREFERENCED_PARAMETER(_InputBufferLength);

    DoTrace(LEVEL_INFO, TFLAG_IOCTL,("+IoDeviceControl - InBufLen:%d, OutBufLen:%d",
            (ULONG) _InputBufferLength, (ULONG) _OutputBufferLength));
    
    switch (_IoControlCode) {  
    case IOCTL_BTHX_GET_VERSION:
    case IOCTL_BTHX_SET_VERSION: 
    case IOCTL_BTHX_QUERY_CAPABILITIES:        
    case IOCTL_BTHX_WRITE_HCI:  
    case IOCTL_BTHX_READ_HCI:           
        Device = WdfIoQueueGetDevice(_Queue);
        WDF_REQUEST_FORWARD_OPTIONS_INIT(&ForwardOptions);
        ForwardOptions.Flags = WDF_REQUEST_FORWARD_OPTION_SEND_AND_FORGET;        
        ParentDevice = WdfPdoGetParent(Device);

        //
        // Forward known IOCTLs to FDO to process
        //
        Status = WdfRequestForwardToParentDeviceIoQueue(_Request,
                                                        WdfDeviceGetDefaultQueue(ParentDevice),
                                                        &ForwardOptions);
        break;  
      
    default:
        //
        // Complete this unexptected IOCTL with default STATUS_INVALID_PARAMETER.
        //        
        DoTrace(LEVEL_ERROR, TFLAG_IOCTL,("Unexpected IOCTL_(0x%x, Func %d)", _IoControlCode, ControlCode));
        break;         
    }
    
    if (!NT_SUCCESS(Status)){
        DoTrace(LEVEL_ERROR, TFLAG_IOCTL,(" IOCTL_(0x%x, Func %d) failed %!STATUS!", _IoControlCode, ControlCode, Status));
        WdfRequestComplete(_Request, Status);
        return;
    }        

    return;
}


Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS