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.
707 lines
22 KiB
707 lines
22 KiB
//**************************************************************************
|
|
//
|
|
// PNP.C -- Xena Gaming Project
|
|
//
|
|
// This module contains PnP Start, Stop, Remove, Power dispatch routines
|
|
// and the IRP cancel routine.
|
|
//
|
|
// Version 3.XX
|
|
//
|
|
// Copyright (c) 1997 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// @doc
|
|
// @module PNP.C | Supports PnP Start, Stop, Remove, Power dispatch routines
|
|
// and the IRP cancel routine.
|
|
//**************************************************************************
|
|
|
|
#include <msgame.h>
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Alloc_text pragma to specify routines that can be paged out.
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, MSGAME_Power)
|
|
#pragma alloc_text (PAGE, MSGAME_PnP)
|
|
#pragma alloc_text (PAGE, MSGAME_StopDevice)
|
|
#pragma alloc_text (PAGE, MSGAME_GetResources)
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Private Data
|
|
//---------------------------------------------------------------------------
|
|
|
|
static PVOID CurrentGameContext = NULL;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func The plug and play dispatch routines.
|
|
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_PnP (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
|
|
{
|
|
LONG i;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION pDevExt;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
|
|
PAGED_CODE ();
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_PnP Enter\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
|
|
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
|
|
|
|
InterlockedIncrement (&pDevExt->IrpCount);
|
|
|
|
if (pDevExt->Removed)
|
|
{
|
|
//
|
|
// Someone sent us another plug and play IRP after removed
|
|
//
|
|
|
|
MsGamePrint ((DBG_SEVERE, "%s: PnP Irp after device removed\n", MSGAME_NAME));
|
|
ASSERT (FALSE);
|
|
|
|
if (!InterlockedDecrement (&pDevExt->IrpCount))
|
|
KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
|
|
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
|
|
return (STATUS_DELETE_PENDING);
|
|
}
|
|
|
|
switch (pIrpStack->MinorFunction)
|
|
{
|
|
case 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.
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (pIrp);
|
|
IoSetCompletionRoutine (pIrp, MSGAME_PnPComplete, pDevExt, TRUE, TRUE, TRUE);
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
if (ntStatus == STATUS_PENDING)
|
|
KeWaitForSingleObject (
|
|
&pDevExt->StartEvent,
|
|
Executive, // Waiting for reason of a driver
|
|
KernelMode, // Waiting in kernel mode
|
|
FALSE, // No allert
|
|
NULL); // No timeout
|
|
|
|
if (NT_SUCCESS (ntStatus))
|
|
{
|
|
//
|
|
// As we are now back from our start device we can do work.
|
|
//
|
|
ntStatus = MSGAME_StartDevice (pDevExt, pIrp);
|
|
}
|
|
|
|
//
|
|
// Return Status
|
|
//
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
case 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.
|
|
//
|
|
|
|
MSGAME_StopDevice (pDevExt, TRUE);
|
|
|
|
//
|
|
// 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 (pIrp);
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
//
|
|
// We have been unexpectedly removed by the user. Stop the device,
|
|
// set status to SUCCESS and call next stack location with this IRP.
|
|
//
|
|
|
|
if (!pDevExt->Surprised && pDevExt->Started)
|
|
MSGAME_StopDevice (pDevExt, TRUE);
|
|
|
|
pDevExt->Surprised = TRUE;
|
|
|
|
//
|
|
// We don't want a completion routine so fire and forget.
|
|
// Set the current stack location to the next location and
|
|
// call the next device after setting status to success.
|
|
//
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
break;
|
|
|
|
case 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.
|
|
|
|
if (pDevExt->Started)
|
|
{
|
|
//
|
|
// Stop the device without touching the hardware.
|
|
//
|
|
MSGAME_StopDevice (pDevExt, FALSE);
|
|
}
|
|
|
|
pDevExt->Removed = TRUE;
|
|
|
|
//
|
|
// Send on the remove IRP
|
|
//
|
|
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
|
|
//
|
|
// Must double-decrement because we start at One
|
|
//
|
|
|
|
i = InterlockedDecrement (&pDevExt->IrpCount);
|
|
ASSERT(i>0);
|
|
|
|
if (InterlockedDecrement (&pDevExt->IrpCount) > 0)
|
|
KeWaitForSingleObject (&pDevExt->RemoveEvent, Executive, KernelMode, FALSE, NULL);
|
|
|
|
//
|
|
// Return success
|
|
//
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
default:
|
|
//
|
|
// Here the filter driver might modify the behavior of these IRPS
|
|
// Please see PlugPlay documentation for use of these IRPs.
|
|
//
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
MsGamePrint ((DBG_INFORM, "%s_PnP calling next driver with minor function %ld at IRQL %ld\n", MSGAME_NAME, pIrpStack->MinorFunction, KeGetCurrentIrql()));
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
break;
|
|
}
|
|
|
|
if (!InterlockedDecrement (&pDevExt->IrpCount))
|
|
KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_PnP exit\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (ntStatus);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Completion routine for Pnp start device
|
|
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @parm PVOID | Context | Pointer to device context
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_PnPComplete (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PDEVICE_EXTENSION pDevExt;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_PnPComplete enter\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
pDevExt = (PDEVICE_EXTENSION) Context;
|
|
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
|
|
|
|
switch (pIrpStack->MajorFunction)
|
|
{
|
|
case IRP_MJ_PNP:
|
|
switch (pIrpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
KeSetEvent (&pDevExt->StartEvent, 0, FALSE);
|
|
|
|
//
|
|
// Take IRP back so we can continue using it during the IRP_MN_START_DEVICE
|
|
// dispatch routine. We will have to call IoCompleteRequest there.
|
|
//
|
|
return (STATUS_MORE_PROCESSING_REQUIRED);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_PnPComplete Exit\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (ntStatus);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func PnP start device IRP handler
|
|
// @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_StartDevice (IN PDEVICE_EXTENSION pDevExt, IN PIRP pIrp)
|
|
{
|
|
PWCHAR HardwareId;
|
|
NTSTATUS ntStatus;
|
|
PDEVICEINFO DevInfo;
|
|
PDEVICE_OBJECT RemoveObject;
|
|
|
|
PAGED_CODE ();
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_StartDevice Enter\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// The PlugPlay system should not have started a removed device!
|
|
//
|
|
|
|
ASSERT (!pDevExt->Removed);
|
|
|
|
if (pDevExt->Started)
|
|
return (STATUS_SUCCESS);
|
|
|
|
//
|
|
// Acquire resources we need for this device
|
|
//
|
|
|
|
ntStatus = MSGAME_GetResources (pDevExt, pIrp);
|
|
if (!NT_SUCCESS(ntStatus))
|
|
return (ntStatus);
|
|
|
|
//
|
|
// Dump debug OEM Data fields
|
|
//
|
|
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[0] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[0]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[1] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[1]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[2] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[2]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[3] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[3]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[4] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[4]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[5] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[5]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[6] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[6]));
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[7] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[7]));
|
|
|
|
//
|
|
// Make sure we are only on one gameport
|
|
//
|
|
|
|
if (CurrentGameContext && (CurrentGameContext != pDevExt->PortInfo.GameContext))
|
|
{
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_StartDevice Cannot Load on Multiple Gameports: 0x%X and 0x%X\n",\
|
|
CurrentGameContext, pDevExt->PortInfo.GameContext, MSGAME_NAME, MSGAME_NAME));
|
|
return (STATUS_DEVICE_CONFIGURATION_ERROR);
|
|
}
|
|
CurrentGameContext = pDevExt->PortInfo.GameContext;
|
|
|
|
//
|
|
// Get the HardwareId for this Start request
|
|
//
|
|
|
|
HardwareId = MSGAME_GetHardwareId (pDevExt->Self);
|
|
if (!HardwareId)
|
|
{
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId Failed\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (STATUS_DEVICE_CONFIGURATION_ERROR);
|
|
}
|
|
|
|
//
|
|
// Initialize OEM Data
|
|
//
|
|
|
|
SET_DEVICE_OBJECT(&pDevExt->PortInfo, pDevExt->Self);
|
|
|
|
//
|
|
// Now start the low level device
|
|
//
|
|
|
|
ntStatus = DEVICE_StartDevice (&pDevExt->PortInfo, HardwareId);
|
|
|
|
//
|
|
// Free HardwareId right away
|
|
//
|
|
|
|
MSGAME_FreeHardwareId (HardwareId);
|
|
|
|
//
|
|
// Check if low-level start device failed
|
|
//
|
|
|
|
if (NT_ERROR(ntStatus))
|
|
{
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_StartDevice Failed\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (ntStatus);
|
|
}
|
|
|
|
//
|
|
// Everything is fine so let's say device has started
|
|
//
|
|
|
|
pDevExt->Started = TRUE;
|
|
|
|
//
|
|
// Return status
|
|
//
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_StartDevice Exit\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func PnP start device IRP handler
|
|
// @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
|
|
// @parm BOOLEAN | TouchTheHardware | Flag to send non PnP Irps to device
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function <en->
|
|
// The PlugPlay system has dictacted the removal of this device.
|
|
// We have no choise but to detach and delete the device object.
|
|
// (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
|
|
//---------------------------------------------------------------------------
|
|
|
|
VOID MSGAME_StopDevice (IN PDEVICE_EXTENSION pDevExt, IN BOOLEAN TouchTheHardware)
|
|
{
|
|
PAGED_CODE ();
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_StopDevice enter \n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// The PlugPlay system should not have started a removed device!
|
|
//
|
|
|
|
ASSERT (!pDevExt->Removed);
|
|
if (!pDevExt->Started)
|
|
return;
|
|
|
|
//
|
|
// Now stop the low level device
|
|
//
|
|
|
|
DEVICE_StopDevice (&pDevExt->PortInfo, TouchTheHardware);
|
|
|
|
//
|
|
// Everything is fine so let's say device has stopped
|
|
//
|
|
|
|
pDevExt->Started = FALSE;
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_StopDevice exit \n", MSGAME_NAME, MSGAME_NAME));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Power dispatch routine.
|
|
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
|
|
{
|
|
PDEVICE_EXTENSION pDevExt;
|
|
NTSTATUS ntStatus;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
|
|
PAGED_CODE ();
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_Power Enter MN_Function %x type %x State %x\n", MSGAME_NAME, MSGAME_NAME,pIrpStack->MinorFunction,pIrpStack->Parameters.Power.Type,pIrpStack->Parameters.Power.State));
|
|
|
|
pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
|
|
|
|
//
|
|
// This IRP was sent to the filter driver. Since we do not know what
|
|
// to do with the IRP, we should pass it on along down the stack.
|
|
//
|
|
|
|
InterlockedIncrement (&pDevExt->IrpCount);
|
|
|
|
if (pDevExt->Removed)
|
|
{
|
|
ntStatus = STATUS_DELETE_PENDING;
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = ntStatus;
|
|
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
|
|
}
|
|
else
|
|
{
|
|
//Is System trying to wake up device
|
|
if ((2 == (pIrpStack->MinorFunction)) && (1 == (pIrpStack->Parameters.Power.Type)) &&( 1 == (pIrpStack->Parameters.Power.State.SystemState)))
|
|
{
|
|
// Clear DeviceDetected to force reset and redetect
|
|
SET_DEVICE_INFO(&(pDevExt->PortInfo),0);
|
|
MsGamePrint ((DBG_CONTROL, "%s: %s_Power Resetting Device Detected\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
|
|
}
|
|
//
|
|
// 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 (pIrp);
|
|
|
|
//
|
|
// PoCallDriver NOT IoCallDriver.
|
|
//
|
|
IoSkipCurrentIrpStackLocation (pIrp);
|
|
ntStatus = PoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
}
|
|
|
|
if (!InterlockedDecrement (&pDevExt->IrpCount))
|
|
KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_Power Exit\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (ntStatus);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Calls GameEnum to request gameport parameters
|
|
// @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_GetResources (IN PDEVICE_EXTENSION pDevExt, IN PIRP pIrp)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
KEVENT IoctlCompleteEvent;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
PIO_STACK_LOCATION pIrpStack, nextStack;
|
|
|
|
PAGED_CODE ();
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_GetResources Enter\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// Issue a synchronous request to get the resources info from GameEnum
|
|
//
|
|
|
|
KeInitializeEvent (&IoctlCompleteEvent, NotificationEvent, FALSE);
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
|
|
nextStack = IoGetNextIrpStackLocation (pIrp);
|
|
ASSERT (nextStack);
|
|
|
|
//
|
|
// Pass the Portinfo buffer of the DeviceExtension
|
|
//
|
|
|
|
pDevExt->PortInfo.Size = sizeof (GAMEPORT);
|
|
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_GAMEENUM_PORT_PARAMETERS;
|
|
nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof (GAMEPORT);
|
|
nextStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof (GAMEPORT);
|
|
pIrp->UserBuffer = &pDevExt->PortInfo;
|
|
|
|
IoSetCompletionRoutine (pIrp, MSGAME_GetResourcesComplete, &IoctlCompleteEvent, TRUE, TRUE, TRUE);
|
|
|
|
MsGamePrint ((DBG_CONTROL, "%s: Calling GameEnum to Get Resources at IRQL=%lu\n", MSGAME_NAME, KeGetCurrentIrql()));
|
|
|
|
ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
|
|
if (ntStatus == STATUS_PENDING)
|
|
ntStatus = KeWaitForSingleObject (&IoctlCompleteEvent, Suspended, KernelMode, FALSE, NULL);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
MsGamePrint ((DBG_VERBOSE, "%s: %s_GetResources Port Obtained = 0x%lX\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.GameContext));
|
|
else MsGamePrint ((DBG_SEVERE, "%s: GameEnum Failed to Provide Resources, Status = %X\n", MSGAME_NAME, ntStatus));
|
|
|
|
//
|
|
// Return Status
|
|
//
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_GetResources Exit\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (pIrp->IoStatus.Status);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Completion routine for GameEnum get reosources driver call
|
|
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
|
|
// @parm PIRP | pIrp | Pointer to IO request packet
|
|
// @parm PVOID | Context | Pointer to device context
|
|
// @rdesc Returns NT status code
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS MSGAME_GetResourcesComplete (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context)
|
|
{
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
|
|
KeSetEvent ((PKEVENT)Context, 0, FALSE);
|
|
|
|
if (pIrp->PendingReturned)
|
|
IoMarkIrpPending (pIrp);
|
|
|
|
return (STATUS_MORE_PROCESSING_REQUIRED);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Gets HardwareId string for device object (assumes caller frees)
|
|
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
|
|
// @rdesc Pointer to allocated memory containing string
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
PWCHAR MSGAME_GetHardwareId (IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
LONG BufferLength = 0;
|
|
PWCHAR Buffer = NULL;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_OBJECT pPDO;
|
|
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_GetHardwareId\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// Walk to end of stack and get pointer to PDO
|
|
//
|
|
|
|
pPDO = DeviceObject;
|
|
while (GET_NEXT_DEVICE_OBJECT(pPDO))
|
|
pPDO = GET_NEXT_DEVICE_OBJECT(pPDO);
|
|
|
|
//
|
|
// Get Buffer length
|
|
//
|
|
|
|
ntStatus = IoGetDeviceProperty(
|
|
pPDO,
|
|
DevicePropertyHardwareID,
|
|
BufferLength,
|
|
Buffer,
|
|
&BufferLength);
|
|
|
|
ASSERT(ntStatus==STATUS_BUFFER_TOO_SMALL);
|
|
|
|
//
|
|
// Allocate room for HardwareID
|
|
//
|
|
|
|
Buffer = ExAllocatePool(PagedPool, BufferLength);
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// If we cannot get the memory to try this, then just say it is a no match
|
|
//
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId failed ExAllocate\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (NULL);
|
|
}
|
|
|
|
//
|
|
// Now get the data
|
|
//
|
|
|
|
ntStatus = IoGetDeviceProperty(
|
|
pPDO,
|
|
DevicePropertyHardwareID,
|
|
BufferLength,
|
|
Buffer,
|
|
&BufferLength);
|
|
|
|
//
|
|
// On error, free memory and return NULL
|
|
//
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId couldn't get id from PDO\n", MSGAME_NAME, MSGAME_NAME));
|
|
ExFreePool(Buffer);
|
|
return (NULL);
|
|
}
|
|
|
|
//
|
|
// Return buffer containing hardware Id - must be freed by caller
|
|
//
|
|
|
|
return (Buffer);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Compares HardwareId strings
|
|
// @parm PWCHAR | HardwareId | Pointer to object hardware id
|
|
// @parm PWCHAR | DeviceId | Pointer to device's hardware id
|
|
// @rdesc True if strings are the same, false if different
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOLEAN MSGAME_CompareHardwareIds (IN PWCHAR HardwareId, IN PWCHAR DeviceId)
|
|
{
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_CompareHardwareIds\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// Peform runtime parameter checks
|
|
//
|
|
|
|
if (!HardwareId || !DeviceId)
|
|
{
|
|
MsGamePrint ((DBG_SEVERE, "%s: %s_CompareHardwareIds - Bogus Strings\n", MSGAME_NAME, MSGAME_NAME));
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Perform char-by-char string compare
|
|
//
|
|
|
|
while (*HardwareId && *DeviceId)
|
|
{
|
|
if (TOUPPER(*HardwareId) != TOUPPER(*DeviceId))
|
|
return (FALSE);
|
|
HardwareId++;
|
|
DeviceId++;
|
|
}
|
|
|
|
//
|
|
// Return success
|
|
//
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// @func Frees HardwareId allocated from MSGAME_GetHardwareId
|
|
// @parm PWCHAR | HardwareId | Pointer to hardware id to free
|
|
// @rdesc None
|
|
// @comm Public function
|
|
//---------------------------------------------------------------------------
|
|
|
|
VOID MSGAME_FreeHardwareId (IN PWCHAR HardwareId)
|
|
{
|
|
MsGamePrint ((DBG_INFORM, "%s: %s_FreeHardwareId\n", MSGAME_NAME, MSGAME_NAME));
|
|
|
|
//
|
|
// Free memory pool
|
|
//
|
|
|
|
if (HardwareId)
|
|
ExFreePool(HardwareId);
|
|
}
|