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.

707 lines
22 KiB

  1. //**************************************************************************
  2. //
  3. // PNP.C -- Xena Gaming Project
  4. //
  5. // This module contains PnP Start, Stop, Remove, Power dispatch routines
  6. // and the IRP cancel routine.
  7. //
  8. // Version 3.XX
  9. //
  10. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  11. //
  12. // @doc
  13. // @module PNP.C | Supports PnP Start, Stop, Remove, Power dispatch routines
  14. // and the IRP cancel routine.
  15. //**************************************************************************
  16. #include <msgame.h>
  17. //---------------------------------------------------------------------------
  18. // Alloc_text pragma to specify routines that can be paged out.
  19. //---------------------------------------------------------------------------
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text (PAGE, MSGAME_Power)
  22. #pragma alloc_text (PAGE, MSGAME_PnP)
  23. #pragma alloc_text (PAGE, MSGAME_StopDevice)
  24. #pragma alloc_text (PAGE, MSGAME_GetResources)
  25. #endif
  26. //---------------------------------------------------------------------------
  27. // Private Data
  28. //---------------------------------------------------------------------------
  29. static PVOID CurrentGameContext = NULL;
  30. //---------------------------------------------------------------------------
  31. // @func The plug and play dispatch routines.
  32. // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
  33. // @parm PIRP | pIrp | Pointer to IO request packet
  34. // @rdesc Returns NT status code
  35. // @comm Public function
  36. //---------------------------------------------------------------------------
  37. NTSTATUS MSGAME_PnP (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
  38. {
  39. LONG i;
  40. NTSTATUS ntStatus;
  41. PDEVICE_EXTENSION pDevExt;
  42. PIO_STACK_LOCATION pIrpStack;
  43. PAGED_CODE ();
  44. MsGamePrint ((DBG_INFORM, "%s: %s_PnP Enter\n", MSGAME_NAME, MSGAME_NAME));
  45. pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
  46. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  47. InterlockedIncrement (&pDevExt->IrpCount);
  48. if (pDevExt->Removed)
  49. {
  50. //
  51. // Someone sent us another plug and play IRP after removed
  52. //
  53. MsGamePrint ((DBG_SEVERE, "%s: PnP Irp after device removed\n", MSGAME_NAME));
  54. ASSERT (FALSE);
  55. if (!InterlockedDecrement (&pDevExt->IrpCount))
  56. KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
  57. pIrp->IoStatus.Information = 0;
  58. pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  59. IoCompleteRequest (pIrp, IO_NO_INCREMENT);
  60. return (STATUS_DELETE_PENDING);
  61. }
  62. switch (pIrpStack->MinorFunction)
  63. {
  64. case IRP_MN_START_DEVICE:
  65. //
  66. // We cannot touch the device (send it any non-Pnp Irps) until a
  67. // start device has been passed down to the lower drivers.
  68. //
  69. IoCopyCurrentIrpStackLocationToNext (pIrp);
  70. IoSetCompletionRoutine (pIrp, MSGAME_PnPComplete, pDevExt, TRUE, TRUE, TRUE);
  71. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  72. if (ntStatus == STATUS_PENDING)
  73. KeWaitForSingleObject (
  74. &pDevExt->StartEvent,
  75. Executive, // Waiting for reason of a driver
  76. KernelMode, // Waiting in kernel mode
  77. FALSE, // No allert
  78. NULL); // No timeout
  79. if (NT_SUCCESS (ntStatus))
  80. {
  81. //
  82. // As we are now back from our start device we can do work.
  83. //
  84. ntStatus = MSGAME_StartDevice (pDevExt, pIrp);
  85. }
  86. //
  87. // Return Status
  88. //
  89. pIrp->IoStatus.Information = 0;
  90. pIrp->IoStatus.Status = ntStatus;
  91. IoCompleteRequest (pIrp, IO_NO_INCREMENT);
  92. break;
  93. case IRP_MN_STOP_DEVICE:
  94. //
  95. // After the start IRP has been sent to the lower driver object, the bus may
  96. // NOT send any more IRPS down ``touch'' until another START has occured.
  97. // Whatever access is required must be done before Irp passed on.
  98. //
  99. MSGAME_StopDevice (pDevExt, TRUE);
  100. //
  101. // We don't need a completion routine so fire and forget.
  102. // Set the current stack location to the next stack location and
  103. // call the next device object.
  104. //
  105. IoSkipCurrentIrpStackLocation (pIrp);
  106. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  107. break;
  108. case IRP_MN_SURPRISE_REMOVAL:
  109. //
  110. // We have been unexpectedly removed by the user. Stop the device,
  111. // set status to SUCCESS and call next stack location with this IRP.
  112. //
  113. if (!pDevExt->Surprised && pDevExt->Started)
  114. MSGAME_StopDevice (pDevExt, TRUE);
  115. pDevExt->Surprised = TRUE;
  116. //
  117. // We don't want a completion routine so fire and forget.
  118. // Set the current stack location to the next location and
  119. // call the next device after setting status to success.
  120. //
  121. pIrp->IoStatus.Information = 0;
  122. pIrp->IoStatus.Status = STATUS_SUCCESS;
  123. IoSkipCurrentIrpStackLocation (pIrp);
  124. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  125. break;
  126. case IRP_MN_REMOVE_DEVICE:
  127. //
  128. // The PlugPlay system has dictacted the removal of this device. We
  129. // have no choice but to detach and delete the device object.
  130. // (If we wanted to express an interest in preventing this removal,
  131. // we should have filtered the query remove and query stop routines.)
  132. // Note: we might receive a remove WITHOUT first receiving a stop.
  133. if (pDevExt->Started)
  134. {
  135. //
  136. // Stop the device without touching the hardware.
  137. //
  138. MSGAME_StopDevice (pDevExt, FALSE);
  139. }
  140. pDevExt->Removed = TRUE;
  141. //
  142. // Send on the remove IRP
  143. //
  144. IoSkipCurrentIrpStackLocation (pIrp);
  145. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  146. //
  147. // Must double-decrement because we start at One
  148. //
  149. i = InterlockedDecrement (&pDevExt->IrpCount);
  150. ASSERT(i>0);
  151. if (InterlockedDecrement (&pDevExt->IrpCount) > 0)
  152. KeWaitForSingleObject (&pDevExt->RemoveEvent, Executive, KernelMode, FALSE, NULL);
  153. //
  154. // Return success
  155. //
  156. return (STATUS_SUCCESS);
  157. default:
  158. //
  159. // Here the filter driver might modify the behavior of these IRPS
  160. // Please see PlugPlay documentation for use of these IRPs.
  161. //
  162. IoSkipCurrentIrpStackLocation (pIrp);
  163. MsGamePrint ((DBG_INFORM, "%s_PnP calling next driver with minor function %ld at IRQL %ld\n", MSGAME_NAME, pIrpStack->MinorFunction, KeGetCurrentIrql()));
  164. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  165. break;
  166. }
  167. if (!InterlockedDecrement (&pDevExt->IrpCount))
  168. KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
  169. MsGamePrint ((DBG_INFORM, "%s: %s_PnP exit\n", MSGAME_NAME, MSGAME_NAME));
  170. return (ntStatus);
  171. }
  172. //---------------------------------------------------------------------------
  173. // @func Completion routine for Pnp start device
  174. // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
  175. // @parm PIRP | pIrp | Pointer to IO request packet
  176. // @parm PVOID | Context | Pointer to device context
  177. // @rdesc Returns NT status code
  178. // @comm Public function
  179. //---------------------------------------------------------------------------
  180. NTSTATUS MSGAME_PnPComplete (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context)
  181. {
  182. PIO_STACK_LOCATION pIrpStack;
  183. PDEVICE_EXTENSION pDevExt;
  184. NTSTATUS ntStatus = STATUS_SUCCESS;
  185. UNREFERENCED_PARAMETER (DeviceObject);
  186. MsGamePrint ((DBG_INFORM, "%s: %s_PnPComplete enter\n", MSGAME_NAME, MSGAME_NAME));
  187. pDevExt = (PDEVICE_EXTENSION) Context;
  188. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  189. switch (pIrpStack->MajorFunction)
  190. {
  191. case IRP_MJ_PNP:
  192. switch (pIrpStack->MinorFunction)
  193. {
  194. case IRP_MN_START_DEVICE:
  195. KeSetEvent (&pDevExt->StartEvent, 0, FALSE);
  196. //
  197. // Take IRP back so we can continue using it during the IRP_MN_START_DEVICE
  198. // dispatch routine. We will have to call IoCompleteRequest there.
  199. //
  200. return (STATUS_MORE_PROCESSING_REQUIRED);
  201. default:
  202. break;
  203. }
  204. break;
  205. default:
  206. break;
  207. }
  208. MsGamePrint ((DBG_INFORM, "%s: %s_PnPComplete Exit\n", MSGAME_NAME, MSGAME_NAME));
  209. return (ntStatus);
  210. }
  211. //---------------------------------------------------------------------------
  212. // @func PnP start device IRP handler
  213. // @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
  214. // @parm PIRP | pIrp | Pointer to IO request packet
  215. // @rdesc Returns NT status code
  216. // @comm Public function
  217. //---------------------------------------------------------------------------
  218. NTSTATUS MSGAME_StartDevice (IN PDEVICE_EXTENSION pDevExt, IN PIRP pIrp)
  219. {
  220. PWCHAR HardwareId;
  221. NTSTATUS ntStatus;
  222. PDEVICEINFO DevInfo;
  223. PDEVICE_OBJECT RemoveObject;
  224. PAGED_CODE ();
  225. MsGamePrint ((DBG_INFORM, "%s: %s_StartDevice Enter\n", MSGAME_NAME, MSGAME_NAME));
  226. //
  227. // The PlugPlay system should not have started a removed device!
  228. //
  229. ASSERT (!pDevExt->Removed);
  230. if (pDevExt->Started)
  231. return (STATUS_SUCCESS);
  232. //
  233. // Acquire resources we need for this device
  234. //
  235. ntStatus = MSGAME_GetResources (pDevExt, pIrp);
  236. if (!NT_SUCCESS(ntStatus))
  237. return (ntStatus);
  238. //
  239. // Dump debug OEM Data fields
  240. //
  241. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[0] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[0]));
  242. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[1] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[1]));
  243. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[2] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[2]));
  244. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[3] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[3]));
  245. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[4] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[4]));
  246. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[5] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[5]));
  247. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[6] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[6]));
  248. MsGamePrint ((DBG_CONTROL, "%s: %s_StartDevice Called With OEM_DATA[7] = 0x%X\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.OemData[7]));
  249. //
  250. // Make sure we are only on one gameport
  251. //
  252. if (CurrentGameContext && (CurrentGameContext != pDevExt->PortInfo.GameContext))
  253. {
  254. MsGamePrint ((DBG_SEVERE, "%s: %s_StartDevice Cannot Load on Multiple Gameports: 0x%X and 0x%X\n",\
  255. CurrentGameContext, pDevExt->PortInfo.GameContext, MSGAME_NAME, MSGAME_NAME));
  256. return (STATUS_DEVICE_CONFIGURATION_ERROR);
  257. }
  258. CurrentGameContext = pDevExt->PortInfo.GameContext;
  259. //
  260. // Get the HardwareId for this Start request
  261. //
  262. HardwareId = MSGAME_GetHardwareId (pDevExt->Self);
  263. if (!HardwareId)
  264. {
  265. MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId Failed\n", MSGAME_NAME, MSGAME_NAME));
  266. return (STATUS_DEVICE_CONFIGURATION_ERROR);
  267. }
  268. //
  269. // Initialize OEM Data
  270. //
  271. SET_DEVICE_OBJECT(&pDevExt->PortInfo, pDevExt->Self);
  272. //
  273. // Now start the low level device
  274. //
  275. ntStatus = DEVICE_StartDevice (&pDevExt->PortInfo, HardwareId);
  276. //
  277. // Free HardwareId right away
  278. //
  279. MSGAME_FreeHardwareId (HardwareId);
  280. //
  281. // Check if low-level start device failed
  282. //
  283. if (NT_ERROR(ntStatus))
  284. {
  285. MsGamePrint ((DBG_SEVERE, "%s: %s_StartDevice Failed\n", MSGAME_NAME, MSGAME_NAME));
  286. return (ntStatus);
  287. }
  288. //
  289. // Everything is fine so let's say device has started
  290. //
  291. pDevExt->Started = TRUE;
  292. //
  293. // Return status
  294. //
  295. MsGamePrint ((DBG_INFORM, "%s: %s_StartDevice Exit\n", MSGAME_NAME, MSGAME_NAME));
  296. return (STATUS_SUCCESS);
  297. }
  298. //---------------------------------------------------------------------------
  299. // @func PnP start device IRP handler
  300. // @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
  301. // @parm BOOLEAN | TouchTheHardware | Flag to send non PnP Irps to device
  302. // @rdesc Returns NT status code
  303. // @comm Public function <en->
  304. // The PlugPlay system has dictacted the removal of this device.
  305. // We have no choise but to detach and delete the device object.
  306. // (If we wanted to express and interest in preventing this removal,
  307. // we should have filtered the query remove and query stop routines.)
  308. // Note! we might receive a remove WITHOUT first receiving a stop
  309. //---------------------------------------------------------------------------
  310. VOID MSGAME_StopDevice (IN PDEVICE_EXTENSION pDevExt, IN BOOLEAN TouchTheHardware)
  311. {
  312. PAGED_CODE ();
  313. MsGamePrint ((DBG_INFORM, "%s: %s_StopDevice enter \n", MSGAME_NAME, MSGAME_NAME));
  314. //
  315. // The PlugPlay system should not have started a removed device!
  316. //
  317. ASSERT (!pDevExt->Removed);
  318. if (!pDevExt->Started)
  319. return;
  320. //
  321. // Now stop the low level device
  322. //
  323. DEVICE_StopDevice (&pDevExt->PortInfo, TouchTheHardware);
  324. //
  325. // Everything is fine so let's say device has stopped
  326. //
  327. pDevExt->Started = FALSE;
  328. MsGamePrint ((DBG_INFORM, "%s: %s_StopDevice exit \n", MSGAME_NAME, MSGAME_NAME));
  329. }
  330. //---------------------------------------------------------------------------
  331. // @func Power dispatch routine.
  332. // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
  333. // @parm PIRP | pIrp | Pointer to IO request packet
  334. // @rdesc Returns NT status code
  335. // @comm Public function
  336. //---------------------------------------------------------------------------
  337. NTSTATUS MSGAME_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
  338. {
  339. PDEVICE_EXTENSION pDevExt;
  340. NTSTATUS ntStatus;
  341. PIO_STACK_LOCATION pIrpStack;
  342. PAGED_CODE ();
  343. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  344. MsGamePrint ((DBG_CONTROL, "%s: %s_Power Enter MN_Function %x type %x State %x\n", MSGAME_NAME, MSGAME_NAME,pIrpStack->MinorFunction,pIrpStack->Parameters.Power.Type,pIrpStack->Parameters.Power.State));
  345. pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
  346. //
  347. // This IRP was sent to the filter driver. Since we do not know what
  348. // to do with the IRP, we should pass it on along down the stack.
  349. //
  350. InterlockedIncrement (&pDevExt->IrpCount);
  351. if (pDevExt->Removed)
  352. {
  353. ntStatus = STATUS_DELETE_PENDING;
  354. pIrp->IoStatus.Information = 0;
  355. pIrp->IoStatus.Status = ntStatus;
  356. IoCompleteRequest (pIrp, IO_NO_INCREMENT);
  357. }
  358. else
  359. {
  360. //Is System trying to wake up device
  361. if ((2 == (pIrpStack->MinorFunction)) && (1 == (pIrpStack->Parameters.Power.Type)) &&( 1 == (pIrpStack->Parameters.Power.State.SystemState)))
  362. {
  363. // Clear DeviceDetected to force reset and redetect
  364. SET_DEVICE_INFO(&(pDevExt->PortInfo),0);
  365. MsGamePrint ((DBG_CONTROL, "%s: %s_Power Resetting Device Detected\n", MSGAME_NAME, MSGAME_NAME));
  366. }
  367. //
  368. // Power IRPS come synchronously; drivers must call
  369. // PoStartNextPowerIrp, when they are ready for the next power irp.
  370. // This can be called here, or in the completetion routine.
  371. //
  372. PoStartNextPowerIrp (pIrp);
  373. //
  374. // PoCallDriver NOT IoCallDriver.
  375. //
  376. IoSkipCurrentIrpStackLocation (pIrp);
  377. ntStatus = PoCallDriver (pDevExt->TopOfStack, pIrp);
  378. }
  379. if (!InterlockedDecrement (&pDevExt->IrpCount))
  380. KeSetEvent (&pDevExt->RemoveEvent, 0, FALSE);
  381. MsGamePrint ((DBG_INFORM, "%s: %s_Power Exit\n", MSGAME_NAME, MSGAME_NAME));
  382. return (ntStatus);
  383. }
  384. //---------------------------------------------------------------------------
  385. // @func Calls GameEnum to request gameport parameters
  386. // @parm PDEVICE_EXTENSION | pDevExt | Pointer to device extenstion
  387. // @parm PIRP | pIrp | Pointer to IO request packet
  388. // @rdesc Returns NT status code
  389. // @comm Public function
  390. //---------------------------------------------------------------------------
  391. NTSTATUS MSGAME_GetResources (IN PDEVICE_EXTENSION pDevExt, IN PIRP pIrp)
  392. {
  393. NTSTATUS ntStatus = STATUS_SUCCESS;
  394. KEVENT IoctlCompleteEvent;
  395. IO_STATUS_BLOCK IoStatus;
  396. PIO_STACK_LOCATION pIrpStack, nextStack;
  397. PAGED_CODE ();
  398. MsGamePrint ((DBG_INFORM, "%s: %s_GetResources Enter\n", MSGAME_NAME, MSGAME_NAME));
  399. //
  400. // Issue a synchronous request to get the resources info from GameEnum
  401. //
  402. KeInitializeEvent (&IoctlCompleteEvent, NotificationEvent, FALSE);
  403. pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
  404. nextStack = IoGetNextIrpStackLocation (pIrp);
  405. ASSERT (nextStack);
  406. //
  407. // Pass the Portinfo buffer of the DeviceExtension
  408. //
  409. pDevExt->PortInfo.Size = sizeof (GAMEPORT);
  410. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  411. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_GAMEENUM_PORT_PARAMETERS;
  412. nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof (GAMEPORT);
  413. nextStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof (GAMEPORT);
  414. pIrp->UserBuffer = &pDevExt->PortInfo;
  415. IoSetCompletionRoutine (pIrp, MSGAME_GetResourcesComplete, &IoctlCompleteEvent, TRUE, TRUE, TRUE);
  416. MsGamePrint ((DBG_CONTROL, "%s: Calling GameEnum to Get Resources at IRQL=%lu\n", MSGAME_NAME, KeGetCurrentIrql()));
  417. ntStatus = IoCallDriver (pDevExt->TopOfStack, pIrp);
  418. if (ntStatus == STATUS_PENDING)
  419. ntStatus = KeWaitForSingleObject (&IoctlCompleteEvent, Suspended, KernelMode, FALSE, NULL);
  420. if (NT_SUCCESS(ntStatus))
  421. MsGamePrint ((DBG_VERBOSE, "%s: %s_GetResources Port Obtained = 0x%lX\n", MSGAME_NAME, MSGAME_NAME, pDevExt->PortInfo.GameContext));
  422. else MsGamePrint ((DBG_SEVERE, "%s: GameEnum Failed to Provide Resources, Status = %X\n", MSGAME_NAME, ntStatus));
  423. //
  424. // Return Status
  425. //
  426. MsGamePrint ((DBG_INFORM, "%s: %s_GetResources Exit\n", MSGAME_NAME, MSGAME_NAME));
  427. return (pIrp->IoStatus.Status);
  428. }
  429. //---------------------------------------------------------------------------
  430. // @func Completion routine for GameEnum get reosources driver call
  431. // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
  432. // @parm PIRP | pIrp | Pointer to IO request packet
  433. // @parm PVOID | Context | Pointer to device context
  434. // @rdesc Returns NT status code
  435. // @comm Public function
  436. //---------------------------------------------------------------------------
  437. NTSTATUS MSGAME_GetResourcesComplete (IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context)
  438. {
  439. UNREFERENCED_PARAMETER (DeviceObject);
  440. KeSetEvent ((PKEVENT)Context, 0, FALSE);
  441. if (pIrp->PendingReturned)
  442. IoMarkIrpPending (pIrp);
  443. return (STATUS_MORE_PROCESSING_REQUIRED);
  444. }
  445. //---------------------------------------------------------------------------
  446. // @func Gets HardwareId string for device object (assumes caller frees)
  447. // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
  448. // @rdesc Pointer to allocated memory containing string
  449. // @comm Public function
  450. //---------------------------------------------------------------------------
  451. PWCHAR MSGAME_GetHardwareId (IN PDEVICE_OBJECT DeviceObject)
  452. {
  453. LONG BufferLength = 0;
  454. PWCHAR Buffer = NULL;
  455. NTSTATUS ntStatus;
  456. PDEVICE_OBJECT pPDO;
  457. MsGamePrint ((DBG_INFORM, "%s: %s_GetHardwareId\n", MSGAME_NAME, MSGAME_NAME));
  458. //
  459. // Walk to end of stack and get pointer to PDO
  460. //
  461. pPDO = DeviceObject;
  462. while (GET_NEXT_DEVICE_OBJECT(pPDO))
  463. pPDO = GET_NEXT_DEVICE_OBJECT(pPDO);
  464. //
  465. // Get Buffer length
  466. //
  467. ntStatus = IoGetDeviceProperty(
  468. pPDO,
  469. DevicePropertyHardwareID,
  470. BufferLength,
  471. Buffer,
  472. &BufferLength);
  473. ASSERT(ntStatus==STATUS_BUFFER_TOO_SMALL);
  474. //
  475. // Allocate room for HardwareID
  476. //
  477. Buffer = ExAllocatePool(PagedPool, BufferLength);
  478. if (!Buffer)
  479. {
  480. //
  481. // If we cannot get the memory to try this, then just say it is a no match
  482. //
  483. MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId failed ExAllocate\n", MSGAME_NAME, MSGAME_NAME));
  484. return (NULL);
  485. }
  486. //
  487. // Now get the data
  488. //
  489. ntStatus = IoGetDeviceProperty(
  490. pPDO,
  491. DevicePropertyHardwareID,
  492. BufferLength,
  493. Buffer,
  494. &BufferLength);
  495. //
  496. // On error, free memory and return NULL
  497. //
  498. if (!NT_SUCCESS(ntStatus))
  499. {
  500. MsGamePrint ((DBG_SEVERE, "%s: %s_GetHardwareId couldn't get id from PDO\n", MSGAME_NAME, MSGAME_NAME));
  501. ExFreePool(Buffer);
  502. return (NULL);
  503. }
  504. //
  505. // Return buffer containing hardware Id - must be freed by caller
  506. //
  507. return (Buffer);
  508. }
  509. //---------------------------------------------------------------------------
  510. // @func Compares HardwareId strings
  511. // @parm PWCHAR | HardwareId | Pointer to object hardware id
  512. // @parm PWCHAR | DeviceId | Pointer to device's hardware id
  513. // @rdesc True if strings are the same, false if different
  514. // @comm Public function
  515. //---------------------------------------------------------------------------
  516. BOOLEAN MSGAME_CompareHardwareIds (IN PWCHAR HardwareId, IN PWCHAR DeviceId)
  517. {
  518. MsGamePrint ((DBG_INFORM, "%s: %s_CompareHardwareIds\n", MSGAME_NAME, MSGAME_NAME));
  519. //
  520. // Peform runtime parameter checks
  521. //
  522. if (!HardwareId || !DeviceId)
  523. {
  524. MsGamePrint ((DBG_SEVERE, "%s: %s_CompareHardwareIds - Bogus Strings\n", MSGAME_NAME, MSGAME_NAME));
  525. return (FALSE);
  526. }
  527. //
  528. // Perform char-by-char string compare
  529. //
  530. while (*HardwareId && *DeviceId)
  531. {
  532. if (TOUPPER(*HardwareId) != TOUPPER(*DeviceId))
  533. return (FALSE);
  534. HardwareId++;
  535. DeviceId++;
  536. }
  537. //
  538. // Return success
  539. //
  540. return (TRUE);
  541. }
  542. //---------------------------------------------------------------------------
  543. // @func Frees HardwareId allocated from MSGAME_GetHardwareId
  544. // @parm PWCHAR | HardwareId | Pointer to hardware id to free
  545. // @rdesc None
  546. // @comm Public function
  547. //---------------------------------------------------------------------------
  548. VOID MSGAME_FreeHardwareId (IN PWCHAR HardwareId)
  549. {
  550. MsGamePrint ((DBG_INFORM, "%s: %s_FreeHardwareId\n", MSGAME_NAME, MSGAME_NAME));
  551. //
  552. // Free memory pool
  553. //
  554. if (HardwareId)
  555. ExFreePool(HardwareId);
  556. }