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

  1. <HTML>
  2. <HEAD>
  3. <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
  4. <META NAME="Generator" CONTENT="Microsoft Word 97">
  5. <TITLE>GameEnum.sys</TITLE>
  6. <META NAME="Template" CONTENT="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
  7. </HEAD>
  8. <BODY TEXT="#000000" LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff" leftmargin="8">
  9. <FONT FACE="Verdana"><H2><A NAME="MYSAMPLE">GameEnum.sys</A> </H2>
  10. <H3>Summary</H3></FONT><FONT FACE="Verdana" SIZE=2>
  11. <P>GameEnum is a WDM driver. It is a bus driver for a legacy Gameport. It works
  12. closely with Hidgame.sys, which controls the children GameEnum enumerates. Keywords
  13. include <B>HID</B>, <B>WDM</B>, and <B>bus driver</B>.</P>
  14. <H3>Building the Sample</H3></FONT><FONT FACE="Verdana" SIZE=2>
  15. <P>The driver works on both x86 and Alpha platforms and is 64-bit compliant. It
  16. builds properly with Visual C 6.0 and supports Plug and Play, Power Management,
  17. and device interfaces.</P>
  18. <P>The driver is installed when a Gameport is discovered via Plug and Play. There
  19. are no special .inf requirements; please see GamePort.inf in the system INF
  20. directory for an example. Once built, the sample produces one binary,
  21. GameEnum.sys. Necessary files include those in this directory and Gameport.h
  22. and Wdm.h. Both checked and free builds are available, and there are no known
  23. bugs or issues to be documented.</P>
  24. <H3>CODE TOUR</H3>
  25. <H4>File Manifest</H4>
  26. </FONT>
  27. <U><PRE>File&#9;&#9;Description</U>
  28. GameSys.htm The documentation for this sample (this file)
  29. Gameenum.h Definitions
  30. Gameenum.c External and internal IOCTL support
  31. Pnp.c Plug and Play functionality
  32. Gameenum.rc Resources
  33. </PRE>
  34. <h4><font face="Verdana">Programming Tour</font></h4>
  35. <font face="Verdana" size="2">
  36. <p>This code tour discusses the steps an audio driver must complete to setup GameEnum.sys as a functioning FDO for the
  37. physical gameport.</p>
  38. <p>The major topics covered in this tour include the following.
  39. </font>
  40. <font FACE="Verdana" SIZE="2">
  41. <ul>
  42. <li><a href="#requirements">Resources requirements made by GameEnum</a></li>
  43. <li><a href="#lower_filter">Definition of a lower filter</a></li>
  44. <li><a href="#supplied">Functions that are supplied to GameEnum's PDOs</a></li>
  45. <li><a href="#override">How to override the supplied functions</a></li>
  46. </ul>
  47. </font>
  48. <h4><font face="Verdana" size="2">
  49. <a name="requirements">Resources requirements made by GameEnum</a>
  50. </font></h4>
  51. <p><font face="Verdana" size="2">
  52. GameEnum acts as an FDO for a traditional gameport. USB joysticks do not
  53. need any additional drivers; DirectInput will open them directly. A kernel driver
  54. for an audio device can enumerate a child device and have GameEnum loaded on top of it.
  55. GameEnum will handle all the details in enumerating, starting, and handling
  56. joysticks plugged into the system.
  57. </font></p>
  58. <p><font face="Verdana" size="2">
  59. The following assumptions are made by GameEnum with regards to its resources:
  60. <ol>
  61. <li>If there are resources provided, it does <i>not</i> have to be the port
  62. <font face="Courier" size="2">0x201</font>. For example, the resources can be in PCI space.</li>
  63. <li>If no resources are assigned to the GameEnum stack, then the PDO must handle
  64. an IOCTL to supply GameEnum with the necessary data on how to access the
  65. gameport hardware. For details on how to implement this,
  66. see <a href="#override">below</a>.</li>
  67. <li>There are no interrupts assigned to it.</li>
  68. </ol>
  69. </font></p>
  70. <h4><font face="Verdana" size="2">
  71. <a name="lower_filter">Definition of a lower filter</a>
  72. </font></h4>
  73. <p><font face="Verdana" size="2">
  74. The term lower filter refers to a device object in the stack below GameEnum which
  75. handles the override IOCTL. This device object can be the PDO itself (if the audio
  76. driver is enumerating the PDO) or an actual filter object that is in between
  77. GameEnum and the PDO in the stack.
  78. </font></p>
  79. <h4><font face="Verdana" size="2">
  80. <a name="supplied">Functions that are supplied to GameEnum's PDOs</a>
  81. </font></h4>
  82. <p><font face="Verdana" size="2">
  83. Once a PDO enumerated by GameEnum has started, it sends down an IOCTL to acquire
  84. the functions it needs to read from and write to the hardware. This information
  85. is sent via the <font face="Courier" size="2">GAMEENUM_PORT_PARAMETERS</font>
  86. structure defined in gameport.h. If the gameport has non-standard ports, then
  87. the lower filter must override this information by handling the override IOCTL,
  88. which is <a href="#override">explained later in this document</a>.
  89. </font></p>
  90. <p><font face="Verdana" size="2">
  91. Here is a brief description of fields that are relevant to a driver that would
  92. override the supplied GameEnum defaults:
  93. </font></p>
  94. <table border=1>
  95. <tr>
  96. <td><font face="Verdana" size="3">
  97. <b>Field Name</b>
  98. </font></td>
  99. <td><font face="Verdana" size="3">
  100. <b>Description</b>
  101. </font></td>
  102. <td><font face="Verdana" size="3">
  103. <b>Default Value</b>
  104. </font></td>
  105. </tr>
  106. <tr>
  107. <td><font face="Verdana" size="2">
  108. <b>ReadAccessor</b>
  109. </font></td>
  110. <td><font face="Verdana" size="2">
  111. The function is used by the joystick driver to read analog data from the gameport hardware / joystick
  112. </font></td>
  113. <td><font face="Verdana" size="2">
  114. READ_PORT_UCHAR
  115. </font></td>
  116. </tr>
  117. <tr>
  118. <td><font face="Verdana" size="2">
  119. <b>ReadAccessorDigital</b>
  120. </font></td>
  121. <td><font face="Verdana" size="2">
  122. The function is used by the joystick driver to read data digitally from the gameport hardware /
  123. joystick. This function is not supplied by default; it is only supplied if
  124. the lower filter handles the override IOCTL.
  125. </font></td>
  126. <td><font face="Verdana" size="2">
  127. NONE
  128. </font></td>
  129. </tr>
  130. <tr>
  131. <td><font face="Verdana" size="2">
  132. <b>WriteAccessor</b>
  133. </font></td>
  134. <td><font face="Verdana" size="2">
  135. The function is used to by the joystick driver write data to the gameport hardware / joystick
  136. </font></td>
  137. <td><font face="Verdana" size="2">
  138. WRITE_PORT_UCHAR
  139. </font></td>
  140. </tr>
  141. <tr>
  142. <td><font face="Verdana" size="2">
  143. <b>GameContext</b>
  144. </font></td>
  145. <td><font face="Verdana" size="2">
  146. Context passed as a parameter to ReadAccessor, ReadAccessorDigital, and WriteAccessor
  147. </font></td>
  148. <td><font face="Verdana" size="2">
  149. Port resource assigned to the stack (0x201 for example)
  150. </font></td>
  151. </tr>
  152. <tr>
  153. </tr>
  154. <tr>
  155. <td><font face="Verdana" size="2">
  156. <b>AcquirePort</b>
  157. </font></td>
  158. <td><font face="Verdana" size="2">
  159. <p>"Acquires" and locks the hardware. This function must be called before any of the Accessor
  160. functions listed above may be called. The Accessor functions must be functional
  161. between calls to AcquirePort and ReleasePort.</p>
  162. <p> This function may fail, so the caller must check the return code before
  163. using the Accessor functions.</p>
  164. </font></td>
  165. <td><font face="Verdana" size="2">
  166. Game_AcquirePort
  167. </font></td>
  168. </tr>
  169. <tr>
  170. <td><font face="Verdana" size="2">
  171. <b>ReleasePort</b>
  172. </font></td>
  173. <td><font face="Verdana" size="2">
  174. "Releases" and unlocks the hardware. This function will be called after the
  175. joystick driver has finished calling the Accessor functions.
  176. </font></td>
  177. <td><font face="Verdana" size="2">
  178. Game_ReleasePort
  179. </font></td>
  180. </tr>
  181. <tr>
  182. <td><font face="Verdana" size="2">
  183. <b>PortContext</b>
  184. </font></td>
  185. <td><font face="Verdana" size="2">
  186. Context passed as a parameter to AcquirePort and ReleasePort.
  187. </font></td>
  188. <td><font face="Verdana" size="2">
  189. Context private to GameEnum
  190. </font></td>
  191. </tr>
  192. </table>
  193. <p><font face="Verdana" size="2">
  194. To override the Accessor functions, all the fields are required, except for
  195. ReadAccessorDigital, which is an optional field. Only override this function if
  196. you can support digital reads on your hardware. The AcquirePort and ReleasePort
  197. functions may be overridden only if the Accessor functions are overridden. All
  198. the fields must be overridden; there are no optional fields.
  199. </font></p>
  200. <h4><font face="Verdana" size="2">
  201. <a name="override">How to override the supplied functions</a>
  202. </font></h4>
  203. <p><font face="Verdana" size="2">
  204. GameEnum will send an internal IOCTL,
  205. <font face="Courier" size="2">IOCTL_GAMEENUM_ACQUIRE_ACCESSORS</font>, down the
  206. stack to the lower filter so that it may override GameEnum's default
  207. functionality. The lower filter must fill in the output buffer for this IOCTL,
  208. which is of the size <font face="Courier" size="2">GAMEENUM_ACQUIRE_ACCESSORS</font>,
  209. defined in gameport.h. The fields in
  210. <font face="Courier" size="2">GAMEENUM_ACQUIRE_ACCESSORS</font> match one to one
  211. with the relevant fields in <font face="Courier" size="2">GAMEENUM_PORT_PARAMETERS</font>
  212. (the structure supplied to GameEnum's PDO).
  213. </font></p>
  214. <p><font face="Verdana" size="2">
  215. When overriding the Accessor functions, you may provide any value for the
  216. GameContext. It does not have to be limited to a port resource value. For instance,
  217. you can pass your device extension as the context, and then pull data off of the
  218. extension to set up the hardware and then perform the actual read. In essence,
  219. you provide another level of indirection to this function call.
  220. </font></p>
  221. <p><font face="Verdana" size="2">
  222. Here is a code snippet that shows how to handle the override IOCTL and perform special
  223. actions on a fictional gameport that requires special init before the port can be
  224. read or written.
  225. </font></p>
  226. <pre>
  227. #ifdef ALLOC_PRAGMA
  228. #pragma alloc_text (PAGE, GameFilter_InternalIoctl)
  229. #endif
  230. typedef struct _DEVICE_EXTENSION {
  231. // ...
  232. // Port address which will enable the game port
  233. PUCHAR GamePortEnableAddress;
  234. // status register
  235. PUCHAR GamePortStatusAddress;
  236. // Port address which we read the data from (ie 0x201 on a traditional ISA card)
  237. PUCHAR GamePortDataAddress;
  238. // Sanity check
  239. BOOLEAN GamePortEnabled;
  240. // ...
  241. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  242. NTSTATUS
  243. DriverEntry (
  244. IN PDRIVER_OBJECT DriverObject,
  245. IN PUNICODE_STRING UniRegistryPath
  246. )
  247. {
  248. UNREFERENCED_PARAMETER (UniRegistryPath);
  249. // ...
  250. DriverObject-&gtMajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
  251. = GameFilter_InternalIoctl;
  252. // ...
  253. return STATUS_SUCCESS;
  254. }
  255. NTSTATUS
  256. GameFilter_InternalIoctl (
  257. PDEVICE_OBJECT DeviceObject,
  258. IN PIRP Irp
  259. )
  260. {
  261. NTSTATUS status;
  262. PIO_STACK_LOCATION stack;
  263. PDEVICE_EXTENSION devExt;
  264. PGAMEENUM_ACQUIRE_ACCESSORS pGameEnumAcquireAccessors;
  265. PAGED_CODE();
  266. stack = IoGetCurrentIrpStackLocation(Irp);
  267. devExt = (PDEVICE_EXTENSION) DeviceObject-&gtDeviceExtension;
  268. switch (stack-&gtParameters.DeviceIoControl.IoControlCode) {
  269. case IOCTL_GAMEENUM_ACQUIRE_ACCESSORS:
  270. pGameEnumAcquireAccessors = (PGAMEENUM_ACQUIRE_ACCESSORS)
  271. Irp-&gtAssociatedIrp.SystemBuffer;
  272. if (stack-&gtParameters.DeviceIoControl.OutputBufferLength &lt
  273. sizeof(GAMEENUM_ACQUIRE_ACCESSORS) ||
  274. pGameEnumAcquireAccessors-&gtSize &lt
  275. sizeof(GAMEENUM_ACQUIRE_ACCESSORS) ) {
  276. status = STATUS_BUFFER_TOO_SMALL;
  277. }
  278. else {
  279. //
  280. // Accessor functions
  281. //
  282. // digital read not supported at this time in this filter
  283. pGameEnumAcquireAccessors-&gtReadAccessorDigital = NULL;
  284. //
  285. // GameEnum does not know how to parse the data address out of the
  286. // range of ports assigned to this PDO, so we must do this on
  287. // behalf of GameEnum.
  288. //
  289. pGameEnumAcquireAccessors-&gtGameContext = (PVOID)
  290. devExt-&gtGamePortDataAddress;
  291. //
  292. // TBD: Need to abstract out the XXX_PORT functions so that we can
  293. // handle registers as well (ie, READ / WRITE_REGISTER_UCHAR)
  294. //
  295. //
  296. // We don't need to do anything special for reads or writes so
  297. // supply the normal read / write functions. Besides, adding
  298. // another level of indirection kills performance because joysticks
  299. // are usually polled continuously.
  300. //
  301. pGameEnumAcquireAccessors-&gtReadAccessor = (PGAMEENUM_READPORT)
  302. READ_PORT_UCHAR;
  303. pGameEnumAcquireAccessors-&gtWriteAccessor = (PGAMEENUM_WRITEPORT)
  304. WRITE_PORT_UCHAR;
  305. //
  306. // Acquire / Release functions
  307. //
  308. pGameEnumAcquireAccessors-&gtPortContext = (PVOID) devExt;
  309. pGameEnumAcquireAccessors-&gtAcquirePort = (PGAMEENUM_ACQUIRE_PORT)
  310. GameFilter_AcquirePort;
  311. pGameEnumAcquireAccessors-&gtReleasePort = (PGAMEENUM_RELEASE_PORT)
  312. GameFilter_ReleasePort;
  313. status = STATUS_SUCCESS;
  314. }
  315. break;
  316. default:
  317. status = STATUS_NOT_SUPPORTED;
  318. }
  319. Irp-&gtIoStatus.Status = status;
  320. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  321. return status;
  322. }
  323. NTSTATUS
  324. GameFilter_AcquirePort(
  325. PVOID Context
  326. )
  327. {
  328. NTSTATUS status = STATUS_NOT_SUPPORTED;
  329. PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION) Context;
  330. UCHAR statusValue;
  331. // function cannot be paged because we can be called at high IRQL
  332. // PAGED_CODE();
  333. //
  334. // TBD: Need to abstract out the XXX_PORT functions so that we can handle
  335. // registers as well (ie, READ / WRITE_REGISTER_UCHAR)
  336. //
  337. if (devExt-&gtGamePortEnabled) {
  338. //
  339. // Already enabled, nothing to do
  340. //
  341. return STATUS_SUCCESS;
  342. }
  343. //
  344. // devExt-&gtGamePortEnableAddress and GamePortStatusAddress were set in
  345. // start device when we parsed the resources assigned to the port
  346. //
  347. WRITE_PORT_UCHAR(devExt-&gtGamePortEnableAddress, 0x1);
  348. statusValue = READ_PORT_UCHAR(devExt-&gtGamePortStatusAddress);
  349. //
  350. // If statusValue's lower 4 bits are set (a magic value really) then the port
  351. // is enabled. Otherwise, we can't enable it at this time.
  352. //
  353. if (statusValue & 0xF) {
  354. devExt-&gtGamePortEnabled = TRUE;
  355. status = STATUS_SUCCESS;
  356. }
  357. else {
  358. //
  359. // Do something here if we want to retry enabling the gameport in the
  360. // "near" future (such as wait on an event or spin in a loop)
  361. //
  362. ;
  363. }
  364. return status;
  365. }
  366. VOID
  367. GameFilter_ReleasePort(
  368. PVOID Context
  369. )
  370. {
  371. PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION) Context;
  372. // function cannot be paged because we can be called at high IRQL
  373. // PAGED_CODE();
  374. ASSERT(devExt-&gtGamePortEnabled);
  375. WRITE_PORT_UCHAR(devExt-&gtGamePortEnableAddress, 0x0);
  376. devExt-&gtGamePortEnabled = FALSE;
  377. }
  378. </pre>
  379. </FONT><P ALIGN="CENTER"><A HREF="#top"><FONT FACE="Verdana" SIZE=2>Top of page</FONT></A><FONT FACE="Verdana" SIZE=2> </P></FONT>
  380. <TABLE CELLSPACING=0 BORDER=0 WIDTH=624>
  381. <TR><TD VALIGN="MIDDLE" BGCOLOR="#00ffff" HEIGHT=2>
  382. <P></TD>
  383. </TR>
  384. </TABLE>
  385. <FONT FACE="MS Sans Serif" SIZE=1><P>&copy; 1998 Microsoft Corporation</FONT><FONT FACE="Verdana" SIZE=2> </P></FONT></BODY>
  386. </HTML>