Source code of Windows XP (NT5)
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.

1446 lines
44 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This is the NT Video port driver PnP enumeration support routines.
  7. Author:
  8. Bruce McQuistan (brucemc) Feb. 1997
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "videoprt.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,pVideoPnPCapabilities)
  17. #pragma alloc_text(PAGE,pVideoPnPResourceRequirements)
  18. #pragma alloc_text(PAGE,pVideoPnPQueryId)
  19. #pragma alloc_text(PAGE,VpAddPdo)
  20. #pragma alloc_text(PAGE,pVideoPortEnumerateChildren)
  21. #pragma alloc_text(PAGE,pVideoPortCleanUpChildList)
  22. #endif
  23. const WCHAR gcwstrDosDeviceName[] = L"\\DosDevices\\LCD";
  24. NTSTATUS
  25. pVideoPnPCapabilities(
  26. IN PCHILD_PDO_EXTENSION PdoExtension,
  27. IN PDEVICE_CAPABILITIES Capabilities
  28. )
  29. /*+
  30. * Function: pVideoPnPCapabilities
  31. * Context: Called in the context of an IRP_MN_QUERY_CAPABILITIES minor function
  32. * and IRP_MJ_PNP major function.
  33. *
  34. * Arguments: PDEVICE_EXTENSION DeviceExtension - a pointer to a
  35. * CHILD_DEVICE_EXTENSION.
  36. *
  37. * PDEVICE_CAPABILITIES Capabilities - a pointer to the
  38. * Parameters.DeviceCapabilities.Capabilities of the IrpStack.
  39. *
  40. *
  41. * Comments: This routine fills in some capabilities data needed by the
  42. * PnP device manager.
  43. *
  44. -*/
  45. {
  46. BOOLEAN success ;
  47. DEVICE_POWER_STATE unused ;
  48. UCHAR count ;
  49. //
  50. // Make sure we're dealing with PDOs here.
  51. //
  52. ASSERT(IS_PDO(PdoExtension));
  53. if (!pVideoPortMapStoD(PdoExtension,
  54. PowerSystemSleeping1,
  55. &unused)) {
  56. return STATUS_UNSUCCESSFUL ;
  57. }
  58. for (count = PowerSystemUnspecified; count < PowerSystemMaximum; count++) {
  59. Capabilities->DeviceState[count] = PdoExtension->DeviceMapping[count] ;
  60. }
  61. //
  62. // Check to make sure that the monitor will actually get turned off
  63. // in sleep states.
  64. //
  65. if (Capabilities->DeviceState[PowerSystemSleeping1] == PowerDeviceD0) {
  66. Capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1 ;
  67. PdoExtension->DeviceMapping[PowerSystemSleeping1] =
  68. PowerDeviceD1 ;
  69. pVideoDebugPrint((0, "VideoPrt: QC - Override D0 for sleep on monitor.\n")) ;
  70. }
  71. PdoExtension->IsMappingReady = TRUE ;
  72. //
  73. // Begin with basic capabilities for the PDO
  74. //
  75. Capabilities->LockSupported = FALSE;
  76. Capabilities->EjectSupported = FALSE;
  77. Capabilities->Removable = FALSE;
  78. Capabilities->DockDevice = FALSE;
  79. //
  80. // Set the Raw bit to TRUE only for monitor like objects, since we
  81. // act as drivers for them.
  82. //
  83. Capabilities->RawDeviceOK = FALSE;
  84. if (PdoExtension->VideoChildDescriptor->Type == Monitor) {
  85. Capabilities->RawDeviceOK = TRUE;
  86. Capabilities->EjectSupported = TRUE;
  87. Capabilities->Removable = TRUE;
  88. Capabilities->SurpriseRemovalOK = TRUE;
  89. Capabilities->SilentInstall = TRUE;
  90. }
  91. //
  92. // Out address field contains the ID returned during enumeration.
  93. // This is key for ACPI devices in order for ACPI to install the
  94. // filter properly.
  95. //
  96. Capabilities->Address = PdoExtension->VideoChildDescriptor->UId;
  97. //
  98. // We do not generate unique IDs for our devices because we maight have
  99. // two video cards with monitors attached, for which the driver would
  100. // end up returning the same ID.
  101. //
  102. Capabilities->UniqueID = FALSE;
  103. //
  104. // The following are totally BOGUS.
  105. //
  106. Capabilities->SystemWake = PowerSystemUnspecified;
  107. Capabilities->DeviceWake = PowerDeviceUnspecified;
  108. Capabilities->D1Latency = 10;
  109. Capabilities->D2Latency = 10;
  110. Capabilities->D3Latency = 10;
  111. return STATUS_SUCCESS;
  112. }
  113. NTSTATUS
  114. pVideoPnPResourceRequirements(
  115. IN PCHILD_PDO_EXTENSION PdoExtension,
  116. OUT PCM_RESOURCE_LIST * ResourceList
  117. )
  118. /*+
  119. * Function: pVideoPnPResourceRequirements
  120. * Context: Called in the context of an IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  121. * minor function and IRP_MJ_PNP major function.
  122. * Arguments: PDEVICE_EXTENSION PdoExtension - a pointer to a CHILD_DEVICE_EXTENSION.
  123. * PCM_RESOURCE_LIST * ResourceList - a pointer to the IRPs
  124. * IoStatus.Information
  125. *
  126. * Comments: This routine tells the PnP device manager that the child
  127. * devices (monitors) don't need system resources. This may not
  128. * be the case for all child devices.
  129. *
  130. -*/
  131. {
  132. PVIDEO_CHILD_DESCRIPTOR pChildDescriptor;
  133. //
  134. // Make sure we're dealing with PDOs here.
  135. //
  136. ASSERT(IS_PDO(PdoExtension));
  137. //
  138. // Get the child descriptor allocated during Enumerate phase.
  139. //
  140. pChildDescriptor = PdoExtension->VideoChildDescriptor;
  141. //
  142. // If the descriptor is null, then there are serious problems.
  143. //
  144. ASSERT(pChildDescriptor);
  145. switch (pChildDescriptor->Type) {
  146. default:
  147. //
  148. // Monitors don't need pci resources.
  149. //
  150. case Monitor:
  151. *ResourceList = NULL;
  152. break;
  153. }
  154. return STATUS_SUCCESS;
  155. }
  156. BOOLEAN pGetACPIEdid(PDEVICE_OBJECT DeviceObject, PVOID pEdid)
  157. /*+
  158. * Function: pGetACPIEdid
  159. * Return Value:
  160. * TRUE: Success
  161. * FALSE: Failure
  162. -*/
  163. {
  164. UCHAR EDIDBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + EDID_BUFFER_SIZE];
  165. ULONG EdidVersion = 2;
  166. BOOLEAN bReturn = FALSE;
  167. RtlZeroMemory(EDIDBuffer, sizeof(EDIDBuffer));
  168. if (NT_SUCCESS (pVideoPortACPIIoctl(IoGetAttachedDevice(DeviceObject),
  169. (ULONG) ('CDD_'),
  170. &EdidVersion,
  171. NULL,
  172. sizeof(EDIDBuffer),
  173. (PACPI_EVAL_OUTPUT_BUFFER) EDIDBuffer) )
  174. )
  175. {
  176. ASSERT(((PACPI_EVAL_OUTPUT_BUFFER)EDIDBuffer)->Argument[0].Type == ACPI_METHOD_ARGUMENT_BUFFER);
  177. ASSERT(((PACPI_EVAL_OUTPUT_BUFFER)EDIDBuffer)->Argument[0].DataLength <= EDID_BUFFER_SIZE);
  178. bReturn = TRUE;
  179. }
  180. RtlCopyMemory(pEdid,
  181. ((PACPI_EVAL_OUTPUT_BUFFER)EDIDBuffer)->Argument[0].Data,
  182. EDID_BUFFER_SIZE);
  183. return bReturn;
  184. }
  185. #define TOTAL_NAMES_SIZE 512
  186. NTSTATUS
  187. pVideoPnPQueryId(
  188. IN PDEVICE_OBJECT DeviceObject,
  189. IN BUS_QUERY_ID_TYPE BusQueryIdType,
  190. IN OUT PWSTR * BusQueryId
  191. )
  192. /*+
  193. * Function: pVideoPnPQueryId
  194. * Context: Called in the context of an IRP_MN_QUERY_ID minor function
  195. * and IRP_MJ_PNP major function.
  196. * Arguments: DeviceObject - a PDEVICE_OBJECT created when we enumerated
  197. * the child device.
  198. * BusQueryIdType - a BUS_QUERY_ID_TYPE passed in by the PnP
  199. * device Manager.
  200. * BusQueryId - a PWSTR * written to in some cases by this
  201. * routine.
  202. *
  203. * Comments:
  204. *
  205. -*/
  206. {
  207. PUSHORT nameBuffer;
  208. LPWSTR deviceName;
  209. WCHAR buffer[64];
  210. PCHILD_PDO_EXTENSION pDeviceExtension;
  211. PVIDEO_CHILD_DESCRIPTOR pChildDescriptor;
  212. PVOID pEdid;
  213. NTSTATUS ntStatus = STATUS_SUCCESS;
  214. //
  215. // Allocate enought to hold a MULTI_SZ. This will be passed to the Io
  216. // subsystem (via BusQueryId) who has the responsibility of freeing it.
  217. //
  218. nameBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  219. TOTAL_NAMES_SIZE,
  220. VP_TAG);
  221. if (!nameBuffer)
  222. {
  223. pVideoDebugPrint((0, "\t Can't allocate nameBuffer\n"));
  224. return STATUS_INSUFFICIENT_RESOURCES;
  225. }
  226. RtlZeroMemory(nameBuffer, TOTAL_NAMES_SIZE);
  227. //
  228. // Get the child descriptor allocated during Enumerate phase.
  229. //
  230. pDeviceExtension = (PCHILD_PDO_EXTENSION) DeviceObject->DeviceExtension;
  231. pChildDescriptor = pDeviceExtension->VideoChildDescriptor;
  232. //
  233. // If the descriptor is null, then there are serious problems.
  234. //
  235. ASSERT(pChildDescriptor);
  236. //
  237. // Setup pEdid.
  238. //
  239. pEdid = &(pChildDescriptor->Buffer);
  240. //
  241. // Switch on the type to set up the strings appropriately. This switch
  242. // generates the UNICODE_STRING deviceName, used by HardwareID and
  243. // DeviceID bus queries.
  244. //
  245. switch(pChildDescriptor->Type) {
  246. case Monitor:
  247. /////////////////////////////////////////////////////////
  248. // Get the EDID if this is an ACPI device.
  249. /////////////////////////////////////////////////////////
  250. pChildDescriptor->ValidEDID = pVideoPortIsValidEDID(pEdid) ? GOOD_EDID : BAD_EDID;
  251. if (pChildDescriptor->bACPIDevice == TRUE)
  252. {
  253. if (pChildDescriptor->ACPIDDCFlag & ACPIDDC_TESTED)
  254. {
  255. if (pChildDescriptor->ValidEDID != GOOD_EDID &&
  256. (pChildDescriptor->ACPIDDCFlag & ACPIDDC_EXIST) )
  257. {
  258. pGetACPIEdid(DeviceObject, pEdid);
  259. pChildDescriptor->ValidEDID = pVideoPortIsValidEDID(pEdid) ? GOOD_EDID : BAD_EDID;
  260. }
  261. }
  262. else
  263. {
  264. //
  265. // If we found Miniport gets a right EDID, it's equivalent to that _DDC method doesn't exist
  266. //
  267. pChildDescriptor->ACPIDDCFlag = ACPIDDC_TESTED;
  268. if (pChildDescriptor->ValidEDID != GOOD_EDID &&
  269. pGetACPIEdid(DeviceObject, pEdid))
  270. {
  271. pChildDescriptor->ACPIDDCFlag |= ACPIDDC_EXIST;
  272. pChildDescriptor->ValidEDID = pVideoPortIsValidEDID(pEdid) ? GOOD_EDID : BAD_EDID;
  273. }
  274. }
  275. }
  276. //
  277. // If there's an EDID, decode it's OEM id. Otherwise, use
  278. // default.
  279. //
  280. if (pChildDescriptor->ValidEDID == GOOD_EDID) {
  281. pVideoDebugPrint((1, "\tNot a bogus edid\n"));
  282. pVideoPortGetEDIDId(pEdid, buffer);
  283. deviceName = buffer;
  284. } else {
  285. //
  286. // Use the passed in default name.
  287. //
  288. deviceName = L"Default_Monitor";
  289. }
  290. break;
  291. case Other:
  292. deviceName = (LPWSTR) pEdid;
  293. break;
  294. default:
  295. pVideoDebugPrint((0, "\t Unsupported Type: %x\n", pChildDescriptor->Type));
  296. ASSERT(FALSE);
  297. deviceName = L"Unknown_Video_Device";
  298. break;
  299. }
  300. pVideoDebugPrint((2, "\t The basic deviceName is %ws\n", deviceName));
  301. //
  302. // Craft a name dependent on what was passed in.
  303. //
  304. switch (BusQueryIdType) {
  305. case BusQueryCompatibleIDs:
  306. //
  307. // Compatible ID used for INF matching.
  308. //
  309. pVideoDebugPrint((2, "\t BusQueryCompatibleIDs\n"));
  310. if (pChildDescriptor->Type != Monitor) {
  311. swprintf(nameBuffer, L"DISPLAY\\%ws", deviceName);
  312. pVideoDebugPrint((2, "\t BusQueryCompatibleIDs = %ws", nameBuffer));
  313. } else {
  314. //
  315. // Put the default PNP id for monitors.
  316. //
  317. swprintf(nameBuffer, L"*PNP09FF");
  318. pVideoDebugPrint((2, "\t BusQueryCompatibleIDs = %ws", nameBuffer));
  319. }
  320. break;
  321. case BusQueryHardwareIDs:
  322. pVideoDebugPrint((2, "\t BusQueryHardwareIDs\n"));
  323. //
  324. // By this time, the keys should have been created, so write
  325. // the data to the registry. In this case the data is a string
  326. // that looks like '\Monitor\<string>' where string is either
  327. // 'Default_Monitor' or a name extracted from the edid.
  328. //
  329. if (pChildDescriptor->Type == Monitor) {
  330. //
  331. // Write the DDC information in the DEVICE part of the
  332. // registry (the part under ENUM\DISPLAY\*)
  333. //
  334. HANDLE hDeviceKey;
  335. NTSTATUS Status;
  336. Status = IoOpenDeviceRegistryKey(DeviceObject,
  337. PLUGPLAY_REGKEY_DEVICE,
  338. MAXIMUM_ALLOWED,
  339. &hDeviceKey);
  340. if (NT_SUCCESS(Status)) {
  341. RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  342. hDeviceKey,
  343. (pChildDescriptor->ValidEDID == GOOD_EDID) ?
  344. L"EDID" : L"BAD_EDID",
  345. REG_BINARY,
  346. pEdid,
  347. EDID_BUFFER_SIZE);
  348. ZwClose(hDeviceKey);
  349. }
  350. swprintf(nameBuffer, L"Monitor\\%ws", deviceName);
  351. } else {
  352. swprintf(nameBuffer, L"DISPLAY\\%ws", deviceName);
  353. }
  354. pVideoDebugPrint((2, "\t BusQueryHardwareIDs = %ws\n", nameBuffer));
  355. break;
  356. case BusQueryDeviceID:
  357. //
  358. // Device ID (top part of the ID)
  359. //
  360. pVideoDebugPrint((2, "\t BusQueryDeviceID\n"));
  361. swprintf(nameBuffer, L"DISPLAY\\%ws", deviceName);
  362. pVideoDebugPrint((2, "\t BusQueryDeviceID = %ws", nameBuffer));
  363. break;
  364. case BusQueryInstanceID:
  365. //
  366. // Instance ID (low part of the ID)
  367. //
  368. pVideoDebugPrint((2, "\t BusQueryInstanceID\n"));
  369. swprintf(nameBuffer, L"%08x&%02x&%02x", pChildDescriptor->UId,
  370. pDeviceExtension->pFdoExtension->SystemIoBusNumber,
  371. pDeviceExtension->pFdoExtension->SlotNumber);
  372. pVideoDebugPrint((2, "\t BusQueryInstanceID = %ws", nameBuffer));
  373. break;
  374. default:
  375. pVideoDebugPrint((0, "\t Bad QueryIdType:%x\n", BusQueryIdType));
  376. return STATUS_NOT_SUPPORTED;
  377. break;
  378. }
  379. pVideoDebugPrint((2, "\t returning %ws\n", nameBuffer));
  380. *BusQueryId = nameBuffer;
  381. return ntStatus;
  382. }
  383. NTSTATUS
  384. VpAddPdo(
  385. PDEVICE_OBJECT DeviceObject,
  386. PVIDEO_CHILD_DESCRIPTOR VideoChildDescriptor
  387. )
  388. /*+
  389. * Function: VpAddPdo
  390. * Context: Called after enumerating a device identified by the miniports
  391. * HwGetVideoChildDescriptor.
  392. *
  393. * Arguments: DeviceObject - a PDEVICE_OBJECT created when we
  394. * enumerated the device.
  395. * VideoChildDescriptor - a PVIDEO_CHILD_DESCRIPTOR allocated
  396. * when we enumerated the device.
  397. * Comments: This routine actually makes the call that creates the child
  398. * device object during enumeration.
  399. *
  400. *
  401. -*/
  402. {
  403. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  404. PCHILD_PDO_EXTENSION pChildDeviceExtension = fdoExtension->ChildPdoList;
  405. PDEVICE_OBJECT pChildPdo;
  406. USHORT nameBuffer[STRING_LENGTH];
  407. NTSTATUS ntStatus;
  408. NTSTATUS ntStatus2;
  409. UNICODE_STRING deviceName;
  410. POWER_STATE state;
  411. PVOID pEdid = VideoChildDescriptor->Buffer;
  412. UNICODE_STRING symbolicLinkName;
  413. //
  414. // Scan the old list to see if this is a duplicate. If a duplicate, mark it as
  415. // VIDEO_ENUMERATED and return STATUS_SUCCESS, because we will want to count it.
  416. // If no duplicates, pChildDeviceExtension will be NULL after exiting this loop
  417. // and a DEVICE_OBJECT will be created for this device instance. Mark the new
  418. // associated CHILD_DEVICE_EXTENSION as VIDEO_ENUMERATED.
  419. //
  420. while (pChildDeviceExtension) {
  421. PVIDEO_CHILD_DESCRIPTOR ChildDescriptor;
  422. BOOLEAN bEqualEDID = FALSE;
  423. ChildDescriptor = pChildDeviceExtension->VideoChildDescriptor;
  424. if (ChildDescriptor->UId == VideoChildDescriptor->UId)
  425. {
  426. if (ChildDescriptor->bACPIDevice == TRUE)
  427. {
  428. VideoChildDescriptor->ACPIDDCFlag = ChildDescriptor->ACPIDDCFlag;
  429. //
  430. // If it's non-monitor device, just ignore
  431. //
  432. if (VideoChildDescriptor->Type != Monitor)
  433. {
  434. bEqualEDID = TRUE;
  435. }
  436. //
  437. // Check the device is active, since inactive CRT may return false EDID
  438. //
  439. else if (pCheckActiveMonitor(pChildDeviceExtension) == FALSE)
  440. {
  441. bEqualEDID = TRUE;
  442. }
  443. else
  444. {
  445. VideoChildDescriptor->ValidEDID =
  446. pVideoPortIsValidEDID(VideoChildDescriptor->Buffer) ? GOOD_EDID : BAD_EDID;
  447. //
  448. // For ACPI system, try to retrieve EDID again.
  449. // At this moment, the handle of DeviceObject is still valid
  450. //
  451. if (VideoChildDescriptor->ValidEDID != GOOD_EDID &&
  452. (ChildDescriptor->ACPIDDCFlag & ACPIDDC_EXIST))
  453. {
  454. if (!pGetACPIEdid(pChildDeviceExtension->ChildDeviceObject,
  455. VideoChildDescriptor->Buffer))
  456. {
  457. bEqualEDID = TRUE;
  458. }
  459. }
  460. if (!bEqualEDID)
  461. {
  462. VideoChildDescriptor->ValidEDID =
  463. pVideoPortIsValidEDID(VideoChildDescriptor->Buffer) ? GOOD_EDID : BAD_EDID;
  464. if (VideoChildDescriptor->ValidEDID == ChildDescriptor->ValidEDID)
  465. {
  466. if (VideoChildDescriptor->ValidEDID != GOOD_EDID ||
  467. memcmp(ChildDescriptor->Buffer,
  468. VideoChildDescriptor->Buffer,
  469. EDID_BUFFER_SIZE) == 0)
  470. {
  471. bEqualEDID = TRUE;
  472. }
  473. }
  474. }
  475. }
  476. }
  477. //
  478. // For non-ACPI system, EDID has already contained VideoChildDescriptor
  479. //
  480. else
  481. {
  482. if (VideoChildDescriptor->Type != Monitor ||
  483. ChildDescriptor->ValidEDID != GOOD_EDID ||
  484. memcmp(ChildDescriptor->Buffer,
  485. VideoChildDescriptor->Buffer,
  486. EDID_BUFFER_SIZE) == 0)
  487. {
  488. bEqualEDID = TRUE;
  489. }
  490. }
  491. }
  492. if (bEqualEDID)
  493. {
  494. pChildDeviceExtension->bIsEnumerated = TRUE;
  495. pVideoDebugPrint((1,
  496. "VpAddPdo: duplicate device:%x\n",
  497. VideoChildDescriptor->UId));
  498. //
  499. // Replace the old child descriptor with the new one. This will
  500. // allow us to detect when and EDID changes, etc.
  501. //
  502. if (pChildDeviceExtension->VideoChildDescriptor->ValidEDID != NO_EDID)
  503. {
  504. RtlCopyMemory(VideoChildDescriptor,
  505. pChildDeviceExtension->VideoChildDescriptor,
  506. sizeof(VIDEO_CHILD_DESCRIPTOR) );
  507. }
  508. ExFreePool(pChildDeviceExtension->VideoChildDescriptor);
  509. pChildDeviceExtension->VideoChildDescriptor = VideoChildDescriptor;
  510. //
  511. // Return STATUS_SUCCESS, because we want to count this as a member of the
  512. // list (it's valid and in there already).
  513. //
  514. return STATUS_SUCCESS;
  515. }
  516. pChildDeviceExtension = pChildDeviceExtension->NextChild;
  517. }
  518. ntStatus = pVideoPortCreateDeviceName(L"\\Device\\VideoPdo",
  519. VideoChildDevices++,
  520. &deviceName,
  521. nameBuffer);
  522. if (NT_SUCCESS(ntStatus)) {
  523. //
  524. // Create the PDO for the child device.
  525. // Notice that we allocate the device extension as the size of
  526. // the FDO extension + the size of the miniports driver extension
  527. // for this device
  528. //
  529. ntStatus = IoCreateDevice(DeviceObject->DriverObject,
  530. sizeof(CHILD_PDO_EXTENSION),
  531. &deviceName,
  532. FILE_DEVICE_UNKNOWN,
  533. 0,
  534. FALSE, //TRUE,
  535. &pChildPdo);
  536. //
  537. // If the DeviceObject wasn't created, we won't get called to process
  538. // the QueryId IRP where VideoChildDescriptor gets freed, so do it
  539. // here.
  540. //
  541. if (!NT_SUCCESS(ntStatus)) {
  542. pVideoDebugPrint((0, "\t IoCreateDevice() failed with status %x\n", ntStatus));
  543. pVideoDebugPrint((0, "\t IoCreateDevice() doesn't like path %ws\n", deviceName.Buffer));
  544. ASSERT(0);
  545. return ntStatus;
  546. }
  547. //
  548. // Create a symbolic link so that user can call us. This was added
  549. // to support new ACPI backlight methods. We will not fail VpAddPdo
  550. // if IoCreateSymbolicLink fails.
  551. //
  552. RtlInitUnicodeString(&symbolicLinkName,
  553. gcwstrDosDeviceName);
  554. ntStatus2 = IoCreateSymbolicLink(&symbolicLinkName,
  555. &deviceName);
  556. //
  557. // Mark this object as supporting buffered I/O so that the I/O system
  558. // will only supply simple buffers in IRPs.
  559. // Set and clear the two power fields to ensure we only get called
  560. // as passive level to do power management operations.
  561. //
  562. pChildPdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  563. pChildPdo->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
  564. pChildPdo->DeviceType = FILE_DEVICE_SCREEN;
  565. //
  566. // Initialize fields in the ChildDeviceExtension.
  567. //
  568. pChildDeviceExtension = pChildPdo->DeviceExtension;
  569. pChildDeviceExtension->VideoChildDescriptor = VideoChildDescriptor;
  570. pChildDeviceExtension->ChildDeviceObject = pChildPdo;
  571. pChildDeviceExtension->pFdoExtension = fdoExtension;
  572. pChildDeviceExtension->Signature = VP_TAG;
  573. pChildDeviceExtension->ExtensionType = TypePdoExtension;
  574. pChildDeviceExtension->ChildUId = VideoChildDescriptor->UId;
  575. pChildDeviceExtension->bIsEnumerated = TRUE;
  576. pChildDeviceExtension->HwDeviceExtension = fdoExtension->HwDeviceExtension;
  577. pChildDeviceExtension->PowerOverride = FALSE;
  578. KeInitializeMutex(&pChildDeviceExtension->SyncMutex, 0);
  579. //
  580. // Initialize the remove lock.
  581. //
  582. IoInitializeRemoveLock(&pChildDeviceExtension->RemoveLock, 0, 0, 256);
  583. //
  584. // Initialize Power stuff.
  585. // Set the devices current power state.
  586. // NOTE - we assume the device is on at this point in time ...
  587. //
  588. pChildDeviceExtension->DevicePowerState = PowerDeviceD0;
  589. state.DeviceState = pChildDeviceExtension->DevicePowerState;
  590. state = PoSetPowerState(pChildPdo,
  591. DevicePowerState,
  592. state);
  593. //
  594. // Insert into list
  595. //
  596. pChildDeviceExtension->NextChild = fdoExtension->ChildPdoList;
  597. fdoExtension->ChildPdoList = pChildDeviceExtension;
  598. }
  599. return ntStatus;
  600. }
  601. NTSTATUS
  602. pVideoPortEnumerateChildren(
  603. PDEVICE_OBJECT DeviceObject,
  604. PIRP Irp
  605. )
  606. /*+
  607. * Function: pVideoPortEnumerateChildren
  608. * Context: Called in the context of an IRP_MN_QUERY_DEVICE_RELATIONS
  609. * minor function and IRP_MJ_PNP major function.
  610. * Arguments:
  611. * PDEVICE_OBJECT deviceObject - Passed in by caller of VideoPortDispatch().
  612. * PIRP pIrp - Passed in by caller of VideoPortDispatch().
  613. *
  614. * Comments: This routine enumerates devices attached to the video card. If
  615. * it's called before the driver is initialized, it returns
  616. * STATUS_INSUFFICIENT_RESOURCES. Otherwise, it attempts to read
  617. * the edid from the device and refer to that via the
  618. * DEVICE_EXTENSION and create a DEVICE_OBJECT (PDO) for each
  619. * detected device. This sets up the IO subsystem for issuing
  620. * further PnP IRPs such as IRP_MN_QUERY_DEVICE_ID
  621. *
  622. *
  623. -*/
  624. {
  625. UCHAR outputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 128];
  626. PCHILD_PDO_EXTENSION pChildDeviceExtension;
  627. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  628. ULONG moreChild;
  629. ULONG moreDevices = 1;
  630. ULONG Unused = 0;
  631. ULONG count = 0;
  632. PACPI_METHOD_ARGUMENT pAcpiArguments = NULL;
  633. VIDEO_CHILD_ENUM_INFO childEnumInfo;
  634. ULONG relationsSize;
  635. PDEVICE_RELATIONS deviceRelations = NULL;
  636. ULONG ulChildCount = 0;
  637. ULONG debugCount = 0;
  638. PDEVICE_OBJECT *pdo;
  639. NTSTATUS ntStatus;
  640. //
  641. // Make sure we are called with an FDO
  642. //
  643. ASSERT(IS_FDO(fdoExtension));
  644. if ((fdoExtension->AllowEarlyEnumeration == FALSE) &&
  645. (fdoExtension->HwInitStatus != HwInitSucceeded))
  646. {
  647. return STATUS_INSUFFICIENT_RESOURCES;
  648. }
  649. //
  650. // Mark all of the child devices as not being enumerated
  651. //
  652. for (pChildDeviceExtension = fdoExtension->ChildPdoList;
  653. pChildDeviceExtension != NULL;
  654. pChildDeviceExtension = pChildDeviceExtension->NextChild)
  655. {
  656. pChildDeviceExtension->bIsEnumerated = FALSE;
  657. }
  658. //
  659. // Let's call ACPI to determine if we have the IDs of the devices that
  660. // need to be enumerated.
  661. //
  662. ntStatus = pVideoPortACPIIoctl(fdoExtension->AttachedDeviceObject,
  663. (ULONG) ('DOD_'),
  664. NULL,
  665. NULL,
  666. sizeof(outputBuffer),
  667. (PACPI_EVAL_OUTPUT_BUFFER) outputBuffer);
  668. if (NT_SUCCESS(ntStatus))
  669. {
  670. count = ((PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)->Count;
  671. pAcpiArguments = &(((PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)->Argument[0]);
  672. }
  673. childEnumInfo.Size = sizeof(VIDEO_CHILD_ENUM_INFO);
  674. childEnumInfo.ChildDescriptorSize = EDID_BUFFER_SIZE;
  675. childEnumInfo.ChildIndex = 0;
  676. childEnumInfo.ACPIHwId = 0;
  677. childEnumInfo.ChildHwDeviceExtension = NULL;
  678. //
  679. // Call the miniport to enumerate the children
  680. // Keep calling for each ACPI device, and then call the driver if it
  681. // has any more devices.
  682. //
  683. while (moreDevices)
  684. {
  685. PVIDEO_CHILD_DESCRIPTOR pVideoChildDescriptor;
  686. //
  687. // Allocate Space for the Child Descriptor
  688. //
  689. pVideoChildDescriptor = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  690. sizeof(VIDEO_CHILD_DESCRIPTOR),
  691. VP_TAG);
  692. if (!pVideoChildDescriptor)
  693. {
  694. break;
  695. }
  696. RtlZeroMemory(pVideoChildDescriptor, sizeof(VIDEO_CHILD_DESCRIPTOR));
  697. //
  698. // On ACPI machine, the HwId contains the ID returned by ACPI
  699. // Otherwise, the value is initialized to NULL and the miniport driver
  700. // must fill it out
  701. //
  702. if (count)
  703. {
  704. ASSERT(pAcpiArguments->Type == 0);
  705. ASSERT(pAcpiArguments->DataLength == 4);
  706. // The lower 16bit are HWID
  707. childEnumInfo.ACPIHwId = pAcpiArguments->Argument & 0x0000FFFF;
  708. pVideoChildDescriptor->bACPIDevice = TRUE;
  709. pAcpiArguments++;
  710. count--;
  711. }
  712. else
  713. {
  714. //
  715. // Increment the child index for non-ACPI devices
  716. //
  717. childEnumInfo.ChildIndex++;
  718. childEnumInfo.ACPIHwId = 0;
  719. }
  720. //
  721. // For ACPI CRTs, Miniport should return EDID directly.
  722. // So for CRT, the buffer is garanteed to be overwriten.
  723. // We use this attibute to distinguish the CRT from LCD and TV.
  724. //
  725. if (pVideoChildDescriptor->bACPIDevice)
  726. {
  727. *((PULONG)pVideoChildDescriptor->Buffer) = NONEDID_SIGNATURE;
  728. }
  729. moreChild = fdoExtension->HwGetVideoChildDescriptor(
  730. fdoExtension->HwDeviceExtension,
  731. &childEnumInfo,
  732. &(pVideoChildDescriptor->Type),
  733. (PUCHAR)(pVideoChildDescriptor->Buffer),
  734. &(pVideoChildDescriptor->UId),
  735. &Unused);
  736. if (moreChild == ERROR_MORE_DATA || moreChild == VIDEO_ENUM_MORE_DEVICES)
  737. {
  738. //
  739. // Perform the required functions on the returned type.
  740. //
  741. ntStatus = VpAddPdo(DeviceObject,
  742. pVideoChildDescriptor);
  743. if (NT_SUCCESS(ntStatus))
  744. {
  745. ++ulChildCount;
  746. }
  747. else
  748. {
  749. moreChild = VIDEO_ENUM_INVALID_DEVICE;
  750. }
  751. }
  752. //
  753. // Stop enumerating the driver returns an error
  754. // For ACPI devices, if miniports returns ERROR_MORE_DATA, stop enumeration.
  755. // If it returns VIDEO_ENUM_MORE_DEVICE, continue on to Non-ACPI device.
  756. // It is the responsibility of Miniport not to enumerate duplicated ACPI and Non-ACPI devices .
  757. //
  758. if (moreChild == ERROR_MORE_DATA &&
  759. (pVideoChildDescriptor->bACPIDevice == TRUE) && (count == 0))
  760. {
  761. moreDevices = 0;
  762. }
  763. if ((moreChild != ERROR_MORE_DATA) &&
  764. (moreChild != VIDEO_ENUM_MORE_DEVICES) &&
  765. (moreChild != VIDEO_ENUM_INVALID_DEVICE)
  766. )
  767. {
  768. moreDevices = 0;
  769. }
  770. //
  771. // Free the memory in case of error.
  772. //
  773. if ((moreChild != ERROR_MORE_DATA) && (moreChild != VIDEO_ENUM_MORE_DEVICES))
  774. {
  775. ExFreePool(pVideoChildDescriptor);
  776. }
  777. }
  778. //
  779. // Now that we know how many devices we have, allocate the blob to be returned and
  780. // fill it.
  781. //
  782. relationsSize = sizeof(DEVICE_RELATIONS) +
  783. (ulChildCount * sizeof(PDEVICE_OBJECT));
  784. deviceRelations = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  785. relationsSize,
  786. VP_TAG);
  787. if (deviceRelations == NULL) {
  788. return STATUS_INSUFFICIENT_RESOURCES;
  789. }
  790. RtlZeroMemory(deviceRelations, relationsSize);
  791. //
  792. // Walk our chain of children, and store them in the relations array.
  793. //
  794. pChildDeviceExtension = fdoExtension->ChildPdoList;
  795. pdo = &(deviceRelations->Objects[0]);
  796. while (pChildDeviceExtension) {
  797. if (pChildDeviceExtension->bIsEnumerated) {
  798. //
  799. // Refcount the ChildDeviceObject.
  800. //
  801. ObReferenceObject(pChildDeviceExtension->ChildDeviceObject);
  802. *pdo++ = pChildDeviceExtension->ChildDeviceObject;
  803. ++debugCount;
  804. }
  805. pChildDeviceExtension = pChildDeviceExtension->NextChild;
  806. }
  807. if (debugCount != ulChildCount) {
  808. pVideoDebugPrint((0, "List management ERROR line %d\n", __LINE__));
  809. ASSERT(FALSE);
  810. }
  811. fdoExtension->ChildPdoNumber = ulChildCount;
  812. deviceRelations->Count = ulChildCount;
  813. //
  814. // Stuff that pDeviceRelations into the IRP and return SUCCESS.
  815. //
  816. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  817. return STATUS_SUCCESS;
  818. }
  819. NTSTATUS
  820. pVideoPortCleanUpChildList(
  821. PFDO_EXTENSION FdoExtension,
  822. PDEVICE_OBJECT DeviceObject
  823. )
  824. /*+
  825. * Function: pVideoPortCleanUpChildList
  826. * Context: Called in the context of an IRP_MN_REMOVE_DEVICE
  827. * minor function and IRP_MJ_PNP major function.
  828. * Arguments:
  829. * PFDO_EXTENSION FdoExtension - Device extension of the parent
  830. * PDEVICE_OBJECT deviceObject - Device object to be deleted
  831. *
  832. * Comments: This routine deletes a monitor device object when it is no
  833. * longer needed
  834. * It actually determines if the device is still present by
  835. * checking the enumerate flag in the device extension
  836. * We only do lazy deletion, that is delete the device objects
  837. * after reenumeration has shown the device not to be there
  838. *
  839. -*/
  840. {
  841. PCHILD_PDO_EXTENSION PrevChild = NULL;
  842. PCHILD_PDO_EXTENSION pChildDeviceExtension = FdoExtension->ChildPdoList;
  843. ASSERT(pChildDeviceExtension != NULL);
  844. //
  845. // Search the ChildPdoList for the device we are
  846. // removing.
  847. //
  848. while (pChildDeviceExtension)
  849. {
  850. if (pChildDeviceExtension->ChildDeviceObject == DeviceObject) {
  851. break;
  852. }
  853. PrevChild = pChildDeviceExtension;
  854. pChildDeviceExtension = pChildDeviceExtension->NextChild;
  855. }
  856. if (pChildDeviceExtension) {
  857. //
  858. // If the device is still enumerated, do not delete it as it is
  859. // too expensive for us to go check for device presence again.
  860. //
  861. if (pChildDeviceExtension->bIsEnumerated) {
  862. return STATUS_SUCCESS;
  863. }
  864. //
  865. // Remove the device from the list.
  866. //
  867. if (PrevChild == NULL) {
  868. FdoExtension->ChildPdoList = pChildDeviceExtension->NextChild;
  869. } else {
  870. PrevChild->NextChild = pChildDeviceExtension->NextChild;
  871. }
  872. //
  873. // Free the memory associated with this child device and then delete it.
  874. //
  875. ExFreePool(pChildDeviceExtension->VideoChildDescriptor);
  876. IoDeleteDevice(DeviceObject);
  877. }
  878. return STATUS_SUCCESS;
  879. }
  880. /*+
  881. * Function: pVideoPortConvertAsciiToWchar
  882. * convert that Ascii into a LPWSTR which
  883. * is then placed in Buffer.
  884. *
  885. *
  886. * Arguments: UCHAR Ascii - Pointer to an ascii string.
  887. *
  888. * WCHAR Buffer[64] - Buffer used to convert from ascii to
  889. * WCHAR.
  890. *
  891. * Comments: If DeviceName is returned to some caller outside the videoprt,
  892. * then Buffer had better have the right lifetime.
  893. *
  894. -*/
  895. VOID
  896. pVideoPortConvertAsciiToWChar(
  897. IN PUCHAR Ascii,
  898. OUT WCHAR Buffer[64]
  899. )
  900. {
  901. ANSI_STRING ansiString;
  902. UNICODE_STRING us;
  903. //
  904. // Create a unicode string holding the ascii Name.
  905. //
  906. RtlInitAnsiString(&ansiString, Ascii);
  907. //
  908. // Attach a buffer to the UNICODE_STRING
  909. //
  910. us.Buffer = Buffer;
  911. us.Length = 0;
  912. us.MaximumLength = 64;
  913. RtlZeroMemory(Buffer, sizeof(Buffer));
  914. RtlAnsiStringToUnicodeString(&us,
  915. &ansiString,
  916. FALSE);
  917. }
  918. NTSTATUS
  919. pVideoPortQueryDeviceText(
  920. IN PDEVICE_OBJECT ChildDeviceObject,
  921. IN DEVICE_TEXT_TYPE TextType,
  922. OUT PWSTR * ReturnValue
  923. )
  924. /*+
  925. * Function:
  926. * Context: Called in the context of an IRP_MN_QUERY_DEVICE_TEXT
  927. * minor function and IRP_MJ_PNP major function.
  928. * Arguments:
  929. * PDEVICE_OBJECT ChildDeviceObject - Passed in by caller
  930. * of pVideoPortPnpDispatch().
  931. *
  932. * DEVICE_TEXT_TYPE TextType - Passed in by caller
  933. * of pVideoPortPnpDispatch().
  934. *
  935. * PWSTR * ReturnValue - Created by caller of
  936. * this routine.
  937. -*/
  938. {
  939. PCHILD_PDO_EXTENSION pdoExtension;
  940. PVIDEO_CHILD_DESCRIPTOR pChildDescriptor;
  941. PAGED_CODE();
  942. //
  943. // Get the child descriptor allocated during Enumerate phase.
  944. //
  945. pdoExtension = (PCHILD_PDO_EXTENSION) ChildDeviceObject->DeviceExtension;
  946. ASSERT(IS_PDO(pdoExtension));
  947. pChildDescriptor = pdoExtension->VideoChildDescriptor;
  948. *ReturnValue = NULL;
  949. switch (TextType) {
  950. case DeviceTextDescription:
  951. if (pChildDescriptor->Type == Monitor)
  952. {
  953. ULONG asciiStringLength = 0;
  954. UCHAR pTmp[64];
  955. PWSTR tmpBuffer = (PWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  956. 128,
  957. VP_TAG);
  958. if (!tmpBuffer) {
  959. return STATUS_INSUFFICIENT_RESOURCES;
  960. }
  961. memset(pTmp, '0', 64);
  962. if (pChildDescriptor->ValidEDID == GOOD_EDID) {
  963. asciiStringLength = pVideoPortGetEdidOemID(&(pChildDescriptor->Buffer), pTmp);
  964. ASSERT(asciiStringLength <= 64);
  965. pVideoPortConvertAsciiToWChar(pTmp, tmpBuffer);
  966. if (asciiStringLength) {
  967. pVideoDebugPrint((2, "Ascii name:%s\n", pTmp));
  968. pVideoDebugPrint((2, "WChar name:%ws\n", tmpBuffer));
  969. }
  970. *ReturnValue = tmpBuffer;
  971. } else {
  972. wcscpy(tmpBuffer, L"Monitor");
  973. *ReturnValue = tmpBuffer;
  974. }
  975. return STATUS_SUCCESS;
  976. }
  977. return STATUS_NOT_SUPPORTED;
  978. default:
  979. return STATUS_NOT_SUPPORTED;
  980. }
  981. }
  982. BOOLEAN pCheckDeviceRelations(PFDO_EXTENSION FdoExtension, BOOLEAN bNewMonitor)
  983. /*+
  984. * Function: pCheckDeviceRelations
  985. * Arguments:
  986. * bNewMonitor New monitor has been plugged in
  987. * Return Value:
  988. * TRUE: Monitors had been changed, need to reenumarate
  989. * FALSE: No child device change
  990. -*/
  991. {
  992. BOOLEAN bInvalidateRelation = FALSE;
  993. PCHILD_PDO_EXTENSION pChildDeviceExtension;
  994. UCHAR pEdid[EDID_BUFFER_SIZE + sizeof(ACPI_EVAL_OUTPUT_BUFFER)];
  995. for (pChildDeviceExtension = FdoExtension->ChildPdoList;
  996. pChildDeviceExtension != NULL;
  997. pChildDeviceExtension = pChildDeviceExtension->NextChild
  998. )
  999. {
  1000. PVIDEO_CHILD_DESCRIPTOR VideoChildDescriptor = pChildDeviceExtension->VideoChildDescriptor;
  1001. BOOLEAN ValidEDID, bEqualEDID = TRUE;
  1002. if (VideoChildDescriptor->bACPIDevice == TRUE)
  1003. {
  1004. //
  1005. // If it's non-monitor device, just ignore
  1006. //
  1007. if (VideoChildDescriptor->Type != Monitor)
  1008. {
  1009. continue;
  1010. }
  1011. //
  1012. // For each output device, we are going to retrieve EDID when it's active.
  1013. //
  1014. if (bNewMonitor)
  1015. {
  1016. VideoChildDescriptor->bInvalidate = TRUE;
  1017. }
  1018. else if (VideoChildDescriptor->bInvalidate == FALSE)
  1019. {
  1020. continue;
  1021. }
  1022. //
  1023. // Check the device is active, since inactive CRT may return false EDID
  1024. // If inactive, delay the EDID retieving until next hotkey switching
  1025. //
  1026. if (pCheckActiveMonitor(pChildDeviceExtension) == FALSE)
  1027. {
  1028. continue;
  1029. }
  1030. VideoChildDescriptor->bInvalidate = FALSE;
  1031. //
  1032. // Get DDC from Miniport first
  1033. //
  1034. {
  1035. VIDEO_CHILD_ENUM_INFO childEnumInfo;
  1036. VIDEO_CHILD_TYPE childType;
  1037. ULONG UId, Unused, moreChild;
  1038. childEnumInfo.Size = sizeof(VIDEO_CHILD_ENUM_INFO);
  1039. childEnumInfo.ChildDescriptorSize = EDID_BUFFER_SIZE;
  1040. childEnumInfo.ChildIndex = 0;
  1041. childEnumInfo.ACPIHwId = VideoChildDescriptor->UId;
  1042. childEnumInfo.ChildHwDeviceExtension = NULL;
  1043. moreChild = FdoExtension->HwGetVideoChildDescriptor(
  1044. FdoExtension->HwDeviceExtension,
  1045. &childEnumInfo,
  1046. &childType,
  1047. (PUCHAR)pEdid,
  1048. &UId,
  1049. &Unused);
  1050. ASSERT (moreChild == ERROR_MORE_DATA || moreChild == VIDEO_ENUM_MORE_DEVICES);
  1051. ValidEDID = pVideoPortIsValidEDID(pEdid) ? GOOD_EDID : BAD_EDID;
  1052. }
  1053. //
  1054. // For ACPI system, retrieve EDID again.
  1055. // At this moment, the handle of DeviceObject is still valid
  1056. //
  1057. if (ValidEDID != GOOD_EDID &&
  1058. VideoChildDescriptor->ACPIDDCFlag & ACPIDDC_EXIST)
  1059. {
  1060. if (!pGetACPIEdid(pChildDeviceExtension->ChildDeviceObject, pEdid))
  1061. {
  1062. continue;
  1063. }
  1064. ValidEDID = pVideoPortIsValidEDID(pEdid) ? GOOD_EDID : BAD_EDID;
  1065. }
  1066. if (VideoChildDescriptor->ValidEDID != ValidEDID)
  1067. {
  1068. bEqualEDID = FALSE;
  1069. }
  1070. else if (ValidEDID == GOOD_EDID)
  1071. {
  1072. if (memcmp(VideoChildDescriptor->Buffer, pEdid, EDID_BUFFER_SIZE) != 0)
  1073. {
  1074. bEqualEDID = FALSE;
  1075. }
  1076. }
  1077. if (!bEqualEDID)
  1078. {
  1079. bInvalidateRelation = TRUE;
  1080. //
  1081. // Forcing UId to become a bad value will invalidate the device
  1082. //
  1083. VideoChildDescriptor->UId = 0xFFFF8086;
  1084. }
  1085. }
  1086. }
  1087. return bInvalidateRelation;
  1088. }
  1089. BOOLEAN pCheckActiveMonitor(PCHILD_PDO_EXTENSION pChildDeviceExtension)
  1090. {
  1091. ULONG UId, flag;
  1092. UId = pChildDeviceExtension->ChildUId;
  1093. if (NT_SUCCESS
  1094. (pVideoMiniDeviceIoControl(pChildDeviceExtension->ChildDeviceObject,
  1095. IOCTL_VIDEO_GET_CHILD_STATE,
  1096. &UId,
  1097. sizeof(ULONG),
  1098. &flag,
  1099. sizeof(ULONG) ) )
  1100. )
  1101. {
  1102. return ((flag & VIDEO_CHILD_ACTIVE) ?
  1103. TRUE :
  1104. FALSE);
  1105. }
  1106. if (pChildDeviceExtension->VideoChildDescriptor->bACPIDevice == TRUE)
  1107. {
  1108. UCHAR outputBuffer[0x10 + sizeof(ACPI_EVAL_OUTPUT_BUFFER)];
  1109. if (NT_SUCCESS
  1110. (pVideoPortACPIIoctl(IoGetAttachedDevice(pChildDeviceExtension->ChildDeviceObject),
  1111. (ULONG) ('SCD_'),
  1112. NULL,
  1113. NULL,
  1114. sizeof(outputBuffer),
  1115. (PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)
  1116. )
  1117. )
  1118. {
  1119. if ( ((PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)->Argument[0].Argument & 0x02)
  1120. {
  1121. return TRUE;
  1122. }
  1123. else
  1124. {
  1125. return FALSE;
  1126. }
  1127. }
  1128. else
  1129. {
  1130. return TRUE;
  1131. }
  1132. }
  1133. else
  1134. {
  1135. //
  1136. // For Non-ACPI machines, if miniport doesn't handle IOCTL_VIDEO_GET_CHILD_STATE, we just assume all Monitors are active
  1137. //
  1138. return TRUE;
  1139. }
  1140. }