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

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. GAMEENUM.C
  5. Abstract:
  6. This module contains contains the entry points for a standard bus
  7. PNP / WDM driver.
  8. @@BEGIN_DDKSPLIT
  9. Author:
  10. Kenneth D. Ray
  11. Doron J. Holan
  12. @@END_DDKSPLIT
  13. Environment:
  14. kernel mode only
  15. Notes:
  16. Revision History:
  17. --*/
  18. #include <wdm.h>
  19. #include <initguid.h>
  20. #include "gameport.h"
  21. #include "gameenum.h"
  22. #include "stdio.h"
  23. //
  24. // Global Debug Level
  25. //
  26. #if DBG
  27. ULONG GameEnumDebugLevel = GAME_DEFAULT_DEBUG_OUTPUT_LEVEL;
  28. #endif
  29. //
  30. // Declare some entry functions as pageable, and make DriverEntry
  31. // discardable
  32. //
  33. NTSTATUS DriverEntry (PDRIVER_OBJECT, PUNICODE_STRING);
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text (INIT, DriverEntry)
  36. #pragma alloc_text (PAGE, Game_DriverUnload)
  37. #pragma alloc_text (PAGE, Game_PortParameters)
  38. #pragma alloc_text (PAGE, Game_CreateClose)
  39. #pragma alloc_text (PAGE, Game_IoCtl)
  40. #pragma alloc_text (PAGE, Game_InternIoCtl)
  41. #endif
  42. NTSTATUS
  43. DriverEntry (
  44. IN PDRIVER_OBJECT DriverObject,
  45. IN PUNICODE_STRING UniRegistryPath
  46. )
  47. /*++
  48. Routine Description:
  49. Initialize the entry points of the driver.
  50. --*/
  51. {
  52. PDEVICE_OBJECT device;
  53. UNREFERENCED_PARAMETER (UniRegistryPath);
  54. Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Driver Entry\n"));
  55. DriverObject->MajorFunction [IRP_MJ_CREATE] =
  56. DriverObject->MajorFunction [IRP_MJ_CLOSE] = Game_CreateClose;
  57. DriverObject->MajorFunction [IRP_MJ_SYSTEM_CONTROL] = Game_SystemControl;
  58. DriverObject->MajorFunction [IRP_MJ_PNP] = Game_PnP;
  59. DriverObject->MajorFunction [IRP_MJ_POWER] = Game_Power;
  60. DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Game_IoCtl;
  61. DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
  62. = Game_InternIoCtl;
  63. DriverObject->DriverUnload = Game_DriverUnload;
  64. DriverObject->DriverExtension->AddDevice = Game_AddDevice;
  65. return STATUS_SUCCESS;
  66. }
  67. NTSTATUS
  68. Game_CreateClose (
  69. IN PDEVICE_OBJECT DeviceObject,
  70. IN PIRP Irp
  71. )
  72. /*++
  73. Routine Description:
  74. Some outside source is trying to create a file against us.
  75. If this is for the FDO (the bus itself) then the caller is trying to
  76. open the propriatary conection to tell us which game port to enumerate.
  77. If this is for the PDO (an object on the bus) then this is a client that
  78. wishes to use the game port.
  79. --*/
  80. {
  81. PIO_STACK_LOCATION irpStack;
  82. NTSTATUS status;
  83. KEVENT event;
  84. PFDO_DEVICE_DATA data;
  85. PAGED_CODE ();
  86. data = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  87. status = Game_IncIoCount (data);
  88. if (!NT_SUCCESS (status)) {
  89. Irp->IoStatus.Information = 0;
  90. Irp->IoStatus.Status = status;
  91. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  92. return status;
  93. }
  94. status = STATUS_SUCCESS;
  95. irpStack = IoGetCurrentIrpStackLocation (Irp);
  96. switch (irpStack->MajorFunction) {
  97. case IRP_MJ_CREATE:
  98. Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Create \n"));
  99. if (0 != irpStack->FileObject->FileName.Length) {
  100. //
  101. // The caller is trying to open a subdirectory off the device
  102. // object name. This is not allowed.
  103. //
  104. status = STATUS_ACCESS_DENIED;
  105. }
  106. break;
  107. case IRP_MJ_CLOSE:
  108. Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Close \n"));
  109. ;
  110. }
  111. Game_DecIoCount (data);
  112. Irp->IoStatus.Status = status;
  113. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  114. return status;
  115. }
  116. NTSTATUS
  117. Game_IoCtl (
  118. IN PDEVICE_OBJECT DeviceObject,
  119. IN PIRP Irp
  120. )
  121. /*++
  122. Routine Description:
  123. Handle user mode expose, remove, and device description requests.
  124. --*/
  125. {
  126. PIO_STACK_LOCATION irpStack;
  127. NTSTATUS status;
  128. ULONG inlen;
  129. ULONG outlen;
  130. PCOMMON_DEVICE_DATA commonData;
  131. PFDO_DEVICE_DATA fdoData;
  132. PVOID buffer;
  133. PAGED_CODE ();
  134. status = STATUS_SUCCESS;
  135. irpStack = IoGetCurrentIrpStackLocation (Irp);
  136. ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
  137. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  138. fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  139. buffer = Irp->AssociatedIrp.SystemBuffer;
  140. //
  141. // We only take Device Control requests for the FDO.
  142. // That is the bus itself.
  143. //
  144. // The request is one of the propriatary Ioctls for
  145. //
  146. // NB we are not a filter driver, so we do not pass on the irp.
  147. //
  148. inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  149. outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  150. if (!commonData->IsFDO) {
  151. //
  152. // These commands are only allowed to go to the FDO.
  153. //
  154. status = STATUS_ACCESS_DENIED;
  155. Irp->IoStatus.Status = status;
  156. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  157. return status;
  158. }
  159. if (!fdoData->Started) {
  160. status = STATUS_DEVICE_NOT_READY;
  161. Irp->IoStatus.Status = status;
  162. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  163. return status;
  164. }
  165. status = Game_IncIoCount (fdoData);
  166. if (!NT_SUCCESS (status)) {
  167. //
  168. // This bus has received the PlugPlay remove IRP. It will no longer
  169. // resond to external requests.
  170. //
  171. Irp->IoStatus.Status = status;
  172. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  173. return status;
  174. }
  175. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  176. case IOCTL_GAMEENUM_EXPOSE_HARDWARE:
  177. if ((inlen == outlen) &&
  178. //
  179. // Make sure it is at least two nulls (ie, an empty multi sz)
  180. // and the size field is set to the declared size of the struct
  181. //
  182. ((sizeof (GAMEENUM_EXPOSE_HARDWARE) + sizeof(UNICODE_NULL) * 2) <=
  183. inlen) &&
  184. //
  185. // The size field should be set to the sizeof the struct as declared
  186. // and *not* the size of the struct plus the multi sz
  187. //
  188. (sizeof (GAMEENUM_EXPOSE_HARDWARE) ==
  189. ((PGAMEENUM_EXPOSE_HARDWARE) buffer)->Size)) {
  190. Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Expose called\n"));
  191. status= Game_Expose((PGAMEENUM_EXPOSE_HARDWARE)buffer,
  192. inlen,
  193. fdoData);
  194. Irp->IoStatus.Information = outlen;
  195. } else {
  196. status = STATUS_INVALID_PARAMETER;
  197. }
  198. break;
  199. case IOCTL_GAMEENUM_REMOVE_HARDWARE:
  200. if ((sizeof (GAMEENUM_REMOVE_HARDWARE) == inlen) &&
  201. (inlen == outlen) &&
  202. (((PGAMEENUM_REMOVE_HARDWARE)buffer)->Size == inlen)) {
  203. Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Remove called\n"));
  204. status= Game_Remove((PGAMEENUM_REMOVE_HARDWARE)buffer, fdoData);
  205. Irp->IoStatus.Information = outlen;
  206. } else {
  207. status = STATUS_INVALID_PARAMETER;
  208. }
  209. break;
  210. case IOCTL_GAMEENUM_PORT_DESC:
  211. if ((sizeof (GAMEENUM_PORT_DESC) == inlen) &&
  212. (inlen == outlen) &&
  213. (((PGAMEENUM_PORT_DESC)buffer)->Size == inlen)) {
  214. Game_KdPrint(fdoData, GAME_DBG_IOCTL_TRACE, ("Port desc called\n"));
  215. //
  216. // Fill in the information first. If there is a lower driver, it
  217. // will change replace the values that gameenum has placed in the
  218. // buffer. We don't care if the call down succeeds or not
  219. //
  220. status = Game_ListPorts ((PGAMEENUM_PORT_DESC) buffer, fdoData);
  221. Game_SendIrpSynchronously (fdoData->TopOfStack,
  222. Irp,
  223. FALSE,
  224. TRUE);
  225. Irp->IoStatus.Information = outlen;
  226. } else {
  227. status = STATUS_INVALID_PARAMETER;
  228. }
  229. break;
  230. default:
  231. status = STATUS_INVALID_PARAMETER;
  232. }
  233. Game_DecIoCount (fdoData);
  234. Irp->IoStatus.Status = status;
  235. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  236. return status;
  237. }
  238. NTSTATUS
  239. Game_InternIoCtl (
  240. PDEVICE_OBJECT DeviceObject,
  241. IN PIRP Irp
  242. )
  243. /*++
  244. Routine Description:
  245. --*/
  246. {
  247. PIO_STACK_LOCATION irpStack, next;
  248. NTSTATUS status;
  249. PCOMMON_DEVICE_DATA commonData;
  250. PPDO_DEVICE_DATA pdoData;
  251. PVOID buffer;
  252. BOOLEAN validAccessors;
  253. ULONG inlen;
  254. ULONG outlen;
  255. PAGED_CODE ();
  256. status = STATUS_SUCCESS;
  257. irpStack = IoGetCurrentIrpStackLocation (Irp);
  258. ASSERT (IRP_MJ_INTERNAL_DEVICE_CONTROL == irpStack->MajorFunction);
  259. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  260. pdoData = (PPDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  261. inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  262. outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  263. //
  264. // We only take Internal Device Control requests for the PDO.
  265. // That is the objects on the bus (representing the game ports)
  266. //
  267. // The request is from a FDO driver attached to this game port device object
  268. // inquiring about the port itself.
  269. //
  270. // NB we are not a filter driver, so we do not pass on the irp.
  271. //
  272. if (commonData->IsFDO) {
  273. Game_KdPrint(((PFDO_DEVICE_DATA) commonData), GAME_DBG_IOCTL_ERROR,
  274. ("internal ioctl called on fdo!\n"))
  275. status = STATUS_ACCESS_DENIED;
  276. } else if (!pdoData->Started) {
  277. //
  278. // The bus has not been started yet
  279. //
  280. status = STATUS_DEVICE_NOT_READY;
  281. } else if (pdoData->Removed) {
  282. //
  283. // This bus has received the PlugPlay remove IRP. It will no longer
  284. // resond to external requests.
  285. //
  286. status = STATUS_DELETE_PENDING;
  287. } else {
  288. buffer = Irp->UserBuffer;
  289. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  290. case IOCTL_GAMEENUM_PORT_PARAMETERS:
  291. if ((inlen == outlen) &&
  292. (outlen == ((PGAMEENUM_PORT_PARAMETERS) buffer)->Size)) {
  293. Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE,
  294. ("Port parameters called\n"));
  295. status = Game_PortParameters ((PGAMEENUM_PORT_PARAMETERS) buffer,
  296. pdoData);
  297. }
  298. else {
  299. Game_KdPrint(pdoData, GAME_DBG_IOCTL_ERROR,
  300. ("InBufLen: %d, OutBufLen: %d, Size: %d\n",
  301. inlen, outlen,
  302. ((PGAMEENUM_PORT_PARAMETERS) buffer)->Size));
  303. status = STATUS_INVALID_PARAMETER;
  304. }
  305. break;
  306. case IOCTL_GAMEENUM_EXPOSE_SIBLING:
  307. if ((inlen == outlen) &&
  308. //
  309. // Make sure that the buffer passed in is of the correct size
  310. //
  311. (sizeof (GAMEENUM_EXPOSE_SIBLING) == inlen) &&
  312. //
  313. // The size field should be set to the sizeof the struct
  314. //
  315. (sizeof (GAMEENUM_EXPOSE_SIBLING) ==
  316. ((PGAMEENUM_EXPOSE_SIBLING) buffer)->Size)) {
  317. Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE, ("Expose sibling"));
  318. status = Game_ExposeSibling ((PGAMEENUM_EXPOSE_SIBLING) buffer,
  319. pdoData);
  320. }
  321. else {
  322. Game_KdPrint(pdoData, GAME_DBG_IOCTL_ERROR,
  323. ("Expected an input and output buffer lengths to be equal (in = %d, out %d)\n"
  324. "Expected an input buffer length of %d, received %d\n"
  325. "Expected GAME_EXPOSE_SIBLING.Size == %d, received %d\n",
  326. inlen, outlen,
  327. sizeof (GAMEENUM_EXPOSE_SIBLING), inlen,
  328. sizeof (GAMEENUM_EXPOSE_SIBLING),
  329. ((PGAMEENUM_EXPOSE_SIBLING) buffer)->Size));
  330. status = STATUS_INVALID_PARAMETER;
  331. }
  332. break;
  333. case IOCTL_GAMEENUM_REMOVE_SELF:
  334. Game_KdPrint(pdoData, GAME_DBG_IOCTL_TRACE, ("Remove self\n"));
  335. status = Game_RemoveSelf (pdoData);
  336. break;
  337. default:
  338. status = STATUS_INVALID_PARAMETER;
  339. }
  340. }
  341. Irp->IoStatus.Status = status;
  342. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  343. return status;
  344. }
  345. VOID
  346. Game_DriverUnload (
  347. IN PDRIVER_OBJECT Driver
  348. )
  349. /*++
  350. Routine Description:
  351. Clean up everything we did in driver entry.
  352. --*/
  353. {
  354. #if (!DBG)
  355. UNREFERENCED_PARAMETER (Driver);
  356. #endif
  357. PAGED_CODE ();
  358. //
  359. // All the device objects should be gone.
  360. //
  361. ASSERT (NULL == Driver->DeviceObject);
  362. //
  363. // Here we free any resources allocated in DriverEntry
  364. //
  365. return;
  366. }
  367. NTSTATUS
  368. Game_PortParameters (
  369. PGAMEENUM_PORT_PARAMETERS Parameters,
  370. PPDO_DEVICE_DATA PdoData
  371. )
  372. {
  373. PFDO_DEVICE_DATA fdoData;
  374. GAMEENUM_ACQUIRE_ACCESSORS gameAccessors;
  375. PIO_STACK_LOCATION next;
  376. NTSTATUS status;
  377. IO_STATUS_BLOCK iosb;
  378. KEVENT event;
  379. PIRP accessorIrp;
  380. PAGED_CODE ();
  381. if (sizeof (GAMEENUM_PORT_PARAMETERS) != Parameters->Size) {
  382. Game_KdPrint(PdoData, GAME_DBG_IOCTL_ERROR,
  383. ("Wanted %d, got %d for size of buffer\n",
  384. sizeof(GAMEENUM_PORT_PARAMETERS), Parameters->Size));
  385. return STATUS_INVALID_PARAMETER;
  386. }
  387. fdoData = FDO_FROM_PDO (PdoData);
  388. KeInitializeEvent (&event, NotificationEvent, FALSE);
  389. RtlZeroMemory(&gameAccessors, sizeof(GAMEENUM_ACQUIRE_ACCESSORS));
  390. gameAccessors.Size = sizeof(GAMEENUM_ACQUIRE_ACCESSORS);
  391. accessorIrp =
  392. IoBuildDeviceIoControlRequest (IOCTL_GAMEENUM_ACQUIRE_ACCESSORS,
  393. fdoData->TopOfStack,
  394. NULL,
  395. 0,
  396. &gameAccessors,
  397. sizeof (GAMEENUM_PORT_PARAMETERS),
  398. TRUE,
  399. &event,
  400. &iosb);
  401. if (!accessorIrp) {
  402. goto Game_NoCustomAccessors;
  403. }
  404. status = IoCallDriver(fdoData->TopOfStack, accessorIrp);
  405. //
  406. // Wait for lower drivers to be done with the Irp
  407. //
  408. if (status == STATUS_PENDING) {
  409. KeWaitForSingleObject (&event,
  410. Executive,
  411. KernelMode,
  412. FALSE,
  413. NULL);
  414. status = iosb.Status;
  415. }
  416. if (!NT_SUCCESS(status) ||
  417. !(gameAccessors.GameContext &&
  418. gameAccessors.WriteAccessor && gameAccessors.ReadAccessor)) {
  419. //
  420. // If TopOfStack or below does not handle this IOCTL, we better have
  421. // received the necessary resources to allow our children to read and
  422. // write to their devices
  423. //
  424. ASSERT (fdoData->GamePortAddress != NULL);
  425. ASSERT (fdoData->ReadPort != NULL);
  426. ASSERT (fdoData->WritePort != NULL);
  427. Game_NoCustomAccessors:
  428. //
  429. // No filter below us (either the IOCTL failed, or not all of the req.
  430. // fields were filled in) ... fill in w/standard values
  431. //
  432. Parameters->ReadAccessor = fdoData->ReadPort;
  433. Parameters->WriteAccessor = fdoData->WritePort;
  434. Parameters->ReadAccessorDigital = NULL;
  435. Parameters->GameContext = fdoData->GamePortAddress;
  436. }
  437. else {
  438. //
  439. // There is a filter below us, fill in w/the appropriate values
  440. //
  441. Parameters->ReadAccessor = gameAccessors.ReadAccessor;
  442. Parameters->WriteAccessor = gameAccessors.WriteAccessor;
  443. Parameters->ReadAccessorDigital = gameAccessors.ReadAccessorDigital;
  444. Parameters->GameContext = gameAccessors.GameContext;
  445. if (gameAccessors.PortContext) {
  446. fdoData->LowerAcquirePort = gameAccessors.AcquirePort;
  447. fdoData->LowerReleasePort = gameAccessors.ReleasePort;
  448. fdoData->LowerPortContext = gameAccessors.PortContext;
  449. }
  450. }
  451. //
  452. // Acquire/release always goes through the gameenum even if a lower
  453. // filter exists
  454. //
  455. Parameters->AcquirePort = (PGAMEENUM_ACQUIRE_PORT) Game_AcquirePort;
  456. Parameters->ReleasePort = (PGAMEENUM_RELEASE_PORT) Game_ReleasePort;
  457. Parameters->PortContext = fdoData;
  458. Parameters->Portion = PdoData->Portion;
  459. Parameters->NumberAxis = PdoData->NumberAxis;
  460. Parameters->NumberButtons = PdoData->NumberButtons;
  461. RtlCopyMemory (&Parameters->OemData,
  462. &PdoData->OemData,
  463. sizeof(GAMEENUM_OEM_DATA));
  464. return STATUS_SUCCESS;
  465. }
  466. NTSTATUS
  467. Game_IncIoCount (
  468. PFDO_DEVICE_DATA Data
  469. )
  470. {
  471. InterlockedIncrement (&Data->OutstandingIO);
  472. if (Data->Removed) {
  473. if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
  474. KeSetEvent (&Data->RemoveEvent, 0, FALSE);
  475. }
  476. return STATUS_DELETE_PENDING;
  477. }
  478. return STATUS_SUCCESS;
  479. }
  480. VOID
  481. Game_DecIoCount (
  482. PFDO_DEVICE_DATA Data
  483. )
  484. {
  485. if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
  486. KeSetEvent (&Data->RemoveEvent, 0, FALSE);
  487. }
  488. }
  489. NTSTATUS
  490. Game_AcquirePort(
  491. PFDO_DEVICE_DATA fdoData
  492. )
  493. {
  494. if (fdoData->Removed) {
  495. Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
  496. ("Acquire failed! Gameport associated with (0x%x) was removed....\n", fdoData));
  497. return STATUS_NO_SUCH_DEVICE;
  498. }
  499. else if (!fdoData->Started) {
  500. Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
  501. ("Acquire failed! Gameport associated with (0x%x) is not started....\n", fdoData));
  502. return STATUS_NO_SUCH_DEVICE;
  503. }
  504. else if (!fdoData->NumPDOs) {
  505. Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
  506. ("Acquire failed! Gameport associated with (0x%x) has no devices attached....\n", fdoData));
  507. return STATUS_NO_SUCH_DEVICE;
  508. }
  509. //
  510. // If fdoData->Acquired is TRUE, then no exchange will take place and the
  511. // value of fdoData->Acquired (TRUE) will be returned
  512. //
  513. if (InterlockedCompareExchange(&fdoData->Acquired, TRUE, FALSE)) {
  514. Game_KdPrint(fdoData, GAME_DBG_ACQUIRE_ERROR,
  515. ("Acquire failed! Gameport associated with (0x%x) was already acquired....\n", fdoData));
  516. return STATUS_DEVICE_BUSY;
  517. }
  518. if (fdoData->LowerPortContext) {
  519. return (*fdoData->LowerAcquirePort)(fdoData->LowerPortContext);
  520. }
  521. else {
  522. return STATUS_SUCCESS;
  523. }
  524. }
  525. VOID
  526. Game_ReleasePort(
  527. PFDO_DEVICE_DATA fdoData
  528. )
  529. {
  530. ASSERT(fdoData->Acquired);
  531. InterlockedExchange(&fdoData->Acquired, FALSE);
  532. if (fdoData->LowerPortContext) {
  533. (*fdoData->LowerReleasePort)(fdoData->LowerPortContext);
  534. }
  535. }