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.

2757 lines
85 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This is the pnp portion of the video port driver.
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. --*/
  11. #include "videoprt.h"
  12. #pragma alloc_text(PAGE,pVideoPortSendIrpToLowerDevice)
  13. #pragma alloc_text(PAGE,pVideoPortPowerCallDownIrpStack)
  14. #pragma alloc_text(PAGE,pVideoPortHibernateNotify)
  15. #pragma alloc_text(PAGE,pVideoPortPnpDispatch)
  16. #pragma alloc_text(PAGE,pVideoPortPowerDispatch)
  17. #pragma alloc_text(PAGE,InitializePowerStruct)
  18. NTSTATUS
  19. VpSetEventCompletion(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN PIRP Irp,
  22. IN PKEVENT Event
  23. )
  24. {
  25. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  26. return STATUS_MORE_PROCESSING_REQUIRED;
  27. }
  28. NTSTATUS
  29. pVideoPortSendIrpToLowerDevice(
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP Irp
  32. )
  33. /*++
  34. Routine Description:
  35. This routine will forward the start request to the next lower device and
  36. block until it's completion.
  37. Arguments:
  38. DeviceObject - the device to which the start request was issued.
  39. Irp - the start request
  40. Return Value:
  41. status
  42. --*/
  43. {
  44. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  45. PKEVENT event;
  46. NTSTATUS status;
  47. event = ExAllocatePoolWithTag(NonPagedPool,
  48. sizeof(KEVENT),
  49. VP_TAG);
  50. if (event == NULL) {
  51. return STATUS_INSUFFICIENT_RESOURCES;
  52. }
  53. KeInitializeEvent(event, SynchronizationEvent, FALSE);
  54. IoCopyCurrentIrpStackLocationToNext(Irp);
  55. IoSetCompletionRoutine(Irp,
  56. VpSetEventCompletion,
  57. event,
  58. TRUE,
  59. TRUE,
  60. TRUE);
  61. status = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  62. if(status == STATUS_PENDING) {
  63. KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  64. status = Irp->IoStatus.Status;
  65. }
  66. ExFreePool(event);
  67. return status;
  68. }
  69. NTSTATUS
  70. pVideoPortCompleteWithMoreProcessingRequired(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. IN PIRP Irp,
  73. IN PKEVENT Event
  74. )
  75. /*++
  76. Routine Description:
  77. This routine is used as a completion routine when an IRP is passed
  78. down the stack but more processing must be done on the way back up.
  79. The effect of using this as a completion routine is that the IRP
  80. will not be destroyed in IoCompleteRequest as called by the lower
  81. level object.
  82. Arguments:
  83. DeviceObject - Supplies the device object
  84. Irp - Supplies the IRP_MN_START_DEVICE irp.
  85. Event - Caller will wait on this event if STATUS_PENDING was
  86. returned.
  87. Return Value:
  88. STATUS_MORE_PROCESSING_REQUIRED
  89. --*/
  90. {
  91. //
  92. // In case someone somewhere returned STATUS_PENDING, set
  93. // the Event our caller may be waiting on.
  94. //
  95. KeSetEvent(Event, 0, FALSE);
  96. return STATUS_MORE_PROCESSING_REQUIRED;
  97. }
  98. NTSTATUS
  99. pVideoPortPowerCallDownIrpStack(
  100. PDEVICE_OBJECT AttachedDeviceObject,
  101. PIRP Irp
  102. )
  103. /*++
  104. Description:
  105. Pass the IRP to the next device object in the device stack. This
  106. routine is used when more processing is required at this level on
  107. this IRP on the way back up.
  108. Note: Waits for completion.
  109. Arguments:
  110. DeviceObject - the Fdo
  111. Irp - the request
  112. Return Value:
  113. Returns the result from calling the next level.
  114. --*/
  115. {
  116. KEVENT event;
  117. NTSTATUS status;
  118. //
  119. // Initialize the event to wait on.
  120. //
  121. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  122. //
  123. // Copy the stack location and set the completion routine.
  124. //
  125. IoCopyCurrentIrpStackLocationToNext(Irp);
  126. IoSetCompletionRoutine(Irp,
  127. pVideoPortCompleteWithMoreProcessingRequired,
  128. &event,
  129. TRUE,
  130. TRUE,
  131. TRUE
  132. );
  133. //
  134. // Call the next driver in the chain.
  135. //
  136. status = PoCallDriver(AttachedDeviceObject, Irp);
  137. if (status == STATUS_PENDING) {
  138. //
  139. // Wait for it.
  140. //
  141. // (peterj: in theory this shouldn't actually happen).
  142. //
  143. // Also, the completion routine does not allow the IRP to
  144. // actually complete so we can still get status from the IRP.
  145. //
  146. KeWaitForSingleObject(
  147. &event,
  148. Executive,
  149. KernelMode,
  150. FALSE,
  151. NULL
  152. );
  153. status = Irp->IoStatus.Status;
  154. }
  155. return status;
  156. }
  157. VOID
  158. pVideoPortHibernateNotify(
  159. IN PDEVICE_OBJECT Pdo,
  160. BOOLEAN IsVideoObject
  161. )
  162. /*++
  163. Routine Description:
  164. Sends a DEVICE_USAGE_NOTIFICATION irp to our parent PDO that
  165. indicates we are on the hibernate path.
  166. Arguments:
  167. Pdo - Supplies our PDO
  168. Return Value:
  169. None.
  170. --*/
  171. {
  172. KEVENT Event;
  173. PIRP Irp;
  174. IO_STATUS_BLOCK IoStatusBlock;
  175. PIO_STACK_LOCATION irpSp;
  176. NTSTATUS status;
  177. PDEVICE_OBJECT targetDevice = Pdo ;
  178. //
  179. // If the PDO is ourselves, the target device is actually the top of
  180. // the device stack.
  181. //
  182. if (IsVideoObject) {
  183. targetDevice = IoGetAttachedDeviceReference (Pdo) ;
  184. }
  185. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  186. Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  187. targetDevice,
  188. NULL,
  189. 0,
  190. NULL,
  191. &Event,
  192. &IoStatusBlock);
  193. if (Irp != NULL) {
  194. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  195. irpSp = IoGetNextIrpStackLocation(Irp);
  196. irpSp->MajorFunction = IRP_MJ_PNP;
  197. irpSp->MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  198. irpSp->Parameters.UsageNotification.InPath = TRUE;
  199. irpSp->Parameters.UsageNotification.Type = DeviceUsageTypeHibernation;
  200. status = IoCallDriver(targetDevice, Irp);
  201. if (status == STATUS_PENDING) {
  202. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  203. }
  204. }
  205. //
  206. // Make sure to deref if the object was referenced when the top of
  207. // the stack was obtained.
  208. //
  209. if (IsVideoObject) {
  210. ObDereferenceObject (targetDevice) ;
  211. }
  212. }
  213. ULONG
  214. VpGetDeviceAddress(
  215. IN PDEVICE_OBJECT DeviceObject
  216. )
  217. /*++
  218. Routine Description:
  219. This routine will get the address of a device (ie. slot number).
  220. Arguments:
  221. DeviceObject - Object for which to retrieve the address
  222. Returns:
  223. The address of the given device.
  224. --*/
  225. {
  226. KEVENT Event;
  227. PIRP QueryIrp = NULL;
  228. IO_STATUS_BLOCK IoStatusBlock;
  229. PIO_STACK_LOCATION NextStack;
  230. NTSTATUS Status;
  231. DEVICE_CAPABILITIES Capabilities;
  232. PFDO_EXTENSION FdoExtension = DeviceObject->DeviceExtension;
  233. RtlZeroMemory(&Capabilities, sizeof(DEVICE_CAPABILITIES));
  234. Capabilities.Size = sizeof(DEVICE_CAPABILITIES);
  235. Capabilities.Version = 1;
  236. Capabilities.Address = Capabilities.UINumber = (ULONG) -1;
  237. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  238. QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
  239. FdoExtension->AttachedDeviceObject,
  240. NULL,
  241. 0,
  242. NULL,
  243. &Event,
  244. &IoStatusBlock);
  245. if (QueryIrp == NULL) {
  246. return STATUS_INSUFFICIENT_RESOURCES;
  247. }
  248. QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
  249. NextStack = IoGetNextIrpStackLocation(QueryIrp);
  250. //
  251. // Set up for a QueryInterface Irp.
  252. //
  253. NextStack->MajorFunction = IRP_MJ_PNP;
  254. NextStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  255. NextStack->Parameters.DeviceCapabilities.Capabilities = &Capabilities;
  256. Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
  257. if (Status == STATUS_PENDING) {
  258. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  259. Status = IoStatusBlock.Status;
  260. }
  261. ASSERT(NT_SUCCESS(Status));
  262. return (Capabilities.Address >> 16) | ((Capabilities.Address & 0x7) << 5);
  263. }
  264. NTSTATUS
  265. pVideoPortPnpDispatch(
  266. IN PDEVICE_OBJECT DeviceObject,
  267. IN PIRP Irp
  268. )
  269. /*++
  270. Routine Description:
  271. This routine is the PnP dispatch routine for the video port driver.
  272. It accepts an I/O Request Packet, transforms it to a video Request
  273. Packet, and forwards it to the appropriate miniport dispatch routine.
  274. Upon returning, it completes the request and return the appropriate
  275. status value.
  276. Arguments:
  277. DeviceObject - Pointer to the device object of the miniport driver to
  278. which the request must be sent.
  279. Irp - Pointer to the request packet representing the I/O request.
  280. Return Value:
  281. The function value os the status of the operation.
  282. --*/
  283. {
  284. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  285. PFDO_EXTENSION combinedExtension;
  286. PFDO_EXTENSION fdoExtension;
  287. PCHILD_PDO_EXTENSION pdoExtension = NULL;
  288. PIO_STACK_LOCATION irpStack;
  289. PVOID ioBuffer;
  290. ULONG inputBufferLength;
  291. ULONG outputBufferLength;
  292. PSTATUS_BLOCK statusBlock;
  293. NTSTATUS finalStatus;
  294. ULONG ioControlCode;
  295. BOOLEAN RemoveLockReleased = FALSE;
  296. PIO_REMOVE_LOCK pRemoveLock;
  297. PCHILD_PDO_EXTENSION childDeviceExtension;
  298. NTSTATUS RemoveLockStatus;
  299. PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
  300. PDEVICE_OBJECT AttachedDevice = NULL;
  301. ULONG ulACPIMethodParam1;
  302. BOOLEAN bSetBacklight = FALSE;
  303. //
  304. // Get a pointer to the current location in the Irp. This is where
  305. // the function codes and parameters are located.
  306. //
  307. irpStack = IoGetCurrentIrpStackLocation(Irp);
  308. //
  309. // Get the pointer to the status buffer.
  310. // Assume SUCCESS for now.
  311. //
  312. statusBlock = (PSTATUS_BLOCK) &Irp->IoStatus;
  313. //
  314. // Get pointer to the port driver's device extension.
  315. //
  316. combinedExtension = DeviceObject->DeviceExtension;
  317. if (IS_PDO(DeviceObject->DeviceExtension)) {
  318. pdoExtension = DeviceObject->DeviceExtension;
  319. fdoExtension = pdoExtension->pFdoExtension;
  320. childDeviceExtension = (PCHILD_PDO_EXTENSION)
  321. DeviceObject->DeviceExtension;
  322. pRemoveLock = &childDeviceExtension->RemoveLock;
  323. } else if (IS_FDO(DeviceObject->DeviceExtension)) {
  324. fdoExtension = DeviceObject->DeviceExtension;
  325. DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
  326. pRemoveLock = &fdoExtension->RemoveLock;
  327. } else {
  328. DoSpecificExtension = DeviceObject->DeviceExtension;
  329. fdoExtension = DoSpecificExtension->pFdoExtension;
  330. combinedExtension = fdoExtension;
  331. pVideoDebugPrint((2, "Pnp/Power irp's not supported by secondary DO\n"));
  332. statusBlock->Status = STATUS_NOT_SUPPORTED;
  333. goto Complete_Irp;
  334. }
  335. //
  336. // Get the requestor mode.
  337. //
  338. combinedExtension->CurrentIrpRequestorMode = Irp->RequestorMode;
  339. #if REMOVE_LOCK_ENABLED
  340. RemoveLockStatus = IoAcquireRemoveLock(pRemoveLock, Irp);
  341. if (NT_SUCCESS(RemoveLockStatus) == FALSE) {
  342. ASSERT(FALSE);
  343. Irp->IoStatus.Information = 0;
  344. Irp->IoStatus.Status = RemoveLockStatus;
  345. IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
  346. return RemoveLockStatus;
  347. }
  348. #endif
  349. //
  350. // Handle IRPs for the PDO. Only PNP IRPs should be going to
  351. // that device.
  352. //
  353. if (IS_PDO(combinedExtension)) {
  354. ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  355. pVideoDebugPrint((2, "VIDEO_TYPE_PDO : IRP_MJ_PNP: "));
  356. switch (irpStack->MinorFunction) {
  357. case IRP_MN_CANCEL_STOP_DEVICE:
  358. pVideoDebugPrint((2, "IRP_MN_CANCEL_STOP_DEVICE\n"));
  359. statusBlock->Status = STATUS_SUCCESS;
  360. break;
  361. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  362. pVideoDebugPrint((2, "IRP_MN_DEVICE_USAGE_NOTIFICATION\n"));
  363. statusBlock->Status = STATUS_SUCCESS;
  364. break;
  365. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  366. pVideoDebugPrint((2, "IRP_MN_QUERY_PNP_DEVICE_STATE\n")) ;
  367. statusBlock->Status = STATUS_SUCCESS;
  368. break;
  369. case IRP_MN_QUERY_CAPABILITIES:
  370. pVideoDebugPrint((2, "IRP_MN_QUERY_CAPABILITIES\n"));
  371. statusBlock->Status = pVideoPnPCapabilities(childDeviceExtension,
  372. irpStack->Parameters.DeviceCapabilities.Capabilities);
  373. break;
  374. case IRP_MN_QUERY_ID:
  375. pVideoDebugPrint((2, "IRP_MN_QUERY_ID\n"));
  376. statusBlock->Status = pVideoPnPQueryId(DeviceObject,
  377. irpStack->Parameters.QueryId.IdType,
  378. (PWSTR *)&(Irp->IoStatus.Information));
  379. break;
  380. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  381. pVideoDebugPrint((2, "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"));
  382. statusBlock->Status =
  383. pVideoPnPResourceRequirements(childDeviceExtension,
  384. (PCM_RESOURCE_LIST * )&(Irp->IoStatus.Information));
  385. break;
  386. case IRP_MN_QUERY_DEVICE_RELATIONS:
  387. pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_RELATIONS\n"));
  388. if (irpStack->Parameters.QueryDeviceRelations.Type ==
  389. TargetDeviceRelation) {
  390. PDEVICE_RELATIONS DeviceRelationsBuffer;
  391. PDEVICE_RELATIONS *pDeviceRelations;
  392. pDeviceRelations = (PDEVICE_RELATIONS *) &statusBlock->Information;
  393. if (*pDeviceRelations) {
  394. //
  395. // The caller supplied a device relation structure.
  396. // However, we do not know if it is big enough, so
  397. // free it and allocate our own.
  398. //
  399. ExFreePool(*pDeviceRelations);
  400. *pDeviceRelations = NULL;
  401. }
  402. DeviceRelationsBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  403. sizeof(DEVICE_RELATIONS),
  404. VP_TAG);
  405. if (DeviceRelationsBuffer) {
  406. DeviceRelationsBuffer->Count = 1;
  407. DeviceRelationsBuffer->Objects[0] = DeviceObject;
  408. *pDeviceRelations = DeviceRelationsBuffer;
  409. ObReferenceObject(DeviceObject);
  410. statusBlock->Status = STATUS_SUCCESS;
  411. } else {
  412. statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
  413. }
  414. }
  415. break;
  416. case IRP_MN_QUERY_DEVICE_TEXT:
  417. pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_TEXT\n"));
  418. statusBlock->Status =
  419. pVideoPortQueryDeviceText(DeviceObject,
  420. irpStack->Parameters.QueryDeviceText.DeviceTextType,
  421. (PWSTR *)&Irp->IoStatus.Information);
  422. break;
  423. case IRP_MN_QUERY_INTERFACE:
  424. pVideoDebugPrint((2, "IRP_MN_QUERY_INTERFACE\n"));
  425. if ((childDeviceExtension->pFdoExtension->HwQueryInterface) &&
  426. (childDeviceExtension->pFdoExtension->HwDeviceExtension)) {
  427. VP_STATUS status;
  428. status =
  429. childDeviceExtension->pFdoExtension->HwQueryInterface(
  430. childDeviceExtension->pFdoExtension->HwDeviceExtension,
  431. (PQUERY_INTERFACE)
  432. &irpStack->Parameters.QueryInterface);
  433. if (status == 0)
  434. {
  435. statusBlock->Status = STATUS_SUCCESS;
  436. }
  437. }
  438. break;
  439. case IRP_MN_SURPRISE_REMOVAL:
  440. case IRP_MN_QUERY_REMOVE_DEVICE:
  441. case IRP_MN_QUERY_STOP_DEVICE:
  442. case IRP_MN_STOP_DEVICE:
  443. pVideoDebugPrint((2, "IRP_MN_SURPRISE_REMOVAL/IRP_MN_QUERY_REMOVE_DEVICE/IRP_MN_QUERY_STOP_DEVICE/IRP_MN_STOP_DEVICE\n"));
  444. if (childDeviceExtension->VideoChildDescriptor->Type == Monitor)
  445. {
  446. if (irpStack->MinorFunction == IRP_MN_SURPRISE_REMOVAL) {
  447. KeWaitForSingleObject (&LCDPanelMutex,
  448. Executive,
  449. KernelMode,
  450. FALSE,
  451. (PTIME)NULL);
  452. if (LCDPanelDevice == DeviceObject) {
  453. LCDPanelDevice = NULL;
  454. }
  455. KeReleaseMutex (&LCDPanelMutex, FALSE);
  456. }
  457. }
  458. statusBlock->Status = STATUS_SUCCESS;
  459. break;
  460. case IRP_MN_CANCEL_REMOVE_DEVICE:
  461. pVideoDebugPrint((2, "IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  462. statusBlock->Status = STATUS_SUCCESS;
  463. break;
  464. case IRP_MN_REMOVE_DEVICE:
  465. pVideoDebugPrint((2, "IRP_MN_REMOVE_DEVICE\n"));
  466. //
  467. // Check the see if this is the LCD Panel. If it is, set the LCD
  468. // panel device object to NULL. If not, leave it alone.
  469. //
  470. KeWaitForSingleObject (&LCDPanelMutex,
  471. Executive,
  472. KernelMode,
  473. FALSE,
  474. (PTIME)NULL);
  475. if (LCDPanelDevice == DeviceObject) {
  476. LCDPanelDevice = NULL;
  477. }
  478. KeReleaseMutex(&LCDPanelMutex, FALSE);
  479. #if REMOVE_LOCK_ENABLED
  480. IoReleaseRemoveLockAndWait(pRemoveLock, Irp);
  481. RemoveLockReleased = TRUE;
  482. #endif
  483. //
  484. // If this is one of our child pdo's, then
  485. // clean it up.
  486. //
  487. statusBlock->Status = pVideoPortCleanUpChildList(childDeviceExtension->pFdoExtension,
  488. DeviceObject);
  489. break;
  490. case IRP_MN_START_DEVICE:
  491. {
  492. UCHAR nextMiniport = FALSE;
  493. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  494. pVideoDebugPrint((2, "IRP_MN_START_DEVICE\n"));
  495. //
  496. // For a non-card device, just return success
  497. //
  498. if (childDeviceExtension->VideoChildDescriptor) {
  499. //
  500. // Once the monitor device is started, create an interface for it.
  501. //
  502. if (childDeviceExtension->VideoChildDescriptor->Type == Monitor)
  503. {
  504. statusBlock->Status = STATUS_SUCCESS;
  505. //
  506. // If the monitor is attached to the video adapter on the hibernation
  507. // path then we want to send notification to the system that the
  508. // monitor is on the hibernation path as well.
  509. //
  510. if (fdoExtension->OnHibernationPath == TRUE)
  511. {
  512. pVideoPortHibernateNotify (DeviceObject, TRUE);
  513. }
  514. //
  515. // If this is the LCD Panel, update the global to indicate as
  516. // much.
  517. //
  518. if (childDeviceExtension->ChildUId == 0x110)
  519. {
  520. KeWaitForSingleObject (&LCDPanelMutex,
  521. Executive,
  522. KernelMode,
  523. FALSE,
  524. (PTIME)NULL);
  525. LCDPanelDevice = DeviceObject;
  526. KeReleaseMutex(&LCDPanelMutex, FALSE);
  527. //
  528. // If the new backlight control interface is implemented,
  529. // set the backlight brightness level.
  530. //
  531. if ((pVpBacklightStatus->bNewAPISupported == TRUE) &&
  532. (pVpBacklightStatus->bACBrightnessKnown == TRUE) &&
  533. (VpRunningOnAC == TRUE))
  534. {
  535. ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucACBrightness;
  536. bSetBacklight = TRUE;
  537. }
  538. if ((pVpBacklightStatus->bNewAPISupported == TRUE) &&
  539. (pVpBacklightStatus->bDCBrightnessKnown == TRUE) &&
  540. (VpRunningOnAC == FALSE))
  541. {
  542. ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucDCBrightness;
  543. bSetBacklight = TRUE;
  544. }
  545. if ((bSetBacklight) && (LCDPanelDevice))
  546. {
  547. AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
  548. // Not checking status here deliberately, as we're not failing
  549. // this IRP if this call fails.
  550. if (AttachedDevice) {
  551. pVideoPortACPIIoctl(
  552. AttachedDevice,
  553. (ULONG) ('MCB_'),
  554. &ulACPIMethodParam1,
  555. NULL,
  556. 0,
  557. NULL);
  558. ObDereferenceObject(AttachedDevice);
  559. }
  560. }
  561. }
  562. }
  563. else if (childDeviceExtension->VideoChildDescriptor->Type == Other)
  564. {
  565. statusBlock->Status = STATUS_SUCCESS;
  566. }
  567. }
  568. else
  569. {
  570. ASSERT(FALSE);
  571. //
  572. // Secondary video cards are handle here.
  573. //
  574. DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  575. IoGetDriverObjectExtension(
  576. DeviceObject->DriverObject,
  577. DeviceObject->DriverObject);
  578. }
  579. }
  580. break;
  581. default:
  582. pVideoDebugPrint((2, "PNP minor function %x not supported!\n", irpStack->MinorFunction ));
  583. statusBlock->Status = STATUS_NOT_SUPPORTED;
  584. break;
  585. }
  586. } else {
  587. ASSERT(IS_FDO(fdoExtension));
  588. ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  589. pVideoDebugPrint((2, "VIDEO_TYPE_FDO : IRP_MJ_PNP: "));
  590. switch (irpStack->MinorFunction) {
  591. case IRP_MN_QUERY_STOP_DEVICE:
  592. pVideoDebugPrint((2, "IRP_MN_QUERY_STOP_DEVICE\n"));
  593. statusBlock->Status = STATUS_UNSUCCESSFUL;
  594. break;
  595. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  596. {
  597. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  598. PIO_RESOURCE_REQUIREMENTS_LIST requirements;
  599. ULONG Length;
  600. pVideoDebugPrint((2, "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"));
  601. DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  602. IoGetDriverObjectExtension(
  603. DeviceObject->DriverObject,
  604. DeviceObject->DriverObject);
  605. //
  606. // We must first pass the Irp down to the PDO.
  607. //
  608. pVideoPortSendIrpToLowerDevice(DeviceObject, Irp);
  609. //
  610. // Determine the bus type and bus number
  611. //
  612. IoGetDeviceProperty(fdoExtension->PhysicalDeviceObject,
  613. DevicePropertyLegacyBusType,
  614. sizeof(fdoExtension->AdapterInterfaceType),
  615. &fdoExtension->AdapterInterfaceType,
  616. &Length);
  617. IoGetDeviceProperty(fdoExtension->PhysicalDeviceObject,
  618. DevicePropertyBusNumber,
  619. sizeof(fdoExtension->SystemIoBusNumber),
  620. &fdoExtension->SystemIoBusNumber,
  621. &Length);
  622. //
  623. // Get bus interface so we can use Get/SetBusData.
  624. //
  625. fdoExtension->ValidBusInterface =
  626. NT_SUCCESS(VpGetBusInterface(fdoExtension));
  627. requirements = irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  628. if (requirements) {
  629. //
  630. // Append any legacy resources decoded by the device.
  631. //
  632. if (DriverObjectExtension->HwInitData.HwInitDataSize >
  633. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) {
  634. if( requirements->InterfaceType == PCIBus )
  635. {
  636. PCI_COMMON_CONFIG ConfigSpace;
  637. VideoPortGetBusData((PVOID)((ULONG_PTR)(fdoExtension) +
  638. sizeof(FDO_EXTENSION) +
  639. sizeof(DEVICE_SPECIFIC_EXTENSION)),
  640. PCIConfiguration,
  641. 0,
  642. &ConfigSpace,
  643. 0,
  644. PCI_COMMON_HDR_LENGTH);
  645. if (((ConfigSpace.BaseClass == PCI_CLASS_PRE_20) &&
  646. (ConfigSpace.SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
  647. ((ConfigSpace.BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
  648. (ConfigSpace.SubClass == PCI_SUBCLASS_VID_VGA_CTLR))) {
  649. if (pVideoPortGetVgaStatusPci((PVOID)((ULONG_PTR)(fdoExtension) + sizeof(FDO_EXTENSION) + sizeof(DEVICE_SPECIFIC_EXTENSION)))) {
  650. if (DriverObjectExtension->HwInitData.HwInitDataSize >
  651. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwGetLegacyResources)) {
  652. if (DriverObjectExtension->HwInitData.HwGetLegacyResources) {
  653. //
  654. // If the miniport supplied a HwGetLegacyResources routine
  655. // it wasn't able to give us a list of resources at
  656. // DriverEntry time. We'll give it a vendor/device id now
  657. // and see if it can give us a list of resources.
  658. //
  659. DriverObjectExtension->HwInitData.HwGetLegacyResources(
  660. ConfigSpace.VendorID,
  661. ConfigSpace.DeviceID,
  662. &DriverObjectExtension->HwInitData.HwLegacyResourceList,
  663. &DriverObjectExtension->HwInitData.HwLegacyResourceCount
  664. );
  665. }
  666. }
  667. if (DriverObjectExtension->HwInitData.HwLegacyResourceList) {
  668. if (VgaHwDeviceExtension) {
  669. ULONG Count;
  670. PVIDEO_ACCESS_RANGE AccessRange;
  671. Count = DriverObjectExtension->HwInitData.HwLegacyResourceCount;
  672. AccessRange = DriverObjectExtension->HwInitData.HwLegacyResourceList;
  673. //
  674. // Mark VGA resources as shared if the vga driver is
  675. // already loaded. Otherwise the PnP driver won't
  676. // be able to start.
  677. //
  678. while (Count--) {
  679. if (VpIsVgaResource(AccessRange)) {
  680. AccessRange->RangeShareable = TRUE;
  681. }
  682. AccessRange++;
  683. }
  684. }
  685. VpAppendToRequirementsList(
  686. DeviceObject,
  687. &requirements,
  688. DriverObjectExtension->HwInitData.HwLegacyResourceCount,
  689. DriverObjectExtension->HwInitData.HwLegacyResourceList);
  690. } else {
  691. //
  692. // The driver didn't specify legacy resources, but we
  693. // know that it is a VGA, so add in the vga resources.
  694. //
  695. pVideoDebugPrint((1, "VGA device didn't specify legacy resources.\n"));
  696. DriverObjectExtension->HwInitData.HwLegacyResourceCount = NUM_VGA_LEGACY_RESOURCES;
  697. DriverObjectExtension->HwInitData.HwLegacyResourceList = VgaLegacyResources;
  698. VpAppendToRequirementsList(
  699. DeviceObject,
  700. &requirements,
  701. NUM_VGA_LEGACY_RESOURCES,
  702. VgaLegacyResources);
  703. }
  704. }
  705. }
  706. }
  707. }
  708. //
  709. // Now if there is an interrupt in the list, but
  710. // the miniport didn't register an ISR, then
  711. // release our claim on the interrupt.
  712. //
  713. if (!DriverObjectExtension->HwInitData.HwInterrupt) {
  714. PIO_RESOURCE_LIST resourceList;
  715. ULONG i;
  716. //
  717. // Scan the IO_RESOURCE_REQUIREMENTS_LIST for an
  718. // interrupt.
  719. //
  720. resourceList = requirements->List;
  721. for (i=0; i<resourceList->Count; i++) {
  722. if (resourceList->Descriptors[i].Type == CmResourceTypeInterrupt) {
  723. //
  724. // We found an interrupt resource swap with last
  725. // element in list, and decrement structure size and
  726. // list count.
  727. //
  728. resourceList->Descriptors[i].Type = CmResourceTypeNull;
  729. pVideoDebugPrint((1, "Removing Int from requirements list.\n"));
  730. }
  731. }
  732. }
  733. } else {
  734. pVideoDebugPrint((0, "We expected a list of resources!\n"));
  735. ASSERT(FALSE);
  736. }
  737. statusBlock->Information = (ULONG_PTR) requirements;
  738. statusBlock->Status = STATUS_SUCCESS;
  739. }
  740. break;
  741. case IRP_MN_START_DEVICE:
  742. {
  743. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  744. PCM_RESOURCE_LIST allocatedResources;
  745. PCM_RESOURCE_LIST translatedResources;
  746. UCHAR nextMiniport = FALSE;
  747. ULONG RawListSize;
  748. ULONG TranslatedListSize;
  749. pVideoDebugPrint((2, "IRP_MN_START_DEVICE\n"));
  750. //
  751. // Retrieve the data we cached away during VideoPortInitialize.
  752. //
  753. DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  754. IoGetDriverObjectExtension(
  755. DeviceObject->DriverObject,
  756. DeviceObject->DriverObject);
  757. ASSERT(DriverObjectExtension);
  758. //
  759. // Grab the allocated resource the system gave us.
  760. //
  761. allocatedResources =
  762. irpStack->Parameters.StartDevice.AllocatedResources;
  763. translatedResources =
  764. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  765. //
  766. // Filter out any resources that we added to the list
  767. // before passing the irp on to PCI.
  768. //
  769. if (DriverObjectExtension->HwInitData.HwInitDataSize >
  770. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) {
  771. if (DriverObjectExtension->HwInitData.HwLegacyResourceList) {
  772. if (allocatedResources) {
  773. irpStack->Parameters.StartDevice.AllocatedResources =
  774. VpRemoveFromResourceList(
  775. allocatedResources,
  776. DriverObjectExtension->HwInitData.HwLegacyResourceCount,
  777. DriverObjectExtension->HwInitData.HwLegacyResourceList);
  778. }
  779. if ((irpStack->Parameters.StartDevice.AllocatedResources !=
  780. allocatedResources) && translatedResources) {
  781. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated =
  782. VpRemoveFromResourceList(
  783. translatedResources,
  784. DriverObjectExtension->HwInitData.HwLegacyResourceCount,
  785. DriverObjectExtension->HwInitData.HwLegacyResourceList);
  786. }
  787. }
  788. }
  789. //
  790. // The first thing we need to do is send the START_DEVICE
  791. // irp on to our parent.
  792. //
  793. pVideoPortSendIrpToLowerDevice(DeviceObject, Irp);
  794. //
  795. // Restore the original resources.
  796. //
  797. if (irpStack->Parameters.StartDevice.AllocatedResources !=
  798. allocatedResources) {
  799. ExFreePool(irpStack->Parameters.StartDevice.AllocatedResources);
  800. irpStack->Parameters.StartDevice.AllocatedResources
  801. = allocatedResources;
  802. }
  803. if (irpStack->Parameters.StartDevice.AllocatedResourcesTranslated !=
  804. translatedResources) {
  805. ExFreePool(irpStack->Parameters.StartDevice.AllocatedResourcesTranslated);
  806. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated
  807. = translatedResources;
  808. }
  809. if (allocatedResources) {
  810. ASSERT(translatedResources);
  811. //
  812. // Cache assigned and translated resources.
  813. //
  814. RawListSize = GetCmResourceListSize(allocatedResources);
  815. TranslatedListSize = GetCmResourceListSize(translatedResources);
  816. ASSERT(RawListSize == TranslatedListSize);
  817. fdoExtension->RawResources = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  818. RawListSize +
  819. TranslatedListSize,
  820. VP_TAG);
  821. fdoExtension->TranslatedResources = (PCM_RESOURCE_LIST)
  822. ((PUCHAR)fdoExtension->RawResources + RawListSize);
  823. if (fdoExtension->RawResources == NULL) {
  824. statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
  825. break;
  826. }
  827. memcpy(fdoExtension->RawResources,
  828. allocatedResources,
  829. RawListSize);
  830. memcpy(fdoExtension->TranslatedResources,
  831. translatedResources,
  832. TranslatedListSize);
  833. }
  834. //
  835. // Get slot/function number
  836. //
  837. fdoExtension->SlotNumber = VpGetDeviceAddress(DeviceObject);
  838. //
  839. // Store the allocatedResources. This will allow us to
  840. // assign these resources when VideoPortGetAccessRanges
  841. // routines are called.
  842. //
  843. // NOTE: We do not actually have to copy the data, because
  844. // we are going to call FindAdapter in the context
  845. // of this function. So, this data will be intact
  846. // until we complete.
  847. //
  848. if ((allocatedResources != NULL) && (translatedResources != NULL)) {
  849. ULONG Count;
  850. PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc;
  851. Count = 0;
  852. InterruptDesc = RtlUnpackPartialDesc(CmResourceTypeInterrupt,
  853. translatedResources,
  854. &Count);
  855. fdoExtension->AllocatedResources = allocatedResources;
  856. fdoExtension->SystemIoBusNumber =
  857. allocatedResources->List->BusNumber;
  858. fdoExtension->AdapterInterfaceType =
  859. allocatedResources->List->InterfaceType;
  860. //
  861. // Tuck away the giblets we need for PnP interrupt support!
  862. //
  863. if (InterruptDesc) {
  864. fdoExtension->InterruptVector =
  865. InterruptDesc->u.Interrupt.Vector;
  866. fdoExtension->InterruptIrql =
  867. (KIRQL)InterruptDesc->u.Interrupt.Level;
  868. fdoExtension->InterruptAffinity =
  869. InterruptDesc->u.Interrupt.Affinity;
  870. }
  871. }
  872. ACQUIRE_DEVICE_LOCK (combinedExtension);
  873. if (VideoPortFindAdapter(DeviceObject->DriverObject,
  874. (PVOID)&(DriverObjectExtension->RegistryPath),
  875. &(DriverObjectExtension->HwInitData),
  876. NULL,
  877. DeviceObject,
  878. &nextMiniport) == NO_ERROR) {
  879. if (nextMiniport == TRUE) {
  880. pVideoDebugPrint((1, "VIDEOPRT: The Again parameter is ignored for PnP drivers.\n"));
  881. }
  882. statusBlock->Status = STATUS_SUCCESS;
  883. //
  884. // Only put the VGA device on the hibernation path. All other
  885. // devices should be allowed to turn off during hibernation or
  886. // shutdown.
  887. //
  888. // Note: This may change in the future if we decide to keep non-VGA
  889. // device (e.g. UGA primary display) on.
  890. //
  891. if (DeviceObject == DeviceOwningVga) {
  892. pVideoPortHibernateNotify(fdoExtension->AttachedDeviceObject, FALSE);
  893. fdoExtension->OnHibernationPath = TRUE;
  894. }
  895. //
  896. // If the system is already up and running, lets call
  897. // HwInitialize now. This will allow us to enumerate
  898. // children.
  899. //
  900. if (VpSystemInitialized) {
  901. VpEnableDisplay(fdoExtension, FALSE);
  902. if (fdoExtension->HwInitialize(fdoExtension->HwDeviceExtension)) {
  903. fdoExtension->HwInitStatus = HwInitSucceeded;
  904. } else {
  905. fdoExtension->HwInitStatus = HwInitFailed;
  906. }
  907. VpEnableDisplay(fdoExtension, TRUE);
  908. }
  909. //
  910. // Indicate that resources have been assigned to this device
  911. // so that a legacy driver can't acquire resources for the
  912. // same device.
  913. //
  914. AddToResourceList(fdoExtension->SystemIoBusNumber,
  915. fdoExtension->SlotNumber);
  916. } else {
  917. statusBlock->Status = STATUS_UNSUCCESSFUL;
  918. if (fdoExtension->RawResources) {
  919. ExFreePool(fdoExtension->RawResources);
  920. }
  921. }
  922. RELEASE_DEVICE_LOCK (combinedExtension);
  923. //
  924. // Do ACPI specific stuff
  925. //
  926. if (NT_SUCCESS(pVideoPortQueryACPIInterface(DoSpecificExtension)))
  927. {
  928. DoSpecificExtension->bACPI = TRUE;
  929. }
  930. }
  931. break;
  932. case IRP_MN_QUERY_ID:
  933. pVideoDebugPrint((2, "IRP_MN_QUERYID with DeviceObject %p\n", DeviceObject));
  934. //
  935. // Return the Hardware ID returned by the video miniport driver
  936. // if it is provided.
  937. //
  938. if (irpStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
  939. {
  940. VIDEO_CHILD_TYPE ChildType;
  941. VIDEO_CHILD_ENUM_INFO childEnumInfo;
  942. ULONG uId;
  943. ULONG unused;
  944. PUCHAR nameBuffer;
  945. nameBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  946. EDID_BUFFER_SIZE,
  947. VP_TAG);
  948. if (nameBuffer)
  949. {
  950. RtlZeroMemory(nameBuffer, EDID_BUFFER_SIZE);
  951. childEnumInfo.Size = sizeof(VIDEO_CHILD_ENUM_INFO);
  952. childEnumInfo.ChildDescriptorSize = EDID_BUFFER_SIZE;
  953. childEnumInfo.ChildIndex = DISPLAY_ADAPTER_HW_ID;
  954. childEnumInfo.ACPIHwId = 0;
  955. childEnumInfo.ChildHwDeviceExtension = NULL;
  956. ACQUIRE_DEVICE_LOCK (combinedExtension);
  957. if (fdoExtension->HwGetVideoChildDescriptor(
  958. fdoExtension->HwDeviceExtension,
  959. &childEnumInfo,
  960. &ChildType,
  961. nameBuffer,
  962. &uId,
  963. &unused) == ERROR_MORE_DATA)
  964. {
  965. statusBlock->Information = (ULONG_PTR) nameBuffer;
  966. statusBlock->Status = STATUS_SUCCESS;
  967. }
  968. RELEASE_DEVICE_LOCK (combinedExtension);
  969. }
  970. }
  971. goto CallNextDriver;
  972. case IRP_MN_QUERY_DEVICE_RELATIONS:
  973. pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_RELATIONS with DeviceObject\n"));
  974. pVideoDebugPrint((2, "\t\t DeviceObject %p, Type = ", DeviceObject));
  975. if (irpStack->Parameters.QueryDeviceRelations.Type == BusRelations) {
  976. pVideoDebugPrint((2, "BusRelations\n"));
  977. ACQUIRE_DEVICE_LOCK (combinedExtension);
  978. //
  979. // Disable VGA driver during the setup. Enumeration code
  980. // in the miniport can touch VGA registers.
  981. //
  982. if (VpSetupTypeAtBoot != SETUPTYPE_NONE)
  983. VpEnableDisplay(fdoExtension, FALSE);
  984. statusBlock->Status = pVideoPortEnumerateChildren(DeviceObject, Irp);
  985. //
  986. // Renable VGA driver back during the setup.
  987. //
  988. if (VpSetupTypeAtBoot != SETUPTYPE_NONE)
  989. VpEnableDisplay(fdoExtension, TRUE);
  990. RELEASE_DEVICE_LOCK (combinedExtension);
  991. if (!NT_SUCCESS(statusBlock->Status)) {
  992. goto Complete_Irp;
  993. }
  994. }
  995. goto CallNextDriver;
  996. case IRP_MN_QUERY_REMOVE_DEVICE:
  997. pVideoDebugPrint((2, "IRP_MN_QUERY_REMOVE_DEVICE\n"));
  998. statusBlock->Status = STATUS_UNSUCCESSFUL;
  999. break;
  1000. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1001. pVideoDebugPrint((2, "IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  1002. statusBlock->Status = STATUS_SUCCESS;
  1003. goto CallNextDriver;
  1004. case IRP_MN_REMOVE_DEVICE:
  1005. pVideoDebugPrint((2, "IRP_MN_REMOVE_DEVICE\n"));
  1006. VpDisableAdapterInterface(fdoExtension);
  1007. pVideoPortSendIrpToLowerDevice(DeviceObject, Irp);
  1008. #if REMOVE_LOCK_ENABLED
  1009. IoReleaseRemoveLockAndWait(pRemoveLock, Irp);
  1010. RemoveLockReleased = TRUE;
  1011. #endif
  1012. //
  1013. // If we are attached to another device, remove the attachment
  1014. //
  1015. if (fdoExtension->AttachedDeviceObject) {
  1016. IoDetachDevice(fdoExtension->AttachedDeviceObject);
  1017. }
  1018. //
  1019. // Remove the DeviceObject
  1020. //
  1021. IoDeleteDevice(DeviceObject);
  1022. statusBlock->Status = STATUS_SUCCESS;
  1023. break;
  1024. case IRP_MN_QUERY_INTERFACE:
  1025. //
  1026. // Normally I would only expect to get this IRP heading for
  1027. // an PDO. However, AndrewGo wants to be able to send down
  1028. // these IRP's and he only has an FDO. Instead of forcing
  1029. // him to get a PDO somehow, we'll just handle the irp for
  1030. // a FDO as well.
  1031. //
  1032. pVideoDebugPrint((2, "IRP_MN_QUERY_INTERFACE\n"));
  1033. ACQUIRE_DEVICE_LOCK (combinedExtension);
  1034. if ((fdoExtension->HwQueryInterface) &&
  1035. (fdoExtension->HwDeviceExtension) &&
  1036. (NO_ERROR == fdoExtension->HwQueryInterface(
  1037. fdoExtension->HwDeviceExtension,
  1038. (PQUERY_INTERFACE)
  1039. &irpStack->Parameters.QueryInterface)))
  1040. {
  1041. statusBlock->Status = STATUS_SUCCESS;
  1042. }
  1043. else if (!NT_SUCCESS(statusBlock->Status))
  1044. {
  1045. //
  1046. // The miniport didn't handle the QueryInterface request, see
  1047. // if its an interface the videoprt supports.
  1048. //
  1049. PQUERY_INTERFACE qi = (PQUERY_INTERFACE)
  1050. &irpStack->Parameters.QueryInterface;
  1051. //
  1052. // If we are responding to a known private GUID, expose
  1053. // the known GUID interface ourselves. Otherwise, pass
  1054. // on to the miniport driver.
  1055. //
  1056. if (IsEqualGUID(qi->InterfaceType, &GUID_AGP_INTERFACE)) {
  1057. PAGP_INTERFACE AgpInterface = (PAGP_INTERFACE)qi->Interface;
  1058. AgpInterface->Size = sizeof(AGP_INTERFACE);
  1059. AgpInterface->Version = AGP_INTERFACE_VERSION;
  1060. AgpInterface->Context = fdoExtension->HwDeviceExtension;
  1061. if (VideoPortGetAgpServices(fdoExtension->HwDeviceExtension,
  1062. &AgpInterface->AgpServices)) {
  1063. statusBlock->Status = STATUS_SUCCESS;
  1064. }
  1065. }
  1066. }
  1067. RELEASE_DEVICE_LOCK (combinedExtension);
  1068. goto CallNextDriver;
  1069. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1070. statusBlock->Status = STATUS_SUCCESS;
  1071. goto CallNextDriver;
  1072. default:
  1073. pVideoDebugPrint((2, "PNP minor function %x not supported - forwarding \n", irpStack->MinorFunction ));
  1074. goto CallNextDriver;
  1075. }
  1076. }
  1077. Complete_Irp:
  1078. //
  1079. // save the final status so we can return it after the IRP is completed.
  1080. //
  1081. finalStatus = statusBlock->Status;
  1082. #if REMOVE_LOCK_ENABLED
  1083. if (RemoveLockReleased == FALSE) {
  1084. IoReleaseRemoveLock(pRemoveLock, Irp);
  1085. }
  1086. #endif
  1087. IoCompleteRequest(Irp,
  1088. IO_VIDEO_INCREMENT);
  1089. return finalStatus;
  1090. CallNextDriver:
  1091. //
  1092. // Call the next driver in the chain.
  1093. //
  1094. IoCopyCurrentIrpStackLocationToNext(Irp);
  1095. finalStatus = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1096. #if REMOVE_LOCK_ENABLED
  1097. if (RemoveLockReleased == FALSE) {
  1098. IoReleaseRemoveLock(pRemoveLock, Irp);
  1099. }
  1100. #endif
  1101. return finalStatus;
  1102. }
  1103. VOID
  1104. InitializePowerStruct(
  1105. IN PIRP Irp,
  1106. OUT PVIDEO_POWER_MANAGEMENT vpPower,
  1107. OUT BOOLEAN *bWakeUp
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. This routine initializes the power management structure we'll pass
  1112. down to the miniport.
  1113. Arguments:
  1114. DeviceObject - The device object for the device.
  1115. Irp - The irp we are handling
  1116. vpPower - A pointer to the power structure we are initializing.
  1117. Returns:
  1118. none.
  1119. --*/
  1120. {
  1121. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1122. if (bWakeUp)
  1123. *bWakeUp = FALSE;
  1124. //
  1125. // Setup for call to the miniport.
  1126. //
  1127. vpPower->Length = sizeof(VIDEO_POWER_MANAGEMENT);
  1128. vpPower->DPMSVersion = 0;
  1129. vpPower->PowerState = irpStack->Parameters.Power.State.DeviceState;
  1130. //
  1131. // Special case hibernation.
  1132. //
  1133. if (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate)
  1134. {
  1135. //
  1136. // This indicates waking from Hibernation.
  1137. //
  1138. if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)
  1139. {
  1140. if (bWakeUp)
  1141. {
  1142. *bWakeUp = TRUE;
  1143. }
  1144. }
  1145. else
  1146. {
  1147. vpPower->PowerState = VideoPowerHibernate;
  1148. }
  1149. }
  1150. else if ((irpStack->Parameters.Power.ShutdownType >= PowerActionShutdown) &&
  1151. (irpStack->Parameters.Power.ShutdownType < PowerActionWarmEject))
  1152. {
  1153. //
  1154. // Special case shutdown - force VideoPowerShutdown.
  1155. //
  1156. // All video adapters must disable interrupts else they may fire an interrupt
  1157. // when the bridge is disabled or when the machine reboots missing #RST on
  1158. // PCI bus causing an interrupt storm.
  1159. //
  1160. // Devices on hibernation path must stay on, the miniport driver must ensure
  1161. // this.
  1162. //
  1163. vpPower->PowerState = VideoPowerShutdown;
  1164. }
  1165. }
  1166. NTSTATUS
  1167. pVideoPortPowerDispatch(
  1168. IN PDEVICE_OBJECT DeviceObject,
  1169. IN PIRP Irp
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. This routine is a system-defined dispatch routine that handles all
  1174. I/O request packets (IRPs) specifically for power. Currently that
  1175. list entails:
  1176. IRP_MJ_POWER:
  1177. IRP_MN_SET_POWER
  1178. IRP_MN_QUERY_POWER
  1179. This routine will process the IRPs as a bus driver for the monitor
  1180. and child device objects and will process the IRPs as a function
  1181. driver for the adapter device object.
  1182. Arguments:
  1183. DeviceObject - Points to the DEVICE_OBJECT that this request is
  1184. targeting.
  1185. Irp - Points to the IRP for this request.
  1186. Return Value:
  1187. A NTSTATUS value indicating the success or failure of the operation.
  1188. --*/
  1189. {
  1190. PFDO_EXTENSION fdoExtension;
  1191. PCHILD_PDO_EXTENSION pdoExtension = NULL;
  1192. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  1193. PIO_STACK_LOCATION irpStack;
  1194. ULONG deviceId;
  1195. VP_STATUS vpStatus;
  1196. VIDEO_POWER_MANAGEMENT vpPowerMgmt;
  1197. POWER_STATE powerState;
  1198. KEVENT event;
  1199. POWER_BLOCK context;
  1200. BOOLEAN bDisplayAdapter;
  1201. BOOLEAN bMonitor;
  1202. BOOLEAN bShutdown;
  1203. NTSTATUS finalStatus = STATUS_SOME_NOT_MAPPED;
  1204. PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
  1205. PDEVICE_OBJECT AttachedDevice = NULL;
  1206. ULONG ulACPIMethodParam1;
  1207. BOOLEAN bSetBacklight = FALSE;
  1208. PAGED_CODE();
  1209. //
  1210. // Get pointer to the port driver's device extension.
  1211. //
  1212. if (IS_PDO(DeviceObject->DeviceExtension)) {
  1213. pVideoDebugPrint((2, "VideoPortPowerDispatch: IS_PDO == TRUE (child device)\n"));
  1214. pdoExtension = DeviceObject->DeviceExtension;
  1215. fdoExtension = pdoExtension->pFdoExtension;
  1216. bDisplayAdapter = FALSE;
  1217. if (pdoExtension->VideoChildDescriptor->Type == Monitor) {
  1218. bMonitor = TRUE;
  1219. } else {
  1220. bMonitor = FALSE;
  1221. }
  1222. } else if (IS_FDO(DeviceObject->DeviceExtension)) {
  1223. pVideoDebugPrint((2, "VideoPortPowerDispatch: IS_FDO == TRUE (video adapter)\n"));
  1224. fdoExtension = DeviceObject->DeviceExtension;
  1225. DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
  1226. bDisplayAdapter = TRUE;
  1227. bMonitor = FALSE;
  1228. } else {
  1229. //
  1230. // This case should never happen, if we got here something went terribly wrong.
  1231. //
  1232. pVideoDebugPrint((0, "VideoPortPowerDispatch: IRP not supported by secondary DeviceObject\n"));
  1233. ASSERT(FALSE);
  1234. //
  1235. // Since this should never happen we don't really need this code here.
  1236. // We're keeping it for now just in case of impossible happening.
  1237. //
  1238. PoStartNextPowerIrp(Irp);
  1239. finalStatus = Irp->IoStatus.Status;
  1240. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1241. return finalStatus;
  1242. }
  1243. //
  1244. // Make sure that FindAdapter has succeeded. This ensures
  1245. // that in the situation where a power IRP is sent before the
  1246. // device is started, no attempt to process it is made.
  1247. //
  1248. if (bDisplayAdapter) {
  1249. if ((fdoExtension->Flags & FINDADAPTER_SUCCEEDED) == 0) {
  1250. pVideoDebugPrint ((1, "VideoPortPowerDispatch: Ignoring S IRP\n"));
  1251. PoStartNextPowerIrp(Irp);
  1252. IoSkipCurrentIrpStackLocation (Irp);
  1253. return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1254. }
  1255. }
  1256. //
  1257. // Initialize the event that is used to synchronize the IRP
  1258. // completions. Also initialize the power context structure.
  1259. //
  1260. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1261. context.Event = &event;
  1262. //
  1263. // Obtain information about the specific request.
  1264. //
  1265. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1266. //
  1267. // Check if this is a shutdown.
  1268. //
  1269. if ((irpStack->Parameters.Power.ShutdownType >= PowerActionShutdown) &&
  1270. (irpStack->Parameters.Power.ShutdownType < PowerActionWarmEject)) {
  1271. bShutdown = TRUE;
  1272. } else {
  1273. bShutdown = FALSE;
  1274. }
  1275. //
  1276. // Set device id.
  1277. //
  1278. deviceId = bDisplayAdapter ? DISPLAY_ADAPTER_HW_ID : pdoExtension->ChildUId;
  1279. //
  1280. // Begin the switch for handling power IRPs
  1281. //
  1282. switch (irpStack->MinorFunction) {
  1283. case IRP_MN_QUERY_POWER:
  1284. //
  1285. // Is this a system or device power IRP?
  1286. //
  1287. if (irpStack->Parameters.Power.Type == SystemPowerState) {
  1288. pVideoDebugPrint((2, "VideoPortPowerDispatch: System query power IRP\n"));
  1289. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject));
  1290. pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n",
  1291. irpStack->Parameters.Power.State.SystemState));
  1292. //
  1293. // This is a system power IRP. The objective here is to
  1294. // quickly determine if we can safely support a proposed
  1295. // transition to the requested system power state.
  1296. //
  1297. if (!pVideoPortMapStoD(DeviceObject->DeviceExtension,
  1298. irpStack->Parameters.Power.State.SystemState,
  1299. &powerState.DeviceState)) {
  1300. pVideoDebugPrint((0, "VideoPortPowerDispatch: Couldn't get S->D mapping\n"));
  1301. finalStatus = STATUS_UNSUCCESSFUL;
  1302. break;
  1303. }
  1304. //
  1305. // Mark the IRP as pending now as unless there is a failure,
  1306. // this IRP will be returned with status_pending.
  1307. //
  1308. IoMarkIrpPending(Irp);
  1309. //
  1310. // Request the power IRP and go.
  1311. //
  1312. finalStatus = PoRequestPowerIrp(DeviceObject,
  1313. IRP_MN_QUERY_POWER,
  1314. powerState,
  1315. pVideoPortPowerIrpComplete,
  1316. Irp,
  1317. NULL);
  1318. } else {
  1319. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device query power IRP\n"));
  1320. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject));
  1321. pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n",
  1322. irpStack->Parameters.Power.State.DeviceState));
  1323. InitializePowerStruct(Irp, &vpPowerMgmt, NULL);
  1324. //
  1325. // For OEMs like Toshiba, they want alway map sleep state to D3 due to a
  1326. // legal patent issue. The patent prohibit them from using more than one
  1327. // sleep state.
  1328. //
  1329. if (bMonitor &&
  1330. fdoExtension->OverrideMonitorPower &&
  1331. (vpPowerMgmt.PowerState >= VideoPowerStandBy) &&
  1332. (vpPowerMgmt.PowerState < VideoPowerOff)) {
  1333. vpPowerMgmt.PowerState = VideoPowerOff;
  1334. }
  1335. //
  1336. // Call the miniport. No need to acquire the miniport lock as
  1337. // power IRP's are serial.
  1338. //
  1339. ACQUIRE_DEVICE_LOCK(fdoExtension);
  1340. vpStatus = fdoExtension->HwGetPowerState(fdoExtension->HwDeviceExtension,
  1341. deviceId,
  1342. &vpPowerMgmt);
  1343. RELEASE_DEVICE_LOCK(fdoExtension);
  1344. if (vpStatus != NO_ERROR) {
  1345. pVideoDebugPrint((1, "VideoPortPowerDispatch: Mini refused state %d\n",
  1346. vpPowerMgmt.PowerState));
  1347. //
  1348. // If this is the shutdown ignore miniport. We should never ever get
  1349. // here, since shutdown IRPs are unconditional, i.e. we're getting only
  1350. // set requests, which are by definition unfailable, but this is just in
  1351. // case power folks change their minds.
  1352. //
  1353. if (bShutdown) {
  1354. pVideoDebugPrint ((1, "VideoPortPowerDispatch: Ignoring miniport - forcing shutdown\n"));
  1355. finalStatus = STATUS_SUCCESS;
  1356. } else {
  1357. finalStatus = STATUS_DEVICE_POWER_FAILURE;
  1358. }
  1359. } else {
  1360. finalStatus = STATUS_SUCCESS;
  1361. }
  1362. }
  1363. //
  1364. // End processing for IRP_MN_QUERY_POWER. Indicate to the system that
  1365. // the next PowerIrp can be sent.
  1366. //
  1367. break;
  1368. case IRP_MN_SET_POWER:
  1369. if (irpStack->Parameters.Power.Type == SystemPowerState) {
  1370. pVideoDebugPrint((2, "VideoPortPowerDispatch: System set power IRP\n")) ;
  1371. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)) ;
  1372. pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n",
  1373. irpStack->Parameters.Power.State.SystemState)) ;
  1374. //
  1375. // Special case:
  1376. //
  1377. // The power guys decided they don't want us to send a D3 set power irp for our devices
  1378. // down the stack if we are going to leave the device on during the shutdown.
  1379. // We want to notify miniport driver but we're not going to request D3 irp.
  1380. //
  1381. // Note: We handle calls to miniport here for all devices on hibernation path at the
  1382. // shutdown (pdo and fdo) since we don't want to get out of order calls.
  1383. //
  1384. if (bShutdown && fdoExtension->OnHibernationPath) {
  1385. //
  1386. // Call the miniport if device is on now.
  1387. //
  1388. powerState.DeviceState = bDisplayAdapter ?
  1389. fdoExtension->DevicePowerState:
  1390. pdoExtension->DevicePowerState;
  1391. if (powerState.DeviceState == PowerDeviceD0) {
  1392. vpPowerMgmt.Length = sizeof(VIDEO_POWER_MANAGEMENT);
  1393. vpPowerMgmt.DPMSVersion = 0;
  1394. vpPowerMgmt.PowerState = VideoPowerShutdown;
  1395. pVideoDebugPrint((2, "VideoPortPowerDispatch: HwSetPowerState for video power state %d\n",
  1396. vpPowerMgmt.PowerState));
  1397. ACQUIRE_DEVICE_LOCK(fdoExtension);
  1398. vpStatus = fdoExtension->HwSetPowerState(fdoExtension->HwDeviceExtension,
  1399. deviceId,
  1400. &vpPowerMgmt);
  1401. RELEASE_DEVICE_LOCK(fdoExtension);
  1402. if (vpStatus != NO_ERROR) {
  1403. pVideoDebugPrint((0, "VideoPortPowerDispatch: ERROR IN MINIPORT!\n"));
  1404. pVideoDebugPrint((0, "VideoPortPowerDispatch: Miniport cannot refuse set power request\n"));
  1405. //
  1406. // Don't assert here for now - not all miniport drivers handle VideoPowerShutdown.
  1407. //
  1408. }
  1409. }
  1410. finalStatus = STATUS_SUCCESS;
  1411. break;
  1412. }
  1413. //
  1414. // If this is a S0 request for the monitor, ignore it (this is
  1415. // so the monitor doesn't power up too early)
  1416. //
  1417. if (bMonitor && (irpStack->Parameters.Power.State.SystemState == PowerSystemWorking)) {
  1418. finalStatus = STATUS_SUCCESS;
  1419. break;
  1420. }
  1421. //
  1422. // Get the device power state that matches the system power
  1423. // state.
  1424. //
  1425. if (!pVideoPortMapStoD(DeviceObject->DeviceExtension,
  1426. irpStack->Parameters.Power.State.SystemState,
  1427. &powerState.DeviceState)) {
  1428. pVideoDebugPrint((0, "VideoPortPowerDispatch: Couldn't get S->D mapping\n"));
  1429. pVideoDebugPrint((0, "VideoPortPowerDispatch: Can't fail the set!!!\n"));
  1430. if (irpStack->Parameters.Power.State.SystemState < PowerSystemSleeping1) {
  1431. powerState.DeviceState = PowerDeviceD0;
  1432. } else {
  1433. powerState.DeviceState = PowerDeviceD3;
  1434. }
  1435. }
  1436. //
  1437. // Request a power IRP for a device power state.
  1438. //
  1439. IoMarkIrpPending(Irp);
  1440. finalStatus = PoRequestPowerIrp(DeviceObject,
  1441. IRP_MN_SET_POWER,
  1442. powerState,
  1443. pVideoPortPowerIrpComplete,
  1444. Irp,
  1445. NULL);
  1446. } else {
  1447. BOOLEAN bWakeUp;
  1448. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device set power IRP\n")) ;
  1449. pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)) ;
  1450. pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n",
  1451. irpStack->Parameters.Power.State.DeviceState)) ;
  1452. //
  1453. // This is a set power request (device request). Here the
  1454. // processing becomes a little more complex. The general
  1455. // behavior is to just quickly tell the miniport to set
  1456. // the requested power state and get out. However, in the
  1457. // case of a hibernation request we will pass a special
  1458. // code to the miniport telling it that this is hibernation.
  1459. // It should save state, but NOT (repeat) NOT power off the
  1460. // device.
  1461. //
  1462. InitializePowerStruct(Irp, &vpPowerMgmt, &bWakeUp);
  1463. powerState.DeviceState = bDisplayAdapter ?
  1464. fdoExtension->DevicePowerState:
  1465. pdoExtension->DevicePowerState;
  1466. //
  1467. // Make sure not to power up the monitor if the override for
  1468. // LCD panels is on.
  1469. //
  1470. if (bMonitor && pdoExtension->PowerOverride &&
  1471. (irpStack->Parameters.Power.State.DeviceState < powerState.DeviceState)) {
  1472. finalStatus = STATUS_SUCCESS;
  1473. break;
  1474. }
  1475. //
  1476. // If this is going to a more powered state. (i.e. waking up)
  1477. // Send the IRP down the stack and then continue processing.
  1478. // Since videoport is the bus driver for the monitors,
  1479. // power down without sending the IRP to the device stack.
  1480. //
  1481. if (bDisplayAdapter &&
  1482. (irpStack->Parameters.Power.State.DeviceState < powerState.DeviceState)) {
  1483. pVideoDebugPrint ((1, "VideoPortPowerDispatch: PowerUp\n"));
  1484. context.Event = &event;
  1485. IoCopyCurrentIrpStackLocationToNext (Irp);
  1486. IoSetCompletionRoutine(Irp,
  1487. pVideoPortPowerUpComplete,
  1488. &context,
  1489. TRUE,
  1490. TRUE,
  1491. TRUE);
  1492. finalStatus = PoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1493. if (!NT_SUCCESS(finalStatus) || finalStatus == STATUS_PENDING) {
  1494. if (finalStatus != STATUS_PENDING) {
  1495. pVideoDebugPrint((0, "VideoPortPowerDispatch: Someone under us FAILED a set power???\n")) ;
  1496. ASSERT(FALSE);
  1497. break;
  1498. } else {
  1499. KeWaitForSingleObject(&event,
  1500. Executive,
  1501. KernelMode,
  1502. FALSE,
  1503. NULL);
  1504. }
  1505. } else {
  1506. context.Status = finalStatus;
  1507. }
  1508. finalStatus = STATUS_ALREADY_DISCONNECTED;
  1509. //
  1510. // End processing if the call to power up failed.
  1511. //
  1512. if (!NT_SUCCESS(context.Status)) {
  1513. pVideoDebugPrint ((0, "VideoPortPowerDispatch: Someone under us FAILED a powerup\n")) ;
  1514. break ;
  1515. }
  1516. }
  1517. //
  1518. // For OEMs like Toshiba, they want alway map sleep state to D3 due to a
  1519. // legal patent issue. The patent prohibit them from using more than one
  1520. // sleep state.
  1521. //
  1522. if (bMonitor &&
  1523. fdoExtension->OverrideMonitorPower &&
  1524. (vpPowerMgmt.PowerState >= VideoPowerStandBy) &&
  1525. (vpPowerMgmt.PowerState < VideoPowerOff)) {
  1526. vpPowerMgmt.PowerState = VideoPowerOff;
  1527. }
  1528. if ((deviceId == 0x110) &&
  1529. (vpPowerMgmt.PowerState == VideoPowerOn))
  1530. {
  1531. //
  1532. // If the new backlight control interface is implemented,
  1533. // set the backlight brightness level.
  1534. //
  1535. if ((pVpBacklightStatus->bNewAPISupported == TRUE) &&
  1536. (pVpBacklightStatus->bACBrightnessKnown == TRUE) &&
  1537. (VpRunningOnAC == TRUE))
  1538. {
  1539. ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucACBrightness;
  1540. bSetBacklight = TRUE;
  1541. }
  1542. if ((pVpBacklightStatus->bNewAPISupported == TRUE) &&
  1543. (pVpBacklightStatus->bDCBrightnessKnown == TRUE) &&
  1544. (VpRunningOnAC == FALSE))
  1545. {
  1546. ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucDCBrightness;
  1547. bSetBacklight = TRUE;
  1548. }
  1549. if ((bSetBacklight) && (LCDPanelDevice))
  1550. {
  1551. AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
  1552. // Not checking status here deliberately, as we're not failing
  1553. // this IRP if this call fails.
  1554. if (AttachedDevice) {
  1555. pVideoPortACPIIoctl(
  1556. AttachedDevice,
  1557. (ULONG) ('MCB_'),
  1558. &ulACPIMethodParam1,
  1559. NULL,
  1560. 0,
  1561. NULL);
  1562. ObDereferenceObject(AttachedDevice);
  1563. }
  1564. }
  1565. }
  1566. //
  1567. // Call the miniport.
  1568. //
  1569. pVideoDebugPrint((2, "VideoPortPowerDispatch: HwSetPowerState for video power state %d\n",
  1570. vpPowerMgmt.PowerState));
  1571. ACQUIRE_DEVICE_LOCK(fdoExtension);
  1572. vpStatus = fdoExtension->HwSetPowerState(fdoExtension->HwDeviceExtension,
  1573. deviceId,
  1574. &vpPowerMgmt);
  1575. RELEASE_DEVICE_LOCK(fdoExtension);
  1576. if (vpStatus != NO_ERROR) {
  1577. pVideoDebugPrint((0, "VideoPortPowerDispatch: ERROR IN MINIPORT!\n"));
  1578. pVideoDebugPrint((0, "VideoPortPowerDispatch: Miniport cannot refuse set power request\n"));
  1579. //
  1580. // Don't assert if shutdown - not all miniport drivers handle VideoPowerShutdown.
  1581. // This code executes for devices not on the hibernation path during the shutdown.
  1582. //
  1583. if (!bShutdown)
  1584. {
  1585. ASSERT(FALSE);
  1586. }
  1587. }
  1588. //
  1589. // Set the power state to let the system know that the power
  1590. // state has been changed for the device.
  1591. //
  1592. PoSetPowerState(DeviceObject,
  1593. DevicePowerState,
  1594. irpStack->Parameters.Power.State);
  1595. if (bDisplayAdapter) {
  1596. fdoExtension->DevicePowerState =
  1597. irpStack->Parameters.Power.State.DeviceState;
  1598. } else {
  1599. pdoExtension->DevicePowerState =
  1600. irpStack->Parameters.Power.State.DeviceState;
  1601. }
  1602. //
  1603. // Do some ACPI related stuff.
  1604. //
  1605. if (bDisplayAdapter && DoSpecificExtension->bACPI && (fdoExtension->DevicePowerState == PowerDeviceD0)) {
  1606. //
  1607. // If we received a Notify before SetPowerState, delay the action until now.
  1608. //
  1609. if (DoSpecificExtension->CachedEventID) {
  1610. pVideoPortACPIEventCallback(DoSpecificExtension, DoSpecificExtension->CachedEventID);
  1611. } else if (bWakeUp) {
  1612. //
  1613. // On waking up from Hibernation, we simulate a notify(VGA, 0x90).
  1614. // This will also set _DOS(0). Some machines don't keep _DOS value,
  1615. // So we have to set the value on waking up.
  1616. //
  1617. pVideoPortACPIEventCallback(DoSpecificExtension, 0x90);
  1618. }
  1619. }
  1620. //
  1621. // Set the final status if the IRP has not been passed down.
  1622. // If the IRP has not been passed down yet, finalStatus is set
  1623. // when it is passed down.
  1624. //
  1625. if (!bDisplayAdapter) {
  1626. //
  1627. // All PDO's must have STATUS_SUCCESS as a SET_POWER IRP
  1628. // cannot fail.
  1629. //
  1630. finalStatus = STATUS_SUCCESS;
  1631. }
  1632. }
  1633. break;
  1634. default:
  1635. //
  1636. // Pass down requests we don't handle if this is an fdo, complete
  1637. // the irp if it is a pdo.
  1638. //
  1639. if (bDisplayAdapter) {
  1640. PoStartNextPowerIrp(Irp);
  1641. IoSkipCurrentIrpStackLocation(Irp);
  1642. return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1643. } else {
  1644. PoStartNextPowerIrp(Irp);
  1645. finalStatus = Irp->IoStatus.Status;
  1646. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1647. return finalStatus;
  1648. }
  1649. }
  1650. //
  1651. // If status pending then just bail out of this routine
  1652. // without completing anything as there is still an power
  1653. // IRP outstanding. The completion routine takes care of
  1654. // ensuring that the IRP is completed.
  1655. //
  1656. if (finalStatus != STATUS_PENDING) {
  1657. //
  1658. // Alert the system that the driver is ready for the next power IRP.
  1659. //
  1660. PoStartNextPowerIrp(Irp);
  1661. //
  1662. // All processing has been finished. Complete the IRP and get out.
  1663. //
  1664. if (bDisplayAdapter) {
  1665. //
  1666. // FDO Irps need to be sent to the bus driver. This path
  1667. // indicates that it is an FDO Irp that has not already been
  1668. // sent to the bus driver. (The only way it would have already
  1669. // been sent is if this is an FDO power-up).
  1670. //
  1671. if (NT_SUCCESS(finalStatus)) {
  1672. pVideoDebugPrint((1, "VideoPortPowerDispatch: Non-powerup FDO\n"));
  1673. IoSkipCurrentIrpStackLocation (Irp);
  1674. return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1675. } else if (finalStatus == STATUS_ALREADY_DISCONNECTED) {
  1676. pVideoDebugPrint((2, "VideoPortPowerDispatch: Power iostatus modified, IRP already sent\n"));
  1677. finalStatus = context.Status;
  1678. }
  1679. pVideoDebugPrint((2, "VideoPortPowerDispatch: Power fell through bDisplayAdapter\n")) ;
  1680. }
  1681. pVideoDebugPrint((1, "VideoPortPowerDispatch: Power completed with %x\n", finalStatus));
  1682. Irp->IoStatus.Status = finalStatus;
  1683. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1684. }
  1685. return finalStatus;
  1686. }
  1687. BOOLEAN
  1688. pVideoPortMapStoD(
  1689. IN PVOID DeviceExtension,
  1690. IN SYSTEM_POWER_STATE SystemState,
  1691. OUT PDEVICE_POWER_STATE DeviceState
  1692. )
  1693. /*++
  1694. Routine Description:
  1695. This routine takes a system power state from a system power IRP and
  1696. maps it to the correct D state for the device based on what is stored
  1697. in its device extension.
  1698. Arguments:
  1699. DeviceExtension - Points to either the FDO or PDO device extension.
  1700. SystemState - The system power state being requested.
  1701. DeviceState - A pointer to the location to store the device state.
  1702. Return Value:
  1703. TRUE if successsful,
  1704. FALSE otherwise.
  1705. --*/
  1706. {
  1707. PFDO_EXTENSION combinedExtension = ((PFDO_EXTENSION)(DeviceExtension));
  1708. if (combinedExtension->IsMappingReady != TRUE) {
  1709. //
  1710. // The mapping from system states to device states has not
  1711. // happened yet. Package up a request to do this and send it
  1712. // to the parent device stack.
  1713. //
  1714. PIRP irp;
  1715. KEVENT event;
  1716. PDEVICE_CAPABILITIES parentCapabilities;
  1717. IO_STATUS_BLOCK statusBlock;
  1718. PIO_STACK_LOCATION stackLocation;
  1719. NTSTATUS status;
  1720. UCHAR count;
  1721. PDEVICE_OBJECT targetDevice;
  1722. pVideoDebugPrint((1, "VideoPrt: No mapping ready. Creating mapping.\n"));
  1723. if (IS_FDO(combinedExtension)) {
  1724. targetDevice = combinedExtension->AttachedDeviceObject;
  1725. } else {
  1726. targetDevice = combinedExtension->pFdoExtension->AttachedDeviceObject;
  1727. }
  1728. //
  1729. // Allocate memory for the device capabilities structure and
  1730. // zero the memory.
  1731. //
  1732. parentCapabilities = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  1733. sizeof (DEVICE_CAPABILITIES),
  1734. VP_TAG);
  1735. if (parentCapabilities == NULL) {
  1736. pVideoDebugPrint((0, "VideoPrt: Couldn't get memory for cap run.\n"));
  1737. return FALSE;
  1738. }
  1739. RtlZeroMemory(parentCapabilities, sizeof (DEVICE_CAPABILITIES));
  1740. parentCapabilities->Size = sizeof (DEVICE_CAPABILITIES) ;
  1741. parentCapabilities->Version = 1 ;
  1742. parentCapabilities->Address = -1 ;
  1743. parentCapabilities->UINumber = -1 ;
  1744. //
  1745. // Prepare the IRP request.
  1746. //
  1747. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1748. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  1749. targetDevice,
  1750. NULL,
  1751. 0,
  1752. NULL,
  1753. &event,
  1754. &statusBlock);
  1755. if (irp == NULL) {
  1756. pVideoDebugPrint((0, "VideoPrt: Couldn't get IRP for cap run.\n"));
  1757. ExFreePool(parentCapabilities);
  1758. return FALSE;
  1759. }
  1760. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1761. stackLocation = IoGetNextIrpStackLocation(irp);
  1762. stackLocation->MajorFunction = IRP_MJ_PNP;
  1763. stackLocation->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  1764. stackLocation->Parameters.DeviceCapabilities.Capabilities =
  1765. parentCapabilities;
  1766. status = IoCallDriver (targetDevice, irp);
  1767. if (status == STATUS_PENDING) {
  1768. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1769. }
  1770. if (!(NT_SUCCESS(statusBlock.Status))) {
  1771. pVideoDebugPrint ((0, "VideoPrt: Couldn't get parent caps.\n"));
  1772. } else {
  1773. for (count = PowerSystemUnspecified;
  1774. count < PowerSystemMaximum;
  1775. count++) {
  1776. #if DBG
  1777. static PUCHAR SystemState[] = {"PowerSystemUnspecified",
  1778. "PowerSystemWorking",
  1779. "PowerSystemSleeping1",
  1780. "PowerSystemSleeping2",
  1781. "PowerSystemSleeping3",
  1782. "PowerSystemHibernate",
  1783. "PowerSystemShutdown",
  1784. "PowerSystemMaximum"};
  1785. static PUCHAR DeviceState[] = {"PowerDeviceUnspecified",
  1786. "PowerDeviceD0",
  1787. "PowerDeviceD1",
  1788. "PowerDeviceD2",
  1789. "PowerDeviceD3",
  1790. "PowerDeviceMaximum"};
  1791. #endif
  1792. combinedExtension->DeviceMapping[count] =
  1793. parentCapabilities->DeviceState[count];
  1794. #if DBG
  1795. pVideoDebugPrint((1, "Mapping %s = %s\n",
  1796. SystemState[count],
  1797. DeviceState[combinedExtension->DeviceMapping[count]]));
  1798. #endif
  1799. }
  1800. //
  1801. // For monitor devices, make sure to map not to D0 for any sleep state.
  1802. //
  1803. if (IS_PDO(combinedExtension) &&
  1804. (((PCHILD_PDO_EXTENSION)(DeviceExtension))->VideoChildDescriptor->Type == Monitor))
  1805. {
  1806. for (count = PowerSystemSleeping1;
  1807. count <= PowerSystemSleeping3;
  1808. count++)
  1809. {
  1810. if ((combinedExtension->DeviceMapping[count] == PowerDeviceD0) ||
  1811. (combinedExtension->pFdoExtension->OverrideMonitorPower))
  1812. {
  1813. pVideoDebugPrint((1, "Override sleep %d to D3\n", count)) ;
  1814. combinedExtension->DeviceMapping[count] = PowerDeviceD3 ;
  1815. }
  1816. }
  1817. }
  1818. }
  1819. ExFreePool(parentCapabilities);
  1820. if (!NT_SUCCESS(statusBlock.Status)) {
  1821. return FALSE;
  1822. }
  1823. combinedExtension->IsMappingReady = TRUE ;
  1824. }
  1825. //
  1826. // Return the mapping now.
  1827. //
  1828. *DeviceState = combinedExtension->DeviceMapping[SystemState];
  1829. return TRUE;
  1830. }
  1831. VOID
  1832. pVideoPortPowerIrpComplete(
  1833. IN PDEVICE_OBJECT DeviceObject,
  1834. IN UCHAR MinorFunction,
  1835. IN POWER_STATE PowerState,
  1836. IN PVOID Context,
  1837. IN PIO_STATUS_BLOCK IoStatus
  1838. )
  1839. /*++
  1840. Routine Description:
  1841. This is a power management IRP completion routine that is set
  1842. each time video requests a device power IRP in response to a
  1843. system power IRP.
  1844. Arguments:
  1845. DeviceObject - Points to the device object that initiated the IRP
  1846. MinorFunction - Specified the minor function code of the completed IRP
  1847. PowerState - Specifies the power state passed to PoRequestPowerIrp
  1848. Context - Specifies the IRP that was pended waiting for this completion
  1849. routine to fire
  1850. IoStatus - Points to the IoStatus block in the completed IRP
  1851. Return Value:
  1852. None.
  1853. --*/
  1854. {
  1855. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension ;
  1856. PIRP irp = (PIRP) Context ;
  1857. if (Context == NULL) {
  1858. //
  1859. // This is the fall through case. Since we have no IRP this
  1860. // is just a place holder since callers of PoRequestPowerIrp
  1861. // must specify a completion routine.
  1862. //
  1863. return;
  1864. }
  1865. //
  1866. // Set the status in the IRP
  1867. //
  1868. irp->IoStatus.Status = IoStatus->Status;
  1869. pVideoDebugPrint((2, "VideoPrt: Power completion Irp status: %X\n",
  1870. IoStatus->Status));
  1871. //
  1872. // Indicate to the system that videoprt is ready for the next
  1873. // power IRP.
  1874. //
  1875. PoStartNextPowerIrp(irp);
  1876. //
  1877. // If this is an FDO, then pass the IRP down to the bus driver.
  1878. //
  1879. if (IS_FDO((PFDO_EXTENSION)(DeviceObject->DeviceExtension)) &&
  1880. NT_SUCCESS(IoStatus->Status)) {
  1881. pVideoDebugPrint((2, "VideoPrt: Completion passing down.\n"));
  1882. IoSkipCurrentIrpStackLocation(irp);
  1883. PoCallDriver(fdoExtension->AttachedDeviceObject, irp);
  1884. } else {
  1885. pVideoDebugPrint((2, "VideoPrt: Completion not passing down.\n"));
  1886. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1887. }
  1888. }
  1889. NTSTATUS
  1890. pVideoPortPowerUpComplete(
  1891. IN PDEVICE_OBJECT DeviceObject,
  1892. IN PIRP Irp,
  1893. IN PVOID Context
  1894. )
  1895. /*++
  1896. Routine Description:
  1897. This is an IRP completion routine that is set when a IRP must be
  1898. passed down the device stack before videoport acts on it. (A power
  1899. up case. The bus must be powered before the device.)
  1900. Arguments:
  1901. DeviceObject - Points to the device object of the owner of the
  1902. completion routine
  1903. Irp - Points to the IRP being completed
  1904. Context - Specifies a videoport-defined context of POWER_BLOCK
  1905. Return Value:
  1906. Always returns STATUS_MORE_PROCESSING_REQUIRED to stop further
  1907. completion of the IRP.
  1908. --*/
  1909. {
  1910. PPOWER_BLOCK block = (PPOWER_BLOCK)Context;
  1911. block->Status = Irp->IoStatus.Status;
  1912. KeSetEvent(block->Event, IO_NO_INCREMENT, FALSE);
  1913. return STATUS_MORE_PROCESSING_REQUIRED;
  1914. }
  1915. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  1916. RtlUnpackPartialDesc(
  1917. IN UCHAR Type,
  1918. IN PCM_RESOURCE_LIST ResList,
  1919. IN OUT PULONG Count
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. Pulls out a pointer to the partial descriptor you're interested in
  1924. Arguments:
  1925. Type - CmResourceTypePort, ...
  1926. ResList - The list to search
  1927. Count - Points to the index of the partial descriptor you're looking
  1928. for, gets incremented if found, i.e., start with *Count = 0,
  1929. then subsequent calls will find next partial, make sense?
  1930. Return Value:
  1931. Pointer to the partial descriptor if found, otherwise NULL
  1932. --*/
  1933. {
  1934. ULONG i, j, hit;
  1935. hit = 0;
  1936. for (i = 0; i < ResList->Count; i++) {
  1937. for (j = 0; j < ResList->List[i].PartialResourceList.Count; j++) {
  1938. if (ResList->List[i].PartialResourceList.PartialDescriptors[j].Type == Type) {
  1939. if (hit == *Count) {
  1940. (*Count)++;
  1941. return &ResList->List[i].PartialResourceList.PartialDescriptors[j];
  1942. } else {
  1943. hit++;
  1944. }
  1945. }
  1946. }
  1947. }
  1948. return NULL;
  1949. }
  1950. NTSTATUS
  1951. pVideoPortSystemControl(
  1952. IN PDEVICE_OBJECT DeviceObject,
  1953. IN PIRP Irp
  1954. )
  1955. /*++
  1956. Routine Description:
  1957. This routine handles SystemControl Irps.
  1958. Arguments:
  1959. DeviceObject - The device object.
  1960. Irp - The system control Irp.
  1961. Returns:
  1962. Status
  1963. Notes:
  1964. This function will simply complete the irp if we are handling for the PDO,
  1965. or send the irp down if the device object is an FDO.
  1966. --*/
  1967. {
  1968. NTSTATUS status;
  1969. if (IS_PDO(DeviceObject->DeviceExtension)) {
  1970. status = Irp->IoStatus.Status;
  1971. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1972. } else {
  1973. PFDO_EXTENSION fdoExtension = (PFDO_EXTENSION)DeviceObject->DeviceExtension;
  1974. IoCopyCurrentIrpStackLocationToNext(Irp);
  1975. status = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp);
  1976. }
  1977. return status;
  1978. }