Leaked source code of windows server 2003
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.
 
 
 
 
 
 

673 lines
20 KiB

/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
GAMEENUM.C
Abstract:
This module contains contains the entry points for a standard bus
PNP / WDM driver.
@@BEGIN_DDKSPLIT
Author:
Kenneth D. Ray
Doron J. Holan
@@END_DDKSPLIT
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <wdm.h>
#include <initguid.h>
#include "gameport.h"
#include "gameenum.h"
#include "stdio.h"
//
// Global Debug Level
//
#if DBG
ULONG GameEnumDebugLevel = GAME_DEFAULT_DEBUG_OUTPUT_LEVEL;
#endif
//
// Declare some entry functions as pageable, and make DriverEntry
// discardable
//
NTSTATUS DriverEntry (PDRIVER_OBJECT, PUNICODE_STRING);
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, Game_DriverUnload)
#pragma alloc_text (PAGE, Game_PortParameters)
#pragma alloc_text (PAGE, Game_CreateClose)
#pragma alloc_text (PAGE, Game_IoCtl)
#pragma alloc_text (PAGE, Game_InternIoCtl)
#endif
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING UniRegistryPath
)
/*++
Routine Description:
Initialize the entry points of the driver.
--*/
{
PDEVICE_OBJECT device;
UNREFERENCED_PARAMETER (UniRegistryPath);
Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Driver Entry\n"));
DriverObject->MajorFunction [IRP_MJ_CREATE] =
DriverObject->MajorFunction [IRP_MJ_CLOSE] = Game_CreateClose;
DriverObject->MajorFunction [IRP_MJ_SYSTEM_CONTROL] = Game_SystemControl;
DriverObject->MajorFunction [IRP_MJ_PNP] = Game_PnP;
DriverObject->MajorFunction [IRP_MJ_POWER] = Game_Power;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Game_IoCtl;
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
= Game_InternIoCtl;
DriverObject->DriverUnload = Game_DriverUnload;
DriverObject->DriverExtension->AddDevice = Game_AddDevice;
return STATUS_SUCCESS;
}
NTSTATUS
Game_CreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Some outside source is trying to create a file against us.
If this is for the FDO (the bus itself) then the caller is trying to
open the propriatary conection to tell us which game port to enumerate.
If this is for the PDO (an object on the bus) then this is a client that
wishes to use the game port.
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
KEVENT event;
PFDO_DEVICE_DATA data;
PAGED_CODE ();
data = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
status = Game_IncIoCount (data);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Create \n"));
if (0 != irpStack->FileObject->FileName.Length) {
//
// The caller is trying to open a subdirectory off the device
// object name. This is not allowed.
//
status = STATUS_ACCESS_DENIED;
}
break;
case IRP_MJ_CLOSE:
Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Close \n"));
;
}
Game_DecIoCount (data);
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Game_IoCtl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Handle user mode expose, remove, and device description requests.
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
ULONG inlen;
ULONG outlen;
PCOMMON_DEVICE_DATA commonData;
PFDO_DEVICE_DATA fdoData;
PVOID buffer;
PAGED_CODE ();
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
buffer = Irp->AssociatedIrp.SystemBuffer;
//
// We only take Device Control requests for the FDO.
// That is the bus itself.
//
// The request is one of the propriatary Ioctls for
//
// NB we are not a filter driver, so we do not pass on the irp.
//
inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (!commonData->IsFDO) {
//
// These commands are only allowed to go to the FDO.
//
status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
if (!fdoData->Started) {
status = STATUS_DEVICE_NOT_READY;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
status = Game_IncIoCount (fdoData);
if (!NT_SUCCESS (status)) {
//
// This bus has received the PlugPlay remove IRP. It will no longer
// resond to external requests.
//
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_GAMEENUM_EXPOSE_HARDWARE:
if ((inlen == outlen) &&
//
// Make sure it is at least two nulls (ie, an empty multi sz)
// and the size field is set to the declared size of the struct
//
((sizeof (GAMEENUM_EXPOSE_HARDWARE) + sizeof(UNICODE_NULL) * 2) <=
inlen) &&
//
// The size field should be set to the sizeof the struct as declared
// and *not* the size of the struct plus the multi sz
//
(sizeof (GAMEENUM_EXPOSE_HARDWARE) ==
((PGAMEENUM_EXPOSE_HARDWARE) buffer)->Size)) {
Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Expose called\n"));
status= Game_Expose((PGAMEENUM_EXPOSE_HARDWARE)buffer,
inlen,
fdoData);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_GAMEENUM_REMOVE_HARDWARE:
if ((sizeof (GAMEENUM_REMOVE_HARDWARE) == inlen) &&
(inlen == outlen) &&
(((PGAMEENUM_REMOVE_HARDWARE)buffer)->Size == inlen)) {
Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Remove called\n"));
status= Game_Remove((PGAMEENUM_REMOVE_HARDWARE)buffer, fdoData);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_GAMEENUM_PORT_DESC:
if ((sizeof (GAMEENUM_PORT_DESC) == inlen) &&
(inlen == outlen) &&
(((PGAMEENUM_PORT_DESC)buffer)->Size == inlen)) {
Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Port desc called\n"));
//
// Fill in the information first. If there is a lower driver, it
// will change replace the values that gameenum has placed in the
// buffer. We don't care if the call down succeeds or not
//
status = Game_ListPorts ((PGAMEENUM_PORT_DESC) buffer, fdoData);
Game_SendIrpSynchronously (fdoData->TopOfStack,
Irp,
FALSE,
TRUE);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
default:
status = STATUS_INVALID_PARAMETER;
}
Game_DecIoCount (fdoData);
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Game_InternIoCtl (
PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
--*/
{
PIO_STACK_LOCATION irpStack, next;
NTSTATUS status;
PCOMMON_DEVICE_DATA commonData;
PPDO_DEVICE_DATA pdoData;
PVOID buffer;
BOOLEAN validAccessors;
ULONG inlen;
ULONG outlen;
PAGED_CODE ();
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_INTERNAL_DEVICE_CONTROL == irpStack->MajorFunction);
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
pdoData = (PPDO_DEVICE_DATA) DeviceObject->DeviceExtension;
inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
//
// We only take Internal Device Control requests for the PDO.
// That is the objects on the bus (representing the game ports)
//
// The request is from a FDO driver attached to this game port device object
// inquiring about the port itself.
//
// NB we are not a filter driver, so we do not pass on the irp.
//
if (commonData->IsFDO) {
Game_KdPrint(((PFDO_DEVICE_DATA) commonData), GAME_DBG_IOCTL_ERROR,
("internal ioctl called on fdo!\n"))
status = STATUS_ACCESS_DENIED;
} else if (!pdoData->Started) {
//
// The bus has not been started yet
//
status = STATUS_DEVICE_NOT_READY;
} else if (pdoData->Removed) {
//
// This bus has received the PlugPlay remove IRP. It will no longer
// resond to external requests.
//
status = STATUS_DELETE_PENDING;
} else {
buffer = Irp->UserBuffer;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_GAMEENUM_PORT_PARAMETERS:
if ((inlen == outlen) &&
(outlen == ((PGAMEENUM_PORT_PARAMETERS) buffer)->Size)) {
Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE,
("Port parameters called\n"));
status = Game_PortParameters ((PGAMEENUM_PORT_PARAMETERS) buffer,
pdoData);
}
else {
Game_KdPrint(pdoData, GAME_DBG_IOCTL_ERROR,
("InBufLen: %d, OutBufLen: %d, Size: %d\n",
inlen, outlen,
((PGAMEENUM_PORT_PARAMETERS) buffer)->Size));
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_GAMEENUM_EXPOSE_SIBLING:
if ((inlen == outlen) &&
//
// Make sure that the buffer passed in is of the correct size
//
(sizeof (GAMEENUM_EXPOSE_SIBLING) == inlen) &&
//
// The size field should be set to the sizeof the struct
//
(sizeof (GAMEENUM_EXPOSE_SIBLING) ==
((PGAMEENUM_EXPOSE_SIBLING) buffer)->Size)) {
Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE, ("Expose sibling"));
status = Game_ExposeSibling ((PGAMEENUM_EXPOSE_SIBLING) buffer,
pdoData);
}
else {
Game_KdPrint(pdoData, GAME_DBG_IOCTL_ERROR,
("Expected an input and output buffer lengths to be equal (in = %d, out %d)\n"
"Expected an input buffer length of %d, received %d\n"
"Expected GAME_EXPOSE_SIBLING.Size == %d, received %d\n",
inlen, outlen,
sizeof (GAMEENUM_EXPOSE_SIBLING), inlen,
sizeof (GAMEENUM_EXPOSE_SIBLING),
((PGAMEENUM_EXPOSE_SIBLING) buffer)->Size));
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_GAMEENUM_REMOVE_SELF:
Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE, ("Remove self\n"));
status = Game_RemoveSelf (pdoData);
break;
default:
status = STATUS_INVALID_PARAMETER;
}
}
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
VOID
Game_DriverUnload (
IN PDRIVER_OBJECT Driver
)
/*++
Routine Description:
Clean up everything we did in driver entry.
--*/
{
#if (!DBG)
UNREFERENCED_PARAMETER (Driver);
#endif
PAGED_CODE ();
//
// All the device objects should be gone.
//
ASSERT (NULL == Driver->DeviceObject);
//
// Here we free any resources allocated in DriverEntry
//
return;
}
NTSTATUS
Game_PortParameters (
PGAMEENUM_PORT_PARAMETERS Parameters,
PPDO_DEVICE_DATA PdoData
)
{
PFDO_DEVICE_DATA fdoData;
GAMEENUM_ACQUIRE_ACCESSORS gameAccessors;
PIO_STACK_LOCATION next;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
KEVENT event;
PIRP accessorIrp;
PAGED_CODE ();
if (sizeof (GAMEENUM_PORT_PARAMETERS) != Parameters->Size) {
Game_KdPrint(PdoData, GAME_DBG_IOCTL_ERROR,
("Wanted %d, got %d for size of buffer\n",
sizeof(GAMEENUM_PORT_PARAMETERS), Parameters->Size));
return STATUS_INVALID_PARAMETER;
}
fdoData = FDO_FROM_PDO (PdoData);
KeInitializeEvent (&event, NotificationEvent, FALSE);
RtlZeroMemory(&gameAccessors, sizeof(GAMEENUM_ACQUIRE_ACCESSORS));
gameAccessors.Size = sizeof(GAMEENUM_ACQUIRE_ACCESSORS);
accessorIrp =
IoBuildDeviceIoControlRequest (IOCTL_GAMEENUM_ACQUIRE_ACCESSORS,
fdoData->TopOfStack,
NULL,
0,
&gameAccessors,
sizeof (GAMEENUM_PORT_PARAMETERS),
TRUE,
&event,
&iosb);
if (!accessorIrp) {
goto Game_NoCustomAccessors;
}
status = IoCallDriver(fdoData->TopOfStack, accessorIrp);
//
// Wait for lower drivers to be done with the Irp
//
if (status == STATUS_PENDING) {
KeWaitForSingleObject (&event,
Executive,
KernelMode,
FALSE,
NULL);
status = iosb.Status;
}
if (!NT_SUCCESS(status) ||
!(gameAccessors.GameContext &&
gameAccessors.WriteAccessor && gameAccessors.ReadAccessor)) {
//
// If TopOfStack or below does not handle this IOCTL, we better have
// received the necessary resources to allow our children to read and
// write to their devices
//
ASSERT (fdoData->GamePortAddress != NULL);
ASSERT (fdoData->ReadPort != NULL);
ASSERT (fdoData->WritePort != NULL);
Game_NoCustomAccessors:
//
// No filter below us (either the IOCTL failed, or not all of the req.
// fields were filled in) ... fill in w/standard values
//
Parameters->ReadAccessor = fdoData->ReadPort;
Parameters->WriteAccessor = fdoData->WritePort;
Parameters->ReadAccessorDigital = NULL;
Parameters->GameContext = fdoData->GamePortAddress;
}
else {
//
// There is a filter below us, fill in w/the appropriate values
//
Parameters->ReadAccessor = gameAccessors.ReadAccessor;
Parameters->WriteAccessor = gameAccessors.WriteAccessor;
Parameters->ReadAccessorDigital = gameAccessors.ReadAccessorDigital;
Parameters->GameContext = gameAccessors.GameContext;
if (gameAccessors.PortContext) {
fdoData->LowerAcquirePort = gameAccessors.AcquirePort;
fdoData->LowerReleasePort = gameAccessors.ReleasePort;
fdoData->LowerPortContext = gameAccessors.PortContext;
}
}
//
// Acquire/release always goes through the gameenum even if a lower
// filter exists
//
Parameters->AcquirePort = (PGAMEENUM_ACQUIRE_PORT) Game_AcquirePort;
Parameters->ReleasePort = (PGAMEENUM_RELEASE_PORT) Game_ReleasePort;
Parameters->PortContext = fdoData;
Parameters->Portion = PdoData->Portion;
Parameters->NumberAxis = PdoData->NumberAxis;
Parameters->NumberButtons = PdoData->NumberButtons;
RtlCopyMemory (&Parameters->OemData,
&PdoData->OemData,
sizeof(GAMEENUM_OEM_DATA));
return STATUS_SUCCESS;
}
NTSTATUS
Game_IncIoCount (
PFDO_DEVICE_DATA Data
)
{
InterlockedIncrement (&Data->OutstandingIO);
if (Data->Removed) {
if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
KeSetEvent (&Data->RemoveEvent, 0, FALSE);
}
return STATUS_DELETE_PENDING;
}
return STATUS_SUCCESS;
}
VOID
Game_DecIoCount (
PFDO_DEVICE_DATA Data
)
{
if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
KeSetEvent (&Data->RemoveEvent, 0, FALSE);
}
}
NTSTATUS
Game_AcquirePort(
PFDO_DEVICE_DATA fdoData
)
{
if (fdoData->Removed) {
Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
("Acquire failed! Gameport associated with (0x%x) was removed....\n", fdoData));
return STATUS_NO_SUCH_DEVICE;
}
else if (!fdoData->Started) {
Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
("Acquire failed! Gameport associated with (0x%x) is not started....\n", fdoData));
return STATUS_NO_SUCH_DEVICE;
}
else if (!fdoData->NumPDOs) {
Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
("Acquire failed! Gameport associated with (0x%x) has no devices attached....\n", fdoData));
return STATUS_NO_SUCH_DEVICE;
}
//
// If fdoData->Acquired is TRUE, then no exchange will take place and the
// value of fdoData->Acquired (TRUE) will be returned
//
if (InterlockedCompareExchange(&fdoData->Acquired, TRUE, FALSE)) {
Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
("Acquire failed! Gameport associated with (0x%x) was already acquired....\n", fdoData));
return STATUS_DEVICE_BUSY;
}
if (fdoData->LowerPortContext) {
return (*fdoData->LowerAcquirePort)(fdoData->LowerPortContext);
}
else {
return STATUS_SUCCESS;
}
}
VOID
Game_ReleasePort(
PFDO_DEVICE_DATA fdoData
)
{
ASSERT(fdoData->Acquired);
InterlockedExchange(&fdoData->Acquired, FALSE);
if (fdoData->LowerPortContext) {
(*fdoData->LowerReleasePort)(fdoData->LowerPortContext);
}
}