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.

2803 lines
89 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. PNP.C
  5. Abstract:
  6. This module contains contains the plugplay calls
  7. PNP / WDM BUS 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 "gameport.h"
  20. #include "gameenum.h"
  21. #include "stdio.h"
  22. #define HWID_TEMPLATE L"gameport"
  23. #define HWID_TEMPLATE_LENGTH 8
  24. #define LOWERCASE(_x_) (_x_|0x20)
  25. #define MAX_DEVICE_ID_LEN 300
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text (PAGE, Game_AddDevice)
  28. #pragma alloc_text (PAGE, Game_SystemControl)
  29. #pragma alloc_text (PAGE, Game_PnP)
  30. #pragma alloc_text (PAGE, Game_Power)
  31. #pragma alloc_text (PAGE, Game_FDO_Power)
  32. #pragma alloc_text (PAGE, Game_PDO_Power)
  33. #pragma alloc_text (PAGE, Game_InitializePdo)
  34. #pragma alloc_text (PAGE, Game_CheckHardwareIDs)
  35. #pragma alloc_text (PAGE, Game_Expose)
  36. #pragma alloc_text (PAGE, Game_ExposeSibling)
  37. #pragma alloc_text (PAGE, Game_Remove)
  38. #pragma alloc_text (PAGE, Game_RemoveSelf)
  39. #pragma alloc_text (PAGE, Game_RemoveEx)
  40. #pragma alloc_text (PAGE, Game_RemovePdo)
  41. #pragma alloc_text (PAGE, Game_RemoveFdo)
  42. #pragma alloc_text (PAGE, Game_ListPorts)
  43. #pragma alloc_text (PAGE, Game_FDO_PnP)
  44. #pragma alloc_text (PAGE, Game_PDO_PnP)
  45. #endif
  46. NTSTATUS
  47. Game_AddDevice(
  48. IN PDRIVER_OBJECT DriverObject,
  49. IN PDEVICE_OBJECT BusPhysicalDeviceObject
  50. )
  51. /*++
  52. Routine Description.
  53. A bus has been found. Attach our FDO to it.
  54. Allocate any required resources. Set things up. And be prepared for the
  55. first ``start device.''
  56. Arguments:
  57. BusPhysicalDeviceObject - Device object representing the bus. That to which we
  58. attach a new FDO.
  59. DriverObject - This very self referenced driver.
  60. --*/
  61. {
  62. NTSTATUS status;
  63. PDEVICE_OBJECT deviceObject;
  64. PFDO_DEVICE_DATA deviceData;
  65. #if DBG
  66. ULONG nameLength;
  67. PWCHAR deviceName;
  68. #endif
  69. PAGED_CODE ();
  70. Game_KdPrint_Def (GAME_DBG_SS_TRACE, ("Add Device: 0x%x\n",
  71. BusPhysicalDeviceObject));
  72. status = IoCreateDevice (
  73. DriverObject, // our driver object
  74. sizeof (FDO_DEVICE_DATA), // device object extension size
  75. NULL, // FDOs do not have names
  76. FILE_DEVICE_BUS_EXTENDER,
  77. FILE_DEVICE_SECURE_OPEN, // No special characteristics
  78. TRUE, // our FDO is exclusive
  79. &deviceObject); // The device object created
  80. if (NT_SUCCESS (status)) {
  81. deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
  82. RtlFillMemory (deviceData, sizeof (FDO_DEVICE_DATA), 0);
  83. #if DBG
  84. deviceData->DebugLevel = GameEnumDebugLevel;
  85. #endif
  86. deviceData->IsFDO = TRUE;
  87. deviceData->Self = deviceObject;
  88. ExInitializeFastMutex (&deviceData->Mutex);
  89. deviceData->Removed = FALSE;
  90. InitializeListHead (&deviceData->PDOs);
  91. // Set the PDO for use with PlugPlay functions
  92. deviceData->UnderlyingPDO = BusPhysicalDeviceObject;
  93. //
  94. // Will get preincremented everytime a new PDO is created ... want the
  95. // first ID to be zero
  96. //
  97. deviceData->UniqueIDCount = GAMEENUM_UNIQUEID_START;
  98. //
  99. // Attach our filter driver to the device stack.
  100. // the return value of IoAttachDeviceToDeviceStack is the top of the
  101. // attachment chain. This is where all the IRPs should be routed.
  102. //
  103. // Our filter will send IRPs to the top of the stack and use the PDO
  104. // for all PlugPlay functions.
  105. //
  106. deviceData->TopOfStack = IoAttachDeviceToDeviceStack (
  107. deviceObject,
  108. BusPhysicalDeviceObject);
  109. if (deviceData->TopOfStack == NULL) {
  110. IoDeleteDevice(deviceObject);
  111. return STATUS_DEVICE_NOT_CONNECTED;
  112. }
  113. // Bias outstanding request to 1 so that we can look for a
  114. // transition to zero when processing the remove device PlugPlay IRP.
  115. deviceData->OutstandingIO = 1;
  116. KeInitializeEvent(&deviceData->RemoveEvent,
  117. SynchronizationEvent,
  118. FALSE); // initialized to not signalled
  119. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  120. deviceObject->Flags |= DO_POWER_PAGABLE;
  121. //
  122. // Tell the PlugPlay system that this device will need an interface
  123. // device class shingle.
  124. //
  125. // It may be that the driver cannot hang the shingle until it starts
  126. // the device itself, so that it can query some of its properties.
  127. // (Aka the shingles guid (or ref string) is based on the properties
  128. // of the device.)
  129. //
  130. status = IoRegisterDeviceInterface (
  131. BusPhysicalDeviceObject,
  132. (LPGUID) &GUID_GAMEENUM_BUS_ENUMERATOR,
  133. NULL, // No ref string
  134. &deviceData->DevClassAssocName);
  135. if (!NT_SUCCESS (status)) {
  136. Game_KdPrint (deviceData, GAME_DBG_SS_ERROR,
  137. ("AddDevice: IoRegisterDeviceInterface failed (%x)", status));
  138. IoDeleteDevice (deviceObject);
  139. return status;
  140. }
  141. //
  142. // If for any reason you need to save values in a safe location that
  143. // clients of this DeviceInterface might be interested in reading
  144. // here is the time to do so, with the function
  145. // IoOpenDeviceClassRegistryKey
  146. // the symbolic link name used is was returned in
  147. // deviceData->DevClassAssocName (the same name which is returned by
  148. // IoGetDeviceClassAssociations and the SetupAPI equivs.
  149. //
  150. #if DBG
  151. nameLength = 0;
  152. status = IoGetDeviceProperty (BusPhysicalDeviceObject,
  153. DevicePropertyPhysicalDeviceObjectName,
  154. 0,
  155. NULL,
  156. &nameLength);
  157. //
  158. // Proceed only if the PDO has a name
  159. //
  160. if (status == STATUS_BUFFER_TOO_SMALL && nameLength != 0) {
  161. deviceName = ExAllocatePool (NonPagedPool, nameLength);
  162. if (NULL == deviceName) {
  163. IoDeleteDevice (deviceObject);
  164. Game_KdPrint (deviceData, GAME_DBG_SS_ERROR,
  165. ("AddDevice: no memory to alloc DeviceName (0x%x)",
  166. nameLength));
  167. return STATUS_INSUFFICIENT_RESOURCES;
  168. }
  169. IoGetDeviceProperty (BusPhysicalDeviceObject,
  170. DevicePropertyPhysicalDeviceObjectName,
  171. nameLength,
  172. deviceName,
  173. &nameLength);
  174. Game_KdPrint (deviceData, GAME_DBG_SS_TRACE,
  175. ("AddDevice: %x to %x->%x (%ws) \n",
  176. deviceObject,
  177. deviceData->TopOfStack,
  178. BusPhysicalDeviceObject,
  179. deviceName));
  180. ExFreePool(deviceName);
  181. }
  182. status = STATUS_SUCCESS;
  183. #endif
  184. if (!NT_SUCCESS (status)) {
  185. Game_KdPrint (deviceData, GAME_DBG_SS_ERROR,
  186. ("AddDevice: IoGetDeviceClass failed (%x)", status));
  187. return status;
  188. }
  189. }
  190. return status;
  191. }
  192. NTSTATUS
  193. Game_SystemControl (
  194. IN PDEVICE_OBJECT DeviceObject,
  195. IN PIRP Irp
  196. )
  197. {
  198. PCOMMON_DEVICE_DATA commonData;
  199. PAGED_CODE ();
  200. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  201. if (commonData->IsFDO) {
  202. IoSkipCurrentIrpStackLocation (Irp);
  203. return IoCallDriver (((PFDO_DEVICE_DATA) commonData)->TopOfStack, Irp);
  204. }
  205. else {
  206. //
  207. // The PDO, just complete the request with the current status
  208. //
  209. NTSTATUS status = Irp->IoStatus.Status;
  210. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  211. return status;
  212. }
  213. }
  214. NTSTATUS
  215. Game_PnP (
  216. IN PDEVICE_OBJECT DeviceObject,
  217. IN PIRP Irp
  218. )
  219. /*++
  220. Routine Description:
  221. Answer the plithera of Irp Major PnP IRPS.
  222. --*/
  223. {
  224. PIO_STACK_LOCATION irpStack;
  225. NTSTATUS status;
  226. PCOMMON_DEVICE_DATA commonData;
  227. KIRQL oldIrq;
  228. PAGED_CODE ();
  229. status = STATUS_SUCCESS;
  230. irpStack = IoGetCurrentIrpStackLocation (Irp);
  231. ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
  232. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  233. if (commonData->IsFDO) {
  234. Game_KdPrint (commonData, GAME_DBG_PNP_TRACE,
  235. ("PNP: Functional DO: %x IRP: %x\n", DeviceObject, Irp));
  236. status = Game_FDO_PnP (
  237. DeviceObject,
  238. Irp,
  239. irpStack,
  240. (PFDO_DEVICE_DATA) commonData);
  241. } else {
  242. Game_KdPrint (commonData, GAME_DBG_PNP_TRACE,
  243. ("PNP: Physical DO: %x IRP: %x\n", DeviceObject, Irp));
  244. status = Game_PDO_PnP (
  245. DeviceObject,
  246. Irp,
  247. irpStack,
  248. (PPDO_DEVICE_DATA) commonData);
  249. }
  250. return status;
  251. }
  252. NTSTATUS
  253. Game_FDO_PnP (
  254. IN PDEVICE_OBJECT DeviceObject,
  255. IN PIRP Irp,
  256. IN PIO_STACK_LOCATION IrpStack,
  257. IN PFDO_DEVICE_DATA DeviceData
  258. )
  259. /*++
  260. Routine Description:
  261. Handle requests from the PlugPlay system for the BUS itself
  262. NB: the various Minor functions of the PlugPlay system will not be
  263. overlapped and do not have to be reentrant
  264. --*/
  265. {
  266. NTSTATUS status;
  267. KEVENT event;
  268. ULONG length;
  269. ULONG i;
  270. PLIST_ENTRY entry;
  271. PPDO_DEVICE_DATA pdoData;
  272. PDEVICE_RELATIONS relations, oldRelations;
  273. PIO_STACK_LOCATION stack;
  274. PAGED_CODE ();
  275. status = Game_IncIoCount (DeviceData);
  276. if (!NT_SUCCESS (status)) {
  277. Irp->IoStatus.Information = 0;
  278. Irp->IoStatus.Status = status;
  279. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  280. return status;
  281. }
  282. stack = IoGetCurrentIrpStackLocation (Irp);
  283. switch (IrpStack->MinorFunction) {
  284. case IRP_MN_START_DEVICE:
  285. //
  286. // BEFORE you are allowed to ``touch'' the device object to which
  287. // the FDO is attached (that send an irp from the bus to the Device
  288. // object to which the bus is attached). You must first pass down
  289. // the start IRP. It might not be powered on, or able to access or
  290. // something.
  291. //
  292. if (DeviceData->Started) {
  293. status = STATUS_SUCCESS;
  294. break;
  295. }
  296. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Start Device\n"));
  297. status = Game_SendIrpSynchronously (DeviceData->TopOfStack, Irp, TRUE, TRUE);
  298. if (NT_SUCCESS(status)) {
  299. //
  300. // Now we can touch the lower device object as it is now started.
  301. //
  302. if ((NULL == stack->Parameters.StartDevice.AllocatedResources) ||
  303. (NULL == stack->Parameters.StartDevice.AllocatedResourcesTranslated)) {
  304. status = STATUS_INSUFFICIENT_RESOURCES;
  305. break;
  306. }
  307. status = Game_StartFdo (DeviceData,
  308. &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList,
  309. &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList);
  310. //
  311. // find the translated resources and store them someplace
  312. // safe for given out for the PDOs.
  313. //
  314. if (NT_SUCCESS (status)) {
  315. //
  316. // Turn on the shingle and point it to the given device object.
  317. //
  318. DeviceData->Started = TRUE;
  319. IoSetDeviceInterfaceState(&DeviceData->DevClassAssocName, TRUE);
  320. }
  321. }
  322. //
  323. // We must now complete the IRP, since we stopped it in the
  324. // completetion routine with MORE_PROCESSING_REQUIRED.
  325. //
  326. Irp->IoStatus.Information = 0;
  327. break;
  328. case IRP_MN_QUERY_STOP_DEVICE:
  329. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Query Stop Device\n"));
  330. //
  331. // Test to see if there are any PDO created as children of this FDO
  332. // If there are then conclude the device is busy and fail the
  333. // query stop.
  334. //
  335. // ISSUE
  336. // We could do better, by seing if the children PDOs are actually
  337. // currently open. If they are not then we could stop, get new
  338. // resouces, fill in the new resouce values, and then when a new client
  339. // opens the PDO use the new resources. But this works for now.
  340. //
  341. if (DeviceData->NumPDOs) {
  342. status = STATUS_UNSUCCESSFUL;
  343. Irp->IoStatus.Status = status;
  344. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  345. } else {
  346. status = STATUS_SUCCESS;
  347. Irp->IoStatus.Status = status;
  348. IoSkipCurrentIrpStackLocation (Irp);
  349. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  350. }
  351. Game_DecIoCount (DeviceData);
  352. return status;
  353. case IRP_MN_STOP_DEVICE:
  354. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Stop Device\n"));
  355. //
  356. // After the start IRP has been sent to the lower driver object, the
  357. // bus may NOT send any more IRPS down ``touch'' until another START
  358. // has occured.
  359. // What ever access is required must be done before the Irp is passed
  360. // on.
  361. //
  362. // Stop device means that the resources given durring Start device
  363. // are no revoked. So we need to stop using them
  364. //
  365. if (DeviceData->Started) {
  366. DeviceData->Started = FALSE;
  367. //
  368. // Free resources given by start device.
  369. //
  370. if (DeviceData->MappedPorts) {
  371. MmUnmapIoSpace (DeviceData->GamePortAddress,
  372. DeviceData->GamePortAddressLength);
  373. }
  374. }
  375. //
  376. // We don't need a completion routine so fire and forget.
  377. //
  378. // Set the current stack location to the next stack location and
  379. // call the next device object.
  380. //
  381. Irp->IoStatus.Status = STATUS_SUCCESS;
  382. IoSkipCurrentIrpStackLocation (Irp);
  383. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  384. Game_DecIoCount (DeviceData);
  385. return status;
  386. case IRP_MN_SURPRISE_REMOVAL:
  387. ASSERT(!DeviceData->Acquired);
  388. Game_RemoveFdo(DeviceData);
  389. Irp->IoStatus.Status = STATUS_SUCCESS;
  390. IoSkipCurrentIrpStackLocation (Irp);
  391. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  392. Game_DecIoCount (DeviceData);
  393. return status;
  394. case IRP_MN_REMOVE_DEVICE:
  395. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Remove Device\n"));
  396. //
  397. // We should assert this because Game_IncIoCount will not succeed if a
  398. // remove has already been sent down.
  399. //
  400. ASSERT(!DeviceData->Removed);
  401. ASSERT(!DeviceData->Acquired);
  402. //
  403. // The PlugPlay system has detected the removal of this device. We
  404. // have no choise but to detach and delete the device objecct.
  405. // (If we wanted to express and interest in preventing this removal,
  406. // we should have filtered the query remove and query stop routines.)
  407. //
  408. // Note! we might receive a remove WITHOUT first receiving a stop.
  409. // ASSERT (!DeviceData->Removed);
  410. //
  411. // We will accept no new requests
  412. //
  413. DeviceData->Removed = TRUE;
  414. //
  415. // Complete any outstanding IRPs queued by the driver here.
  416. //
  417. // Perform (surpise) remove code
  418. Game_RemoveFdo(DeviceData);
  419. //
  420. // Here if we had any outstanding requests in a personal queue we should
  421. // complete them all now.
  422. //
  423. // Note, the device is guarenteed stopped, so we cannot send it any non-
  424. // PNP IRPS.
  425. //
  426. //
  427. // Fire and forget
  428. //
  429. Irp->IoStatus.Status = STATUS_SUCCESS;
  430. IoSkipCurrentIrpStackLocation (Irp);
  431. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  432. //
  433. // Wait for all outstanding requests to complete
  434. //
  435. i = InterlockedDecrement (&DeviceData->OutstandingIO);
  436. ASSERT (0 < i);
  437. if (0 != InterlockedDecrement (&DeviceData->OutstandingIO)) {
  438. NTSTATUS waitStatus;
  439. Game_KdPrint (DeviceData, GAME_DBG_PNP_INFO,
  440. ("Remove Device waiting for request to complete\n"));
  441. waitStatus = KeWaitForSingleObject (&DeviceData->RemoveEvent,
  442. Executive,
  443. KernelMode,
  444. FALSE, // Not Alertable
  445. NULL); // No timeout
  446. ASSERT (waitStatus == STATUS_SUCCESS);
  447. }
  448. //
  449. // Free the associated resources
  450. //
  451. //
  452. // Detatch from the undelying devices.
  453. //
  454. Game_KdPrint(DeviceData, GAME_DBG_PNP_INFO,
  455. ("IoDetachDevice: 0x%x\n", DeviceData->TopOfStack));
  456. IoDetachDevice (DeviceData->TopOfStack);
  457. Game_KdPrint(DeviceData, GAME_DBG_PNP_INFO,
  458. ("IoDeleteDevice1: 0x%x\n", DeviceObject));
  459. ExAcquireFastMutex (&DeviceData->Mutex);
  460. for (entry = DeviceData->PDOs.Flink;
  461. entry != &DeviceData->PDOs;
  462. ) {
  463. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  464. ASSERT (pdoData->Removed);
  465. ASSERT (pdoData->Attached);
  466. //
  467. // We set this to false so that Game_RemovePdo will delete the DO
  468. // and free any of the allocated memory associated with the PDO.
  469. //
  470. pdoData->Attached = FALSE;
  471. //
  472. // Go to the next link in the list. Once the pdo is deleted, entry
  473. // is no longer a valid pointer.
  474. //
  475. entry = entry->Flink;
  476. //
  477. // Once Game_RemovePdo is called, pdoData and the pdo itself cannot
  478. // be touched becuase they will have been deleted. RemoveEntryList
  479. // does not modify the value Link->Flink, so the state after this
  480. // one is safe
  481. //
  482. RemoveEntryList (&pdoData->Link);
  483. Game_RemovePdo (pdoData->Self, pdoData);
  484. DeviceData->NumPDOs--;
  485. }
  486. ASSERT(DeviceData->NumPDOs == 0);
  487. ExReleaseFastMutex (&DeviceData->Mutex);
  488. IoDeleteDevice (DeviceObject);
  489. return status;
  490. case IRP_MN_QUERY_DEVICE_RELATIONS:
  491. if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) {
  492. //
  493. // We don't support this
  494. //
  495. goto GAME_FDO_PNP_DEFAULT;
  496. }
  497. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Query Relations "));
  498. //
  499. // Tell the plug and play system about all the PDOs.
  500. //
  501. // There might also be device relations below and above this FDO,
  502. // so, be sure to propagate the relations from the upper drivers.
  503. //
  504. // No Completion routine is needed so long as the status is preset
  505. // to success. (PDOs complete plug and play irps with the current
  506. // IoStatus.Status and IoStatus.Information as the default.)
  507. //
  508. ExAcquireFastMutex (&DeviceData->Mutex);
  509. oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  510. if (oldRelations) {
  511. i = oldRelations->Count;
  512. if (!DeviceData->NumPDOs) {
  513. //
  514. // There is a device relations struct already present and we have
  515. // nothing to add to it, so just call IoSkip and IoCall
  516. //
  517. ExReleaseFastMutex (&DeviceData->Mutex);
  518. goto GAME_FDO_PNP_DEFAULT;
  519. }
  520. }
  521. else {
  522. i = 0;
  523. }
  524. // The current number of PDOs
  525. Game_KdPrint_Cont (DeviceData, GAME_DBG_PNP_TRACE,
  526. ("#PDOS = %d + %d\n", i, DeviceData->NumPDOs));
  527. //
  528. // Need to allocate a new relations structure and add our
  529. // PDOs to it.
  530. //
  531. length = sizeof(DEVICE_RELATIONS) +
  532. ((DeviceData->NumPDOs + i) * sizeof (PDEVICE_OBJECT));
  533. relations = (PDEVICE_RELATIONS) ExAllocatePool (PagedPool, length);
  534. if (NULL == relations) {
  535. ExReleaseFastMutex (&DeviceData->Mutex);
  536. status = STATUS_INSUFFICIENT_RESOURCES;
  537. break;
  538. }
  539. //
  540. // Copy in the device objects so far
  541. //
  542. if (i) {
  543. RtlCopyMemory (
  544. relations->Objects,
  545. oldRelations->Objects,
  546. i * sizeof (PDEVICE_OBJECT));
  547. }
  548. relations->Count = DeviceData->NumPDOs + i;
  549. //
  550. // For each PDO on this bus add a pointer to the device relations
  551. // buffer, being sure to take out a reference to that object.
  552. // The PlugPlay system will dereference the object when it is done with
  553. // it and free the device relations buffer.
  554. //
  555. for (entry = DeviceData->PDOs.Flink;
  556. entry != &DeviceData->PDOs;
  557. entry = entry->Flink, i++) {
  558. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  559. ASSERT (pdoData->Attached);
  560. relations->Objects[i] = pdoData->Self;
  561. ObReferenceObject (pdoData->Self);
  562. }
  563. //
  564. // Replace the relations structure in the IRP with the new
  565. // one.
  566. //
  567. if (oldRelations) {
  568. ExFreePool (oldRelations);
  569. }
  570. Irp->IoStatus.Information = (ULONG_PTR) relations;
  571. ExReleaseFastMutex (&DeviceData->Mutex);
  572. //
  573. // Set up and pass the IRP further down the stack
  574. //
  575. Irp->IoStatus.Status = STATUS_SUCCESS;
  576. IoSkipCurrentIrpStackLocation (Irp);
  577. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  578. Game_DecIoCount (DeviceData);
  579. return status;
  580. case IRP_MN_CANCEL_REMOVE_DEVICE:
  581. case IRP_MN_CANCEL_STOP_DEVICE:
  582. case IRP_MN_QUERY_REMOVE_DEVICE:
  583. //
  584. // For query remove, if we were to fail this call then we would need to
  585. // complete the IRP here. Since we are not, set the status to SUCCESS
  586. // and call the next driver.
  587. //
  588. // For the cancel(s), we must set the status to notify the PnP subsystem
  589. // that the irp was correctly handled
  590. //
  591. Irp->IoStatus.Status = STATUS_SUCCESS;
  592. IoSkipCurrentIrpStackLocation (Irp);
  593. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  594. Game_DecIoCount (DeviceData);
  595. return status;
  596. GAME_FDO_PNP_DEFAULT:
  597. default:
  598. //
  599. // In the default case we merely call the next driver since
  600. // we don't know what to do.
  601. //
  602. //
  603. // Fire and Forget
  604. //
  605. IoSkipCurrentIrpStackLocation (Irp);
  606. //
  607. // Done, do NOT complete the IRP, it will be processed by the lower
  608. // device object, which will complete the IRP
  609. //
  610. status = IoCallDriver (DeviceData->TopOfStack, Irp);
  611. Game_DecIoCount (DeviceData);
  612. return status;
  613. }
  614. Irp->IoStatus.Status = status;
  615. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  616. Game_DecIoCount (DeviceData);
  617. return status;
  618. }
  619. UCHAR
  620. Game_ReadPortUchar (
  621. IN UCHAR * x
  622. )
  623. {
  624. return READ_PORT_UCHAR (x);
  625. }
  626. VOID
  627. Game_WritePortUchar (
  628. IN UCHAR * x,
  629. IN UCHAR y
  630. )
  631. {
  632. WRITE_PORT_UCHAR (x,y);
  633. }
  634. UCHAR
  635. Game_ReadRegisterUchar (
  636. IN UCHAR * x
  637. )
  638. {
  639. return READ_REGISTER_UCHAR (x);
  640. }
  641. VOID
  642. Game_WriteRegisterUchar (
  643. IN UCHAR * x,
  644. IN UCHAR y
  645. )
  646. {
  647. WRITE_REGISTER_UCHAR (x,y);
  648. }
  649. NTSTATUS
  650. Game_StartFdo (
  651. IN PFDO_DEVICE_DATA FdoData,
  652. IN PCM_PARTIAL_RESOURCE_LIST PartialResourceList,
  653. IN PCM_PARTIAL_RESOURCE_LIST PartialResourceListTranslated
  654. )
  655. /*++
  656. Routine Description:
  657. Parses the resource lists to see what type of accessors to use.
  658. Arguments:
  659. DeviceObject - Pointer to the device object.
  660. PartialResourceList - untranslated resources
  661. PartialResourceListTranslated - translated resources
  662. Return Value:
  663. Status is returned.
  664. --*/
  665. {
  666. ULONG i;
  667. NTSTATUS status = STATUS_SUCCESS;
  668. PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
  669. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceTrans;
  670. Game_KdPrint (FdoData, GAME_DBG_PNP_TRACE, ("StartFdo\n"));
  671. for (i = 0,
  672. resource = &PartialResourceList->PartialDescriptors[0],
  673. resourceTrans = &PartialResourceListTranslated->PartialDescriptors[0];
  674. i < PartialResourceList->Count && NT_SUCCESS(status);
  675. i++, resource++, resourceTrans++) {
  676. switch (resource->Type) {
  677. case CmResourceTypePort:
  678. #if _X86_
  679. FdoData->ReadPort = READ_PORT_UCHAR;
  680. FdoData->WritePort = WRITE_PORT_UCHAR;
  681. #else
  682. FdoData->ReadPort = Game_ReadPortUchar;
  683. FdoData->WritePort = Game_WritePortUchar;
  684. #endif
  685. FdoData->PhysicalAddress = resource->u.Port.Start;
  686. Game_KdPrint (FdoData, GAME_DBG_PNP_INFO,
  687. ("HardwareResource: Port (%x) -> ",
  688. FdoData->PhysicalAddress.LowPart));
  689. switch (resourceTrans->Type) {
  690. case CmResourceTypePort:
  691. // Nothing to do here but note the address;
  692. //@@BEGIN_DDKSPLIT
  693. // On Win9x, VJoyD.VxD handles the resources for gameports.
  694. // It only uses ports and it assumes that the first range is
  695. // always the gameport. It uses a second range of a devnode
  696. // only if the second range is within the original standard
  697. // range of 200-20f. All other ports are assumed to be audio
  698. // ports on the hosting sound card.
  699. //@@END_DDKSPLIT
  700. // For better compatibility with Win9x, always use only the
  701. // first port range.
  702. if( FdoData->GamePortAddress == 0 ) {
  703. FdoData->GamePortAddress =
  704. (PVOID)(ULONG_PTR) resourceTrans->u.Port.Start.QuadPart;
  705. ASSERT (resourceTrans->u.Port.Length == resource->u.Port.Length);
  706. FdoData->GamePortAddressLength = resourceTrans->u.Port.Length;
  707. Game_KdPrint_Cont (FdoData, GAME_DBG_PNP_INFO,
  708. ("Port: (%x)\n", FdoData->GamePortAddress));
  709. } else {
  710. Game_KdPrint_Cont (FdoData, GAME_DBG_PNP_INFO,
  711. ("Ignoring additional port: (%x)\n", FdoData->GamePortAddress));
  712. }
  713. break;
  714. case CmResourceTypeMemory:
  715. //
  716. // We need to map the memory
  717. //
  718. FdoData->GamePortAddress =
  719. MmMapIoSpace (resourceTrans->u.Memory.Start,
  720. resourceTrans->u.Memory.Length,
  721. MmNonCached);
  722. ASSERT (resourceTrans->u.Port.Length == resource->u.Port.Length);
  723. FdoData->GamePortAddressLength = resourceTrans->u.Memory.Length;
  724. FdoData->MappedPorts = TRUE;
  725. Game_KdPrint_Cont (FdoData, GAME_DBG_PNP_INFO,
  726. ("Mem: (%x)\n", FdoData->GamePortAddress));
  727. break;
  728. default:
  729. Game_KdPrint_Cont (FdoData, GAME_DBG_PNP_INFO,
  730. ("Unknown \n", FdoData->GamePortAddress));
  731. TRAP ();
  732. }
  733. break;
  734. case CmResourceTypeMemory:
  735. ASSERT (CmResourceTypeMemory == resourceTrans->Type);
  736. #if _X86_
  737. FdoData->ReadPort = READ_REGISTER_UCHAR;
  738. FdoData->WritePort = WRITE_REGISTER_UCHAR;
  739. #else
  740. FdoData->ReadPort = Game_ReadRegisterUchar;
  741. FdoData->WritePort = Game_WriteRegisterUchar;
  742. #endif
  743. FdoData->PhysicalAddress = resource->u.Memory.Start;
  744. FdoData->GamePortAddress =
  745. MmMapIoSpace (resourceTrans->u.Memory.Start,
  746. resourceTrans->u.Memory.Length,
  747. MmNonCached);
  748. FdoData->MappedPorts = TRUE;
  749. Game_KdPrint (FdoData, GAME_DBG_PNP_INFO,
  750. ("HardwareResource: Memory (%x) -> Mem (%x)",
  751. FdoData->PhysicalAddress.LowPart,
  752. FdoData->GamePortAddress));
  753. break;
  754. case CmResourceTypeInterrupt:
  755. default:
  756. // Hun? Allow this to succeed...perhaps whomever enumerated the PDO
  757. // below us needs this resource for the game port
  758. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  759. ("Unhandled resource type (0x%x)\n",
  760. resource->Type));
  761. // status = STATUS_UNSUCCESSFUL;
  762. }
  763. }
  764. return status;
  765. }
  766. void
  767. Game_RemoveFdo (
  768. IN PFDO_DEVICE_DATA FdoData
  769. )
  770. /*++
  771. Routine Description:
  772. Frees any memory allocated by the FDO and unmaps any IO mapped as well.
  773. --*/
  774. {
  775. PAGED_CODE ();
  776. if (FdoData->SurpriseRemoved) {
  777. return;
  778. }
  779. //
  780. // We set this b/c if we get called twice, that means a surprise removal
  781. // called this function first
  782. //
  783. FdoData->SurpriseRemoved = TRUE;
  784. //
  785. // Clean up any resources here
  786. //
  787. if (FdoData->Started) {
  788. FdoData->Started = FALSE;
  789. //
  790. // Free resources given by start device.
  791. //
  792. if (FdoData->MappedPorts) {
  793. MmUnmapIoSpace (FdoData->GamePortAddress, 1);
  794. // Here we are assuming that joysticks only use on port.
  795. // This is the way it has always been, and might always
  796. // continue to be. This assumption is everywhere in this stack.
  797. }
  798. IoSetDeviceInterfaceState (&FdoData->DevClassAssocName, FALSE);
  799. }
  800. //
  801. // Make the DI go away. Some drivers may choose to remove the DCA
  802. // when they receive a stop or even a query stop. We just don't care.
  803. //
  804. if (FdoData->DevClassAssocName.Buffer != NULL) {
  805. ExFreePool (FdoData->DevClassAssocName.Buffer);
  806. RtlZeroMemory (&FdoData->DevClassAssocName,
  807. sizeof (UNICODE_STRING));
  808. }
  809. }
  810. NTSTATUS
  811. Game_SendIrpSynchronously (
  812. IN PDEVICE_OBJECT DeviceObject,
  813. IN PIRP Irp,
  814. IN BOOLEAN NotImplementedIsValid,
  815. IN BOOLEAN CopyToNext
  816. )
  817. {
  818. KEVENT event;
  819. NTSTATUS status;
  820. PAGED_CODE();
  821. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  822. if (CopyToNext) {
  823. IoCopyCurrentIrpStackLocationToNext(Irp);
  824. }
  825. IoSetCompletionRoutine(Irp,
  826. Game_CompletionRoutine,
  827. &event,
  828. TRUE,
  829. TRUE,
  830. TRUE
  831. );
  832. status = IoCallDriver(DeviceObject, Irp);
  833. //
  834. // Wait for lower drivers to be done with the Irp
  835. //
  836. if (status == STATUS_PENDING) {
  837. KeWaitForSingleObject(&event,
  838. Executive,
  839. KernelMode,
  840. FALSE,
  841. NULL
  842. );
  843. status = Irp->IoStatus.Status;
  844. }
  845. if (NotImplementedIsValid && (status == STATUS_NOT_IMPLEMENTED ||
  846. status == STATUS_INVALID_DEVICE_REQUEST)) {
  847. status = STATUS_SUCCESS;
  848. }
  849. return status;
  850. }
  851. NTSTATUS
  852. Game_CompletionRoutine (
  853. IN PDEVICE_OBJECT DeviceObject,
  854. IN PIRP Irp,
  855. IN PVOID Context
  856. )
  857. /*++
  858. Routine Description:
  859. A completion routine for use when calling the lower device objects to
  860. which our bus (FDO) is attached.
  861. --*/
  862. {
  863. UNREFERENCED_PARAMETER (DeviceObject);
  864. UNREFERENCED_PARAMETER (Irp);
  865. // if (Irp->PendingReturned) {
  866. // IoMarkIrpPending( Irp );
  867. // }
  868. KeSetEvent ((PKEVENT) Context, 1, FALSE);
  869. return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
  870. }
  871. NTSTATUS
  872. Game_PDO_PnP (
  873. IN PDEVICE_OBJECT DeviceObject,
  874. IN PIRP Irp,
  875. IN PIO_STACK_LOCATION IrpStack,
  876. IN PPDO_DEVICE_DATA DeviceData
  877. )
  878. /*++
  879. Routine Description:
  880. Handle requests from the PlugPlay system for the devices on the BUS
  881. --*/
  882. {
  883. PDEVICE_CAPABILITIES deviceCapabilities;
  884. ULONG information;
  885. PWCHAR buffer, buffer2;
  886. ULONG length, length2, i, j;
  887. NTSTATUS status;
  888. PAGED_CODE ();
  889. status = Irp->IoStatus.Status;
  890. //
  891. // NB: since we are a bus enumerator, we have no one to whom we could
  892. // defer these irps. Therefore we do not pass them down but merely
  893. // return them.
  894. //
  895. switch (IrpStack->MinorFunction) {
  896. case IRP_MN_QUERY_CAPABILITIES:
  897. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Query Caps \n"));
  898. //
  899. // Get the packet.
  900. //
  901. deviceCapabilities=IrpStack->Parameters.DeviceCapabilities.Capabilities;
  902. //
  903. // Set the capabilities.
  904. //
  905. deviceCapabilities->Version = 1;
  906. deviceCapabilities->Size = sizeof (DEVICE_CAPABILITIES);
  907. // We cannot wake the system.
  908. deviceCapabilities->SystemWake = PowerSystemUnspecified;
  909. deviceCapabilities->DeviceWake = PowerDeviceUnspecified;
  910. // We have no latencies
  911. deviceCapabilities->D1Latency = 0;
  912. deviceCapabilities->D2Latency = 0;
  913. deviceCapabilities->D3Latency = 0;
  914. // No locking or ejection
  915. deviceCapabilities->LockSupported = FALSE;
  916. deviceCapabilities->EjectSupported = FALSE;
  917. // Device can be physically removed.
  918. // Technically there is no physical device to remove, but this bus
  919. // driver can yank the PDO from the PlugPlay system, when ever it
  920. // receives an IOCTL_GAMEENUM_REMOVE_PORT device control command.
  921. deviceCapabilities->Removable = FALSE;
  922. deviceCapabilities->SurpriseRemovalOK = TRUE;
  923. // not Docking device
  924. deviceCapabilities->DockDevice = FALSE;
  925. deviceCapabilities->UniqueID = FALSE;
  926. status = STATUS_SUCCESS;
  927. break;
  928. case IRP_MN_QUERY_ID:
  929. // Query the IDs of the device
  930. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE,
  931. ("QueryID: 0x%x\n", IrpStack->Parameters.QueryId.IdType));
  932. //
  933. // If the query requires having a hardware ID, check we have one
  934. //
  935. #if DBG
  936. if (( IrpStack->Parameters.QueryId.IdType == BusQueryDeviceID )
  937. || ( IrpStack->Parameters.QueryId.IdType == BusQueryHardwareIDs )
  938. || ( IrpStack->Parameters.QueryId.IdType == BusQueryInstanceID )) {
  939. if (DeviceData->HardwareIDs) {
  940. ULONG tmplength = 1024; // No reason to be as long as this
  941. ASSERT( NT_SUCCESS( Game_CheckHardwareIDs (DeviceData->HardwareIDs,
  942. &tmplength, FDO_FROM_PDO (DeviceData) ) ) );
  943. } else {
  944. ASSERT( !"No hardware ID for QueryId" );
  945. }
  946. }
  947. #endif
  948. switch (IrpStack->Parameters.QueryId.IdType) {
  949. case BusQueryDeviceID:
  950. // this can be the same as the hardware ids (which requires a multi
  951. // sz) ... we are just allocating more than enough memory
  952. case BusQueryHardwareIDs:
  953. // return a multi WCHAR (null terminated) string (null terminated)
  954. // array for use in matching hardare ids in inf files;
  955. //
  956. buffer = DeviceData->HardwareIDs;
  957. while (*(buffer++)) {
  958. while (*(buffer++)) {
  959. ;
  960. }
  961. }
  962. length = (ULONG)(buffer - DeviceData->HardwareIDs) * sizeof (WCHAR);
  963. buffer = ExAllocatePool (PagedPool, length);
  964. if (buffer) {
  965. RtlCopyMemory (buffer, DeviceData->HardwareIDs, length);
  966. status = STATUS_SUCCESS;
  967. }
  968. else {
  969. status = STATUS_INSUFFICIENT_RESOURCES;
  970. }
  971. Irp->IoStatus.Information = (ULONG_PTR) buffer;
  972. break;
  973. case BusQueryInstanceID:
  974. //
  975. // Take the first hardware id and append an underscore and number
  976. // to it
  977. // total length =
  978. // length of hw id + underscore + number (11 digits to be safe) +
  979. // null
  980. //
  981. buffer = buffer2 = DeviceData->HardwareIDs;
  982. while (*(buffer++)) {
  983. while (*(buffer++)) {
  984. ;
  985. }
  986. }
  987. while ('\\' != *(buffer2++)) {
  988. ;
  989. }
  990. length = (ULONG)(buffer - buffer2) * sizeof (WCHAR);
  991. length += 1 + 11 + 1;
  992. buffer = ExAllocatePool (PagedPool, length);
  993. if (buffer) {
  994. swprintf(buffer, L"%ws_%02d", buffer2, DeviceData->UniqueID);
  995. Game_KdPrint (DeviceData, GAME_DBG_PNP_INFO,
  996. ("UniqueID: %ws\n", buffer));
  997. status = STATUS_SUCCESS;
  998. }
  999. else {
  1000. status = STATUS_INSUFFICIENT_RESOURCES;
  1001. }
  1002. Irp->IoStatus.Information = (ULONG_PTR) buffer;
  1003. break;
  1004. case BusQueryCompatibleIDs:
  1005. // The generic ids for installation of this pdo.
  1006. if (DeviceData->AnalogCompatible) {
  1007. // Only applicable for analog devices
  1008. length = GAMEENUM_COMPATIBLE_IDS_LENGTH * sizeof (WCHAR);
  1009. buffer = ExAllocatePool (PagedPool, length);
  1010. if (buffer) {
  1011. RtlCopyMemory (buffer, GAMEENUM_COMPATIBLE_IDS, length);
  1012. status = STATUS_SUCCESS;
  1013. }
  1014. else {
  1015. status = STATUS_INSUFFICIENT_RESOURCES;
  1016. }
  1017. Irp->IoStatus.Information = (ULONG_PTR) buffer;
  1018. }
  1019. else {
  1020. // For incompatible devices report an empty list
  1021. buffer = ExAllocatePool (PagedPool, sizeof(L"\0"));
  1022. if (buffer) {
  1023. *(ULONG *)buffer = 0; // double unicode-NULL.
  1024. status = STATUS_SUCCESS;
  1025. } else {
  1026. status = STATUS_INSUFFICIENT_RESOURCES;
  1027. }
  1028. Irp->IoStatus.Information = (ULONG_PTR) buffer;
  1029. }
  1030. break;
  1031. }
  1032. break;
  1033. case IRP_MN_START_DEVICE:
  1034. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Start Device \n"));
  1035. // Here we do what ever initialization and ``turning on'' that is
  1036. // required to allow others to access this device.
  1037. DeviceData->Started = TRUE;
  1038. DeviceData->Removed = FALSE;
  1039. status = STATUS_SUCCESS;
  1040. break;
  1041. case IRP_MN_STOP_DEVICE:
  1042. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Stop Device \n"));
  1043. // Here we shut down the device. The opposite of start.
  1044. DeviceData->Started = FALSE;
  1045. status = STATUS_SUCCESS;
  1046. break;
  1047. case IRP_MN_SURPRISE_REMOVAL:
  1048. // just mark that it happened, cleaning up the device extension will
  1049. // occur later
  1050. ASSERT(!(FDO_FROM_PDO (DeviceData))->Acquired);
  1051. DeviceData->SurpriseRemoved = TRUE;
  1052. status = STATUS_SUCCESS;
  1053. break;
  1054. case IRP_MN_REMOVE_DEVICE:
  1055. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Remove Device \n"));
  1056. ASSERT(!(FDO_FROM_PDO (DeviceData))->Acquired);
  1057. //
  1058. // The remove IRP code for a PDO uses the following steps:
  1059. //
  1060. // � Complete any requests queued in the driver
  1061. // � If the device is still attached to the system,
  1062. // then complete the request and return.
  1063. // � Otherwise, cleanup device specific allocations, memory, events...
  1064. // � Call IoDeleteDevice
  1065. // � Return from the dispatch routine.
  1066. //
  1067. status = Game_RemovePdo(DeviceObject, DeviceData);
  1068. break;
  1069. case IRP_MN_QUERY_STOP_DEVICE:
  1070. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Q Stop Device \n"));
  1071. // No reason here why we can't stop the device.
  1072. // If there were a reason we should speak now for answering success
  1073. // here may result in a stop device irp.
  1074. status = STATUS_SUCCESS;
  1075. break;
  1076. case IRP_MN_CANCEL_STOP_DEVICE:
  1077. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Cancel Stop Device \n"));
  1078. //
  1079. // The stop was canceled. Whatever state we set, or resources we put
  1080. // on hold in anticipation of the forcoming STOP device IRP should be
  1081. // put back to normal. Someone, in the long list of concerned parties,
  1082. // has failed the stop device query.
  1083. //
  1084. status = STATUS_SUCCESS;
  1085. break;
  1086. case IRP_MN_QUERY_REMOVE_DEVICE:
  1087. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Q Remove Device \n"));
  1088. //
  1089. // Just like Query Stop only now the impending doom is the remove irp
  1090. //
  1091. status = STATUS_SUCCESS;
  1092. break;
  1093. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1094. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE, ("Can Remove Device \n"));
  1095. //
  1096. // Clean up a remove that did not go through, just like cancel STOP.
  1097. //
  1098. status = STATUS_SUCCESS;
  1099. break;
  1100. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1101. if (TargetDeviceRelation ==
  1102. IrpStack->Parameters.QueryDeviceRelations.Type) {
  1103. PDEVICE_RELATIONS deviceRelations;
  1104. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  1105. if (!deviceRelations) {
  1106. deviceRelations = (PDEVICE_RELATIONS)
  1107. ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
  1108. if (!deviceRelations) {
  1109. status = STATUS_INSUFFICIENT_RESOURCES;
  1110. break;
  1111. }
  1112. }
  1113. else if (deviceRelations->Count != 0) {
  1114. //
  1115. // Nobody but the PDO should be setting this value!
  1116. //
  1117. ASSERT(deviceRelations->Count == 0);
  1118. //
  1119. // Deref any objects that were previously in the list
  1120. //
  1121. for (i = 0; i < deviceRelations->Count; i++) {
  1122. ObDereferenceObject(deviceRelations->Objects[i]);
  1123. deviceRelations->Objects[i] = NULL;
  1124. }
  1125. }
  1126. deviceRelations->Count = 1;
  1127. deviceRelations->Objects[0] = DeviceData->Self;
  1128. ObReferenceObject(DeviceData->Self);
  1129. status = STATUS_SUCCESS;
  1130. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  1131. break;
  1132. }
  1133. // fall through
  1134. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  1135. case IRP_MN_READ_CONFIG:
  1136. case IRP_MN_WRITE_CONFIG: // we have no config space
  1137. case IRP_MN_EJECT:
  1138. case IRP_MN_SET_LOCK:
  1139. case IRP_MN_QUERY_INTERFACE: // We do not have any non IRP based interfaces.
  1140. default:
  1141. Game_KdPrint (DeviceData, GAME_DBG_PNP_TRACE,
  1142. ("PNP Not handled 0x%x\n", IrpStack->MinorFunction));
  1143. // this is a leaf node
  1144. // status = STATUS_NOT_IMPLEMENTED
  1145. // For PnP requests to the PDO that we do not understand we should
  1146. // return the IRP WITHOUT setting the status or information fields.
  1147. // They may have already been set by a filter (eg acpi).
  1148. break;
  1149. }
  1150. Irp->IoStatus.Status = status;
  1151. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1152. return status;
  1153. }
  1154. NTSTATUS
  1155. Game_RemovePdo (
  1156. PDEVICE_OBJECT Device,
  1157. PPDO_DEVICE_DATA PdoData
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. The PlugPlay subsystem has instructed that this PDO should be removed.
  1162. We should therefore
  1163. Complete any requests queued in the driver
  1164. If the device is still attached to the system,
  1165. then complete the request and return.
  1166. Otherwise, cleanup device specific allocations, memory, events...
  1167. Call IoDeleteDevice
  1168. Return from the dispatch routine.
  1169. Note that if the device is still connected to the bus (IE in this case
  1170. the control panel has not yet told us that the game device has disappeared)
  1171. then the PDO must remain around, and must be returned during any
  1172. query Device relaions IRPS.
  1173. --*/
  1174. {
  1175. PAGED_CODE ();
  1176. PdoData->Removed = TRUE;
  1177. //
  1178. // Complete any outsanding requests with STATUS_DELETE_PENDING.
  1179. //
  1180. // Game enum does not queue any irps at this time so we have nothing to do.
  1181. //
  1182. // Attached is set to true when the pdo is exposed via one of the IOCTLs.
  1183. // It is set to FALSE when a remove IOCTL is received. This means that we
  1184. // can get a remove on a device that still exists, so we don't delete it.
  1185. //
  1186. if (PdoData->Attached) {
  1187. return STATUS_SUCCESS;
  1188. }
  1189. //
  1190. // Free any resources.
  1191. //
  1192. if (PdoData->HardwareIDs) {
  1193. ExFreePool (PdoData->HardwareIDs);
  1194. PdoData->HardwareIDs = NULL;
  1195. }
  1196. Game_KdPrint(PdoData, GAME_DBG_PNP_INFO,
  1197. ("IoDeleteDevice2: 0x%x\n", Device));
  1198. IoDeleteDevice (Device);
  1199. return STATUS_SUCCESS;
  1200. }
  1201. VOID
  1202. Game_InitializePdo (
  1203. PDEVICE_OBJECT Pdo,
  1204. PFDO_DEVICE_DATA FdoData
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. Set the PDO into a known good starting state
  1209. --*/
  1210. {
  1211. PPDO_DEVICE_DATA pdoData;
  1212. PAGED_CODE ();
  1213. pdoData = (PPDO_DEVICE_DATA) Pdo->DeviceExtension;
  1214. Game_KdPrint(pdoData, GAME_DBG_SS_NOISE,
  1215. ("pdo 0x%x, extension 0x%x\n", Pdo, pdoData));
  1216. //
  1217. // Initialize the rest
  1218. //
  1219. pdoData->IsFDO = FALSE;
  1220. pdoData->Self = Pdo;
  1221. #if DBG
  1222. pdoData->DebugLevel = GameEnumDebugLevel;
  1223. #endif
  1224. pdoData->ParrentFdo = FdoData->Self;
  1225. pdoData->Started = FALSE; // irp_mn_start has yet to be received
  1226. pdoData->Attached = TRUE; // attached to the bus
  1227. pdoData->Removed = FALSE; // no irp_mn_remove as of yet
  1228. pdoData->UniqueID = InterlockedIncrement(&FdoData->UniqueIDCount);
  1229. Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  1230. Pdo->Flags |= DO_POWER_PAGABLE;
  1231. ExAcquireFastMutex (&FdoData->Mutex);
  1232. InsertTailList(&FdoData->PDOs, &pdoData->Link);
  1233. FdoData->NumPDOs++;
  1234. ExReleaseFastMutex (&FdoData->Mutex);
  1235. }
  1236. NTSTATUS
  1237. Game_CheckHardwareIDs (
  1238. PWCHAR pwszOrgId,
  1239. PULONG puLenLimit,
  1240. PFDO_DEVICE_DATA FdoData
  1241. )
  1242. /*++
  1243. Routine Description:
  1244. Check that the hardware ID we've been given is matches format "Gameport\XXX" where XXX must
  1245. be between 0x20 and 0x7f inclusive but not be a ',' or '\'. We also have to make sure that we
  1246. do not overrun our buffer length. The length of the total buffer must be less than MAX_DEVICE_ID_LEN
  1247. and each individual entry must be less than 64 characters
  1248. --*/
  1249. {
  1250. PWCHAR pwszId;
  1251. ULONG total_length=0;
  1252. UCHAR ucEntries = 0;
  1253. #if DBG
  1254. PWCHAR pwszLastId;
  1255. #else
  1256. UNREFERENCED_PARAMETER (FdoData);
  1257. #endif
  1258. PAGED_CODE ();
  1259. Game_KdPrint (FdoData, GAME_DBG_PNP_TRACE, ("Game_CheckHardwareIDs - given ID string %.64lS length %d \n",pwszOrgId,*puLenLimit));
  1260. pwszId = pwszOrgId;
  1261. //
  1262. // Trivial rejection first - null string
  1263. if (*pwszId == UNICODE_NULL)
  1264. {
  1265. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,("hardware ID invalid - buffer NULL\n"));
  1266. return STATUS_INVALID_PARAMETER;
  1267. }
  1268. //
  1269. // Loop through at most 2 hardware IDs until the NULL terminator or end of buffer
  1270. //
  1271. while (*pwszId != UNICODE_NULL && total_length<=*puLenLimit)
  1272. {
  1273. PWCHAR pwszTemplate = HWID_TEMPLATE;
  1274. ULONG length=0;
  1275. #if DBG
  1276. //
  1277. // Keep track of the beginning of each ID for debug messages
  1278. //
  1279. pwszLastId = pwszId;
  1280. #endif
  1281. //
  1282. // Limit us to 2 entries
  1283. //
  1284. if (++ucEntries>2)
  1285. break;
  1286. //
  1287. // Length remaining must be long enough for an completion entry
  1288. // Which is template + 4 characters (slash,char,null,null)
  1289. //
  1290. if (HWID_TEMPLATE_LENGTH + 4 > (*puLenLimit)-total_length)
  1291. {
  1292. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1293. ("hardware ID \"%.64lS\" invalid - entry too short\n",pwszLastId));
  1294. return STATUS_INVALID_PARAMETER;
  1295. }
  1296. //
  1297. // Hardware ID must start with HWID_TEMPLATE
  1298. //
  1299. while (++length <= HWID_TEMPLATE_LENGTH)
  1300. {
  1301. if (LOWERCASE(*(pwszId++)) != *(pwszTemplate++))
  1302. {
  1303. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1304. ("hardware ID \"%.64lS\" invalid - does not match template\n",pwszLastId));
  1305. return STATUS_INVALID_PARAMETER;
  1306. }
  1307. }
  1308. //
  1309. // Must have a separator
  1310. //
  1311. if ((*(pwszId++) != OBJ_NAME_PATH_SEPARATOR))
  1312. {
  1313. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1314. ("hardware ID \"%.64lS\" invalid - no separator\n",pwszLastId));
  1315. return STATUS_INVALID_PARAMETER;
  1316. }
  1317. //
  1318. // We have a successful match of HWID_TEMPLATE_LENGTH + 1 characters
  1319. // Now our Id string check - check for NULL case first
  1320. //
  1321. if (*pwszId == UNICODE_NULL)
  1322. {
  1323. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1324. ("hardware ID \"%.64lS\" invalid format\n",pwszLastId));
  1325. return STATUS_INVALID_PARAMETER;
  1326. }
  1327. //
  1328. // Otherwise we loop until we overrun or hit NULL
  1329. while ((++length + total_length < *puLenLimit) && (*pwszId != UNICODE_NULL))
  1330. {
  1331. if ((*pwszId == OBJ_NAME_PATH_SEPARATOR) ||
  1332. (*pwszId < 0x20) ||
  1333. (*pwszId > 0x7f) ||
  1334. (*pwszId == L','))
  1335. {
  1336. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1337. ("hardware ID \"%.64lS\" invalid - bad character at length=%d\n",pwszLastId,length));
  1338. return STATUS_INVALID_PARAMETER;
  1339. }
  1340. if (length > 64)
  1341. {
  1342. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1343. ("hardware ID \"%.64lS\" invalid - ID %d too long at length=%d\n",pwszLastId,ucEntries,length));
  1344. return STATUS_INVALID_PARAMETER;
  1345. }
  1346. pwszId++;
  1347. }
  1348. //
  1349. // We need to increment to either the second NULL or next string
  1350. // If we had a null we test for either another entry or final NULL
  1351. // in the while loop
  1352. // If we ran too far we will pick it up in the while loop test and break
  1353. // out of the loop.
  1354. //
  1355. total_length += length;
  1356. pwszId++;
  1357. }
  1358. //
  1359. // If we have run off the end of the buffer return an error
  1360. //
  1361. if (total_length > *puLenLimit)
  1362. {
  1363. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1364. ("hardware ID \"%.64lS\" invalid - length > buffer limit\n",pwszLastId));
  1365. return STATUS_INVALID_PARAMETER;
  1366. }
  1367. //
  1368. // Copy the actual (maybe truncated) length back to the caller
  1369. //
  1370. *puLenLimit = ++total_length;
  1371. Game_KdPrint (FdoData, GAME_DBG_PNP_TRACE, ("Game_CheckHardwareIDs - succeeded. Final ID string \"%.64lS\" length %d \n",pwszOrgId,*puLenLimit));
  1372. return STATUS_SUCCESS;
  1373. }
  1374. NTSTATUS
  1375. Game_Expose (
  1376. PGAMEENUM_EXPOSE_HARDWARE Expose,
  1377. ULONG ExposeSize,
  1378. PFDO_DEVICE_DATA FdoData
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. This driver has just detected a new device on the bus. (Actually the
  1383. control panels has just told us that something has arived, but who is
  1384. counting?)
  1385. We therefore need to create a new PDO, initialize it, add it to the list
  1386. of PDOs for this FDO bus, and then tell Plug and Play that all of this
  1387. happened so that it will start sending prodding IRPs.
  1388. --*/
  1389. {
  1390. PDEVICE_OBJECT pdo, firstPdo = NULL;
  1391. PLIST_ENTRY entry;
  1392. PPDO_DEVICE_DATA pdoData;
  1393. NTSTATUS status;
  1394. ULONG length;
  1395. KIRQL irql;
  1396. BOOLEAN first = TRUE;
  1397. UCHAR i;
  1398. PAGED_CODE ();
  1399. if (FdoData->Self != Expose->PortHandle) {
  1400. return STATUS_INVALID_PARAMETER;
  1401. }
  1402. else if (FdoData->NumPDOs != 0) {
  1403. //
  1404. // Only one valid expose per PDO ... a remove hardware will decrement
  1405. // NumPDOs to 0
  1406. //
  1407. return STATUS_INVALID_DEVICE_REQUEST;
  1408. }
  1409. else if (Expose->NumberJoysticks > 2 || Expose->NumberJoysticks < 0) {
  1410. return STATUS_INVALID_PARAMETER;
  1411. }
  1412. length = (ExposeSize - sizeof (GAMEENUM_EXPOSE_HARDWARE))/sizeof(WCHAR);
  1413. if (length >MAX_DEVICE_ID_LEN) {
  1414. Game_KdPrint (FdoData, GAME_DBG_PNP_ERROR,
  1415. ("Expose failed because length of Hardware ID too long at %d\n",length));
  1416. return STATUS_INVALID_PARAMETER;
  1417. }
  1418. Game_KdPrint (FdoData, GAME_DBG_PNP_INFO,
  1419. ("Exposing PDO\n"
  1420. "======PortHandle: 0x%x\n"
  1421. "======NumJoysticks: %d\n"
  1422. "======NumAxis: %d\n"
  1423. "======NumButtons: %d\n"
  1424. "======HardwareId: %ws\n"
  1425. "======Length: %d\n",
  1426. Expose->PortHandle,
  1427. Expose->NumberJoysticks,
  1428. Expose->NumberAxis,
  1429. Expose->NumberButtons,
  1430. Expose->HardwareIDs,
  1431. length));
  1432. #if DBG
  1433. for (i = 0; i < SIZE_GAMEENUM_OEM_DATA; i++) {
  1434. Game_KdPrint (FdoData, GAME_DBG_PNP_INFO,
  1435. ("=====OemData[%d] = 0x%x\n",
  1436. i,
  1437. Expose->OemData[i]
  1438. ));
  1439. }
  1440. #endif
  1441. status = Game_CheckHardwareIDs (Expose->HardwareIDs, &length, FdoData);
  1442. if (!NT_SUCCESS (status)) {
  1443. return status;
  1444. }
  1445. //
  1446. // Create the PDOs
  1447. //
  1448. length *= sizeof(WCHAR);
  1449. Game_KdPrint(FdoData, GAME_DBG_PNP_NOISE,
  1450. ("GAME: Expose->HardwareHandle = 0x%x\n", FdoData->TopOfStack));
  1451. Expose->HardwareHandle = FdoData->TopOfStack;
  1452. for (i = 0; i < Expose->NumberJoysticks; i++) {
  1453. status = IoCreateDevice(FdoData->Self->DriverObject,
  1454. sizeof (PDO_DEVICE_DATA),
  1455. NULL,
  1456. FILE_DEVICE_BUS_EXTENDER,
  1457. 0,
  1458. FALSE,
  1459. &pdo);
  1460. if (!NT_SUCCESS (status)) {
  1461. pdo = NULL;
  1462. goto GameExposeError;
  1463. }
  1464. ASSERT (pdo != NULL);
  1465. if (!firstPdo) {
  1466. firstPdo = pdo;
  1467. }
  1468. pdoData = (PPDO_DEVICE_DATA) pdo->DeviceExtension;
  1469. //
  1470. // Copy the hardware IDs
  1471. //
  1472. if (NULL == (pdoData->HardwareIDs = ExAllocatePool(NonPagedPool, length))) {
  1473. status = STATUS_INSUFFICIENT_RESOURCES;
  1474. goto GameExposeError;
  1475. }
  1476. RtlCopyMemory (pdoData->HardwareIDs, Expose->HardwareIDs, length);
  1477. //
  1478. // If there are more than two IDs, the check returns the length for
  1479. // the first two. In case there were more than two, zero out the
  1480. // last WCHAR of the copy in order to double NULL terminate.
  1481. //
  1482. pdoData->HardwareIDs[(length/sizeof(WCHAR))-1] = UNICODE_NULL;
  1483. if (1 == Expose->NumberJoysticks) {
  1484. pdoData->Portion = GameenumWhole;
  1485. }
  1486. else if (2 == Expose->NumberJoysticks) {
  1487. if (first) {
  1488. pdoData->Portion = GameenumFirstHalf;
  1489. first = FALSE;
  1490. }
  1491. else {
  1492. pdoData->Portion = GameenumSecondHalf;
  1493. }
  1494. }
  1495. pdoData->UnitID = Expose->UnitID;
  1496. pdoData->NumberAxis = Expose->NumberAxis;
  1497. pdoData->NumberButtons = Expose->NumberButtons;
  1498. #ifndef GAMEENUM_FLAG_COMPATIDCTRL
  1499. //
  1500. // The flags to control the exposing of a compatible ID were not
  1501. // implemented in Windows 2000. If the flags are not defined,
  1502. // assume this is being built in a Windows 2000 environment. The
  1503. // driver will work either way but if analog compatility is assumed,
  1504. // unsigned joystick drivers will always be outranked by the signed
  1505. // generic driver even if the generic driver does not work.
  1506. //
  1507. pdoData->AnalogCompatible = TRUE;
  1508. #else
  1509. pdoData->AnalogCompatible = ( Expose->Flags & ( GAMEENUM_FLAG_COMPATIDCTRL | GAMEENUM_FLAG_NOCOMPATID ) )
  1510. != ( GAMEENUM_FLAG_COMPATIDCTRL | GAMEENUM_FLAG_NOCOMPATID );
  1511. #endif
  1512. RtlCopyMemory (&pdoData->OemData,
  1513. &Expose->OemData,
  1514. sizeof(GAMEENUM_OEM_DATA));
  1515. Game_InitializePdo (pdo,
  1516. FdoData);
  1517. }
  1518. IoInvalidateDeviceRelations (FdoData->UnderlyingPDO, BusRelations);
  1519. GameExposeError:
  1520. if (!NT_SUCCESS(status)) {
  1521. //
  1522. // Clean up the current pdo.
  1523. //
  1524. if (pdo) {
  1525. IoDeleteDevice(pdo);
  1526. }
  1527. //
  1528. // delete the first PDO if it exists. More to do here b/c it was
  1529. // actually fully initialized
  1530. //
  1531. if (!first) {
  1532. ASSERT(firstPdo != NULL);
  1533. pdoData = (PPDO_DEVICE_DATA) firstPdo->DeviceExtension;
  1534. ASSERT (pdoData->Portion == GameenumFirstHalf);
  1535. ExFreePool (pdoData->HardwareIDs);
  1536. pdoData->HardwareIDs = NULL;
  1537. IoDeleteDevice (firstPdo);
  1538. }
  1539. //
  1540. // remove all pdos from our linked list
  1541. //
  1542. for (entry = FdoData->PDOs.Flink;
  1543. entry != &FdoData->PDOs;
  1544. entry = entry->Flink) {
  1545. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  1546. RemoveEntryList (&pdoData->Link);
  1547. }
  1548. FdoData->NumPDOs = 0;
  1549. FdoData->UniqueIDCount = GAMEENUM_UNIQUEID_START;
  1550. Expose->HardwareHandle = NULL;
  1551. }
  1552. return status;
  1553. }
  1554. NTSTATUS
  1555. Game_ExposeSibling (
  1556. PGAMEENUM_EXPOSE_SIBLING ExposeSibling,
  1557. PPDO_DEVICE_DATA SiblingPdo
  1558. )
  1559. /*++
  1560. Routine Description:
  1561. This driver has just detected a new device on the bus. (Actually the
  1562. control panels has just told us that something has arived, but who is
  1563. counting?)
  1564. We therefore need to create a new PDO, initialize it, add it to the list
  1565. of PDOs for this FDO bus, and then tell Plug and Play that all of this
  1566. happened so that it will start sending prodding IRPs.
  1567. --*/
  1568. {
  1569. UCHAR i;
  1570. PDEVICE_OBJECT pdo;
  1571. PPDO_DEVICE_DATA pdoData;
  1572. PFDO_DEVICE_DATA fdoData;
  1573. ULONG length;
  1574. PWCHAR buffer;
  1575. NTSTATUS status;
  1576. PAGED_CODE ();
  1577. fdoData = FDO_FROM_PDO (SiblingPdo);
  1578. //
  1579. // Check to make sure we have a valid multi sz string before we allocate
  1580. // device objects and other assorted items
  1581. //
  1582. if (ExposeSibling->HardwareIDs) {
  1583. //
  1584. // We don't know how long the hardware IDs are but the value
  1585. // of MAX_DEVICE_ID_LEN is the most allowed.
  1586. //
  1587. length = MAX_DEVICE_ID_LEN;
  1588. status = Game_CheckHardwareIDs (ExposeSibling->HardwareIDs, &length, fdoData);
  1589. }
  1590. else {
  1591. length = 0;
  1592. status = STATUS_SUCCESS;
  1593. }
  1594. Game_KdPrint (SiblingPdo, GAME_DBG_PNP_INFO,
  1595. ("Exposing Sibling PDO\n"
  1596. "======HardwareHandle: 0x%x\n"
  1597. "======UnitID: %d\n"
  1598. "======Sting Length: %d\n",
  1599. ExposeSibling->HardwareHandle,
  1600. (ULONG) ExposeSibling->UnitID,
  1601. length
  1602. ));
  1603. #if DBG
  1604. for (i = 0; i < SIZE_GAMEENUM_OEM_DATA; i++) {
  1605. Game_KdPrint (SiblingPdo, GAME_DBG_PNP_INFO,
  1606. ("=====OemData[%d] = 0x%x\n",
  1607. i,
  1608. ExposeSibling->OemData[i]
  1609. ));
  1610. }
  1611. #endif
  1612. if (!NT_SUCCESS (status)) {
  1613. return status;
  1614. }
  1615. status = IoCreateDevice(fdoData->Self->DriverObject,
  1616. sizeof (PDO_DEVICE_DATA),
  1617. NULL,
  1618. FILE_DEVICE_BUS_EXTENDER,
  1619. 0,
  1620. FALSE,
  1621. &pdo);
  1622. if (!NT_SUCCESS (status)) {
  1623. return status;
  1624. }
  1625. ASSERT (pdo != NULL);
  1626. Game_KdPrint (fdoData, GAME_DBG_PNP_NOISE,
  1627. ("ExposeSibling->HardwareHandle = 0x%x\n", pdo));
  1628. ExposeSibling->HardwareHandle = pdo;
  1629. pdoData = (PPDO_DEVICE_DATA) pdo->DeviceExtension;
  1630. pdoData->UnitID = ExposeSibling->UnitID;
  1631. RtlCopyMemory (&pdoData->OemData,
  1632. &ExposeSibling->OemData,
  1633. sizeof(GAMEENUM_OEM_DATA));
  1634. //
  1635. // Check to see if the multi sz was supplied
  1636. //
  1637. if (length) {
  1638. //
  1639. // Another hardware ID was given ... use it!
  1640. //
  1641. Game_KdPrint (fdoData, GAME_DBG_PNP_INFO,
  1642. ("Using IDs from struct\n"));
  1643. //
  1644. // Length now represents the actual size of memory to copy instead of
  1645. // the number of chars in the array
  1646. //
  1647. length *= sizeof(WCHAR);
  1648. buffer = ExposeSibling->HardwareIDs;
  1649. }
  1650. else {
  1651. //
  1652. // No hardware ID was given, use the siblings ID
  1653. //
  1654. Game_KdPrint (fdoData, GAME_DBG_PNP_INFO,
  1655. ("Using IDs from sibling\n"));
  1656. buffer = SiblingPdo->HardwareIDs;
  1657. while (*(buffer++)) {
  1658. while (*(buffer++)) {
  1659. ;
  1660. }
  1661. }
  1662. length = (ULONG) (buffer - SiblingPdo->HardwareIDs) * sizeof (WCHAR);
  1663. buffer = SiblingPdo->HardwareIDs;
  1664. }
  1665. pdoData->HardwareIDs = ExAllocatePool(NonPagedPool, length);
  1666. if (NULL == pdoData->HardwareIDs) {
  1667. IoDeleteDevice (pdo);
  1668. return STATUS_INSUFFICIENT_RESOURCES;
  1669. }
  1670. RtlCopyMemory (pdoData->HardwareIDs, buffer, length);
  1671. //
  1672. // If there are more than two IDs, the check returns the length for the
  1673. // first two. In case there were more than two, zero out the last WCHAR
  1674. // of the copy in order to double NULL terminate.
  1675. //
  1676. pdoData->HardwareIDs[(length/sizeof(WCHAR))-1] = UNICODE_NULL;
  1677. pdoData->AnalogCompatible = SiblingPdo->AnalogCompatible;
  1678. Game_InitializePdo (pdo,
  1679. fdoData);
  1680. IoInvalidateDeviceRelations (fdoData->UnderlyingPDO, BusRelations);
  1681. return status;
  1682. }
  1683. NTSTATUS
  1684. Game_Remove (
  1685. PGAMEENUM_REMOVE_HARDWARE Remove,
  1686. PFDO_DEVICE_DATA FdoData
  1687. )
  1688. {
  1689. PAGED_CODE ();
  1690. ASSERT (Remove->Size == sizeof(GAMEENUM_REMOVE_HARDWARE));
  1691. if (Remove->HardwareHandle != FdoData->TopOfStack) {
  1692. Game_KdPrint(FdoData, GAME_DBG_PNP_NOISE,
  1693. ("GAME: Remove->HardwareHandle = 0x%x, expecting 0x%x\n",
  1694. Remove->HardwareHandle, FdoData->TopOfStack));
  1695. return STATUS_INVALID_PARAMETER;
  1696. }
  1697. return Game_RemoveEx (NULL, FdoData);
  1698. }
  1699. NTSTATUS
  1700. Game_RemoveSelf (
  1701. PPDO_DEVICE_DATA PdoData
  1702. )
  1703. {
  1704. PAGED_CODE ();
  1705. return Game_RemoveEx (PdoData->Self, FDO_FROM_PDO (PdoData) );
  1706. }
  1707. NTSTATUS
  1708. Game_RemoveEx (
  1709. PDEVICE_OBJECT RemoveDO,
  1710. PFDO_DEVICE_DATA FdoData
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. This driver has just detected that a device has departed from the bus.
  1715. (Atcually either the control panel has just told us that somehting has
  1716. departed or a PDO has removed itself)
  1717. We therefore need to flag the PDO as no longer attached, remove it from
  1718. the linked list of PDOs for this bus, and then tell Plug and Play about it.
  1719. Parameters
  1720. RemoveDO - if NULL, then remove all the items in the list, otherwise
  1721. it is the PDO to remove from the list
  1722. FdoData - contains the list to iterate over
  1723. Returns:
  1724. STATUS_SUCCESS upon successful removal from the list
  1725. STATUS_INVALID_PARAMETER if the removal was unsuccessful
  1726. --*/
  1727. {
  1728. PLIST_ENTRY entry;
  1729. PPDO_DEVICE_DATA pdoData;
  1730. BOOLEAN found = FALSE, removeAll = (RemoveDO == NULL);
  1731. PVOID handle = NULL;
  1732. PAGED_CODE ();
  1733. ExAcquireFastMutex (&FdoData->Mutex);
  1734. if (removeAll) {
  1735. Game_KdPrint (FdoData, GAME_DBG_IOCTL_NOISE,
  1736. ("removing all the pdos!\n"));
  1737. }
  1738. else {
  1739. Game_KdPrint (FdoData, GAME_DBG_IOCTL_NOISE,
  1740. ("removing 0x%x\n", RemoveDO));
  1741. }
  1742. if (FdoData->NumPDOs == 0) {
  1743. //
  1744. // We got a 2nd remove...somebody in user space isn't playing nice!!!
  1745. //
  1746. Game_KdPrint (FdoData, GAME_DBG_IOCTL_ERROR,
  1747. ("BAD BAD BAD...2 removes!!! Send only one!\n"));
  1748. ExReleaseFastMutex (&FdoData->Mutex);
  1749. return STATUS_NO_SUCH_DEVICE;
  1750. }
  1751. for (entry = FdoData->PDOs.Flink;
  1752. entry != &FdoData->PDOs;
  1753. entry = entry->Flink) {
  1754. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  1755. handle = pdoData->Self;
  1756. Game_KdPrint (FdoData, GAME_DBG_IOCTL_NOISE,
  1757. ("found DO 0x%x\n", handle));
  1758. if (removeAll || handle == RemoveDO) {
  1759. Game_KdPrint (FdoData, GAME_DBG_IOCTL_INFO,
  1760. ("removed 0x%x\n", handle));
  1761. pdoData->Attached = FALSE;
  1762. RemoveEntryList (&pdoData->Link);
  1763. FdoData->NumPDOs--;
  1764. found = TRUE;
  1765. if (!removeAll) {
  1766. break;
  1767. }
  1768. }
  1769. }
  1770. ExReleaseFastMutex (&FdoData->Mutex);
  1771. if (FdoData->NumPDOs == 0) {
  1772. FdoData->UniqueIDCount = GAMEENUM_UNIQUEID_START;
  1773. }
  1774. if (found) {
  1775. IoInvalidateDeviceRelations (FdoData->UnderlyingPDO, BusRelations);
  1776. return STATUS_SUCCESS;
  1777. }
  1778. Game_KdPrint (FdoData, GAME_DBG_IOCTL_ERROR,
  1779. ("0x%x was not removed (not in list)\n", RemoveDO));
  1780. return STATUS_INVALID_PARAMETER;
  1781. }
  1782. NTSTATUS
  1783. Game_ListPorts (
  1784. PGAMEENUM_PORT_DESC Desc,
  1785. PFDO_DEVICE_DATA FdoData
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. This driver has just detected that a device has departed from the bus.
  1790. (Actually the control panels has just told us that something has departed,
  1791. but who is counting?
  1792. We therefore need to flag the PDO as no longer attached, remove it from
  1793. the linked list of PDOs for this bus, and then tell Plug and Play about it.
  1794. --*/
  1795. {
  1796. PAGED_CODE ();
  1797. Desc->PortHandle = FdoData->Self;
  1798. Desc->PortAddress = FdoData->PhysicalAddress;
  1799. return STATUS_SUCCESS;
  1800. }
  1801. NTSTATUS
  1802. Game_Power (
  1803. IN PDEVICE_OBJECT DeviceObject,
  1804. IN PIRP Irp
  1805. )
  1806. /*++
  1807. We do nothing special for power;
  1808. --*/
  1809. {
  1810. PIO_STACK_LOCATION irpStack;
  1811. NTSTATUS status;
  1812. PCOMMON_DEVICE_DATA commonData;
  1813. PAGED_CODE ();
  1814. status = STATUS_SUCCESS;
  1815. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1816. ASSERT (IRP_MJ_POWER == irpStack->MajorFunction);
  1817. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  1818. if (commonData->IsFDO) {
  1819. status = Game_FDO_Power ((PFDO_DEVICE_DATA) DeviceObject->DeviceExtension,
  1820. Irp);
  1821. } else {
  1822. status = Game_PDO_Power ((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension,
  1823. Irp);
  1824. }
  1825. return status;
  1826. }
  1827. NTSTATUS
  1828. Game_PowerComplete (
  1829. IN PDEVICE_OBJECT DeviceObject,
  1830. IN PIRP Irp,
  1831. IN PVOID Context
  1832. );
  1833. VOID
  1834. Game_FdoPowerTransitionPoRequestComplete (
  1835. IN PDEVICE_OBJECT DeviceObject,
  1836. IN UCHAR MinorFunction,
  1837. IN POWER_STATE DevicePowerState,
  1838. IN PIRP SystemStateIrp,
  1839. IN PIO_STATUS_BLOCK IoStatus
  1840. )
  1841. {
  1842. PIO_STACK_LOCATION stack;
  1843. PFDO_DEVICE_DATA fdoData;
  1844. UNREFERENCED_PARAMETER (MinorFunction);
  1845. UNREFERENCED_PARAMETER (IoStatus);
  1846. fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  1847. stack = IoGetCurrentIrpStackLocation (SystemStateIrp);
  1848. if (DevicePowerState.DeviceState == PowerDeviceD0) {
  1849. //
  1850. // We are powering up (the D0 Irp just completed). Since we sent the
  1851. // S irp down the stack and requested the D irp on the way back up the
  1852. // stack, just complete the S irp now
  1853. //
  1854. PoSetPowerState (DeviceObject,
  1855. stack->Parameters.Power.Type,
  1856. stack->Parameters.Power.State);
  1857. fdoData->SystemState = stack->Parameters.Power.State.SystemState;
  1858. SystemStateIrp->IoStatus.Status = IoStatus->Status;
  1859. PoStartNextPowerIrp (SystemStateIrp);
  1860. IoCompleteRequest (SystemStateIrp, IO_NO_INCREMENT);
  1861. //
  1862. // From Game_FDO_Power when we originally received the IRP
  1863. //
  1864. Game_DecIoCount (fdoData);
  1865. }
  1866. else {
  1867. //
  1868. // We are powering down (the D3 Irp just completed). Since we requested
  1869. // the D irp before sending the S irp down the stack, we must send it
  1870. // down now. We will catch the S irp on the way back up to record the
  1871. // S state
  1872. //
  1873. ASSERT (DevicePowerState.DeviceState == PowerDeviceD3);
  1874. IoCopyCurrentIrpStackLocationToNext (SystemStateIrp);
  1875. IoSetCompletionRoutine (SystemStateIrp,
  1876. Game_PowerComplete,
  1877. NULL,
  1878. TRUE,
  1879. TRUE,
  1880. TRUE);
  1881. PoCallDriver (fdoData->TopOfStack, SystemStateIrp);
  1882. }
  1883. }
  1884. VOID
  1885. Game_PdoPowerDownComplete (
  1886. IN PDEVICE_OBJECT DeviceObject,
  1887. IN UCHAR MinorFunction,
  1888. IN POWER_STATE PowerState,
  1889. IN PVOID Context,
  1890. IN PIO_STATUS_BLOCK IoStatus
  1891. )
  1892. {
  1893. PFDO_DEVICE_DATA data = (PFDO_DEVICE_DATA) Context;
  1894. UNREFERENCED_PARAMETER (DeviceObject);
  1895. UNREFERENCED_PARAMETER (MinorFunction);
  1896. UNREFERENCED_PARAMETER (PowerState);
  1897. #if !DBG
  1898. UNREFERENCED_PARAMETER (IoStatus);
  1899. #endif
  1900. ASSERT( NT_SUCCESS (IoStatus->Status));
  1901. if (0 == InterlockedDecrement (&data->PoweredDownDevices)) {
  1902. KeSetEvent (&data->PoweredDownEvent, 1, FALSE);
  1903. }
  1904. }
  1905. NTSTATUS
  1906. Game_PowerComplete (
  1907. IN PDEVICE_OBJECT DeviceObject,
  1908. IN PIRP Irp,
  1909. IN PVOID Context
  1910. )
  1911. {
  1912. POWER_STATE powerState;
  1913. POWER_STATE_TYPE powerType;
  1914. PIO_STACK_LOCATION stack;
  1915. PFDO_DEVICE_DATA data;
  1916. NTSTATUS status;
  1917. UNREFERENCED_PARAMETER (Context);
  1918. data = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  1919. stack = IoGetCurrentIrpStackLocation (Irp);
  1920. powerType = stack->Parameters.Power.Type;
  1921. powerState = stack->Parameters.Power.State;
  1922. status = STATUS_SUCCESS;
  1923. switch (stack->MinorFunction) {
  1924. case IRP_MN_SET_POWER:
  1925. switch (powerType) {
  1926. case DevicePowerState:
  1927. //
  1928. // Power up complete
  1929. //
  1930. ASSERT (powerState.DeviceState < data->DeviceState);
  1931. data->DeviceState = powerState.DeviceState;
  1932. PoSetPowerState (data->Self, powerType, powerState);
  1933. break;
  1934. case SystemPowerState:
  1935. //
  1936. // Ususally the work of requesting the Device Power IRP on
  1937. // behalf of the SystemPower Irp is work done by the Function
  1938. // (FDO) driver. In order, however that Joystick function drivers
  1939. // have a more simplified power code path (AKA they merely need
  1940. // pass on ALL power IRPS) will will do this work for them in the
  1941. // PDO.
  1942. //
  1943. // NB: This assumes that we will never have any "clever" power
  1944. // management for a gaming device attached through a legacy
  1945. // gaming port. By which I mean that the HIDGame driver will not
  1946. // be able to select a "D" state based on the "S" state; as it is
  1947. // done for the HidGame driver.
  1948. //
  1949. // Any yahoo putting wakeup capabilities into a legacy joystick
  1950. // should be shot. It will require special hardware. If you are
  1951. // adding extra hardware then you should not be doing so to this
  1952. // nasty RC circuit.
  1953. //
  1954. if (powerState.SystemState > data->SystemState) {
  1955. //
  1956. // Powering Down...
  1957. //
  1958. // We are on the completion end of an S irp. (The D3 power irp
  1959. // has already been sent and completed down this stack.) The
  1960. // remaining thing to do is set the state in the extension, then
  1961. // decrement the IoCount that was incremented when we first got
  1962. // the irp (this is done at the end of this function).
  1963. //
  1964. data->SystemState = powerState.SystemState;
  1965. PoSetPowerState (data->Self,
  1966. stack->Parameters.Power.Type,
  1967. stack->Parameters.Power.State);
  1968. }
  1969. else {
  1970. //
  1971. // Powering Up...
  1972. //
  1973. // Request a D power irp for ourself. Do not complete this S irp
  1974. // until the D irp has been completed. (Completion of the S irp
  1975. // is done in Game_FdoPowerTransitionPoRequestComplete).
  1976. // Decrementing the IO count will happen in the same function.
  1977. //
  1978. ASSERT (powerState.SystemState < data->SystemState);
  1979. powerState.DeviceState = PowerDeviceD0;
  1980. status =
  1981. PoRequestPowerIrp (data->Self,
  1982. IRP_MN_SET_POWER,
  1983. powerState,
  1984. Game_FdoPowerTransitionPoRequestComplete,
  1985. Irp,
  1986. NULL); // no return Irp
  1987. if (status != STATUS_PENDING) {
  1988. ASSERT (!NT_SUCCESS (status));
  1989. Irp->IoStatus.Status = status;
  1990. PoStartNextPowerIrp (Irp);
  1991. Game_DecIoCount (data);
  1992. }
  1993. else {
  1994. //
  1995. // We need to:
  1996. // Start next power irp, release the removelock, and complete
  1997. // the irp in the PoRequestComplete routine.
  1998. //
  1999. //
  2000. // The irp might completed by the time we get here, so call
  2001. // PoStartNextPowerIrp in the PO irp completion function.
  2002. //
  2003. status = STATUS_MORE_PROCESSING_REQUIRED;
  2004. }
  2005. return status;
  2006. }
  2007. break;
  2008. }
  2009. break;
  2010. default:
  2011. #define GAME_UNHANDLED_MN_POWER 0x0
  2012. ASSERT (0xBADBAD == GAME_UNHANDLED_MN_POWER);
  2013. #undef GAME_UNHANDLED_MN_POWER
  2014. status = STATUS_NOT_SUPPORTED;
  2015. break;
  2016. }
  2017. if (NT_SUCCESS(status)) {
  2018. PoStartNextPowerIrp (Irp);
  2019. Game_DecIoCount (data);
  2020. }
  2021. return status;
  2022. }
  2023. NTSTATUS
  2024. Game_FDO_Power (
  2025. PFDO_DEVICE_DATA Data,
  2026. PIRP Irp
  2027. )
  2028. {
  2029. NTSTATUS status;
  2030. BOOLEAN hookit = FALSE, wait = FALSE;
  2031. POWER_STATE powerState;
  2032. POWER_STATE_TYPE powerType;
  2033. PIO_STACK_LOCATION stack;
  2034. PLIST_ENTRY entry;
  2035. PPDO_DEVICE_DATA pdoData;
  2036. stack = IoGetCurrentIrpStackLocation (Irp);
  2037. powerType = stack->Parameters.Power.Type;
  2038. powerState = stack->Parameters.Power.State;
  2039. PAGED_CODE ();
  2040. status = Game_IncIoCount (Data);
  2041. if (!NT_SUCCESS (status)) {
  2042. PoStartNextPowerIrp (Irp);
  2043. Irp->IoStatus.Information = 0;
  2044. Irp->IoStatus.Status = status;
  2045. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  2046. return status;
  2047. }
  2048. switch (stack->MinorFunction) {
  2049. case IRP_MN_SET_POWER:
  2050. Game_KdPrint(Data,
  2051. GAME_DBG_PNP_TRACE,
  2052. ("Game-PnP Setting %s state to %d\n",
  2053. ((powerType == SystemPowerState) ? "System" : "Device"),
  2054. powerState.SystemState));
  2055. switch (powerType) {
  2056. case DevicePowerState:
  2057. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  2058. if (Data->DeviceState == powerState.DeviceState) {
  2059. break;
  2060. } else if (Data->DeviceState < powerState.DeviceState) {
  2061. //
  2062. // Powering down
  2063. //
  2064. //
  2065. // Iterate through the PDOs and make sure that they are all
  2066. // powered down.
  2067. //
  2068. // Initially set PoweredDownDevices to the number of PDOs. If
  2069. // a pdo is not powered down, PoweredDownDevices will be
  2070. // decremented upon completion of the power down irp sent to
  2071. // that particular PDO. Otherwise, the PDO is already powered
  2072. // down so just decrement the count.
  2073. //
  2074. Data->PoweredDownDevices = Data->NumPDOs;
  2075. KeInitializeEvent (&Data->PoweredDownEvent,
  2076. SynchronizationEvent,
  2077. FALSE);
  2078. for (entry = Data->PDOs.Flink;
  2079. entry != &Data->PDOs;
  2080. entry = entry->Flink) {
  2081. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  2082. if (pdoData->DeviceState == PowerDeviceD0) {
  2083. wait = TRUE;
  2084. powerState.DeviceState = PowerDeviceD3;
  2085. PoRequestPowerIrp (pdoData->Self,
  2086. IRP_MN_SET_POWER,
  2087. powerState,
  2088. Game_PdoPowerDownComplete,
  2089. Data,
  2090. NULL);
  2091. }
  2092. else {
  2093. //
  2094. // All the power down irps to the PDOs can complete
  2095. // before we get to this already powered down PDO, so
  2096. // set the event if it is the last and we have a PDO
  2097. // that needed powering down.
  2098. //
  2099. if (InterlockedDecrement(&Data->PoweredDownDevices) == 0
  2100. && wait) {
  2101. KeSetEvent (&Data->PoweredDownEvent, 1, FALSE);
  2102. }
  2103. }
  2104. }
  2105. if (wait) {
  2106. KeWaitForSingleObject (&Data->PoweredDownEvent,
  2107. Executive,
  2108. KernelMode,
  2109. FALSE,
  2110. NULL);
  2111. #if DBG
  2112. ///
  2113. // Make SURE that all the PDOs are trully powered down
  2114. //
  2115. for (entry = Data->PDOs.Flink;
  2116. entry != &Data->PDOs;
  2117. entry = entry->Flink) {
  2118. pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
  2119. ASSERT(pdoData->DeviceState != PowerDeviceD0);
  2120. }
  2121. #endif
  2122. }
  2123. ASSERT(Data->PoweredDownDevices == 0);
  2124. //
  2125. // Make sure powerState is the one sent down to us, not the
  2126. // modified version above
  2127. //
  2128. powerState = stack->Parameters.Power.State;
  2129. PoSetPowerState (Data->Self, powerType, powerState);
  2130. Data->DeviceState = powerState.DeviceState;
  2131. } else {
  2132. //
  2133. // Powering Up
  2134. //
  2135. hookit = TRUE;
  2136. }
  2137. break;
  2138. case SystemPowerState:
  2139. if (Data->SystemState == powerState.SystemState) {
  2140. status = STATUS_SUCCESS;
  2141. } else if (Data->SystemState < powerState.SystemState) {
  2142. //
  2143. // Powering down
  2144. //
  2145. //
  2146. // Request a D3 irp in response to this S irp. The D3 irp must
  2147. // completed before send this S irp down the stack. We will send
  2148. // the S irp down the stack when
  2149. // Game_FdoPowerTransitionPoRequestComplete is called.
  2150. //
  2151. //
  2152. // We don't need to increment our IO count b/c we incremented it
  2153. // at the beginning of this function and won't decrement it until
  2154. // the S Irp completes
  2155. //
  2156. IoMarkIrpPending (Irp);
  2157. powerState.DeviceState = PowerDeviceD3;
  2158. PoRequestPowerIrp (Data->Self,
  2159. IRP_MN_SET_POWER,
  2160. powerState,
  2161. Game_FdoPowerTransitionPoRequestComplete,
  2162. Irp,
  2163. NULL); // no IRP
  2164. return STATUS_PENDING;
  2165. } else {
  2166. //
  2167. // Powering Up
  2168. //
  2169. //
  2170. // We must request a D irp for this S irp, but only after the S
  2171. // irp has come back up the stack. Hook the return of the irp
  2172. // and request the D irp in Game_PowerComplete
  2173. //
  2174. hookit = TRUE;
  2175. }
  2176. break;
  2177. }
  2178. break;
  2179. case IRP_MN_QUERY_POWER:
  2180. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  2181. break;
  2182. default:
  2183. break;
  2184. }
  2185. IoCopyCurrentIrpStackLocationToNext (Irp);
  2186. if (hookit) {
  2187. ASSERT (STATUS_SUCCESS == status);
  2188. //
  2189. // If we are returning STATUS_PENDING, the irp must marked as such as well
  2190. //
  2191. IoMarkIrpPending (Irp);
  2192. IoSetCompletionRoutine (Irp,
  2193. Game_PowerComplete,
  2194. NULL,
  2195. TRUE,
  2196. TRUE,
  2197. TRUE);
  2198. //
  2199. // NOTE!!! PoCallDriver NOT IoCallDriver.
  2200. //
  2201. PoCallDriver (Data->TopOfStack, Irp);
  2202. //
  2203. // We are returning pending instead of the result from PoCallDriver becuase:
  2204. // 1 we are changing the status in the completion routine
  2205. // 2 we will not be completing this irp in the completion routine
  2206. //
  2207. status = STATUS_PENDING;
  2208. } else {
  2209. //
  2210. // Power IRPS come synchronously; drivers must call
  2211. // PoStartNextPowerIrp, when they are ready for the next power
  2212. // irp. This can be called here, or in the completetion
  2213. // routine, but never the less must be called.
  2214. //
  2215. PoStartNextPowerIrp (Irp);
  2216. status = PoCallDriver (Data->TopOfStack, Irp);
  2217. Game_DecIoCount (Data);
  2218. }
  2219. return status;
  2220. }
  2221. VOID
  2222. Game_PdoPoRequestComplete (
  2223. IN PDEVICE_OBJECT DeviceObject,
  2224. IN UCHAR MinorFunction,
  2225. IN POWER_STATE DevicePowerState,
  2226. IN PIRP SystemStateIrp,
  2227. IN PIO_STATUS_BLOCK IoStatus
  2228. )
  2229. {
  2230. PIO_STACK_LOCATION stack;
  2231. PPDO_DEVICE_DATA pdoData;
  2232. UNREFERENCED_PARAMETER (MinorFunction);
  2233. UNREFERENCED_PARAMETER (DevicePowerState);
  2234. UNREFERENCED_PARAMETER (IoStatus);
  2235. pdoData = (PPDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  2236. stack = IoGetCurrentIrpStackLocation (SystemStateIrp);
  2237. PoSetPowerState (DeviceObject,
  2238. stack->Parameters.Power.Type,
  2239. stack->Parameters.Power.State);
  2240. pdoData->SystemState = stack->Parameters.Power.State.SystemState;
  2241. //
  2242. // Set the S irp's status to the status of the D irp
  2243. //
  2244. SystemStateIrp->IoStatus.Status = IoStatus->Status;
  2245. PoStartNextPowerIrp (SystemStateIrp);
  2246. IoCompleteRequest (SystemStateIrp, IO_NO_INCREMENT);
  2247. }
  2248. NTSTATUS
  2249. Game_PDO_Power (
  2250. PPDO_DEVICE_DATA PdoData,
  2251. PIRP Irp
  2252. )
  2253. {
  2254. KIRQL irql;
  2255. NTSTATUS status = STATUS_SUCCESS;
  2256. PIO_STACK_LOCATION stack;
  2257. POWER_STATE powerState;
  2258. POWER_STATE_TYPE powerType;
  2259. PAGED_CODE();
  2260. stack = IoGetCurrentIrpStackLocation (Irp);
  2261. powerType = stack->Parameters.Power.Type;
  2262. powerState = stack->Parameters.Power.State;
  2263. switch (stack->MinorFunction) {
  2264. case IRP_MN_SET_POWER:
  2265. switch (powerType) {
  2266. case DevicePowerState:
  2267. PoSetPowerState (PdoData->Self, powerType, powerState);
  2268. PdoData->DeviceState = powerState.DeviceState;
  2269. break;
  2270. case SystemPowerState:
  2271. //
  2272. // Make the IRP pending and request a D irp for this stack. When
  2273. // the D irp completes, Game_PdoPoRequestComplete will be called. In
  2274. // that function, we complete this S irp
  2275. //
  2276. IoMarkIrpPending(Irp);
  2277. if (PowerSystemWorking == powerState.SystemState) {
  2278. powerState.DeviceState = PowerDeviceD0;
  2279. } else {
  2280. powerState.DeviceState = PowerDeviceD3;
  2281. }
  2282. status = PoRequestPowerIrp (PdoData->Self,
  2283. IRP_MN_SET_POWER,
  2284. powerState,
  2285. Game_PdoPoRequestComplete,
  2286. Irp,
  2287. NULL); // no return IRP
  2288. if (status != STATUS_PENDING) {
  2289. ASSERT (!NT_SUCCESS (status));
  2290. break;
  2291. }
  2292. return status;
  2293. default:
  2294. TRAP ();
  2295. status = STATUS_NOT_IMPLEMENTED;
  2296. break;
  2297. }
  2298. break;
  2299. case IRP_MN_QUERY_POWER:
  2300. status = STATUS_SUCCESS;
  2301. break;
  2302. case IRP_MN_WAIT_WAKE:
  2303. case IRP_MN_POWER_SEQUENCE:
  2304. default:
  2305. status = STATUS_NOT_SUPPORTED;
  2306. break;
  2307. }
  2308. PoStartNextPowerIrp (Irp);
  2309. Irp->IoStatus.Status = status;
  2310. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  2311. return status;
  2312. }