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.
 
 
 
 
 
 

458 lines
15 KiB

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<META NAME="Generator" CONTENT="Microsoft Word 97">
<TITLE>GameEnum.sys</TITLE>
<META NAME="Template" CONTENT="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
</HEAD>
<BODY TEXT="#000000" LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff" leftmargin="8">
<FONT FACE="Verdana"><H2><A NAME="MYSAMPLE">GameEnum.sys</A> </H2>
<H3>Summary</H3></FONT><FONT FACE="Verdana" SIZE=2>
<P>GameEnum is a WDM driver. It is a bus driver for a legacy Gameport. It works
closely with Hidgame.sys, which controls the children GameEnum enumerates. Keywords
include <B>HID</B>, <B>WDM</B>, and <B>bus driver</B>.</P>
<H3>Building the Sample</H3></FONT><FONT FACE="Verdana" SIZE=2>
<P>The driver works on both x86 and Alpha platforms and is 64-bit compliant. It
builds properly with Visual C 6.0 and supports Plug and Play, Power Management,
and device interfaces.</P>
<P>The driver is installed when a Gameport is discovered via Plug and Play. There
are no special .inf requirements; please see GamePort.inf in the system INF
directory for an example. Once built, the sample produces one binary,
GameEnum.sys. Necessary files include those in this directory and Gameport.h
and Wdm.h. Both checked and free builds are available, and there are no known
bugs or issues to be documented.</P>
<H3>CODE TOUR</H3>
<H4>File Manifest</H4>
</FONT>
<U><PRE>File&#9;&#9;Description</U>
GameSys.htm The documentation for this sample (this file)
Gameenum.h Definitions
Gameenum.c External and internal IOCTL support
Pnp.c Plug and Play functionality
Gameenum.rc Resources
</PRE>
<h4><font face="Verdana">Programming Tour</font></h4>
<font face="Verdana" size="2">
<p>This code tour discusses the steps an audio driver must complete to setup GameEnum.sys as a functioning FDO for the
physical gameport.</p>
<p>The major topics covered in this tour include the following.
</font>
<font FACE="Verdana" SIZE="2">
<ul>
<li><a href="#requirements">Resources requirements made by GameEnum</a></li>
<li><a href="#lower_filter">Definition of a lower filter</a></li>
<li><a href="#supplied">Functions that are supplied to GameEnum's PDOs</a></li>
<li><a href="#override">How to override the supplied functions</a></li>
</ul>
</font>
<h4><font face="Verdana" size="2">
<a name="requirements">Resources requirements made by GameEnum</a>
</font></h4>
<p><font face="Verdana" size="2">
GameEnum acts as an FDO for a traditional gameport. USB joysticks do not
need any additional drivers; DirectInput will open them directly. A kernel driver
for an audio device can enumerate a child device and have GameEnum loaded on top of it.
GameEnum will handle all the details in enumerating, starting, and handling
joysticks plugged into the system.
</font></p>
<p><font face="Verdana" size="2">
The following assumptions are made by GameEnum with regards to its resources:
<ol>
<li>If there are resources provided, it does <i>not</i> have to be the port
<font face="Courier" size="2">0x201</font>. For example, the resources can be in PCI space.</li>
<li>If no resources are assigned to the GameEnum stack, then the PDO must handle
an IOCTL to supply GameEnum with the necessary data on how to access the
gameport hardware. For details on how to implement this,
see <a href="#override">below</a>.</li>
<li>There are no interrupts assigned to it.</li>
</ol>
</font></p>
<h4><font face="Verdana" size="2">
<a name="lower_filter">Definition of a lower filter</a>
</font></h4>
<p><font face="Verdana" size="2">
The term lower filter refers to a device object in the stack below GameEnum which
handles the override IOCTL. This device object can be the PDO itself (if the audio
driver is enumerating the PDO) or an actual filter object that is in between
GameEnum and the PDO in the stack.
</font></p>
<h4><font face="Verdana" size="2">
<a name="supplied">Functions that are supplied to GameEnum's PDOs</a>
</font></h4>
<p><font face="Verdana" size="2">
Once a PDO enumerated by GameEnum has started, it sends down an IOCTL to acquire
the functions it needs to read from and write to the hardware. This information
is sent via the <font face="Courier" size="2">GAMEENUM_PORT_PARAMETERS</font>
structure defined in gameport.h. If the gameport has non-standard ports, then
the lower filter must override this information by handling the override IOCTL,
which is <a href="#override">explained later in this document</a>.
</font></p>
<p><font face="Verdana" size="2">
Here is a brief description of fields that are relevant to a driver that would
override the supplied GameEnum defaults:
</font></p>
<table border=1>
<tr>
<td><font face="Verdana" size="3">
<b>Field Name</b>
</font></td>
<td><font face="Verdana" size="3">
<b>Description</b>
</font></td>
<td><font face="Verdana" size="3">
<b>Default Value</b>
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>ReadAccessor</b>
</font></td>
<td><font face="Verdana" size="2">
The function is used by the joystick driver to read analog data from the gameport hardware / joystick
</font></td>
<td><font face="Verdana" size="2">
READ_PORT_UCHAR
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>ReadAccessorDigital</b>
</font></td>
<td><font face="Verdana" size="2">
The function is used by the joystick driver to read data digitally from the gameport hardware /
joystick. This function is not supplied by default; it is only supplied if
the lower filter handles the override IOCTL.
</font></td>
<td><font face="Verdana" size="2">
NONE
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>WriteAccessor</b>
</font></td>
<td><font face="Verdana" size="2">
The function is used to by the joystick driver write data to the gameport hardware / joystick
</font></td>
<td><font face="Verdana" size="2">
WRITE_PORT_UCHAR
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>GameContext</b>
</font></td>
<td><font face="Verdana" size="2">
Context passed as a parameter to ReadAccessor, ReadAccessorDigital, and WriteAccessor
</font></td>
<td><font face="Verdana" size="2">
Port resource assigned to the stack (0x201 for example)
</font></td>
</tr>
<tr>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>AcquirePort</b>
</font></td>
<td><font face="Verdana" size="2">
<p>"Acquires" and locks the hardware. This function must be called before any of the Accessor
functions listed above may be called. The Accessor functions must be functional
between calls to AcquirePort and ReleasePort.</p>
<p> This function may fail, so the caller must check the return code before
using the Accessor functions.</p>
</font></td>
<td><font face="Verdana" size="2">
Game_AcquirePort
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>ReleasePort</b>
</font></td>
<td><font face="Verdana" size="2">
"Releases" and unlocks the hardware. This function will be called after the
joystick driver has finished calling the Accessor functions.
</font></td>
<td><font face="Verdana" size="2">
Game_ReleasePort
</font></td>
</tr>
<tr>
<td><font face="Verdana" size="2">
<b>PortContext</b>
</font></td>
<td><font face="Verdana" size="2">
Context passed as a parameter to AcquirePort and ReleasePort.
</font></td>
<td><font face="Verdana" size="2">
Context private to GameEnum
</font></td>
</tr>
</table>
<p><font face="Verdana" size="2">
To override the Accessor functions, all the fields are required, except for
ReadAccessorDigital, which is an optional field. Only override this function if
you can support digital reads on your hardware. The AcquirePort and ReleasePort
functions may be overridden only if the Accessor functions are overridden. All
the fields must be overridden; there are no optional fields.
</font></p>
<h4><font face="Verdana" size="2">
<a name="override">How to override the supplied functions</a>
</font></h4>
<p><font face="Verdana" size="2">
GameEnum will send an internal IOCTL,
<font face="Courier" size="2">IOCTL_GAMEENUM_ACQUIRE_ACCESSORS</font>, down the
stack to the lower filter so that it may override GameEnum's default
functionality. The lower filter must fill in the output buffer for this IOCTL,
which is of the size <font face="Courier" size="2">GAMEENUM_ACQUIRE_ACCESSORS</font>,
defined in gameport.h. The fields in
<font face="Courier" size="2">GAMEENUM_ACQUIRE_ACCESSORS</font> match one to one
with the relevant fields in <font face="Courier" size="2">GAMEENUM_PORT_PARAMETERS</font>
(the structure supplied to GameEnum's PDO).
</font></p>
<p><font face="Verdana" size="2">
When overriding the Accessor functions, you may provide any value for the
GameContext. It does not have to be limited to a port resource value. For instance,
you can pass your device extension as the context, and then pull data off of the
extension to set up the hardware and then perform the actual read. In essence,
you provide another level of indirection to this function call.
</font></p>
<p><font face="Verdana" size="2">
Here is a code snippet that shows how to handle the override IOCTL and perform special
actions on a fictional gameport that requires special init before the port can be
read or written.
</font></p>
<pre>
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, GameFilter_InternalIoctl)
#endif
typedef struct _DEVICE_EXTENSION {
// ...
// Port address which will enable the game port
PUCHAR GamePortEnableAddress;
// status register
PUCHAR GamePortStatusAddress;
// Port address which we read the data from (ie 0x201 on a traditional ISA card)
PUCHAR GamePortDataAddress;
// Sanity check
BOOLEAN GamePortEnabled;
// ...
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING UniRegistryPath
)
{
UNREFERENCED_PARAMETER (UniRegistryPath);
// ...
DriverObject-&gtMajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
= GameFilter_InternalIoctl;
// ...
return STATUS_SUCCESS;
}
NTSTATUS
GameFilter_InternalIoctl (
PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status;
PIO_STACK_LOCATION stack;
PDEVICE_EXTENSION devExt;
PGAMEENUM_ACQUIRE_ACCESSORS pGameEnumAcquireAccessors;
PAGED_CODE();
stack = IoGetCurrentIrpStackLocation(Irp);
devExt = (PDEVICE_EXTENSION) DeviceObject-&gtDeviceExtension;
switch (stack-&gtParameters.DeviceIoControl.IoControlCode) {
case IOCTL_GAMEENUM_ACQUIRE_ACCESSORS:
pGameEnumAcquireAccessors = (PGAMEENUM_ACQUIRE_ACCESSORS)
Irp-&gtAssociatedIrp.SystemBuffer;
if (stack-&gtParameters.DeviceIoControl.OutputBufferLength &lt
sizeof(GAMEENUM_ACQUIRE_ACCESSORS) ||
pGameEnumAcquireAccessors-&gtSize &lt
sizeof(GAMEENUM_ACQUIRE_ACCESSORS) ) {
status = STATUS_BUFFER_TOO_SMALL;
}
else {
//
// Accessor functions
//
// digital read not supported at this time in this filter
pGameEnumAcquireAccessors-&gtReadAccessorDigital = NULL;
//
// GameEnum does not know how to parse the data address out of the
// range of ports assigned to this PDO, so we must do this on
// behalf of GameEnum.
//
pGameEnumAcquireAccessors-&gtGameContext = (PVOID)
devExt-&gtGamePortDataAddress;
//
// TBD: Need to abstract out the XXX_PORT functions so that we can
// handle registers as well (ie, READ / WRITE_REGISTER_UCHAR)
//
//
// We don't need to do anything special for reads or writes so
// supply the normal read / write functions. Besides, adding
// another level of indirection kills performance because joysticks
// are usually polled continuously.
//
pGameEnumAcquireAccessors-&gtReadAccessor = (PGAMEENUM_READPORT)
READ_PORT_UCHAR;
pGameEnumAcquireAccessors-&gtWriteAccessor = (PGAMEENUM_WRITEPORT)
WRITE_PORT_UCHAR;
//
// Acquire / Release functions
//
pGameEnumAcquireAccessors-&gtPortContext = (PVOID) devExt;
pGameEnumAcquireAccessors-&gtAcquirePort = (PGAMEENUM_ACQUIRE_PORT)
GameFilter_AcquirePort;
pGameEnumAcquireAccessors-&gtReleasePort = (PGAMEENUM_RELEASE_PORT)
GameFilter_ReleasePort;
status = STATUS_SUCCESS;
}
break;
default:
status = STATUS_NOT_SUPPORTED;
}
Irp-&gtIoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
GameFilter_AcquirePort(
PVOID Context
)
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION) Context;
UCHAR statusValue;
// function cannot be paged because we can be called at high IRQL
// PAGED_CODE();
//
// TBD: Need to abstract out the XXX_PORT functions so that we can handle
// registers as well (ie, READ / WRITE_REGISTER_UCHAR)
//
if (devExt-&gtGamePortEnabled) {
//
// Already enabled, nothing to do
//
return STATUS_SUCCESS;
}
//
// devExt-&gtGamePortEnableAddress and GamePortStatusAddress were set in
// start device when we parsed the resources assigned to the port
//
WRITE_PORT_UCHAR(devExt-&gtGamePortEnableAddress, 0x1);
statusValue = READ_PORT_UCHAR(devExt-&gtGamePortStatusAddress);
//
// If statusValue's lower 4 bits are set (a magic value really) then the port
// is enabled. Otherwise, we can't enable it at this time.
//
if (statusValue & 0xF) {
devExt-&gtGamePortEnabled = TRUE;
status = STATUS_SUCCESS;
}
else {
//
// Do something here if we want to retry enabling the gameport in the
// "near" future (such as wait on an event or spin in a loop)
//
;
}
return status;
}
VOID
GameFilter_ReleasePort(
PVOID Context
)
{
PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION) Context;
// function cannot be paged because we can be called at high IRQL
// PAGED_CODE();
ASSERT(devExt-&gtGamePortEnabled);
WRITE_PORT_UCHAR(devExt-&gtGamePortEnableAddress, 0x0);
devExt-&gtGamePortEnabled = FALSE;
}
</pre>
</FONT><P ALIGN="CENTER"><A HREF="#top"><FONT FACE="Verdana" SIZE=2>Top of page</FONT></A><FONT FACE="Verdana" SIZE=2> </P></FONT>
<TABLE CELLSPACING=0 BORDER=0 WIDTH=624>
<TR><TD VALIGN="MIDDLE" BGCOLOR="#00ffff" HEIGHT=2>
<P></TD>
</TR>
</TABLE>
<FONT FACE="MS Sans Serif" SIZE=1><P>&copy; 1998 Microsoft Corporation</FONT><FONT FACE="Verdana" SIZE=2> </P></FONT></BODY>
</HTML>