1120 lines
34 KiB
C
1120 lines
34 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains plug & play code for the inport mouse
|
|
|
|
Environment:
|
|
|
|
Kernel & user mode.
|
|
|
|
Revision History:
|
|
|
|
Feb-1998 : Initial writing, Doron Holan
|
|
|
|
--*/
|
|
|
|
#include "inport.h"
|
|
#include "inplog.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, InportAddDevice)
|
|
#pragma alloc_text(PAGE, InportPnP)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
InportAddDevice (
|
|
IN PDRIVER_OBJECT Driver,
|
|
IN PDEVICE_OBJECT PDO
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS result code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PDEVICE_OBJECT device;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = IoCreateDevice(Driver,
|
|
sizeof(DEVICE_EXTENSION),
|
|
NULL, // no name for this Filter DO
|
|
FILE_DEVICE_INPORT_PORT,
|
|
0,
|
|
FALSE,
|
|
&device);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) device->DeviceExtension;
|
|
|
|
//
|
|
// Initialize the fields.
|
|
//
|
|
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
|
|
|
|
deviceExtension->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
|
|
if (deviceExtension->TopOfStack == NULL) {
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
//
|
|
// 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 = INPORT_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(deviceExtension->TopOfStack);
|
|
|
|
deviceExtension->Self = device;
|
|
deviceExtension->Removed = FALSE;
|
|
deviceExtension->Started = FALSE;
|
|
deviceExtension->UnitId = 0;
|
|
|
|
IoInitializeRemoveLock (&deviceExtension->RemoveLock, INP_POOL_TAG, 1, 10);
|
|
#if defined(NEC_98)
|
|
deviceExtension->PowerState = PowerDeviceD0;
|
|
|
|
#endif // defined(NEC_98)
|
|
//
|
|
// Initialize WMI
|
|
//
|
|
deviceExtension->WmiLibInfo.GuidCount = sizeof(WmiGuidList) /
|
|
sizeof(WMIGUIDREGINFO);
|
|
deviceExtension->WmiLibInfo.GuidList = WmiGuidList;
|
|
deviceExtension->WmiLibInfo.QueryWmiRegInfo = InportQueryWmiRegInfo;
|
|
deviceExtension->WmiLibInfo.QueryWmiDataBlock = InportQueryWmiDataBlock;
|
|
deviceExtension->WmiLibInfo.SetWmiDataBlock = InportSetWmiDataBlock;
|
|
deviceExtension->WmiLibInfo.SetWmiDataItem = InportSetWmiDataItem;
|
|
deviceExtension->WmiLibInfo.ExecuteWmiMethod = NULL;
|
|
deviceExtension->WmiLibInfo.WmiFunctionControl = NULL;
|
|
|
|
IoWMIRegistrationControl(deviceExtension->Self,
|
|
WMIREG_ACTION_REGISTER
|
|
);
|
|
|
|
deviceExtension->PDO = PDO;
|
|
|
|
device->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
device->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
|
|
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
InpReleaseResourcesEx(
|
|
PVOID Context
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = Context;
|
|
|
|
KeRemoveQueueDpc(&deviceExtension->IsrDpc);
|
|
KeRemoveQueueDpc(&deviceExtension->IsrDpcRetry);
|
|
KeRemoveQueueDpc(&deviceExtension->ErrorLogDpc);
|
|
|
|
// KeCancelTimer(&deviceExtension->DataConsumptionTimer);
|
|
|
|
if (deviceExtension->Configuration.UnmapRegistersRequired) {
|
|
MmUnmapIoSpace(deviceExtension->Configuration.DeviceRegisters[0],
|
|
deviceExtension->Configuration.PortList[0].u.Port.Length);
|
|
}
|
|
|
|
//
|
|
// Clear out the config info. If we get started again, than it will be filled
|
|
// in again. If is from a remove, then it is essentially a no-op
|
|
//
|
|
RtlZeroMemory(&deviceExtension->Configuration,
|
|
sizeof(INPORT_CONFIGURATION_INFORMATION));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
InpReleaseResources(
|
|
PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
InpPrint((2, "INPORT-InpReleaseResources: Enter\n"));
|
|
|
|
if (DeviceExtension->InterruptObject) {
|
|
KeSynchronizeExecution(
|
|
DeviceExtension->InterruptObject,
|
|
InpReleaseResourcesEx,
|
|
(PVOID) DeviceExtension);
|
|
|
|
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
|
|
DeviceExtension->InterruptObject = NULL;
|
|
}
|
|
else {
|
|
InpReleaseResourcesEx((PVOID) DeviceExtension);
|
|
}
|
|
|
|
InpPrint((2, "INPORT-InpReleaseResources: Exit\n"));
|
|
}
|
|
|
|
NTSTATUS
|
|
InpPnPComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The pnp IRP is in the process of completing.
|
|
signal
|
|
|
|
Arguments:
|
|
Context set to the device object in question.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION stack;
|
|
NTSTATUS status;
|
|
PKEVENT event;
|
|
|
|
InpPrint((2, "INPORT-InpPnPComplete: Enter\n"));
|
|
|
|
status = STATUS_SUCCESS;
|
|
event = (PKEVENT) Context;
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (Irp->PendingReturned) {
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
KeSetEvent(event,
|
|
0,
|
|
FALSE);
|
|
|
|
InpPrint((2, "INPORT-InpPnPComplete: Exit\n"));
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
InportPnP (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The plug and play dispatch routines.
|
|
|
|
Most of these this filter driver will completely ignore.
|
|
In all cases it must pass on the IRP to the lower driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object.
|
|
|
|
Irp - pointer to an I/O Request Packet.
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION stack;
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Someone gave us a pnp irp after a remove. Unthinkable!
|
|
//
|
|
ASSERT(FALSE);
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
InpPrint((2, "INPORT-InportPnP: Enter (min func=0x%x)\n", stack->MinorFunction));
|
|
|
|
switch (stack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
|
|
#if defined(NEC_98)
|
|
Globals.DeviceObject = (PDEVICE_OBJECT)DeviceObject;
|
|
#endif // defined(NEC_98)
|
|
//
|
|
// If we have been started (and not stopped), then just ignore this start
|
|
//
|
|
if (deviceExtension->Started) {
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Not allowed to touch the hardware until all of the lower DO's have
|
|
// had a chance to look at it
|
|
//
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
KeInitializeEvent(&event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
(PIO_COMPLETION_ROUTINE) InpPnPComplete,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = IoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
if (STATUS_PENDING == status) {
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Executive, // Waiting for reason of a driver
|
|
KernelMode, // Waiting in kernel mode
|
|
FALSE, // No alert
|
|
NULL); // No timeout
|
|
}
|
|
|
|
if (NT_SUCCESS (status) && NT_SUCCESS (Irp->IoStatus.Status)) {
|
|
status = InpStartDevice(
|
|
DeviceObject->DeviceExtension,
|
|
stack->Parameters.StartDevice.AllocatedResourcesTranslated);
|
|
if (NT_SUCCESS(status)) {
|
|
deviceExtension->Started = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// 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 = InpSendIrpSynchronously(deviceExtension->TopOfStack, Irp);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
//
|
|
// The PlugPlay system has dictacted the removal of this device. We
|
|
// have no choise but to detach and delete the device objecct.
|
|
// (If we wanted to express and interest in preventing this removal,
|
|
// we should have filtered the query remove and query stop routines.)
|
|
//
|
|
// Note! we might receive a remove WITHOUT first receiving a stop.
|
|
//
|
|
InpPrint((2, "INPORT-InportPnP: remove device \n"));
|
|
|
|
deviceExtension->Removed = TRUE;
|
|
|
|
//
|
|
// Here if we had any outstanding requests in a personal queue we should
|
|
// complete them all now.
|
|
//
|
|
// Note, the device could be GONE so we cannot send it any non-
|
|
// PNP IRPS.
|
|
//
|
|
InpReleaseResources(deviceExtension);
|
|
|
|
//
|
|
// Perform specific operations for a remove
|
|
//
|
|
IoWMIRegistrationControl(deviceExtension->Self,
|
|
WMIREG_ACTION_DEREGISTER
|
|
);
|
|
|
|
//
|
|
// Send on the remove IRP
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
|
|
//
|
|
// Wait for the remove lock to free.
|
|
//
|
|
IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
|
|
|
|
IoDetachDevice(deviceExtension->TopOfStack);
|
|
IoDeleteDevice(deviceExtension->Self);
|
|
|
|
InpPrint((2, "INPORT-InportPnP: exit (%x)\n", STATUS_SUCCESS));
|
|
return STATUS_SUCCESS;
|
|
|
|
// NOTE:
|
|
// handle this case if you want to add/remove resources that will be given
|
|
// during start device. Add resources before passing the irp down.
|
|
// Remove resources when the irp is coming back up
|
|
// See dd\input\pnpi8042\pnp.c, I8xFilterResourceRequirements for an example
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
|
|
#if !defined(NEC_98)
|
|
|
|
status = InpSendIrpSynchronously(deviceExtension->TopOfStack, Irp);
|
|
|
|
//
|
|
// If the lower filter does not support this Irp, this is
|
|
// OK, we can ignore this error
|
|
//
|
|
if (status == STATUS_NOT_SUPPORTED) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
InpFilterResourceRequirements(DeviceObject, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
InpPrint((2, "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;
|
|
#else
|
|
InpPrint((2, "INPORT-InportPnP: IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"));
|
|
#endif
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
#if defined(NEC_98)
|
|
//
|
|
// Don't let either of the requests succeed, otherwise the mouse might be rendered useless.
|
|
//
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
break;
|
|
#endif
|
|
case IRP_MN_STOP_DEVICE:
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
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:
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
default:
|
|
//
|
|
// Here the filter driver might modify the behavior of these IRPS
|
|
// Please see PlugPlay documentation for use of these IRPs.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
break;
|
|
}
|
|
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
|
|
InpPrint((2, "INPORT-InportPnP: exit (%x)\n", status));
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
InportPower (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
NOTE:
|
|
You must write power code!!!
|
|
|
|
System power irps can be ignored.
|
|
Device power irps will be sent by mouclass. The transition from D0 to some
|
|
lower usually involves doing nothing (maybe power down h/w if you have control
|
|
over this). The transition from a lower power state to D0 must be handled by
|
|
reinitializing the device.
|
|
|
|
Please read http://titanic for Power documentation (especially on the use
|
|
of PoCallDriver and PoStartNextPowerIrp)
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION stack;
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
POWER_STATE powerState;
|
|
POWER_STATE_TYPE powerType;
|
|
|
|
InpPrint((2, "INPORT-InportPower: Enter\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
powerType = stack->Parameters.Power.Type;
|
|
powerState = stack->Parameters.Power.State;
|
|
|
|
status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
PoStartNextPowerIrp(Irp);
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
switch (stack->MinorFunction) {
|
|
case IRP_MN_SET_POWER:
|
|
InpPrint((2, "INPORT-InportPower: Power Setting %s state to %d\n",
|
|
((powerType == SystemPowerState) ? "System"
|
|
: "Device"),
|
|
powerState.SystemState));
|
|
#if defined(NEC_98)
|
|
//
|
|
// Don't handle anything but DevicePowerState changes
|
|
//
|
|
if (stack->Parameters.Power.Type != DevicePowerState) {
|
|
InpPrint((2,"INPORT-InportPower: not a device power irp\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check for no change in state, and if none, do nothing
|
|
//
|
|
if (stack->Parameters.Power.State.DeviceState ==
|
|
deviceExtension->PowerState) {
|
|
InpPrint((2,"INPORT-InportPower: no change in state (PowerDeviceD%d)\n",
|
|
deviceExtension->PowerState-1
|
|
));
|
|
break;
|
|
}
|
|
|
|
switch (stack->Parameters.Power.State.DeviceState) {
|
|
case PowerDeviceD0:
|
|
InpPrint((2,"INPORT-InportPower: Powering up to PowerDeviceD0\n"));
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
InportPowerUpToD0Complete,
|
|
NULL,
|
|
TRUE, // on success
|
|
TRUE, // on error
|
|
TRUE // on cancel
|
|
);
|
|
|
|
//
|
|
// PoStartNextPowerIrp() gets called in InportPowerUpToD0Complete
|
|
//
|
|
return PoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
|
|
case PowerDeviceD1:
|
|
case PowerDeviceD2:
|
|
case PowerDeviceD3:
|
|
InpPrint((
|
|
2,"INPORT-InportPower: Powering down to PowerDeviceD%d\n",
|
|
stack->Parameters.Power.State.DeviceState-1
|
|
));
|
|
|
|
PoSetPowerState(DeviceObject,
|
|
stack->Parameters.Power.Type,
|
|
stack->Parameters.Power.State
|
|
);
|
|
deviceExtension->PowerState = stack->Parameters.Power.State.DeviceState;
|
|
|
|
//
|
|
// 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;
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
return PoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
|
|
default:
|
|
InpPrint((2,"INPORT-InportPower: unknown state\n"));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
#else // defined(NEC_98)
|
|
break;
|
|
|
|
#endif // defined(NEC_98)
|
|
case IRP_MN_QUERY_POWER:
|
|
InpPrint((2, "INPORT-InportPower: Power query %s status to %d\n",
|
|
((powerType == SystemPowerState) ? "System"
|
|
: "Device"),
|
|
powerState.SystemState));
|
|
break;
|
|
default:
|
|
InpPrint((2, "INPORT-InportPower: Power minor (0x%x) no known\n", stack->MinorFunction));
|
|
}
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
PoCallDriver(deviceExtension->TopOfStack, Irp);
|
|
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
|
|
|
|
InpPrint((2, "INPORT-InportPower: Exit\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if !defined(NEC_98)
|
|
VOID
|
|
InpFilterResourceRequirements(
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
PCM_RESOURCE_LIST AllocatedResources;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST pReqList = NULL,
|
|
newReqList = NULL;
|
|
PIO_RESOURCE_LIST pResList = NULL,
|
|
pNewResList = NULL;
|
|
PIO_RESOURCE_DESCRIPTOR pResDesc = NULL,
|
|
pNewResDesc = NULL;
|
|
ULONG i = 0, reqCount, size = 0;
|
|
BOOLEAN foundInt = FALSE, foundPorts = FALSE;
|
|
PIO_STACK_LOCATION stack;
|
|
INTERFACE_TYPE interfaceType = Isa;
|
|
ULONG busNumber = 0;
|
|
CONFIGURATION_TYPE controllerType = PointerController;
|
|
CONFIGURATION_TYPE peripheralType = PointerPeripheral;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(DeviceObject);
|
|
ASSERT(DeviceObject->DeviceExtension);
|
|
|
|
InpPrint((1, "Received IRP_MN_FILTER_RESOURCE_REQUIREMENTS for Inport\n"));
|
|
|
|
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
|
|
//
|
|
InpPrint((1, "NULL resource list in InpFilterResourceRequirements\n"));
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
pResList = &pReqList->List[0];
|
|
|
|
for (i = 0; i < pResList->Count; i++) {
|
|
pResDesc = &pResList->Descriptors[i];
|
|
switch (pResDesc->Type) {
|
|
case CmResourceTypePort:
|
|
foundPorts = TRUE;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
foundInt = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundPorts && !foundInt)
|
|
size = pReqList->ListSize + 2 * sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
else if (!foundPorts || !foundInt)
|
|
size = pReqList->ListSize + sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
else {
|
|
//
|
|
// Nothing to filter, just leave
|
|
//
|
|
ASSERT(foundPorts);
|
|
ASSERT(foundInt);
|
|
return;
|
|
}
|
|
|
|
ASSERT(size != 0);
|
|
newReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)
|
|
ExAllocatePool(
|
|
NonPagedPool,
|
|
size
|
|
);
|
|
|
|
if (!newReqList) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Clear out the newly allocated list
|
|
//
|
|
RtlZeroMemory(newReqList,
|
|
size
|
|
);
|
|
|
|
//
|
|
// Copy the entire old list
|
|
//
|
|
RtlCopyMemory(newReqList,
|
|
pReqList,
|
|
pReqList->ListSize
|
|
);
|
|
|
|
pResList = &newReqList->List[0];
|
|
if (!foundPorts) {
|
|
pResDesc = &pResList->Descriptors[pResList->Count++];
|
|
pResDesc->Type = CmResourceTypePort;
|
|
}
|
|
if (!foundInt) {
|
|
pResDesc = &pResList->Descriptors[pResList->Count++];
|
|
pResDesc->Type = CmResourceTypeInterrupt;
|
|
}
|
|
|
|
pResList = &newReqList->List[0];
|
|
interfaceType = Isa;
|
|
status = IoQueryDeviceDescription(
|
|
&interfaceType,
|
|
&busNumber,
|
|
&controllerType,
|
|
NULL,
|
|
&peripheralType,
|
|
NULL,
|
|
InpFindResourcesCallout,
|
|
(PVOID) pResList
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) { // fill in with defaults
|
|
PINPORT_CONFIGURATION_INFORMATION configuration = &deviceExtension->Configuration;
|
|
ULONG InterruptLevel;
|
|
InpPrint((1, "Failed IoQueryDeviceDescription, status = 0x%x\n...try the registry...\n", status));
|
|
InpServiceParameters(deviceExtension,
|
|
&Globals.RegistryPath);
|
|
InterruptLevel = configuration->MouseInterrupt.u.Interrupt.Level;
|
|
pResList = &newReqList->List[0];
|
|
for (i = 0; i < pResList->Count; i++) {
|
|
pResDesc = &pResList->Descriptors[i];
|
|
switch (pResDesc->Type) {
|
|
case CmResourceTypePort:
|
|
if (foundPorts) break;
|
|
pResDesc->Option = 0; // fixed resources
|
|
pResDesc->ShareDisposition = INPORT_REGISTER_SHARE? CmResourceShareShared:CmResourceShareDeviceExclusive;
|
|
pResDesc->Flags = CM_RESOURCE_PORT_IO;
|
|
pResDesc->u.Port.Length = INP_DEF_PORT_SPAN;
|
|
pResDesc->u.Port.Alignment = 1;
|
|
pResDesc->u.Port.MinimumAddress.HighPart = 0;
|
|
pResDesc->u.Port.MinimumAddress.LowPart = INP_DEF_PORT;
|
|
pResDesc->u.Port.MaximumAddress.HighPart = 0;
|
|
pResDesc->u.Port.MaximumAddress.LowPart = INP_DEF_PORT+INP_DEF_PORT_SPAN-1;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
if (foundInt) break;
|
|
pResDesc->Option = 0; // fixed resources
|
|
pResDesc->ShareDisposition = INPORT_REGISTER_SHARE? CmResourceShareShared:CmResourceShareDeviceExclusive;
|
|
pResDesc->Flags = CM_RESOURCE_INTERRUPT_LATCHED; //Isa
|
|
pResDesc->u.Interrupt.MinimumVector = InterruptLevel;
|
|
pResDesc->u.Interrupt.MaximumVector = InterruptLevel;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
newReqList->ListSize = size;
|
|
//
|
|
// Free the old list and place the new one in its place
|
|
//
|
|
ExFreePool(pReqList);
|
|
stack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
|
|
newReqList;
|
|
Irp->IoStatus.Information = (ULONG_PTR) newReqList;
|
|
}
|
|
|
|
NTSTATUS
|
|
InpFindResourcesCallout(
|
|
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, PortResDesc = NULL, IntResDesc = NULL;
|
|
BOOLEAN foundInt = FALSE,
|
|
foundPorts = FALSE;
|
|
|
|
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];
|
|
|
|
InpPrint((2, "InpFindPortCallout 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:
|
|
PortResDesc = resourceDescriptor;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
IntResDesc = resourceDescriptor;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < pResList->Count; i++) {
|
|
pResDesc = &pResList->Descriptors[i];
|
|
switch (pResDesc->Type) {
|
|
case CmResourceTypePort:
|
|
if (PortResDesc) {
|
|
resourceDescriptor = PortResDesc;
|
|
pResDesc->Option = 0; // fixed resources
|
|
pResDesc->ShareDisposition = INPORT_REGISTER_SHARE? CmResourceShareShared:CmResourceShareDeviceExclusive;
|
|
pResDesc->Flags = CM_RESOURCE_PORT_IO;
|
|
pResDesc->u.Port.Alignment = 1;
|
|
pResDesc->u.Port.Length = INP_DEF_PORT_SPAN;
|
|
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;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
if (IntResDesc) {
|
|
resourceDescriptor = IntResDesc;
|
|
pResDesc->Option = 0; // fixed resources
|
|
pResDesc->ShareDisposition = INPORT_REGISTER_SHARE? CmResourceShareShared:CmResourceShareDeviceExclusive;
|
|
pResDesc->Flags = CM_RESOURCE_INTERRUPT_LATCHED; //Isa
|
|
pResDesc->u.Interrupt.MinimumVector = resourceDescriptor->u.Interrupt.Level;
|
|
pResDesc->u.Interrupt.MaximumVector = resourceDescriptor->u.Interrupt.Level;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (PortResDesc && IntResDesc)
|
|
status = STATUS_SUCCESS;
|
|
else
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
InpPrint((2, "InpFindPortCallout exit (0x%x)\n", status));
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
InpSendIrpSynchronously (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent(&event,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
InpPnPComplete,
|
|
&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;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#if defined(NEC_98)
|
|
NTSTATUS
|
|
InportPowerUpToD0Complete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reinitializes the Inport Mouse 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;
|
|
PIO_STACK_LOCATION stack;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PWORK_QUEUE_ITEM item;
|
|
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = Irp->IoStatus.Status;
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Reset the power state to powered up
|
|
//
|
|
deviceExtension->PowerState = PowerDeviceD0;
|
|
|
|
//
|
|
// Everything has been powered up, let the system know about it
|
|
//
|
|
PoSetPowerState(DeviceObject,
|
|
stack->Parameters.Power.Type,
|
|
stack->Parameters.Power.State
|
|
);
|
|
|
|
item = (PWORK_QUEUE_ITEM) ExAllocatePool(NonPagedPool,
|
|
sizeof(WORK_QUEUE_ITEM));
|
|
if (!item) {
|
|
//
|
|
// must elaborate here
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ExInitializeWorkItem(item, InportReinitializeHardware, item);
|
|
ExQueueWorkItem(item, DelayedWorkQueue);
|
|
}
|
|
|
|
InpPrint((2,"INPORT-InportPowerUpToD0Complete: PowerUpToD0Complete, exit\n"));
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
return status;
|
|
}
|
|
|
|
#endif // defined(NEC_98)
|