summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRahul Ramadas <[email protected]>2019-11-12 10:52:06 -0800
committerAdonais Romero González <[email protected]>2019-11-12 10:52:06 -0800
commitd805073e39ec65e391b4fc2141ecb2120755a76c (patch)
tree0ebe5f2f293cd147762dc8562e262c00c56f41f9
parenta354bc3a60e2ad00dc3c763de694738a7d0eb396 (diff)
Update the Bluetooth Serial HCI Bus Driver sample to exemplify PLDR (#438)99498
-rw-r--r--bluetooth/serialhcibus/WDK/device.c23
-rw-r--r--bluetooth/serialhcibus/driver.h61
-rw-r--r--bluetooth/serialhcibus/pdo.c342
3 files changed, 357 insertions, 69 deletions
diff --git a/bluetooth/serialhcibus/WDK/device.c b/bluetooth/serialhcibus/WDK/device.c
index 11859e9f..a78088cf 100644
--- a/bluetooth/serialhcibus/WDK/device.c
+++ b/bluetooth/serialhcibus/WDK/device.c
@@ -255,3 +255,26 @@ Return Value:
return STATUS_SUCCESS;
}
+_Use_decl_annotations_
+VOID
+DeviceDoPLDR(
+ WDFDEVICE _Fdo
+ )
+/*++
+
+Routine Description:
+
+ This vendor-specific routine takes appropriate actions necessary to fully reset the device.
+
+Arguments:
+
+ _Fdo - Framework device object representing the FDO.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(_Fdo);
+}
diff --git a/bluetooth/serialhcibus/driver.h b/bluetooth/serialhcibus/driver.h
index 4d9decca..bb006ece 100644
--- a/bluetooth/serialhcibus/driver.h
+++ b/bluetooth/serialhcibus/driver.h
@@ -28,6 +28,7 @@ Environment:
#define INITGUID
#include <guiddef.h>
+#include <wdmguid.h>
#include <ntddser.h> // Constants and types for access Serial device
#include <BthXDDI.h> // BT Extensible Transport DDI
@@ -80,6 +81,40 @@ typedef enum _IDLE_CAP_STATE {
IdleCapCanTurnOff = 3 // Can enter D3 (off) and not remote wake to save max power while device is off.
} IDLE_CAP_STATE;
+//
+// Reset recovery support capability. Multiple implementations are provided to choose from and
+// customize as appropriate.
+//
+typedef enum _RESET_RECOVERY_SUPPORT_TYPE {
+ ResetRecoveryTypeNone = 0, // Reset-recovery is not implemented in the driver. This may be
+ // used if the stack does not support reset-recovery at all, or
+ // if ACPI firmware already implements reset-recovery in the context
+ // of the child device stack (i.e., the stack that loads on the
+ // PDO created by this driver). In that case, the bus driver does
+ // not need any additional code to support reset-recovery. However,
+ // it does need to support GUID_REENUMERATE_SELF_INTERFACE_STANDARD,
+ // which is most easily achieved by using WDF dynamic-enumeration
+ // for creating PDOs.
+
+ ResetRecoveryTypeParentResetInterface = 1, // Delegate to GUID_DEVICE_RESET_INTERFACE_STANDARD
+ // support in the parent stack. The parent stack, i.e., the
+ // stack on which this driver loads as the FDO, must have
+ // support for GUID_DEVICE_RESET_INTERFACE_STANDARD. This is
+ // typically provided by the ACPI bus driver, if the ACPI device
+ // supports D3Cold (_PR3) or a power resource for reset (_PRR +
+ // _RST). See the documentation of
+ // GUID_DEVICE_RESET_INTERFACE_STANDARD for more information.
+
+ ResetRecoveryTypeDriverImplemented = 2, // Reset recovery is implemented in the driver.
+ // Hardware-specific techniques are used to power-cycle the controller.
+
+} RESET_RECOVERY_TYPE;
+
+//
+// Driver author may choose whichever reset-recovery strategy works best for their platform.
+//
+#define SUPPORTED_RESET_RECOVERY_TYPE ResetRecoveryTypeDriverImplemented
+
#ifdef DYNAMIC_ENUM
//
// The goal of the identification and address description abstractions is that enough
@@ -304,6 +339,11 @@ typedef struct _PDO_EXTENSION
//
ULONG SerialNo;
+ //
+ // Type of reset-recovery support implemented.
+ //
+ RESET_RECOVERY_TYPE ResetRecoveryType;
+
} PDO_EXTENSION, *PPDO_EXTENSION;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_EXTENSION, PdoGetExtension)
@@ -383,8 +423,17 @@ EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FdoIoQuDeviceControl;
// PDO creation
#ifdef DYNAMIC_ENUM
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PdoResetHandlerDynamic(_In_ PVOID _InterfaceContext,
+ _In_ DEVICE_RESET_TYPE _ResetType,
+ _In_ ULONG _Flags,
+ _In_opt_ PVOID _ResetParameters);
+
EVT_WDF_CHILD_LIST_CREATE_DEVICE FdoEvtDeviceListCreatePdo;
+_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
PdoCreateDynamic(_In_ WDFDEVICE Device,
_In_ PWDFDEVICE_INIT DeviceInit,
@@ -430,6 +479,13 @@ EVT_WDF_DEVICE_D0_EXIT PdoDevD0Exit;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PdoIoQuDeviceControl;
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+PdoResetHandler(_In_ PVOID _InterfaceContext,
+ _In_ DEVICE_RESET_TYPE _ResetType,
+ _In_ ULONG _Flags,
+ _In_opt_ PVOID _ResetParameters);
+
NTSTATUS
PdoCreate(_In_ WDFDEVICE _Device,
_In_ PWSTR _HardwareIds,
@@ -508,6 +564,7 @@ DevicePowerOn(_In_ WDFDEVICE _Device);
NTSTATUS
DevicePowerOff(_In_ WDFDEVICE _Device);
-#endif
-
+VOID
+DeviceDoPLDR(_In_ WDFDEVICE _Fdo);
+#endif
diff --git a/bluetooth/serialhcibus/pdo.c b/bluetooth/serialhcibus/pdo.c
index 74ee6350..48e4abd1 100644
--- a/bluetooth/serialhcibus/pdo.c
+++ b/bluetooth/serialhcibus/pdo.c
@@ -26,21 +26,81 @@ Environment:
#pragma alloc_text(PAGE, PdoDevD0Entry)
#pragma alloc_text(PAGE, PdoDevPrepareHardware)
#pragma alloc_text(PAGE, PdoDevReleaseHardware)
-#endif
+#pragma alloc_text(PAGE, PdoResetHandler)
+#ifdef DYNAMIC_ENUM
+#pragma alloc_text(PAGE, PdoCreateDynamic)
+#pragma alloc_text(PAGE, PdoResetHandlerDynamic)
+#endif // DYNAMIC_ENUM
+#endif // ALLOC_PRAGMA
#define MAX_ID_LEN 80
+#ifdef DYNAMIC_ENUM
+_Use_decl_annotations_
+NTSTATUS
+PdoResetHandlerDynamic(
+ PVOID _InterfaceContext,
+ DEVICE_RESET_TYPE _ResetType,
+ ULONG _Flags,
+ PVOID _ResetParameters
+ )
+/*++
-#ifdef DYNAMIC_ENUM
+Routine Description:
+
+ This is the reset handler invoked by a driver that queries our GUID_DEVICE_RESET_INTERFACE_STANDARD interface.
+ This is the version used if PDOs are created using WDF dynamic enumeration.
+
+Arguments:
+
+ _InterfaceContext - This is expected to be a PPDO_EXTENSION.
+
+ _ResetType - This is expected to be PlatformLevelDeviceReset because that is all we support.
+
+ _Flags - Unused, because no flags are defined currently.
+
+ _ResetParameters - Unused, because it is only used for FunctionLevelDeviceReset.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+{
+ PPDO_EXTENSION PdoExtension = (PPDO_EXTENSION) _InterfaceContext;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_Flags);
+ UNREFERENCED_PARAMETER(_ResetParameters);
+
+ if (_ResetType != PlatformLevelDeviceReset) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ DeviceDoPLDR(PdoExtension->FdoExtension->WdfDevice);
+
+ //
+ // The bus driver is expected to cause the device to be surprise removed as part of PLDR. For
+ // many hardware buses, this happens naturally, but for a software bus like us, we need to do it
+ // ourselves. WDF dynamic enumeration makes this convenient because it already supports
+ // GUID_REENUMERATE_SELF_INTERFACE_STANDARD, so we can simply call WdfDeviceSetFailed to
+ // re-enumerate the device.
+ //
+ WdfDeviceSetFailed((WDFDEVICE) WdfObjectContextGetObject(PdoExtension), WdfDeviceFailedAttemptRestart);
+ return STATUS_SUCCESS;
+}
+
+_Use_decl_annotations_
NTSTATUS
PdoCreateDynamic(
- _In_ WDFDEVICE _Device,
- _In_ PWDFDEVICE_INIT _DeviceInit,
- _In_ PWCHAR _HardwareIds,
- _In_ ULONG _SerialNo
+ WDFDEVICE _Device,
+ PWDFDEVICE_INIT _DeviceInit,
+ PWCHAR _HardwareIds,
+ ULONG _SerialNo
)
/*++
@@ -56,20 +116,20 @@ Return Value:
--*/
{
- 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;
-
+ 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;
+ WDF_QUERY_INTERFACE_CONFIG DeviceResetInterfaceConfig;
+ DEVICE_RESET_INTERFACE_STANDARD ResetInterface;
PAGED_CODE();
@@ -85,9 +145,9 @@ Return Value:
//
// Provide DeviceID, HardwareIDs, CompatibleIDs and InstanceId
//
- RtlInitUnicodeString(&deviceId, _HardwareIds);
+ RtlInitUnicodeString(&DeviceId, _HardwareIds);
- Status = WdfPdoInitAssignDeviceID(_DeviceInit, &deviceId);
+ Status = WdfPdoInitAssignDeviceID(_DeviceInit, &DeviceId);
if (!NT_SUCCESS(Status)) {
return Status;
}
@@ -95,22 +155,22 @@ Return Value:
//
// NOTE: same string is used to initialize hardware id too
//
- Status = WdfPdoInitAddHardwareID(_DeviceInit, &deviceId);
+ Status = WdfPdoInitAddHardwareID(_DeviceInit, &DeviceId);
if (!NT_SUCCESS(Status)) {
return Status;
}
- Status = WdfPdoInitAddCompatibleID(_DeviceInit, &compatId );
+ Status = WdfPdoInitAddCompatibleID(_DeviceInit, &CompatId );
if (!NT_SUCCESS(Status)) {
return Status;
}
- Status = RtlUnicodeStringPrintf(&buffer, L"%02d", _SerialNo);
+ Status = RtlUnicodeStringPrintf(&Buffer, L"%02d", _SerialNo);
if (!NT_SUCCESS(Status)) {
return Status;
}
- Status = WdfPdoInitAssignInstanceID(_DeviceInit, &buffer);
+ Status = WdfPdoInitAssignInstanceID(_DeviceInit, &Buffer);
if (!NT_SUCCESS(Status)) {
return Status;
}
@@ -124,7 +184,7 @@ Return Value:
// coinstallers to display in the device manager. FriendlyName takes
// precedence over the DeviceDesc from the INF file.
//
- Status = RtlUnicodeStringPrintf( &buffer,
+ Status = RtlUnicodeStringPrintf( &Buffer,
L"SerialHciBus_%02d",
_SerialNo );
if (!NT_SUCCESS(Status)) {
@@ -140,8 +200,8 @@ Return Value:
// WdfPdoInitSetDefaultLocale.
//
Status = WdfPdoInitAddDeviceText(_DeviceInit,
- &buffer,
- &deviceLocation,
+ &Buffer,
+ &DeviceLocation,
0x409 );
if (!NT_SUCCESS(Status)) {
return Status;
@@ -153,7 +213,7 @@ Return Value:
// 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);
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&PdoAttributes, PDO_EXTENSION);
//
// Allow to forward requests to its FDO of this bus driver by using
@@ -166,7 +226,7 @@ Return Value:
// to this call, framework creates a WDM deviceobject.
//
Status = WdfDeviceCreate(&_DeviceInit,
- &pdoAttributes,
+ &PdoAttributes,
&ChildDevice);
if (!NT_SUCCESS(Status)) {
@@ -191,7 +251,7 @@ Return Value:
PdoExtension->SerialNo = _SerialNo;
-
+ PdoExtension->ResetRecoveryType = SUPPORTED_RESET_RECOVERY_TYPE;
//
// Set some properties for the child device.
@@ -211,31 +271,31 @@ Return Value:
//
PnpCaps.SurpriseRemovalOK = WdfTrue;
- pnpCaps.Address = _SerialNo;
- pnpCaps.UINumber = _SerialNo;
+ PnpCaps.Address = _SerialNo;
+ PnpCaps.UINumber = _SerialNo;
- WdfDeviceSetPnpCapabilities(ChildDevice, &pnpCaps);
+ WdfDeviceSetPnpCapabilities(ChildDevice, &PnpCaps);
- WDF_DEVICE_POWER_CAPABILITIES_INIT(&powerCaps);
+ WDF_DEVICE_POWER_CAPABILITIES_INIT(&PowerCaps);
- powerCaps.DeviceD1 = WdfFalse;
- powerCaps.DeviceD2 = WdfTrue;
+ PowerCaps.DeviceD1 = WdfFalse;
+ PowerCaps.DeviceD2 = WdfTrue;
- powerCaps.WakeFromD0 = WdfFalse;
- powerCaps.WakeFromD1 = WdfFalse;
- powerCaps.WakeFromD2 = WdfTrue;
- powerCaps.WakeFromD3 = WdfTrue;
+ PowerCaps.WakeFromD0 = WdfFalse;
+ PowerCaps.WakeFromD1 = WdfFalse;
+ PowerCaps.WakeFromD2 = WdfTrue;
+ PowerCaps.WakeFromD3 = WdfTrue;
- powerCaps.DeviceWake = PowerDeviceD2;
+ 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;
+ 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);
+ WdfDeviceSetPowerCapabilities(ChildDevice, &PowerCaps);
//
@@ -263,7 +323,52 @@ Return Value:
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
-
+
+ if (PdoExtension->ResetRecoveryType == ResetRecoveryTypeParentResetInterface) {
+
+ //
+ // Instruct WDF to simply forward a request for the reset interface to the parent stack, so
+ // that it reaches the ACPI bus/filter driver. That way when the reset interface is invoked,
+ // it is the parent stack that gets reset and re-enumerated.
+ //
+
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&DeviceResetInterfaceConfig, NULL, &GUID_DEVICE_RESET_INTERFACE_STANDARD, NULL);
+ DeviceResetInterfaceConfig.SendQueryToParentStack = TRUE;
+
+ Status = WdfDeviceAddQueryInterface(ChildDevice, &DeviceResetInterfaceConfig);
+ if (!NT_SUCCESS(Status)) {
+ DoTrace(LEVEL_ERROR, TFLAG_PNP, ("WdfDeviceAddQueryInterface failed, %!STATUS!", Status));
+ goto Cleanup;
+ }
+
+ } else if (PdoExtension->ResetRecoveryType == ResetRecoveryTypeDriverImplemented) {
+
+ RtlZeroMemory(&ResetInterface, sizeof(ResetInterface));
+ ResetInterface.Size = sizeof(ResetInterface);
+ ResetInterface.Version = DEVICE_RESET_INTERFACE_VERSION;
+ ResetInterface.Context = PdoExtension;
+
+ //
+ // Since this interface is expected to be used only by drivers in the same stack, reference
+ // counting is not required. If there is an expectation that drivers may query for the
+ // interface using a remote I/O target to this stack (unusual for this interface), reference
+ // counting must be implemented.
+ //
+ ResetInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
+ ResetInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
+
+ ResetInterface.SupportedResetTypes = (1 << PlatformLevelDeviceReset);
+ ResetInterface.DeviceReset = PdoResetHandlerDynamic;
+
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&DeviceResetInterfaceConfig, (PINTERFACE) &ResetInterface, &GUID_DEVICE_RESET_INTERFACE_STANDARD, NULL);
+ Status = WdfDeviceAddQueryInterface(ChildDevice, &DeviceResetInterfaceConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ DoTrace(LEVEL_ERROR, TFLAG_PNP, ("WdfDeviceAddQueryInterface failed, %!STATUS!", Status));
+ goto Cleanup;
+ }
+ }
+
Cleanup:
@@ -291,7 +396,62 @@ Cleanup:
#endif
+_Use_decl_annotations_
+NTSTATUS
+PdoResetHandler(
+ PVOID _InterfaceContext,
+ DEVICE_RESET_TYPE _ResetType,
+ ULONG _Flags,
+ PVOID _ResetParameters
+)
+/*++
+
+Routine Description:
+
+ This is the reset handler invoked by a driver that queries our GUID_DEVICE_RESET_INTERFACE_STANDARD interface.
+ This is the version used if PDOs are created using WDF static enumeration.
+
+Arguments:
+
+ _InterfaceContext - This is expected to be a PPDO_EXTENSION.
+
+ _ResetType - This is expected to be PlatformLevelDeviceReset because that is all we support.
+
+ _Flags - Unused, because no flags are defined currently.
+
+ _ResetParameters - Unused, because it is only used for FunctionLevelDeviceReset.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+{
+ PPDO_EXTENSION PdoExtension = (PPDO_EXTENSION) _InterfaceContext;
+ WDFDEVICE Fdo = PdoExtension->FdoExtension->WdfDevice;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_Flags);
+ UNREFERENCED_PARAMETER(_ResetParameters);
+
+ if (_ResetType != PlatformLevelDeviceReset) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ DeviceDoPLDR(Fdo);
+
+ //
+ // The bus driver is expected to cause the device to be surprise removed as part of PLDR. For
+ // many hardware buses, this happens naturally, but for a software bus like us, we need to do it
+ // ourselves.
+ //
+ FdoRemoveOneChildDevice(Fdo, BLUETOOTH_FUNC_IDS);
+ FdoCreateOneChildDevice(Fdo, BT_PDO_HARDWARE_IDS, BLUETOOTH_FUNC_IDS);
+
+ return STATUS_SUCCESS;
+}
NTSTATUS
PdoCreate(
@@ -319,21 +479,23 @@ Return Value:
--*/
{
- 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;
+ 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;
+ WDF_QUERY_INTERFACE_CONFIG DeviceResetInterfaceConfig;
+ DEVICE_RESET_INTERFACE_STANDARD ResetInterface;
DoTrace(LEVEL_INFO, TFLAG_PNP, (" +PdoCreate: HWID(%S), compatID(%S)", _HardwareIds, BT_PDO_COMPATIBLE_IDS));
@@ -524,6 +686,7 @@ Return Value:
PdoExtension->SerialNo = _SerialNo;
+ PdoExtension->ResetRecoveryType = SUPPORTED_RESET_RECOVERY_TYPE;
//
// Set PnP and Power capabilities for this child device.
@@ -593,7 +756,52 @@ Return Value:
DoTrace(LEVEL_INFO, TFLAG_PNP, (" WdfIoQueueCreate (%!STATUS!)", Status));
if (!NT_SUCCESS(Status)) {
goto Cleanup;
- }
+ }
+
+ if (PdoExtension->ResetRecoveryType == ResetRecoveryTypeParentResetInterface) {
+
+ //
+ // Instruct WDF to simply forward a request for the reset interface to the parent stack, so
+ // that it reaches the ACPI bus/filter driver. That way when the reset interface is invoked,
+ // it is the parent stack that gets reset and re-enumerated.
+ //
+
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&DeviceResetInterfaceConfig, NULL, &GUID_DEVICE_RESET_INTERFACE_STANDARD, NULL);
+ DeviceResetInterfaceConfig.SendQueryToParentStack = TRUE;
+
+ Status = WdfDeviceAddQueryInterface(ChildDevice, &DeviceResetInterfaceConfig);
+ if (!NT_SUCCESS(Status)) {
+ DoTrace(LEVEL_ERROR, TFLAG_PNP, ("WdfDeviceAddQueryInterface failed, %!STATUS!", Status));
+ goto Cleanup;
+ }
+
+ } else if (PdoExtension->ResetRecoveryType == ResetRecoveryTypeDriverImplemented) {
+
+ RtlZeroMemory(&ResetInterface, sizeof(ResetInterface));
+ ResetInterface.Size = sizeof(ResetInterface);
+ ResetInterface.Version = DEVICE_RESET_INTERFACE_VERSION;
+ ResetInterface.Context = PdoExtension;
+
+ //
+ // Since this interface is expected to be used only by drivers in the same stack, reference
+ // counting is not required. If there is an expectation that drivers may query for the
+ // interface using a remote I/O target to this stack (unusual for this interface), reference
+ // counting must be implemented.
+ //
+ ResetInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
+ ResetInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
+
+ ResetInterface.SupportedResetTypes = (1 << PlatformLevelDeviceReset);
+ ResetInterface.DeviceReset = PdoResetHandler;
+
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&DeviceResetInterfaceConfig, (PINTERFACE) &ResetInterface, &GUID_DEVICE_RESET_INTERFACE_STANDARD, NULL);
+ Status = WdfDeviceAddQueryInterface(ChildDevice, &DeviceResetInterfaceConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ DoTrace(LEVEL_ERROR, TFLAG_PNP, ("WdfDeviceAddQueryInterface failed, %!STATUS!", Status));
+ goto Cleanup;
+ }
+ }
//
// Add this device to the FDO's collection of children.