|
|
/*++
Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved
Module Name:
pnp.c
Abstract:
This module contains general PnP and Power code for the i8042prt Driver.
Environment:
Kernel mode.
Revision History:
--*/ #include "i8042prt.h"
#include "i8042log.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, I8xAddDevice)
#pragma alloc_text(PAGE, I8xFilterResourceRequirements)
#pragma alloc_text(PAGE, I8xFindPortCallout)
#pragma alloc_text(PAGE, I8xManuallyRemoveDevice)
#pragma alloc_text(PAGE, I8xPnP)
#pragma alloc_text(PAGE, I8xPower)
#pragma alloc_text(PAGE, I8xRegisterDeviceInterface)
#pragma alloc_text(PAGE, I8xRemovePort)
#pragma alloc_text(PAGE, I8xSendIrpSynchronously)
#endif
NTSTATUS I8xAddDevice ( IN PDRIVER_OBJECT Driver, IN PDEVICE_OBJECT PDO ) /*++
Routine Description:
Adds a device to the stack and sets up the appropriate flags and device extension for the newly created device. Arguments:
Driver - The driver object PDO - the device that we are attaching ourselves on top of Return Value:
NTSTATUS result code.
--*/ { PCOMMON_DATA commonData; PIO_ERROR_LOG_PACKET errorLogEntry; PDEVICE_OBJECT device; NTSTATUS status = STATUS_SUCCESS; ULONG maxSize;
PAGED_CODE();
Print(DBG_PNP_TRACE, ("enter Add Device \n"));
maxSize = sizeof(PORT_KEYBOARD_EXTENSION) > sizeof(PORT_MOUSE_EXTENSION) ? sizeof(PORT_KEYBOARD_EXTENSION) : sizeof(PORT_MOUSE_EXTENSION);
status = IoCreateDevice(Driver, // driver
maxSize, // size of extension
NULL, // device name
FILE_DEVICE_8042_PORT, // device type ?? unknown at this time!!!
0, // device characteristics
FALSE, // exclusive
&device // new device
);
if (!NT_SUCCESS(status)) { return (status); }
RtlZeroMemory(device->DeviceExtension, maxSize);
commonData = GET_COMMON_DATA(device->DeviceExtension); commonData->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
if (commonData->TopOfStack == NULL) { //
// Not good; in only extreme cases will this fail
//
errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(Driver, (UCHAR)sizeof(IO_ERROR_LOG_PACKET)); if (errorLogEntry) { errorLogEntry->ErrorCode = I8042_ATTACH_DEVICE_FAILED; errorLogEntry->DumpDataSize = 0; errorLogEntry->SequenceNumber = 0; errorLogEntry->MajorFunctionCode = 0; errorLogEntry->IoControlCode = 0; errorLogEntry->RetryCount = 0; errorLogEntry->UniqueErrorValue = 0; errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_CONNECTED;
IoWriteErrorLogEntry (errorLogEntry); }
IoDeleteDevice (device); return STATUS_DEVICE_NOT_CONNECTED; }
ASSERT(commonData->TopOfStack);
commonData->Self = device; commonData->PDO = PDO; commonData->PowerState = PowerDeviceD0;
KeInitializeSpinLock(&commonData->InterruptSpinLock);
//
// Initialize the data consumption timer
//
KeInitializeTimer(&commonData->DataConsumptionTimer);
//
// Initialize the port DPC queue to log overrun and internal
// device errors.
//
KeInitializeDpc( &commonData->ErrorLogDpc, (PKDEFERRED_ROUTINE) I8042ErrorLogDpc, device );
//
// Initialize the device completion DPC for requests that exceed the
// maximum number of retries.
//
KeInitializeDpc( &commonData->RetriesExceededDpc, (PKDEFERRED_ROUTINE) I8042RetriesExceededDpc, device );
//
// Initialize the device completion DPC for requests that have timed out
//
KeInitializeDpc( &commonData->TimeOutDpc, (PKDEFERRED_ROUTINE) I8042TimeOutDpc, device );
//
// Initialize the port completion DPC object in the device extension.
// This DPC routine handles the completion of successful set requests.
//
IoInitializeDpcRequest(device, I8042CompletionDpc);
IoInitializeRemoveLock(&commonData->RemoveLock, I8042_POOL_TAG, 0, 0);
device->Flags |= DO_BUFFERED_IO; device->Flags |= DO_POWER_PAGABLE; device->Flags &= ~DO_DEVICE_INITIALIZING;
Print(DBG_PNP_TRACE, ("Add Device (0x%x)\n", status));
return status; }
NTSTATUS I8xSendIrpSynchronously ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN BOOLEAN Strict ) /*++
Routine Description:
Generic routine to send an irp DeviceObject and wait for its return up the device stack. Arguments:
DeviceObject - The device object to which we want to send the Irp Irp - The Irp we want to send Return Value:
return code from the Irp --*/ { KEVENT event; NTSTATUS status;
PAGED_CODE();
KeInitializeEvent(&event, SynchronizationEvent, FALSE );
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, I8xPnPComplete, &event, TRUE, TRUE, TRUE );
status = IoCallDriver(DeviceObject, Irp);
//
// Wait for lower drivers to be done with the Irp
//
if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; }
if (!Strict && (status == STATUS_NOT_SUPPORTED || status == STATUS_INVALID_DEVICE_REQUEST)) { status = STATUS_SUCCESS; }
return status; }
NTSTATUS I8xPnPComplete ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event ) /*++
Routine Description:
Completion routine for all PnP IRPs Arguments:
DeviceObject - Pointer to the DeviceObject
Irp - Pointer to the request packet Event - The event to set once processing is complete
Return Value:
STATUS_MORE_PROCESSING_REQUIRED
--*/ { UNREFERENCED_PARAMETER (DeviceObject); UNREFERENCED_PARAMETER (Irp);
//
// Since this completion routines sole purpose in life is to synchronize
// Irp, we know that unless something else happens that the IoCallDriver
// will unwind AFTER the we have complete this Irp. Therefore we should
// NOT bubble up the pending bit.
//
// if (Irp->PendingReturned) {
// IoMarkIrpPending(Irp);
// }
//
KeSetEvent(Event, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS I8xPnP ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
This is the dispatch routine for PnP requests Arguments:
DeviceObject - Pointer to the device object
Irp - Pointer to the request packet
Return Value:
STATUS_SUCCESSFUL if successful, an valid NTSTATUS error code otherwise
--*/ { PPORT_KEYBOARD_EXTENSION kbExtension; PPORT_MOUSE_EXTENSION mouseExtension; PCOMMON_DATA commonData; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_SUCCESS; KIRQL oldIrql;
PAGED_CODE();
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension); stack = IoGetCurrentIrpStackLocation(Irp);
status = IoAcquireRemoveLock(&commonData->RemoveLock, Irp); if (!NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status; }
Print(DBG_PNP_TRACE, ("I8xPnP (%s), enter (min func=0x%x)\n", commonData->IsKeyboard ? "kb" : "mou", (ULONG) stack->MinorFunction ));
switch (stack->MinorFunction) { case IRP_MN_START_DEVICE:
//
// The device is starting.
//
// We cannot touch the device (send it any non pnp irps) until a
// start device has been passed down to the lower drivers.
//
status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, TRUE);
if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { //
// As we are successfully now back from our start device
// we can do work.
ExAcquireFastMutexUnsafe(&Globals.DispatchMutex);
if (commonData->Started) { Print(DBG_PNP_ERROR, ("received 1+ starts on %s\n", commonData->IsKeyboard ? "kb" : "mouse" )); } else { //
// commonData->IsKeyboard is set during
// IOCTL_INTERNAL_KEYBOARD_CONNECT to TRUE and
// IOCTL_INTERNAL_MOUSE_CONNECT to FALSE
//
if (IS_KEYBOARD(commonData)) { status = I8xKeyboardStartDevice( (PPORT_KEYBOARD_EXTENSION) DeviceObject->DeviceExtension, stack->Parameters.StartDevice.AllocatedResourcesTranslated ); } else { status = I8xMouseStartDevice( (PPORT_MOUSE_EXTENSION) DeviceObject->DeviceExtension, stack->Parameters.StartDevice.AllocatedResourcesTranslated ); } if (NT_SUCCESS(status)) { InterlockedIncrement(&Globals.StartedDevices); commonData->Started = TRUE; } }
ExReleaseFastMutexUnsafe(&Globals.DispatchMutex); }
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: //
// The general rule of thumb for handling this minor code is this:
// add resources when the irp is going down the stack and
// remove resources when the irp is coming back up the stack
//
// The irp has the original resources on the way down.
//
status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE);
if (NT_SUCCESS(status)) { status = I8xFilterResourceRequirements(DeviceObject, Irp ); } else { Print(DBG_PNP_ERROR, ("error pending filter res req event (0x%x)\n", status )); } //
// Irp->IoStatus.Information will contain the new i/o resource
// requirements list so leave it alone
//
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
break; case IRP_MN_QUERY_PNP_DEVICE_STATE:
status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE); if (NT_SUCCESS(status)) { (PNP_DEVICE_STATE) Irp->IoStatus.Information |= commonData->PnpDeviceState; } else { Print(DBG_PNP_ERROR, ("error pending query pnp device state event (0x%x)\n", status ));
} //
// Irp->IoStatus.Information will contain the new i/o resource
// requirements list so leave it alone
//
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
//
// Don't let either of the requests succeed, otherwise the kb/mouse
// might be rendered useless.
//
// NOTE: this behavior is particular to i8042prt. Any other driver,
// especially any other keyboard or port driver, should
// succeed the query remove or stop. i8042prt has this different
// behavior because of the shared I/O ports but independent interrupts.
//
// FURTHERMORE, if you allow the query to succeed, it should be sent
// down the stack (see sermouse.sys for an example of how to do this)
//
case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: status = (MANUALLY_REMOVED(commonData) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
//
// If we succeed the irp, we must send it down the stack
//
if (NT_SUCCESS(status)) { IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(commonData->TopOfStack, Irp); } else { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } break;
//
// PnP rules dictate we send the IRP down to the PDO first
//
case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, FALSE);
Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
// case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_REMOVE_DEVICE: Print(DBG_PNP_INFO, ("(surprise) remove device (0x%x function 0x%x)\n", commonData->Self, (ULONG) stack->MinorFunction));
if (commonData->Initialized) { IoWMIRegistrationControl(commonData->Self, WMIREG_ACTION_DEREGISTER ); }
if (commonData->Started) { InterlockedDecrement(&Globals.StartedDevices); }
//
// Wait for any pending I/O to drain
//
IoReleaseRemoveLockAndWait(&commonData->RemoveLock, Irp);
ExAcquireFastMutexUnsafe(&Globals.DispatchMutex); if (IS_KEYBOARD(commonData)) { I8xKeyboardRemoveDevice(DeviceObject); } else { I8xMouseRemoveDevice(DeviceObject); } ExReleaseFastMutexUnsafe(&Globals.DispatchMutex);
//
// Set these flags so that when a surprise remove is sent, it will be
// handled just like a remove, and when the remove comes, no other
// removal type actions will occur.
//
commonData->Started = FALSE; commonData->Initialized = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(commonData->TopOfStack, Irp);
IoDetachDevice(commonData->TopOfStack); IoDeleteDevice(DeviceObject); return status;
case IRP_MN_QUERY_CAPABILITIES:
//
// Change the device caps to not allow wait wake requests on level
// triggered interrupts for mice because when an errant mouse movement
// occurs while we are going to sleep, the interrupt will remain
// triggered indefinitely.
//
// If the mouse does not have a level triggered interrupt, just let the
// irp go by...
//
if (commonData->Started && IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) {
Print(DBG_PNP_NOISE, ("query caps, mouse is level triggered\n"));
status = I8xSendIrpSynchronously(commonData->TopOfStack, Irp, TRUE); if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { PDEVICE_CAPABILITIES devCaps;
Print(DBG_PNP_INFO, ("query caps, removing wake caps\n"));
stack = IoGetCurrentIrpStackLocation(Irp); devCaps = stack->Parameters.DeviceCapabilities.Capabilities;
ASSERT(devCaps);
if (devCaps) { Print(DBG_PNP_NOISE, ("old DeviceWake was D%d and SystemWake was S%d.\n", devCaps->DeviceWake-1, devCaps->SystemWake-1 )) ;
devCaps->DeviceWake = PowerDeviceUnspecified; devCaps->SystemWake = PowerSystemUnspecified; } }
IoCompleteRequest(Irp, IO_NO_INCREMENT); break; }
case IRP_MN_STOP_DEVICE: case IRP_MN_QUERY_DEVICE_RELATIONS: case IRP_MN_QUERY_INTERFACE: case IRP_MN_QUERY_DEVICE_TEXT: case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: case IRP_MN_READ_CONFIG: case IRP_MN_WRITE_CONFIG: case IRP_MN_EJECT: case IRP_MN_SET_LOCK: case IRP_MN_QUERY_ID: default: //
// Here the driver below i8042prt might modify the behavior of these IRPS
// Please see PlugPlay documentation for use of these IRPs.
//
IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(commonData->TopOfStack, Irp); break; }
Print(DBG_PNP_TRACE, ("I8xPnP (%s) exit (status=0x%x)\n", commonData->IsKeyboard ? "kb" : "mou", status ));
IoReleaseRemoveLock(&commonData->RemoveLock, Irp);
return status; }
LONG I8xManuallyRemoveDevice( PCOMMON_DATA CommonData ) /*++
Routine Description:
Invalidates CommonData->PDO's device state and sets the manually removed flag Arguments:
CommonData - represent either the keyboard or mouse Return Value:
new device count for that particular type of device --*/ { LONG deviceCount;
PAGED_CODE();
if (IS_KEYBOARD(CommonData)) {
deviceCount = InterlockedDecrement(&Globals.AddedKeyboards); if (deviceCount < 1) { Print(DBG_PNP_INFO, ("clear kb (manually remove)\n")); CLEAR_KEYBOARD_PRESENT(); }
} else {
deviceCount = InterlockedDecrement(&Globals.AddedMice); if (deviceCount < 1) { Print(DBG_PNP_INFO, ("clear mou (manually remove)\n")); CLEAR_MOUSE_PRESENT(); } }
CommonData->PnpDeviceState |= PNP_DEVICE_REMOVED | PNP_DEVICE_DONT_DISPLAY_IN_UI; IoInvalidateDeviceState(CommonData->PDO);
return deviceCount; }
#define PhysAddrCmp(a,b) ( (a).LowPart == (b).LowPart && (a).HighPart == (b).HighPart )
BOOLEAN I8xRemovePort( IN PIO_RESOURCE_DESCRIPTOR ResDesc ) /*++
Routine Description:
If the physical address contained in the ResDesc is not in the list of previously seen physicall addresses, it is placed within the list. Arguments:
ResDesc - contains the physical address
Return Value:
TRUE - if the physical address was found in the list FALSE - if the physical address was not found in the list (and thus inserted into it) --*/ { ULONG i; PHYSICAL_ADDRESS address;
PAGED_CODE();
if (Globals.ControllerData->KnownPortsCount == -1) { return FALSE; }
address = ResDesc->u.Port.MinimumAddress; for (i = 0; i < Globals.ControllerData->KnownPortsCount; i++) { if (PhysAddrCmp(address, Globals.ControllerData->KnownPorts[i])) { return TRUE; } }
if (Globals.ControllerData->KnownPortsCount < MaximumPortCount) { Globals.ControllerData->KnownPorts[ Globals.ControllerData->KnownPortsCount++] = address; }
Print(DBG_PNP_INFO, ("Saw port [0x%08x %08x] - [0x%08x %08x]\n", address.HighPart, address.LowPart, ResDesc->u.Port.MaximumAddress.HighPart, ResDesc->u.Port.MaximumAddress.LowPart ));
return FALSE; }
NTSTATUS I8xFindPortCallout( IN PVOID Context, IN PUNICODE_STRING PathName, IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PKEY_VALUE_FULL_INFORMATION *BusInformation, IN CONFIGURATION_TYPE ControllerType, IN ULONG ControllerNumber, IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, IN CONFIGURATION_TYPE PeripheralType, IN ULONG PeripheralNumber, IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ) /*++
Routine Description:
This is the callout routine sent as a parameter to IoQueryDeviceDescription. It grabs the keyboard controller and peripheral configuration information.
Arguments:
Context - Context parameter that was passed in by the routine that called IoQueryDeviceDescription.
PathName - The full pathname for the registry key.
BusType - Bus interface type (Isa, Eisa, Mca, etc.).
BusNumber - The bus sub-key (0, 1, etc.).
BusInformation - Pointer to the array of pointers to the full value information for the bus.
ControllerType - The controller type (should be KeyboardController).
ControllerNumber - The controller sub-key (0, 1, etc.).
ControllerInformation - Pointer to the array of pointers to the full value information for the controller key.
PeripheralType - The peripheral type (should be KeyboardPeripheral).
PeripheralNumber - The peripheral sub-key.
PeripheralInformation - Pointer to the array of pointers to the full value information for the peripheral key.
Return Value:
None. If successful, will have the following side-effects:
- Sets DeviceObject->DeviceExtension->HardwarePresent. - Sets configuration fields in DeviceObject->DeviceExtension->Configuration.
--*/ { PUCHAR controllerData; NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG i, listCount, portCount = 0; PIO_RESOURCE_LIST pResList = (PIO_RESOURCE_LIST) Context; PIO_RESOURCE_DESCRIPTOR pResDesc; PKEY_VALUE_FULL_INFORMATION controllerInfo = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
PAGED_CODE();
UNREFERENCED_PARAMETER(PathName); UNREFERENCED_PARAMETER(BusType); UNREFERENCED_PARAMETER(BusNumber); UNREFERENCED_PARAMETER(BusInformation); UNREFERENCED_PARAMETER(ControllerType); UNREFERENCED_PARAMETER(ControllerNumber); UNREFERENCED_PARAMETER(PeripheralType); UNREFERENCED_PARAMETER(PeripheralNumber); UNREFERENCED_PARAMETER(PeripheralInformation);
pResDesc = pResList->Descriptors + pResList->Count; controllerInfo = ControllerInformation[IoQueryDeviceConfigurationData];
Print(DBG_PNP_TRACE, ("I8xFindPortCallout enter\n"));
if (controllerInfo->DataLength != 0) { controllerData = ((PUCHAR) controllerInfo) + controllerInfo->DataOffset; controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
resourceDescriptor = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
for (i = 0; i < listCount; i++, resourceDescriptor++) { switch(resourceDescriptor->Type) { case CmResourceTypePort: if (portCount < 2) {
Print(DBG_PNP_INFO, ("found port [0x%x 0x%x] with length %d\n", resourceDescriptor->u.Port.Start.HighPart, resourceDescriptor->u.Port.Start.LowPart, resourceDescriptor->u.Port.Length ));
pResDesc->Type = resourceDescriptor->Type; pResDesc->Flags = resourceDescriptor->Flags; pResDesc->ShareDisposition = CmResourceShareDeviceExclusive;
pResDesc->u.Port.Alignment = 1; pResDesc->u.Port.Length = resourceDescriptor->u.Port.Length; pResDesc->u.Port.MinimumAddress.QuadPart = resourceDescriptor->u.Port.Start.QuadPart; pResDesc->u.Port.MaximumAddress.QuadPart = pResDesc->u.Port.MinimumAddress.QuadPart + pResDesc->u.Port.Length - 1;
pResList->Count++;
//
// We want to record the ports we stole from the kb as seen
// so that if the keyboard is started later, we can trim
// its resources and not have a resource conflict...
//
// ...we are getting too smart for ourselves here :]
//
I8xRemovePort(pResDesc); pResDesc++; }
status = STATUS_SUCCESS;
break;
default: Print(DBG_PNP_NOISE, ("type 0x%x found\n", (LONG) resourceDescriptor->Type)); break; } }
}
Print(DBG_PNP_TRACE, ("I8xFindPortCallout exit (0x%x)\n", status)); return status; }
NTSTATUS I8xFilterResourceRequirements( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
Iterates through the resource requirements list contained in the IRP and removes any duplicate requests for I/O ports. (This is a common problem on the Alphas.) No removal is performed if more than one resource requirements list is present. Arguments:
DeviceObject - A pointer to the device object
Irp - A pointer to the request packet which contains the resource req. list.
Return Value:
None. --*/ { PIO_RESOURCE_REQUIREMENTS_LIST pReqList = NULL, pNewReqList = NULL; PIO_RESOURCE_LIST pResList = NULL, pNewResList = NULL; PIO_RESOURCE_DESCRIPTOR pResDesc = NULL, pNewResDesc = NULL; ULONG i = 0, j = 0, removeCount, reqCount, size; BOOLEAN foundInt = FALSE, foundPorts = FALSE;
PIO_STACK_LOCATION stack;
PAGED_CODE();
ASSERT(DeviceObject); ASSERT(DeviceObject->DeviceExtension);
Print(DBG_PNP_NOISE, ("Received IRP_MN_FILTER_RESOURCE_REQUIREMENTS for %s\n", (GET_COMMON_DATA(DeviceObject->DeviceExtension))->IsKeyboard ? "kb" : "mouse" ));
stack = IoGetCurrentIrpStackLocation(Irp);
//
// The list can be in either the information field, or in the current
// stack location. The Information field has a higher precedence over
// the stack location.
//
if (Irp->IoStatus.Information == 0) { pReqList = stack->Parameters.FilterResourceRequirements.IoResourceRequirementList; Irp->IoStatus.Information = (ULONG_PTR) pReqList; } else { pReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information; }
if (!pReqList) { //
// Not much can be done here except return
//
Print(DBG_PNP_MASK & ~ DBG_PNP_TRACE, ("(%s) NULL resource list in I8xFilterResourceRequirements\n", (GET_COMMON_DATA(DeviceObject->DeviceExtension))->IsKeyboard ? "kb" : "mou" ));
return STATUS_SUCCESS; }
ASSERT(Irp->IoStatus.Information != 0); ASSERT(pReqList != 0);
reqCount = pReqList->AlternativeLists;
//
// Only one AlternativeList is supported. If there is more than one list,
// then there is now way of knowing which list will be chosen. Also, if
// there are multiple lists, then chances are that a list with no i/o port
// conflicts will be chosen.
//
if (reqCount > 1) { return STATUS_SUCCESS; }
pResList = pReqList->List; removeCount = 0;
for (j = 0; j < pResList->Count; j++) { pResDesc = &pResList->Descriptors[j]; switch (pResDesc->Type) { case CmResourceTypePort: Print(DBG_PNP_INFO, ("option = 0x%x, flags = 0x%x\n", (LONG) pResDesc->Option, (LONG) pResDesc->Flags ));
if (I8xRemovePort(pResDesc)) { //
// Increment the remove count and tag this resource as
// one that we don't want to copy to the new list
//
removeCount++; pResDesc->Type = I8X_REMOVE_RESOURCE; }
foundPorts = TRUE; break;
case CmResourceTypeInterrupt: if (Globals.ControllerData->Configuration.SharedInterrupts) { if (pResDesc->ShareDisposition != CmResourceShareShared) { Print(DBG_PNP_INFO, ("forcing non shared int to shared\n")); } pResDesc->ShareDisposition = CmResourceShareShared; }
foundInt = TRUE; break;
default: break; } }
if (removeCount) { size = pReqList->ListSize;
//
// One element of the array is already allocated (via the struct
// definition) so make sure that we are allocating at least that
// much memory.
//
ASSERT(pResList->Count >= removeCount); if (pResList->Count > 1) { size -= removeCount * sizeof(IO_RESOURCE_DESCRIPTOR); }
pNewReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
if (!pNewReqList) { //
// This is not good, but the system doesn't really need to know about
// this, so just fix up our munging and return the original list
//
pReqList = stack->Parameters.FilterResourceRequirements.IoResourceRequirementList; reqCount = pReqList->AlternativeLists; removeCount = 0; for (i = 0; i < reqCount; i++) { pResList = &pReqList->List[i]; for (j = 0; j < pResList->Count; j++) { pResDesc = &pResList->Descriptors[j]; if (pResDesc->Type == I8X_REMOVE_RESOURCE) { pResDesc->Type = CmResourceTypePort; } } }
return STATUS_SUCCESS; }
//
// Clear out the newly allocated list
//
RtlZeroMemory(pNewReqList, size );
//
// Copy the list header information except for the IO resource list
// itself
//
RtlCopyMemory(pNewReqList, pReqList, sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST) ); pNewReqList->ListSize = size;
pResList = pReqList->List; pNewResList = pNewReqList->List;
//
// Copy the list header information except for the IO resource
// descriptor list itself
//
RtlCopyMemory(pNewResList, pResList, sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR) );
pNewResList->Count = 0; pNewResDesc = pNewResList->Descriptors;
for (j = 0; j < pResList->Count; j++) { pResDesc = &pResList->Descriptors[j]; if (pResDesc->Type != I8X_REMOVE_RESOURCE) { //
// Keep this resource, so copy it into the new list and
// incement the count and the location for the next
// IO resource descriptor
//
*pNewResDesc = *pResDesc; pNewResDesc++; pNewResList->Count++;
Print(DBG_PNP_INFO, ("List #%d, Descriptor #%d ... keeping res type %d\n", i, j, (ULONG) pResDesc->Type )); } else { //
// Decrement the remove count so we can assert it is
// zero once we are done
//
Print(DBG_PNP_INFO, ("Removing port [0x%08x %08x] - [0x%#08x %08x]\n", pResDesc->u.Port.MinimumAddress.HighPart, pResDesc->u.Port.MinimumAddress.LowPart, pResDesc->u.Port.MaximumAddress.HighPart, pResDesc->u.Port.MaximumAddress.LowPart )); removeCount--; } }
ASSERT(removeCount == 0);
//
// There have been bugs where the old list was being used. Zero it out to
// make sure that no conflicts arise. (Not to mention the fact that some
// other code is accessing freed memory
//
RtlZeroMemory(pReqList, pReqList->ListSize );
//
// Free the old list and place the new one in its place
//
ExFreePool(pReqList); stack->Parameters.FilterResourceRequirements.IoResourceRequirementList = pNewReqList; Irp->IoStatus.Information = (ULONG_PTR) pNewReqList; } else if (!KEYBOARD_PRESENT() && !foundPorts && foundInt) { INTERFACE_TYPE interfaceType; NTSTATUS status; ULONG prevCount; CONFIGURATION_TYPE controllerType = KeyboardController; CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
ASSERT( MOUSE_PRESENT() );
Print(DBG_PNP_INFO, ("Adding ports to res list!\n"));
//
// We will now yank the resources from the keyboard to start the mouse
// solo
//
size = pReqList->ListSize + 2 * sizeof(IO_RESOURCE_DESCRIPTOR); pNewReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool( PagedPool, size );
if (!pNewReqList) { return STATUS_SUCCESS; }
//
// Clear out the newly allocated list
//
RtlZeroMemory(pNewReqList, size );
//
// Copy the entire old list
//
RtlCopyMemory(pNewReqList, pReqList, pReqList->ListSize );
pResList = pReqList->List; pNewResList = pNewReqList->List;
prevCount = pNewResList->Count; for (i = 0; i < MaximumInterfaceType; i++) {
//
// Get the registry information for this device.
//
interfaceType = i; status = IoQueryDeviceDescription( &interfaceType, NULL, &controllerType, NULL, &peripheralType, NULL, I8xFindPortCallout, (PVOID) pNewResList );
if (NT_SUCCESS(status) || prevCount != pNewResList->Count) { break; } }
if (NT_SUCCESS(status) || prevCount != pNewResList->Count) { pNewReqList->ListSize = size - (2 - (pNewResList->Count - prevCount)); //
// Free the old list and place the new one in its place
//
ExFreePool(pReqList); stack->Parameters.FilterResourceRequirements.IoResourceRequirementList = pNewReqList; Irp->IoStatus.Information = (ULONG_PTR) pNewReqList; } else { ExFreePool(pNewReqList); } }
return STATUS_SUCCESS; }
NTSTATUS I8xRegisterDeviceInterface( PDEVICE_OBJECT PDO, CONST GUID * Guid, PUNICODE_STRING SymbolicName ) { NTSTATUS status;
PAGED_CODE();
status = IoRegisterDeviceInterface( PDO, Guid, NULL, SymbolicName );
if (NT_SUCCESS(status)) { status = IoSetDeviceInterfaceState(SymbolicName, TRUE ); }
return status; }
void I8xSetPowerFlag( IN ULONG Flag, IN BOOLEAN Set ) { KIRQL irql;
KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql); if (Set) { Globals.PowerFlags |= Flag; } else { Globals.PowerFlags &= ~Flag; } KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql); }
BOOLEAN I8xCheckPowerFlag( ULONG Flag ) { KIRQL irql; BOOLEAN rVal = FALSE;
KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql); if (Globals.PowerFlags & Flag) { rVal = TRUE; } KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql); return rVal; }
NTSTATUS I8xPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
This is the dispatch routine for power requests.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
STATUS_SUCCESSFUL if successful, an valid NTSTATUS error code otherwise
--*/ { PCOMMON_DATA commonData; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
stack = IoGetCurrentIrpStackLocation(Irp);
Print(DBG_POWER_TRACE, ("Power (%s), enter\n", commonData->IsKeyboard ? "keyboard" : "mouse" ));
//
// A power irp can be sent to the device before we have been started or
// initialized. Since the code below relies on StartDevice() to have
// executed, just fire and forget the irp
//
if (!commonData->Started || !commonData->Initialized) { PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(commonData->TopOfStack, Irp); }
switch(stack->MinorFunction) { case IRP_MN_WAIT_WAKE: Print(DBG_POWER_NOISE, ("Got IRP_MN_WAIT_WAKE\n" ));
//
// Fail all wait wake requests on level triggered interrupts for mice
// because when an errant mouse movement occurs while we are going to
// sleep, it will keep the interrupt triggered indefinitely.
//
// We should not even get into this situation because the caps of the
// mouse should have been altered to not report wait wake
//
if (IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) {
PoStartNextPowerIrp(Irp); status = Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; IoCompleteRequest(Irp, IO_NO_INCREMENT);
Print(DBG_POWER_INFO | DBG_POWER_ERROR, ("failing a wait wake request on a level triggered mouse\n"));
return status; }
break;
case IRP_MN_POWER_SEQUENCE: Print(DBG_POWER_NOISE, ("Got IRP_MN_POWER_SEQUENCE\n" )); break;
case IRP_MN_SET_POWER: Print(DBG_POWER_NOISE, ("Got IRP_MN_SET_POWER\n" ));
//
// Don't handle anything but DevicePowerState changes
//
if (stack->Parameters.Power.Type != DevicePowerState) { commonData->SystemState = stack->Parameters.Power.State.SystemState;
Print(DBG_POWER_INFO, ("system power irp, S%d\n", commonData->SystemState-1)); break; }
//
// Check for no change in state, and if none, do nothing. This state
// can occur when the device is armed for wake. We will get a D0 in
// response to the WW irp completing and then another D0 corresponding
// to the S0 irp sent to the stack.
//
if (stack->Parameters.Power.State.DeviceState == commonData->PowerState) { Print(DBG_POWER_INFO, ("no change in state (PowerDeviceD%d)\n", commonData->PowerState-1 )); break; }
switch (stack->Parameters.Power.State.DeviceState) { case PowerDeviceD0: Print(DBG_POWER_INFO, ("Powering up to PowerDeviceD0\n"));
IoAcquireRemoveLock(&commonData->RemoveLock, Irp);
if (IS_KEYBOARD(commonData)) { I8xSetPowerFlag(KBD_POWERED_UP_STARTED, TRUE); } else { I8xSetPowerFlag(MOU_POWERED_UP_STARTED, TRUE); } //
// PoSetPowerState will be called in I8xReinitalizeHardware for each
// device once all the devices have powered back up
//
IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, I8xPowerUpToD0Complete, NULL, TRUE, // on success
TRUE, // on error
TRUE // on cancel
);
//
// PoStartNextPowerIrp() gets called when the irp gets completed
// in either the completion routine or the resulting work item
//
// It is OK to call PoCallDriver and return pending b/c we are
// pending the irp in the completion routine and we may change
// the completion status if we can't alloc pool. If we return the
// value from PoCallDriver, we are tied to that status value on the
// way back up.
//
IoMarkIrpPending(Irp); PoCallDriver(commonData->TopOfStack, Irp); return STATUS_PENDING;
case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3: Print(DBG_POWER_INFO, ("Powering down to PowerDeviceD%d\n", stack->Parameters.Power.State.DeviceState-1 ));
//
// If WORK_ITEM_QUEUED is set, that means that a work item is
// either queued to be run, or running now so we don't want to yank
// any devices underneath from the work item
//
if (I8xCheckPowerFlag(WORK_ITEM_QUEUED)) { Print(DBG_POWER_INFO | DBG_POWER_ERROR, ("denying power down request because work item is running\n" ));
PoStartNextPowerIrp(Irp); status = Irp->IoStatus.Status = STATUS_POWER_STATE_INVALID; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status; }
if (IS_KEYBOARD(commonData)) { I8xSetPowerFlag(KBD_POWERED_DOWN, TRUE); } else { I8xSetPowerFlag(MOU_POWERED_DOWN, TRUE); }
PoSetPowerState(DeviceObject, stack->Parameters.Power.Type, stack->Parameters.Power.State );
//
// Disconnect level triggered interupts on mice when we go into
// low power so errant mouse movement doesn't leave the interrupt
// signalled for long periods of time
//
if (IS_MOUSE(commonData) && IS_LEVEL_TRIGGERED(commonData)) { PKINTERRUPT interrupt = commonData->InterruptObject;
Print(DBG_POWER_NOISE, ("disconnecting interrupt on level triggered mouse\n") );
commonData->InterruptObject = NULL; if (interrupt) { IoDisconnectInterrupt(interrupt); } }
commonData->PowerState = stack->Parameters.Power.State.DeviceState; commonData->ShutdownType = stack->Parameters.Power.ShutdownType;
//
// For what we are doing, we don't need a completion routine
// since we don't race on the power requests.
//
Irp->IoStatus.Status = STATUS_SUCCESS; PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(commonData->TopOfStack, Irp);
default: Print(DBG_POWER_INFO, ("unknown state\n")); break; } break;
case IRP_MN_QUERY_POWER: Print(DBG_POWER_NOISE, ("Got IRP_MN_QUERY_POWER\n" )); break;
default: Print(DBG_POWER_NOISE, ("Got unhandled minor function (%d)\n", stack->MinorFunction )); break; }
Print(DBG_POWER_TRACE, ("Power, exit\n"));
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(commonData->TopOfStack, Irp); }
NTSTATUS I8xPowerUpToD0Complete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++
Routine Description:
Reinitializes the i8042 haardware after any type of hibernation/sleep. Arguments:
DeviceObject - Pointer to the device object
Irp - Pointer to the request Context - Context passed in from the funciton that set the completion routine. UNUSED.
Return Value:
STATUS_SUCCESSFUL if successful, an valid NTSTATUS error code otherwise
--*/ { NTSTATUS status = STATUS_SUCCESS; PCOMMON_DATA commonData; PPOWER_UP_WORK_ITEM item; KIRQL irql; UCHAR poweredDownDevices = 0, poweredUpDevices = 0, failedDevices = 0; BOOLEAN queueItem = FALSE, clearFlags = FALSE, failMouIrp = FALSE; PIRP mouIrp = NULL, kbdIrp = NULL;
UNREFERENCED_PARAMETER(Context);
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
Print(DBG_POWER_TRACE, ("PowerUpToD0Complete (%s), Enter\n", commonData->IsKeyboard ? "kb" : "mouse" ));
//
// We can use a regular work item because we have a non completed power irp
// which has an outstanding reference to this stack.
//
item = (PPOWER_UP_WORK_ITEM) ExAllocatePool(NonPagedPool, sizeof(POWER_UP_WORK_ITEM));
KeAcquireSpinLock(&Globals.ControllerData->PowerSpinLock, &irql);
Print(DBG_POWER_TRACE, ("Power up to D0 completion enter, power flags 0x%x\n", Globals.PowerFlags));
if (NT_SUCCESS(Irp->IoStatus.Status)) { commonData->OutstandingPowerIrp = Irp; status = STATUS_MORE_PROCESSING_REQUIRED;
if (IS_KEYBOARD(commonData)) { KEYBOARD_POWERED_UP_SUCCESSFULLY(); } else { MOUSE_POWERED_UP_SUCCESSFULLY(); } } else { if (IS_KEYBOARD(commonData)) { KEYBOARD_POWERED_UP_FAILURE(); } else { MOUSE_POWERED_UP_FAILURE(); } }
if (KEYBOARD_POWERED_DOWN_SUCCESS()) { Print(DBG_POWER_NOISE, ("--kbd powered down successfully\n")); poweredDownDevices++; } if (MOUSE_POWERED_DOWN_SUCCESS()) { Print(DBG_POWER_NOISE, ("--mou powered down successfully\n")); poweredDownDevices++; }
if (KEYBOARD_POWERED_UP_SUCCESS()) { Print(DBG_POWER_NOISE, ("++kbd powered up successfully\n")); poweredUpDevices++; } if (MOUSE_POWERED_UP_SUCCESS()) { Print(DBG_POWER_NOISE, ("++mou powered up successfully\n")); poweredUpDevices++; }
if (KEYBOARD_POWERED_UP_FAILED()) { Print(DBG_POWER_NOISE|DBG_POWER_ERROR, (">>kbd powered down failed\n")); failedDevices++; } if (MOUSE_POWERED_UP_FAILED()) { Print(DBG_POWER_NOISE|DBG_POWER_ERROR, (">>mou powered down failed\n")); failedDevices++; }
Print(DBG_POWER_INFO, ("up %d, down %d, failed %d, flags 0x%x\n", (ULONG) poweredUpDevices, (ULONG) poweredDownDevices, (ULONG) failedDevices, Globals.PowerFlags));
if ((poweredUpDevices + failedDevices) == poweredDownDevices) { if (poweredUpDevices > 0) { //
// The ports are associated with the keyboard. If it has failed to
// power up while the mouse succeeded, we still need to fail the
// mouse b/c there is no hardware to talk to
//
if (failedDevices > 0 && KEYBOARD_POWERED_UP_FAILED()) { ASSERT(MOUSE_POWERED_UP_SUCCESS()); ASSERT(Globals.KeyboardExtension->OutstandingPowerIrp == NULL);
mouIrp = Globals.MouseExtension->OutstandingPowerIrp; Globals.MouseExtension->OutstandingPowerIrp = NULL; Globals.PowerFlags &= ~MOU_POWER_FLAGS; clearFlags = TRUE;
if (mouIrp != Irp) { //
// we have queued the irp, complete it later in this
// function under a special case
//
failMouIrp = TRUE; } else { //
// The mouse irp is the current irp. We have already
// completed the kbd irp in our previous processing. Set
// the irp status to some unsuccessful value so that we will
// call PoStartNextPowerIrp later in this function. Also
// set status to != STATUS_MORE_PROCESSING_REQUIRED so the
// irp will be completed when the function exits.
//
status = mouIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; }
} else { Print(DBG_POWER_INFO, ("at least one device powered up!\n")); queueItem = TRUE; } } else { Print(DBG_POWER_INFO, ("all devices failed power up, 0x%x\n", Globals.PowerFlags));
clearFlags = TRUE; } } else { //
// the other device is still powered down, wait for it to power back
// up before processing power states
//
Print(DBG_POWER_INFO, ("queueing, waiting for 2nd dev obj to power cycle\n")); }
if (queueItem || clearFlags) { //
// Extract the irp from each successfully started device and clear the
// associated power flags for the device
//
if (MOUSE_POWERED_UP_SUCCESS()) { mouIrp = Globals.MouseExtension->OutstandingPowerIrp; Globals.MouseExtension->OutstandingPowerIrp = NULL;
ASSERT(!TEST_PWR_FLAGS(MOU_POWERED_UP_FAILURE)); Globals.PowerFlags &= ~MOU_POWER_FLAGS; } else { Globals.PowerFlags &= ~(MOU_POWERED_UP_FAILURE); }
if (KEYBOARD_POWERED_UP_SUCCESS()) { kbdIrp = Globals.KeyboardExtension->OutstandingPowerIrp; Globals.KeyboardExtension->OutstandingPowerIrp = NULL;
ASSERT(!TEST_PWR_FLAGS(KBD_POWERED_UP_FAILURE)); Globals.PowerFlags &= ~(KBD_POWER_FLAGS); } else { Globals.PowerFlags &= ~(KBD_POWERED_UP_FAILURE); }
//
// Mark that the work item is queued. This is used to make sure that 2
// work items are not queued concucrrently
//
if (item && queueItem) { Print(DBG_POWER_INFO, ("setting work item queued flag\n"));
Globals.PowerFlags |= WORK_ITEM_QUEUED; } }
KeReleaseSpinLock(&Globals.ControllerData->PowerSpinLock, irql);
if (queueItem) { if (item == NULL) { //
// complete any queued power irps
//
Print(DBG_POWER_INFO | DBG_POWER_ERROR, ("failed to alloc work item\n"));
//
// what about PoSetPowerState?
//
if (mouIrp != NULL) { Print(DBG_POWER_ERROR | DBG_POWER_INFO, ("completing mouse power irp 0x%x", mouIrp));
mouIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; mouIrp->IoStatus.Information = 0x0;
PoStartNextPowerIrp(mouIrp); IoCompleteRequest(mouIrp, IO_NO_INCREMENT); IoReleaseRemoveLock(&Globals.MouseExtension->RemoveLock, mouIrp); mouIrp = NULL; }
if (kbdIrp != NULL) { Print(DBG_POWER_ERROR | DBG_POWER_INFO, ("completing kbd power irp 0x%x", kbdIrp));
kbdIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; kbdIrp->IoStatus.Information = 0x0;
PoStartNextPowerIrp(kbdIrp); IoCompleteRequest(kbdIrp, IO_NO_INCREMENT); IoReleaseRemoveLock(&Globals.KeyboardExtension->RemoveLock, kbdIrp); kbdIrp = NULL; }
//
// The passed in Irp has just been completed; by returning more
// processing required, it will not be double completed
//
return STATUS_MORE_PROCESSING_REQUIRED; } else { RtlZeroMemory(item, sizeof(*item));
if (MOUSE_STARTED()) { SET_RECORD_STATE(Globals.MouseExtension, RECORD_RESUME_FROM_POWER); } Print(DBG_POWER_INFO, ("queueing work item for init\n")); item->KeyboardPowerIrp = kbdIrp; item->MousePowerIrp = mouIrp;
ExInitializeWorkItem(&item->Item, I8xReinitializeHardware, item); ExQueueWorkItem(&item->Item, DelayedWorkQueue); } } else if (item != NULL) { Print(DBG_POWER_NOISE,("freeing unused item %p\n", item)); ExFreePool(item); item = NULL; }
if (failMouIrp) { Print(DBG_POWER_INFO | DBG_POWER_ERROR, ("failing successful mouse irp %p because kbd failed power up\n", mouIrp));
PoStartNextPowerIrp(mouIrp); IoCompleteRequest(mouIrp, IO_NO_INCREMENT); IoReleaseRemoveLock(&Globals.MouseExtension->RemoveLock, mouIrp); mouIrp = NULL; }
if (!NT_SUCCESS(Irp->IoStatus.Status)) { Print(DBG_POWER_INFO | DBG_POWER_ERROR, ("irp %p failed, starting next\n", Irp));
PoStartNextPowerIrp(Irp); Irp = NULL; ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); }
return status; }
|