Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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