windows-nt/Source/XPSP1/NT/drivers/wdm/input/hidclass/device.c

896 lines
29 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
device.c
Abstract
Resource management routines for devices and collections
Author:
ervinp
Environment:
Kernel mode only
Revision History:
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, HidpStartDevice)
#pragma alloc_text(PAGE, HidpStartCollectionPDO)
#pragma alloc_text(PAGE, AllocDeviceResources)
#pragma alloc_text(PAGE, FreeDeviceResources)
#pragma alloc_text(PAGE, AllocCollectionResources)
#pragma alloc_text(PAGE, FreeCollectionResources)
#pragma alloc_text(PAGE, InitializeCollection)
#pragma alloc_text(PAGE, HidpCleanUpFdo)
#pragma alloc_text(PAGE, HidpRemoveDevice)
#pragma alloc_text(PAGE, HidpRemoveCollection)
#endif
/*
********************************************************************************
* AllocDeviceResources
********************************************************************************
*
*
*/
NTSTATUS AllocDeviceResources(FDO_EXTENSION *fdoExt)
{
ULONG numCollections;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
/*
* This will allocate fdoExt->rawReportDescription
*/
status = HidpGetDeviceDescriptor(fdoExt);
if (NT_SUCCESS(status)){
/*
* Ask HIDPARSE to fill in the HIDP_DEVICE_DESC for this device.
*/
status = HidP_GetCollectionDescription(
fdoExt->rawReportDescription,
fdoExt->rawReportDescriptionLength,
NonPagedPool,
&fdoExt->deviceDesc);
if (NT_SUCCESS(status)){
fdoExt->devDescInitialized = TRUE;
numCollections = fdoExt->deviceDesc.CollectionDescLength;
ASSERT(numCollections);
fdoExt->classCollectionArray = ALLOCATEPOOL(NonPagedPool, numCollections*sizeof(HIDCLASS_COLLECTION));
if (!fdoExt->classCollectionArray){
fdoExt->classCollectionArray = BAD_POINTER;
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
RtlZeroMemory(fdoExt->classCollectionArray, numCollections*sizeof(HIDCLASS_COLLECTION));
}
}
}
else {
fdoExt->rawReportDescription = BAD_POINTER;
}
DBGSUCCESS(status, FALSE)
return status;
}
/*
********************************************************************************
* FreeDeviceResources
********************************************************************************
*
*
*/
VOID FreeDeviceResources(FDO_EXTENSION *fdoExt)
{
ULONG i;
PAGED_CODE();
for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++) {
FreeCollectionResources(fdoExt, fdoExt->classCollectionArray[i].CollectionNumber);
}
/*
* Free the stuff returned by HIDPARSE's HidP_GetCollectionDescription.
*/
if (fdoExt->devDescInitialized){
HidP_FreeCollectionDescription(&fdoExt->deviceDesc);
#if DBG
fdoExt->deviceDesc.CollectionDesc = BAD_POINTER;
fdoExt->deviceDesc.ReportIDs = BAD_POINTER;
#endif
}
fdoExt->deviceDesc.CollectionDescLength = 0;
/*
* Free the raw report descriptor allocated during START_DEVICE by HidpGetDeviceDescriptor().
*/
if (ISPTR(fdoExt->rawReportDescription)){
ExFreePool(fdoExt->rawReportDescription);
}
fdoExt->rawReportDescription = BAD_POINTER;
if (ISPTR(fdoExt->classCollectionArray)){
ExFreePool(fdoExt->classCollectionArray);
}
fdoExt->classCollectionArray = BAD_POINTER;
}
/*
********************************************************************************
* AllocCollectionResources
********************************************************************************
*
*
*/
NTSTATUS AllocCollectionResources(FDO_EXTENSION *fdoExt, ULONG collectionNum)
{
PHIDCLASS_COLLECTION collection;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
collection = GetHidclassCollection(fdoExt, collectionNum);
if (collection){
ULONG descriptorLen;
descriptorLen = collection->hidCollectionInfo.DescriptorSize;
if (descriptorLen){
collection->phidDescriptor = ALLOCATEPOOL(NonPagedPool, descriptorLen);
if (collection->phidDescriptor){
status = HidpGetCollectionDescriptor(
fdoExt,
collection->CollectionNumber,
collection->phidDescriptor,
&descriptorLen);
}
else {
collection->phidDescriptor = BAD_POINTER;
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(status)){
ULONG i = collection->CollectionIndex;
ULONG inputLength;
ASSERT(fdoExt->devDescInitialized);
inputLength = fdoExt->deviceDesc.CollectionDesc[i].InputLength;
if (inputLength){
if (collection->hidCollectionInfo.Polled){
collection->cookedInterruptReportBuf = BAD_POINTER;
}
else {
collection->cookedInterruptReportBuf = ALLOCATEPOOL(NonPagedPool, inputLength);
if (!collection->cookedInterruptReportBuf){
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
fdoExt->isOutputOnlyDevice = FALSE;
}
else {
/*
* This is an output-only device (e.g. USB monitor)
*/
DBGWARN(("Zero input length -> output-only device."))
collection->cookedInterruptReportBuf = BAD_POINTER;
}
}
}
else {
ASSERT(descriptorLen > 0);
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
else {
status = STATUS_DEVICE_DATA_ERROR;
}
DBGSUCCESS(status, TRUE)
return status;
}
/*
********************************************************************************
* FreeCollectionResources
********************************************************************************
*
*
*/
VOID FreeCollectionResources(FDO_EXTENSION *fdoExt, ULONG collectionNum)
{
PHIDCLASS_COLLECTION collection;
PAGED_CODE();
collection = GetHidclassCollection(fdoExt, collectionNum);
if (collection){
if (collection->hidCollectionInfo.Polled){
if (ISPTR(collection->savedPolledReportBuf)){
ExFreePool(collection->savedPolledReportBuf);
}
collection->savedPolledReportBuf = BAD_POINTER;
}
else {
if (ISPTR(collection->cookedInterruptReportBuf)){
ExFreePool(collection->cookedInterruptReportBuf);
}
else {
// this is an output-only collection
}
}
collection->cookedInterruptReportBuf = BAD_POINTER;
if (ISPTR(collection->phidDescriptor)){
ExFreePool(collection->phidDescriptor);
}
collection->phidDescriptor = BAD_POINTER;
}
else {
TRAP;
}
}
/*
********************************************************************************
* InitializeCollection
********************************************************************************
*
*
*/
NTSTATUS InitializeCollection(FDO_EXTENSION *fdoExt, ULONG collectionIndex)
{
PHIDCLASS_COLLECTION collection;
ULONG descriptorBufLen;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT(ISPTR(fdoExt->classCollectionArray));
collection = &fdoExt->classCollectionArray[collectionIndex];
RtlZeroMemory(collection, sizeof(HIDCLASS_COLLECTION));
ASSERT(fdoExt->devDescInitialized);
collection->CollectionNumber = fdoExt->deviceDesc.CollectionDesc[collectionIndex].CollectionNumber;
collection->CollectionIndex = collectionIndex;
InitializeListHead(&collection->FileExtensionList);
KeInitializeSpinLock(&collection->FileExtensionListSpinLock);
KeInitializeSpinLock(&collection->powerEventSpinLock);
KeInitializeSpinLock(&collection->secureReadLock);
collection->secureReadMode = 0;
descriptorBufLen = sizeof(HID_COLLECTION_INFORMATION);
status = HidpGetCollectionInformation( fdoExt,
collection->CollectionNumber,
&collection->hidCollectionInfo,
&descriptorBufLen);
DBGSUCCESS(status, TRUE)
return status;
}
void
HidpGetRemoteWakeEnableState(
PDO_EXTENSION *pdoExt
)
{
HANDLE hKey;
NTSTATUS status;
ULONG tmp;
BOOLEAN wwEnableFound;
hKey = NULL;
wwEnableFound = FALSE;
status = IoOpenDeviceRegistryKey (pdoExt->pdo,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_ALL,
&hKey);
if (NT_SUCCESS (status)) {
UNICODE_STRING valueName;
ULONG length;
ULONG value;
PKEY_VALUE_FULL_INFORMATION fullInfo;
PAGED_CODE();
RtlInitUnicodeString (&valueName, HIDCLASS_REMOTE_WAKE_ENABLE);
length = sizeof (KEY_VALUE_FULL_INFORMATION)
+ valueName.MaximumLength
+ sizeof(value);
fullInfo = ExAllocatePool (PagedPool, length);
if (fullInfo) {
status = ZwQueryValueKey (hKey,
&valueName,
KeyValueFullInformation,
fullInfo,
length,
&length);
if (NT_SUCCESS (status)) {
DBGASSERT (sizeof(value) == fullInfo->DataLength,
("Value data wrong length for REmote wake reg value."),
TRUE);
RtlCopyMemory (&value,
((PUCHAR) fullInfo) + fullInfo->DataOffset,
fullInfo->DataLength);
pdoExt->remoteWakeEnabled = (value ? TRUE : FALSE);
}
ExFreePool (fullInfo);
}
ZwClose (hKey);
hKey = NULL;
}
}
WMIGUIDREGINFO HidClassWmiGuidList =
{
&GUID_POWER_DEVICE_WAKE_ENABLE,
1,
0 // wait wake
};
WMIGUIDREGINFO HidClassFdoWmiGuidList =
{
&GUID_POWER_DEVICE_ENABLE,
1,
0
};
/*
********************************************************************************
* HidpStartCollectionPDO
********************************************************************************
*
*
*/
NTSTATUS HidpStartCollectionPDO(FDO_EXTENSION *fdoExt, PDO_EXTENSION *pdoExt, PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
/*
* Initialize the collection only if it's not already initialized.
* This is so we don't destroy the FileExtensionList after a STOP/START.
*/
if (pdoExt->state == COLLECTION_STATE_UNINITIALIZED){
pdoExt->state = COLLECTION_STATE_INITIALIZED;
}
if (NT_SUCCESS(status)){
PHIDCLASS_COLLECTION collection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
if (collection){
/*
* If all collection PDOs for this device FDO are initialized,
* figure out the maximum report size and finish starting the device.
*/
if (AnyClientPDOsInitialized(fdoExt, TRUE)){
DBGSTATE(fdoExt->state, DEVICE_STATE_START_SUCCESS, FALSE)
/*
* If this is a polled collection,
* start the background polling loop FOR EACH COLLECTION.
* Otherwise, if it's an ordinary interrupt collection,
* start the ping-pong IRPs for it.
*/
if (collection->hidCollectionInfo.Polled){
if (HidpSetMaxReportSize(fdoExt)){
ULONG i;
for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++){
PHIDCLASS_COLLECTION ctn;
ctn = &fdoExt->classCollectionArray[i];
/*
* If one of the collections is polled, they
* should ALL be polled.
*/
ASSERT(ctn->hidCollectionInfo.Polled);
ctn->PollInterval_msec = DEFAULT_POLL_INTERVAL_MSEC;
/*
* Allocate the buffer for saving the polled device's
* last report. Allocate one more byte than the max
* report size for the device in case we have to
* prepend a report id byte.
*/
ctn->savedPolledReportBuf = ALLOCATEPOOL(NonPagedPool, fdoExt->maxReportSize+1);
if (ctn->savedPolledReportBuf){
ctn->polledDataIsStale = TRUE;
StartPollingLoop(fdoExt, ctn, TRUE);
status = STATUS_SUCCESS;
}
else {
ASSERT(ctn->savedPolledReportBuf);
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
}
else if (fdoExt->isOutputOnlyDevice){
/*
* Don't start ping-pong IRPs.
*/
}
else {
status = HidpStartAllPingPongs(fdoExt);
}
}
if (NT_SUCCESS(status)) {
pdoExt->state = COLLECTION_STATE_RUNNING;
#if DBG
collection->Signature = HIDCLASS_COLLECTION_SIG;
#endif
/*
* Create the 'file-name' used by clients to open this device.
*/
HidpCreateSymbolicLink(pdoExt, pdoExt->collectionNum, TRUE, pdoExt->pdo);
if (!pdoExt->MouseOrKeyboard &&
WAITWAKE_SUPPORTED(fdoExt)) {
//
// register for the wait wake guid as well
//
pdoExt->WmiLibInfo.GuidCount = sizeof (HidClassWmiGuidList) /
sizeof (WMIGUIDREGINFO);
ASSERT (1 == pdoExt->WmiLibInfo.GuidCount);
//
// See if the user has enabled remote wake for the device
// PRIOR to registering with WMI.
//
HidpGetRemoteWakeEnableState(pdoExt);
pdoExt->WmiLibInfo.GuidList = &HidClassWmiGuidList;
pdoExt->WmiLibInfo.QueryWmiRegInfo = HidpQueryWmiRegInfo;
pdoExt->WmiLibInfo.QueryWmiDataBlock = HidpQueryWmiDataBlock;
pdoExt->WmiLibInfo.SetWmiDataBlock = HidpSetWmiDataBlock;
pdoExt->WmiLibInfo.SetWmiDataItem = HidpSetWmiDataItem;
pdoExt->WmiLibInfo.ExecuteWmiMethod = NULL;
pdoExt->WmiLibInfo.WmiFunctionControl = NULL;
IoWMIRegistrationControl(pdoExt->pdo, WMIREG_ACTION_REGISTER);
if (SHOULD_SEND_WAITWAKE(pdoExt)) {
HidpCreateRemoteWakeIrp(pdoExt);
}
}
if (AllClientPDOsInitialized(fdoExt, TRUE)){
HidpStartIdleTimeout(fdoExt, TRUE);
}
}
}
else {
status = STATUS_DEVICE_DATA_ERROR;
}
}
DBGSUCCESS(status, FALSE)
return status;
}
/*
********************************************************************************
* HidpStartDevice
********************************************************************************
*
*
*/
NTSTATUS HidpStartDevice(PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, PIRP Irp)
{
FDO_EXTENSION *fdoExt;
enum deviceState previousState;
NTSTATUS status;
ULONG i;
PAGED_CODE();
ASSERT(!HidDeviceExtension->isClientPdo);
fdoExt = &HidDeviceExtension->fdoExt;
previousState = fdoExt->state;
fdoExt->state = DEVICE_STATE_STARTING;
/*
* Get the power-state conversion table
*/
status = HidpQueryDeviceCapabilities(
HidDeviceExtension->hidExt.PhysicalDeviceObject,
&fdoExt->deviceCapabilities);
if (NT_SUCCESS(status)){
/*
* Alert the rest of the driver stack that the device is starting.
*/
IoCopyCurrentIrpStackLocationToNext(Irp);
status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
if (NT_SUCCESS(status)){
/*
* If we're just resuming from STOP,
* there's nothing else to do;
* otherwise, need to call down the USB stack
* for some info and allocate some resources.
*/
if (previousState == DEVICE_STATE_INITIALIZED){
status = AllocDeviceResources(fdoExt);
if (NT_SUCCESS(status)){
/*
* Assume this is an output-only device until we start
* a collection-pdo which handles inputs.
* Only set fdoExt->isOutputOnlyDevice on the first start
* not on a subsequent start following a stop.
*/
fdoExt->isOutputOnlyDevice = TRUE;
/*
* Initialize WMI stuff
*/
fdoExt->WmiLibInfo.GuidCount = sizeof(HidClassFdoWmiGuidList) /
sizeof (WMIGUIDREGINFO);
fdoExt->WmiLibInfo.GuidList = &HidClassFdoWmiGuidList;
fdoExt->WmiLibInfo.QueryWmiRegInfo = HidpQueryWmiRegInfo;
fdoExt->WmiLibInfo.QueryWmiDataBlock = HidpQueryWmiDataBlock;
fdoExt->WmiLibInfo.SetWmiDataBlock = HidpSetWmiDataBlock;
fdoExt->WmiLibInfo.SetWmiDataItem = HidpSetWmiDataItem;
fdoExt->WmiLibInfo.ExecuteWmiMethod = NULL;
fdoExt->WmiLibInfo.WmiFunctionControl = NULL;
/*
* Allocate all the collection resources before allocating
* the pingpong irps, so that we can set a maximum report
* size.
*/
for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++) {
// If one of these fails, we will clean up properly
// in the remove routine, so there's no need to
// bother cleaning up here.
status = InitializeCollection(fdoExt, i);
if (!NT_SUCCESS(status)){
break;
}
status = AllocCollectionResources(fdoExt, fdoExt->deviceDesc.CollectionDesc[i].CollectionNumber);
if (!NT_SUCCESS(status)){
break;
}
}
/*
* We need ot allocate the pingpongs in the fdo start
* routine due to race conditions introduced by selective
* suspend.
*/
if (!fdoExt->isOutputOnlyDevice &&
!fdoExt->driverExt->DevicesArePolled) {
status = HidpReallocPingPongIrps(fdoExt, MIN_PINGPONG_IRPS);
}
if (NT_SUCCESS(status)){
/*
* We will have to create an array of PDOs, one for each device class.
* The following call will cause NTKERN to call us back with
* IRP_MN_QUERY_DEVICE_RELATIONS and initialize its collection-PDOs.
*/
IoInvalidateDeviceRelations(HidDeviceExtension->hidExt.PhysicalDeviceObject, BusRelations);
}
}
}
else if (previousState == DEVICE_STATE_STOPPED){
//
// Any request that comes in when we are in low power will be
// dealt with at that time
//
DBGSTATE(fdoExt->prevState, DEVICE_STATE_START_SUCCESS, TRUE)
}
else {
TRAP;
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
if (NT_SUCCESS(status)){
fdoExt->state = DEVICE_STATE_START_SUCCESS;
#if WIN95_BUILD
/*
* Send down the WaitWake IRP.
* This allows the device to wake up the system.
*
* Note: On Win98 there is no way for a client to
* send a WaitWake IRP. Therefore we initiate
* a WaitWake IRP for every device, not just
* if a client sends us a WaitWake IRP, like on NT.
*/
/*
* We could have been suspended, stopped, then started again. In
* this case, we need to not send a WW irp because we already have
* on pending.
*/
if (fdoExt->deviceCapabilities.SystemWake > PowerSystemWorking) {
SubmitWaitWakeIrp(HidDeviceExtension);
}
#endif
#if DBG
{
ULONG i;
// Win98 doesn't have good debug extensions
DBGVERBOSE(("Started fdoExt %ph with %d collections: ", fdoExt, fdoExt->deviceDesc.CollectionDescLength))
for (i = 0; i < fdoExt->deviceDesc.CollectionDescLength; i++){
DBGVERBOSE((" - collection #%d: (in=%xh,out=%xh,feature=%xh) usagePage %xh, usage %xh ",
fdoExt->deviceDesc.CollectionDesc[i].CollectionNumber,
fdoExt->deviceDesc.CollectionDesc[i].InputLength,
fdoExt->deviceDesc.CollectionDesc[i].OutputLength,
fdoExt->deviceDesc.CollectionDesc[i].FeatureLength,
fdoExt->deviceDesc.CollectionDesc[i].UsagePage,
fdoExt->deviceDesc.CollectionDesc[i].Usage))
}
}
#endif
}
else {
fdoExt->state = DEVICE_STATE_START_FAILURE;
}
DBGSUCCESS(status, FALSE)
return status;
}
VOID
HidpCleanUpFdo(FDO_EXTENSION *fdoExt)
{
PAGED_CODE();
if (fdoExt->openCount == 0){
/*
* This is the last CLOSE on an alreay-removed device.
*
* Free resources and the FDO name
* (wPdoName that was allocated in HidpAddDevice);
*
*/
DequeueFdoExt(fdoExt);
FreeDeviceResources(fdoExt);
RtlFreeUnicodeString(&fdoExt->name);
IoWMIRegistrationControl(fdoExt->fdo, WMIREG_ACTION_DEREGISTER);
/*
* Delete the device-FDO and all collection-PDOs
* Don't touch fdoExt after this.
*/
HidpDeleteDeviceObjects(fdoExt);
}
}
/*
********************************************************************************
* HidpRemoveDevice
********************************************************************************
*
*/
NTSTATUS HidpRemoveDevice(FDO_EXTENSION *fdoExt, IN PIRP Irp)
{
BOOLEAN proceedWithRemove;
NTSTATUS status;
PIRP IdleIrp;
PAGED_CODE();
/*
* All collection-PDOs should have been removed by now,
* but we want to verify this.
* Only allow removal of this device-FDO if all the
* collection-PDOs are removed
* (or if they never got created in the first place).
*/
if (fdoExt->prevState == DEVICE_STATE_START_FAILURE){
proceedWithRemove = TRUE;
}
else if (fdoExt->prevState == DEVICE_STATE_STOPPED){
/*
* If a device fails to initialize, it may get
* STOP_DEVICE before being removed, so we want to
* go ahead and remove it without calling
* AllClientPDOsInitialized, which accesses some
* data which may not have been initialized.
* In this case we're never checking for the
* case that the device was initialized successfully,
* then stopped, and then removed without its
* collection-PDOs being removed; but this is an
* illegal case, so we'll just punt on it.
*/
proceedWithRemove = TRUE;
}
else if (AllClientPDOsInitialized(fdoExt, FALSE)){
proceedWithRemove = TRUE;
}
else {
/*
* This shouldn't happen -- all the collection-PDOs
* should have been removed before the device-FDO.
*/
DBGERR(("State of fdo %x state is %d",fdoExt->fdo,fdoExt->state))
TRAP;
proceedWithRemove = FALSE;
}
if (proceedWithRemove){
PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension =
CONTAINING_RECORD(fdoExt, HIDCLASS_DEVICE_EXTENSION, fdoExt);
DBGASSERT((fdoExt->state == DEVICE_STATE_REMOVING ||
fdoExt->state == DEVICE_STATE_INITIALIZED ||
fdoExt->state == DEVICE_STATE_START_FAILURE),
("Device is in incorrect state: %x", fdoExt->state),
TRUE)
if (ISPTR(fdoExt->waitWakeIrp)){
IoCancelIrp(fdoExt->waitWakeIrp);
fdoExt->waitWakeIrp = BAD_POINTER;
}
HidpCancelIdleNotification(fdoExt, TRUE);
if (ISPTR(fdoExt->idleNotificationRequest)) {
IoFreeIrp(fdoExt->idleNotificationRequest);
fdoExt->idleNotificationRequest = BAD_POINTER;
}
while (IdleIrp = DequeuePowerDelayedIrp(fdoExt)) {
IdleIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(IdleIrp, IO_NO_INCREMENT);
}
DestroyPingPongs(fdoExt);
/*
* Note: THE ORDER OF THESE ACTIONS IS VERY CRITICAL
*/
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (Irp);
status = HidpCallDriver(fdoExt->fdo, Irp);
fdoExt->state = DEVICE_STATE_REMOVED;
DerefDriverExt(fdoExt->driverExt->MinidriverObject);
fdoExt->driverExt = BAD_POINTER;
/*
* After Detach we can no longer send IRPS to this device
* object as it will be GONE!
*/
IoDetachDevice(HidDeviceExtension->hidExt.NextDeviceObject);
/*
* If all client handles on this device have been closed,
* destroy the objects and our context for it;
* otherwise, we'll do this when the last client closes
* their handle.
*
* On NT we can only get here if all our creates have been closed, so
* this is unnecessary, but on Win9x, a remove can be sent with valid
* opens against the stack.
*
* Don't touch fdoExt after this.
*/
HidpCleanUpFdo(fdoExt);
}
else {
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
DBGSUCCESS(status, FALSE)
return status;
}
/*
********************************************************************************
* HidpRemoveCollection
********************************************************************************
*
*/
VOID HidpRemoveCollection(FDO_EXTENSION *fdoExt, PDO_EXTENSION *pdoExt, IN PIRP Irp)
{
PAGED_CODE();
//
// This pdo is no longer available as it has been removed.
// It should still be returned for each Query Device Relations
// IRPS to the HID bus, but it itself should respond to all
// IRPS with STATUS_DELETE_PENDING.
//
if (pdoExt->prevState == COLLECTION_STATE_UNINITIALIZED || // for started pdos
pdoExt->state == COLLECTION_STATE_UNINITIALIZED){ // For unstarted pdos
pdoExt->state = COLLECTION_STATE_UNINITIALIZED;
DBGVERBOSE(("HidpRemoveCollection: collection uninitialized."))
}
else {
ULONG ctnIndx = pdoExt->collectionIndex;
PHIDCLASS_COLLECTION collection = &fdoExt->classCollectionArray[ctnIndx];
ULONG numReportIDs = fdoExt->deviceDesc.ReportIDsLength;
PIRP remoteWakeIrp;
if (!pdoExt->MouseOrKeyboard &&
WAITWAKE_SUPPORTED(fdoExt)) {
//
// Unregister for remote wakeup.
//
IoWMIRegistrationControl (pdoExt->pdo, WMIREG_ACTION_DEREGISTER);
}
remoteWakeIrp = (PIRP)
InterlockedExchangePointer(&pdoExt->remoteWakeIrp, NULL);
if (remoteWakeIrp) {
IoCancelIrp(remoteWakeIrp);
}
pdoExt->state = COLLECTION_STATE_UNINITIALIZED;
/*
* Destroy this collection.
* This will also abort all pending reads on this collection-PDO.
*/
HidpDestroyCollection(fdoExt, collection);
}
DBGVERBOSE(("HidpRemoveCollection: removed pdo %ph (refCount=%xh)", pdoExt->pdo, (ULONG)(*(((PUCHAR)pdoExt->pdo)-0x18))))
}