You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
741 lines
22 KiB
741 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1998 - 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract: This module contains PnP Start, Stop, Remove,
|
|
Power dispatch routines and IRP cancel routine.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
@@BEGIN_DDKSPLIT
|
|
Author:
|
|
|
|
Eliyas Yakub (Mar, 11, 1997)
|
|
Revision History:
|
|
|
|
Updated by Eliyas on Feb 5 1998
|
|
Om Sharma ( April 15, 1998)
|
|
MarcAnd 02-Jul-98 Quick tidy for DDK
|
|
|
|
@@END_DDKSPLIT
|
|
--*/
|
|
|
|
#include "hidgame.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, HGM_RemoveDevice)
|
|
#pragma alloc_text (PAGE, HGM_PnP)
|
|
#pragma alloc_text (PAGE, HGM_InitDevice)
|
|
#pragma alloc_text (PAGE, HGM_GetResources)
|
|
#pragma alloc_text (PAGE, HGM_Power)
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_IncRequestCount |
|
|
*
|
|
* Try to increment the request count but fail if the device is
|
|
* being removed.
|
|
*
|
|
* @parm IN PDEVICE_EXTENSION | DeviceExtension |
|
|
*
|
|
* Pointer to the device extension.
|
|
*
|
|
* @rvalue STATUS_SUCCESS | success
|
|
* @rvalue STATUS_DELETE_PENDING | PnP IRP received after device was removed
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS EXTERNAL
|
|
HGM_IncRequestCount
|
|
(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
|
|
InterlockedIncrement( &DeviceExtension->RequestCount );
|
|
ASSERT( DeviceExtension->RequestCount > 0 );
|
|
|
|
if( DeviceExtension->fRemoved )
|
|
{
|
|
/*
|
|
* PnP has already told us to remove the device so fail and make
|
|
* sure that the event has been set.
|
|
*/
|
|
if( 0 == InterlockedDecrement( &DeviceExtension->RequestCount ) )
|
|
{
|
|
KeSetEvent( &DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE );
|
|
}
|
|
ntStatus = STATUS_DELETE_PENDING;
|
|
}
|
|
else
|
|
{
|
|
ntStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func VOID | HGM_DecRequestCount |
|
|
*
|
|
* Decrement the request count and set event if this is the last.
|
|
*
|
|
* @parm IN PDEVICE_EXTENSION | DeviceExtension |
|
|
*
|
|
* Pointer to the device extension.
|
|
*
|
|
*****************************************************************************/
|
|
VOID EXTERNAL
|
|
HGM_DecRequestCount
|
|
(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
LONG LocalCount;
|
|
|
|
LocalCount = InterlockedDecrement( &DeviceExtension->RequestCount );
|
|
|
|
ASSERT( DeviceExtension->RequestCount >= 0 );
|
|
|
|
if( LocalCount == 0 )
|
|
{
|
|
/*
|
|
* PnP has already told us to remove the device so the PnP remove
|
|
* code should have set device as removed and should be waiting on
|
|
* the event.
|
|
*/
|
|
ASSERT( DeviceExtension->fRemoved );
|
|
KeSetEvent( &DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func VOID | HGM_RemoveDevice |
|
|
*
|
|
* FDO Remove routine
|
|
*
|
|
* @parm IN PDEVICE_EXTENSION | DeviceExtension |
|
|
*
|
|
* Pointer to the device extension.
|
|
*
|
|
*****************************************************************************/
|
|
VOID INTERNAL
|
|
HGM_RemoveDevice
|
|
(
|
|
PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
if (DeviceExtension->fSurpriseRemoved) {
|
|
return;
|
|
}
|
|
|
|
DeviceExtension->fSurpriseRemoved = TRUE;
|
|
|
|
/*
|
|
* Acquire mutex before modifying the Global Linked list of devices
|
|
*/
|
|
ExAcquireFastMutex (&Global.Mutex);
|
|
|
|
/*
|
|
* Remove this device from the linked list of devices
|
|
*/
|
|
RemoveEntryList(&DeviceExtension->Link);
|
|
|
|
/*
|
|
* Release the mutex
|
|
*/
|
|
ExReleaseFastMutex (&Global.Mutex);
|
|
} /* HGM_RemoveDevice */
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_PnP |
|
|
*
|
|
* Plug and Play dispatch routine for this driver.
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DeviceObject |
|
|
*
|
|
* Pointer to the device object.
|
|
*
|
|
* @parm IN PIRP | Irp |
|
|
*
|
|
* Pointer to an I/O request packet.
|
|
*
|
|
* @rvalue STATUS_SUCCESS | success
|
|
* @rvalue STATUS_DELETE_PENDING | PnP IRP received after device was removed
|
|
* @rvalue ??? | Return from IoCallDriver() or HGM_InitDevice()
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS EXTERNAL
|
|
HGM_PnP
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
KEVENT StartEvent;
|
|
|
|
PAGED_CODE();
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
|
|
("HGM_PnP(DeviceObject=0x%x,Irp=0x%x)",\
|
|
DeviceObject, Irp ));
|
|
/*
|
|
* Get a pointer to the device extension
|
|
*/
|
|
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
|
|
|
|
ntStatus = HGM_IncRequestCount( DeviceExtension );
|
|
if (!NT_SUCCESS (ntStatus))
|
|
{
|
|
/*
|
|
* Someone sent us another plug and play IRP after removed
|
|
*/
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
|
|
("HGM_PnP: PnP IRP after device was removed\n"));
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
} else
|
|
{
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
/*
|
|
* Get a pointer to the current location in the Irp
|
|
*/
|
|
IrpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
switch(IrpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
|
|
("HGM_Pnp: IRP_MN_START_DEVICE"));
|
|
/*
|
|
* We cannot touch the device (send it any non pnp irps) until a
|
|
* start device has been passed down to the lower drivers.
|
|
*/
|
|
KeInitializeEvent(&StartEvent, NotificationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
IoSetCompletionRoutine (Irp, HGM_PnPComplete, &StartEvent, TRUE, TRUE, TRUE);
|
|
ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
|
|
|
|
if( NT_SUCCESS(ntStatus ) )
|
|
{
|
|
ntStatus = KeWaitForSingleObject
|
|
(
|
|
&StartEvent,
|
|
Executive, /* Waiting for reason of a driver */
|
|
KernelMode, /* Waiting in kernel mode */
|
|
FALSE, /* No allert */
|
|
NULL /* No timeout */
|
|
);
|
|
}
|
|
|
|
if(NT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = Irp->IoStatus.Status;
|
|
}
|
|
|
|
if(NT_SUCCESS (ntStatus))
|
|
{
|
|
/*
|
|
* As we are now back from our start device we can do work.
|
|
*/
|
|
ntStatus = HGM_InitDevice (DeviceObject, Irp);
|
|
} else
|
|
{
|
|
HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
|
|
("HGM_Pnp: IRP_MN_START_DEVICE ntStatus =0x%x",\
|
|
ntStatus));
|
|
}
|
|
|
|
|
|
DeviceExtension->fStarted = TRUE;
|
|
|
|
/*
|
|
* Return Status
|
|
*/
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
|
|
("HGM_Pnp: IRP_MN_STOP_DEVICE"));
|
|
/*
|
|
* After the start IRP has been sent to the lower driver object, the bus may
|
|
* NOT send any more IRPS down ``touch'' until another START has occured.
|
|
* Whatever access is required must be done before Irp passed on.
|
|
*/
|
|
|
|
DeviceExtension->fStarted = FALSE;
|
|
|
|
/*
|
|
* We don't need a completion routine so fire and forget.
|
|
* Set the current stack location to the next stack location and
|
|
* call the next device object.
|
|
*/
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
|
|
("HGM_Pnp: IRP_MN_SURPRISE_REMOVAL"));
|
|
|
|
HGM_RemoveDevice(DeviceExtension);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
|
|
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
|
|
("HGM_Pnp: IRP_MN_REMOVE_DEVICE"));
|
|
|
|
/*
|
|
* The PlugPlay system has dictacted the removal of this device. We
|
|
* have no choice but to detach and delete the device object.
|
|
* (If we wanted to express an 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.
|
|
*/
|
|
|
|
/*
|
|
* Make sure we do not allow more IRPs to start touching the device
|
|
*/
|
|
DeviceExtension->fRemoved = TRUE;
|
|
|
|
/*
|
|
* Stop the device without touching the hardware.
|
|
*/
|
|
HGM_RemoveDevice(DeviceExtension);
|
|
|
|
/*
|
|
* Send on the remove IRP
|
|
*/
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
|
|
|
|
|
|
/*
|
|
* Remove this IRPs hold which should leave the initial 1 plus
|
|
* any other IRP holds.
|
|
*/
|
|
{
|
|
LONG RequestCount = InterlockedDecrement( &DeviceExtension->RequestCount );
|
|
ASSERT( RequestCount > 0 );
|
|
}
|
|
|
|
/*
|
|
* If someone has already started, wait for them to finish
|
|
*/
|
|
if( InterlockedDecrement( &DeviceExtension->RequestCount ) > 0 )
|
|
{
|
|
KeWaitForSingleObject( &DeviceExtension->RemoveEvent,
|
|
Executive, KernelMode, FALSE, NULL );
|
|
}
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_PnP Exit 1", ntStatus);
|
|
|
|
return ntStatus;
|
|
|
|
default:
|
|
HGM_DBGPRINT(FILE_PNP | HGM_WARN,\
|
|
("HGM_PnP: IrpStack->MinorFunction Not handled 0x%x", \
|
|
IrpStack->MinorFunction));
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
|
|
ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
|
|
break;
|
|
}
|
|
|
|
HGM_DecRequestCount( DeviceExtension );
|
|
}
|
|
|
|
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_PnP", ntStatus);
|
|
|
|
return ntStatus;
|
|
} /* HGM_PnP */
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_InitDevice |
|
|
*
|
|
* Get the device information and attempt to initialize a configuration
|
|
* for a device. If we cannot identify this as a valid HID device or
|
|
* configure the device, our start device function is failed.
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DeviceObject |
|
|
*
|
|
* Pointer to the device object.
|
|
*
|
|
* @parm IN PIRP | Irp |
|
|
*
|
|
* Pointer to an I/O request packet.
|
|
*
|
|
* @rvalue STATUS_SUCCESS | success
|
|
* @rvalue STATUS_DEVICE_CONFIGURATION_ERROR | Resources overlap
|
|
* @rvalue ??? | Return from HGM_GetResources() or HGM_JoystickConfig()
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS INTERNAL
|
|
HGM_InitDevice
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
|
|
("HGM_InitDevice(DeviceObject=0x%x,Irp=0x%x)", \
|
|
DeviceObject,Irp));
|
|
|
|
/*
|
|
* Get a pointer to the device extension
|
|
*/
|
|
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
|
|
|
|
/*
|
|
* Get resource information from GameEnum and store it in the device extension
|
|
*/
|
|
ntStatus = HGM_GetResources(DeviceObject,Irp);
|
|
if( NT_SUCCESS(ntStatus) )
|
|
{
|
|
ntStatus = HGM_InitAnalog(DeviceObject);
|
|
}
|
|
else
|
|
{
|
|
HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
|
|
("HGM_InitDevice: HGM_GetResources Failed"));
|
|
}
|
|
|
|
if( !NT_SUCCESS(ntStatus) )
|
|
{
|
|
/*
|
|
* Acquire mutex before modifying the Global Linked list of devices
|
|
*/
|
|
ExAcquireFastMutex (&Global.Mutex);
|
|
|
|
/*
|
|
* Remove this device from the linked list of devices
|
|
*/
|
|
RemoveEntryList(&DeviceExtension->Link);
|
|
|
|
/*
|
|
* Release the mutex
|
|
*/
|
|
ExReleaseFastMutex (&Global.Mutex);
|
|
}
|
|
|
|
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_InitDevice", ntStatus);
|
|
|
|
return ntStatus;
|
|
} /* HGM_InitDevice */
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_GetResources |
|
|
*
|
|
* Gets gameport resource information from the GameEnum driver
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DeviceObject |
|
|
*
|
|
* Pointer to the device object.
|
|
*
|
|
* @parm IN PIRP | Irp |
|
|
*
|
|
* Pointer to an I/O request packet.
|
|
*
|
|
* @rvalue STATUS_SUCCESS | success
|
|
* @rvalue ??? | Return from IoCallDriver()
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS INTERNAL
|
|
HGM_GetResources
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
GAMEENUM_PORT_PARAMETERS PortInfo;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
KEVENT IoctlCompleteEvent;
|
|
PIO_STACK_LOCATION irpStack, nextStack;
|
|
int i;
|
|
PAGED_CODE ();
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
|
|
("HGM_GetResources(DeviceObject=0x%x,Irp=0x%x)",\
|
|
DeviceObject, Irp));
|
|
|
|
/*
|
|
* Get a pointer to the device extension
|
|
*/
|
|
|
|
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
|
|
|
|
|
|
/*
|
|
* issue a synchronous request to get the resources info from GameEnum
|
|
*/
|
|
|
|
KeInitializeEvent(&IoctlCompleteEvent, NotificationEvent, FALSE);
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
nextStack = IoGetNextIrpStackLocation(Irp);
|
|
ASSERTMSG("HGM_GetResources:",nextStack != NULL);
|
|
|
|
/*
|
|
* pass the Portinfo buffer of the DeviceExtension
|
|
*/
|
|
|
|
nextStack->MajorFunction =
|
|
IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_GAMEENUM_PORT_PARAMETERS;
|
|
|
|
PortInfo.Size =
|
|
nextStack->Parameters.DeviceIoControl.InputBufferLength =
|
|
nextStack->Parameters.DeviceIoControl.OutputBufferLength =
|
|
sizeof (PortInfo);
|
|
|
|
Irp->UserBuffer = &PortInfo;
|
|
|
|
IoSetCompletionRoutine (Irp, HGM_PnPComplete,
|
|
&IoctlCompleteEvent, TRUE, TRUE, TRUE);
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_BABBLE,\
|
|
("calling GameEnum"));
|
|
|
|
ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
|
|
|
|
if( NT_SUCCESS(ntStatus) )
|
|
{
|
|
ntStatus = KeWaitForSingleObject(
|
|
&IoctlCompleteEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
}
|
|
|
|
if( NT_SUCCESS(ntStatus) )
|
|
{
|
|
ntStatus = Irp->IoStatus.Status;
|
|
}
|
|
DeviceExtension->GameContext = PortInfo.GameContext;
|
|
DeviceExtension->ReadAccessor = PortInfo.ReadAccessor;
|
|
DeviceExtension->WriteAccessor = PortInfo.WriteAccessor;
|
|
DeviceExtension->ReadAccessorDigital= PortInfo.ReadAccessorDigital;
|
|
DeviceExtension->AcquirePort = PortInfo.AcquirePort;
|
|
DeviceExtension->ReleasePort = PortInfo.ReleasePort;
|
|
DeviceExtension->PortContext = PortInfo.PortContext;
|
|
DeviceExtension->nAxes = PortInfo.NumberAxis;
|
|
DeviceExtension->nButtons = PortInfo.NumberButtons;
|
|
|
|
#ifdef CHANGE_DEVICE
|
|
/*
|
|
* Stash the NextDeviceObject in the device extension so that we can
|
|
* call GameEnum IRPs when we're not responding to an IRP
|
|
*/
|
|
DeviceExtension->NextDeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
|
|
#endif /* CHANGE_DEVICE */
|
|
|
|
RtlCopyMemory(DeviceExtension->HidGameOemData.Game_Oem_Data, PortInfo.OemData, sizeof(PortInfo.OemData));
|
|
|
|
for(i=0x0;
|
|
i < sizeof(PortInfo.OemData)/sizeof(PortInfo.OemData[0]);
|
|
i++)
|
|
{
|
|
HGM_DBGPRINT( FILE_PNP | HGM_BABBLE2,\
|
|
("JoystickConfig: PortInfo.OemData[%d]=0x%x",\
|
|
i, PortInfo.OemData[i]) );
|
|
}
|
|
|
|
|
|
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_GetResources", Irp->IoStatus.Status);
|
|
|
|
return Irp->IoStatus.Status;
|
|
} /* HGM_GetResources */
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_PnPComplete |
|
|
*
|
|
* Completion routine for PnP IRPs.
|
|
* Not pageable because it is a completion routine.
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DeviceObject |
|
|
*
|
|
* Pointer to the device object.
|
|
*
|
|
* @parm IN PIRP | Irp |
|
|
*
|
|
* Pointer to an I/O request packet.
|
|
*
|
|
* @rvalue STATUS_MORE_PROCESSING_REQUIRED | We want the IRP back
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS INTERNAL
|
|
HGM_PnPComplete
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
|
|
("HGM_PnPComplete(DeviceObject=0x%x,Irp=0x%x,Context=0x%x)", \
|
|
DeviceObject, Irp, Context));
|
|
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
KeSetEvent ((PKEVENT) Context, 0, FALSE);
|
|
|
|
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_PnpComplete", ntStatus);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HGM_Power |
|
|
*
|
|
* The power dispatch routine.
|
|
* <nl>This driver does not recognize power IRPS. It merely sends them down,
|
|
* unmodified to the next device on the attachment stack.
|
|
* As this is a POWER irp, and therefore a special irp, special power irp
|
|
* handling is required. No completion routine is required.
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DeviceObject |
|
|
*
|
|
* Pointer to the device object.
|
|
*
|
|
* @parm IN PIRP | Irp |
|
|
*
|
|
* Pointer to an I/O request packet.
|
|
*
|
|
*
|
|
* @rvalue STATUS_SUCCESS | success
|
|
* @rvalue ??? | Return from PoCallDriver()
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS INTERNAL
|
|
HGM_Power
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
PAGED_CODE ();
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_FENTRY,\
|
|
("Enter HGM_Power(DeviceObject=0x%x,Irp=0x%x)",DeviceObject, Irp));
|
|
|
|
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
|
|
|
|
/*
|
|
* Since we do not know what to do with the IRP, we should pass
|
|
* it on along down the stack.
|
|
*/
|
|
|
|
ntStatus = HGM_IncRequestCount( DeviceExtension );
|
|
if (!NT_SUCCESS (ntStatus))
|
|
{
|
|
/*
|
|
* Someone sent us another plug and play IRP after removed
|
|
*/
|
|
|
|
HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\
|
|
("HGM_Power: PnP IRP after device was removed\n"));
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
} else
|
|
{
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
|
|
/*
|
|
* Power IRPS come synchronously; drivers must call
|
|
* PoStartNextPowerIrp, when they are ready for the next power irp.
|
|
* This can be called here, or in the completetion routine.
|
|
*/
|
|
PoStartNextPowerIrp (Irp);
|
|
|
|
/*
|
|
* NOTE!!! PoCallDriver NOT IoCallDriver.
|
|
*/
|
|
ntStatus = PoCallDriver (GET_NEXT_DEVICE_OBJECT (DeviceObject), Irp);
|
|
|
|
HGM_DecRequestCount( DeviceExtension );
|
|
}
|
|
|
|
|
|
HGM_EXITPROC(FILE_IOCTL | HGM_FEXIT, "HGM_Power", ntStatus);
|
|
return ntStatus;
|
|
} /* HGM_Power */
|
|
|