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.

9648 lines
274 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. videoprt.c
  5. Abstract:
  6. This is the NT Video port driver.
  7. Author:
  8. Andre Vachon (andreva) 18-Dec-1991
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This module is a driver which implements OS dependant functions on the
  13. behalf of the video drivers
  14. Revision History:
  15. --*/
  16. #define INITGUID
  17. #include "videoprt.h"
  18. NTSTATUS
  19. DriverEntry(
  20. IN PDRIVER_OBJECT DriverObject,
  21. IN PUNICODE_STRING RegistryPath
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(INIT,DriverEntry)
  25. #pragma alloc_text(PAGE,pVideoPortCreateDeviceName)
  26. #pragma alloc_text(PAGE,pVideoPortDispatch)
  27. #pragma alloc_text(PAGE,VideoPortFreeDeviceBase)
  28. #pragma alloc_text(PAGE,pVideoPortFreeDeviceBase)
  29. #pragma alloc_text(PAGE,pVideoPortGetDeviceBase)
  30. #pragma alloc_text(PAGE,VideoPortGetDeviceBase)
  31. #pragma alloc_text(PAGE,pVideoPortGetDeviceDataRegistry)
  32. #pragma alloc_text(PAGE,VideoPortGetDeviceData)
  33. #pragma alloc_text(PAGE,pVideoPortGetRegistryCallback)
  34. #pragma alloc_text(PAGE,VideoPortGetRegistryParameters)
  35. #pragma alloc_text(PAGE,pVPInit)
  36. #pragma alloc_text(PAGE,VpInitializeBusCallback)
  37. #pragma alloc_text(PAGE,VpDriverUnload)
  38. #pragma alloc_text(PAGE,VpAddDevice)
  39. #pragma alloc_text(PAGE,VpCreateDevice)
  40. #pragma alloc_text(PAGE,VideoPortInitialize)
  41. #pragma alloc_text(PAGE,UpdateRegValue)
  42. #pragma alloc_text(PAGE,VideoPortLegacyFindAdapter)
  43. #pragma alloc_text(PAGE,VideoPortFindAdapter2)
  44. #pragma alloc_text(PAGE,VideoPortFindAdapter)
  45. #pragma alloc_text(PAGE,pVideoPortMapToNtStatus)
  46. #pragma alloc_text(PAGE,pVideoPortMapUserPhysicalMem)
  47. #pragma alloc_text(PAGE,VideoPortMapMemory)
  48. #pragma alloc_text(PAGE,VideoPortMapBankedMemory)
  49. #pragma alloc_text(PAGE,VideoPortAllocateBuffer)
  50. #pragma alloc_text(PAGE,VideoPortReleaseBuffer)
  51. #pragma alloc_text(PAGE,VideoPortScanRom)
  52. #pragma alloc_text(PAGE,VideoPortSetRegistryParameters)
  53. #pragma alloc_text(PAGE,VideoPortUnmapMemory)
  54. #pragma alloc_text(PAGE,VpEnableDisplay)
  55. #pragma alloc_text(PAGE,VpWin32kCallout)
  56. #pragma alloc_text(PAGE,VpAllowFindAdapter)
  57. #pragma alloc_text(PAGE,VpTranslateBusAddress)
  58. #if DBG
  59. #pragma alloc_text(PAGE,BuildRequirements)
  60. #pragma alloc_text(PAGE,DumpRequirements)
  61. #pragma alloc_text(PAGE,DumpResourceList)
  62. #pragma alloc_text(PAGE,DumpUnicodeString)
  63. #endif
  64. #pragma alloc_text(PAGE,VideoPortCreateSecondaryDisplay)
  65. #pragma alloc_text(PAGE,VideoPortQueryServices)
  66. #pragma alloc_text(PAGE,VpInterfaceDefaultReference)
  67. #pragma alloc_text(PAGE,VpInterfaceDefaultDereference)
  68. #pragma alloc_text(PAGE,VpEnableAdapterInterface)
  69. #pragma alloc_text(PAGE,VpDisableAdapterInterface)
  70. //
  71. // VideoPortQueryPerformanceCounter() cannot be pageable.
  72. //
  73. #endif
  74. NTSTATUS
  75. DriverEntry(
  76. IN PDRIVER_OBJECT DriverObject,
  77. IN PUNICODE_STRING RegistryPath
  78. )
  79. /*++
  80. Routine Description:
  81. Temporary entry point needed to initialize the video port driver.
  82. Arguments:
  83. DriverObject - Pointer to the driver object created by the system.
  84. Return Value:
  85. STATUS_SUCCESS
  86. --*/
  87. {
  88. UNREFERENCED_PARAMETER(DriverObject);
  89. ASSERT(0);
  90. //
  91. //
  92. //
  93. // WARNING !!!
  94. //
  95. // This function is never called because we are loaded as a DLL by other video drivers !
  96. //
  97. //
  98. //
  99. //
  100. //
  101. //
  102. // We always return STATUS_SUCCESS because otherwise no video miniport
  103. // driver will be able to call us.
  104. //
  105. return STATUS_SUCCESS;
  106. } // end DriverEntry()
  107. NTSTATUS
  108. pVideoPortCreateDeviceName(
  109. PWSTR DeviceString,
  110. ULONG DeviceNumber,
  111. PUNICODE_STRING UnicodeString,
  112. PWCHAR UnicodeBuffer
  113. )
  114. /*++
  115. Routine Description:
  116. Helper function that does string manipulation to create a device name
  117. --*/
  118. {
  119. WCHAR ntNumberBuffer[STRING_LENGTH];
  120. UNICODE_STRING ntNumberUnicodeString;
  121. //
  122. // Create the name buffer
  123. //
  124. UnicodeString->Buffer = UnicodeBuffer;
  125. UnicodeString->Length = 0;
  126. UnicodeString->MaximumLength = STRING_LENGTH;
  127. //
  128. // Create the miniport driver object name.
  129. //
  130. ntNumberUnicodeString.Buffer = ntNumberBuffer;
  131. ntNumberUnicodeString.Length = 0;
  132. ntNumberUnicodeString.MaximumLength = STRING_LENGTH;
  133. if (NT_SUCCESS(RtlIntegerToUnicodeString(DeviceNumber,
  134. 10,
  135. &ntNumberUnicodeString))) {
  136. if (NT_SUCCESS(RtlAppendUnicodeToString(UnicodeString,
  137. DeviceString))) {
  138. if (NT_SUCCESS(RtlAppendUnicodeStringToString(UnicodeString,
  139. &ntNumberUnicodeString))) {
  140. UnicodeString->MaximumLength = (USHORT)
  141. (UnicodeString->Length + sizeof(UNICODE_NULL));
  142. return STATUS_SUCCESS;
  143. }
  144. }
  145. }
  146. return STATUS_INSUFFICIENT_RESOURCES;
  147. } // pVideoPortCreateDeviceName()
  148. VOID
  149. VideoPortDebugPrint(
  150. VIDEO_DEBUG_LEVEL DebugPrintLevel,
  151. PCHAR DebugMessage,
  152. ...
  153. )
  154. /*++
  155. Routine Description:
  156. This routine allows the miniport drivers (as well as the port driver) to
  157. display error messages to the debug port when running in the debug
  158. environment.
  159. When running a non-debugged system, all references to this call are
  160. eliminated by the compiler.
  161. Arguments:
  162. DebugPrintLevel - Debug print level being:
  163. 0 = Error Level (always prints no matter what on a checked build)
  164. 1 = Warning Level (prints only when VIDEO filter is on for this level or higher)
  165. 2 = Trace Level (see above)
  166. 3 = Info Level (see above)
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. va_list ap;
  172. va_start(ap, DebugMessage);
  173. if (VideoDebugLevel && (VideoDebugLevel >= (ULONG)DebugPrintLevel)) {
  174. vDbgPrintEx(DPFLTR_VIDEO_ID, 0, DebugMessage, ap);
  175. } else {
  176. vDbgPrintEx(DPFLTR_VIDEO_ID, DebugPrintLevel, DebugMessage, ap);
  177. }
  178. va_end(ap);
  179. } // VideoPortDebugPrint()
  180. VOID
  181. VpEnableDisplay(
  182. PFDO_EXTENSION fdoExtension,
  183. BOOLEAN bState
  184. )
  185. /*++
  186. Routine Description:
  187. This routine enables/disables the current display so that we can execut
  188. the drivers FindAdapter code.
  189. Arugments:
  190. bState - Should the display be enabled or disabled
  191. Returns:
  192. none
  193. Notes:
  194. The device lock for the passed in fdoExtension must be held
  195. before this routine is called!
  196. --*/
  197. {
  198. if (!InbvCheckDisplayOwnership()) {
  199. VIDEO_WIN32K_CALLBACKS_PARAMS calloutParams;
  200. //
  201. // The system is up and running. Notify GDI to enable/disable
  202. // the current display.
  203. //
  204. calloutParams.CalloutType = VideoFindAdapterCallout;
  205. calloutParams.Param = bState;
  206. RELEASE_DEVICE_LOCK(fdoExtension);
  207. VpWin32kCallout(&calloutParams);
  208. ACQUIRE_DEVICE_LOCK(fdoExtension);
  209. } else {
  210. //
  211. // The boot driver is still in control. Modify the state of the
  212. // boot driver.
  213. //
  214. InbvEnableBootDriver(bState);
  215. }
  216. }
  217. VOID
  218. VpWin32kCallout(
  219. PVIDEO_WIN32K_CALLBACKS_PARAMS calloutParams
  220. )
  221. /*++
  222. Routine Description:
  223. This routine makes a callout into win32k. It attaches to csrss
  224. to guarantee that win32k is in the address space on hydra machines.
  225. Arguments:
  226. calloutParams - a pointer to the callout struture.
  227. Returns:
  228. none.
  229. --*/
  230. {
  231. if (Win32kCallout && CsrProcess) {
  232. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  233. (*Win32kCallout)(calloutParams);
  234. KeDetachProcess();
  235. }
  236. }
  237. BOOLEAN
  238. VpAllowFindAdapter(
  239. PFDO_EXTENSION fdoExtension
  240. )
  241. /*++
  242. Routine Description:
  243. Determine if we allow this device to be used if part of a multi-function
  244. board.
  245. Arguments;
  246. fdoExtension - The device extenstion for the object in question.
  247. Returns:
  248. TRUE if the device is allowed as part of a multi-function board.
  249. FALSE otherwise.
  250. --*/
  251. {
  252. BOOLEAN bRet = TRUE;
  253. if ((fdoExtension->AdapterInterfaceType == PCIBus) &&
  254. ((fdoExtension->Flags & PNP_ENABLED) == PNP_ENABLED)) {
  255. PCI_COMMON_CONFIG ConfigSpace;
  256. if (PCI_COMMON_HDR_LENGTH ==
  257. VideoPortGetBusData(fdoExtension->HwDeviceExtension,
  258. PCIConfiguration,
  259. 0,
  260. &ConfigSpace,
  261. 0,
  262. PCI_COMMON_HDR_LENGTH)) {
  263. if (PCI_MULTIFUNCTION_DEVICE(&ConfigSpace)) {
  264. ULONG MultiFunc = 0;
  265. //
  266. // This is a multi-function device. So only allow
  267. // HwInitialize if the INF indicated we'd be multi-function.
  268. //
  269. VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
  270. L"MultiFunctionSupported",
  271. FALSE,
  272. VpRegistryCallback,
  273. &MultiFunc);
  274. if (MultiFunc == 0) {
  275. pVideoDebugPrint((Warn, "VIDEOPRT: Multifunction board not allowed to start\n"));
  276. bRet = FALSE;
  277. }
  278. }
  279. }
  280. }
  281. return bRet;
  282. }
  283. NTSTATUS
  284. pVideoPortDispatch(
  285. IN PDEVICE_OBJECT DeviceObject,
  286. IN PIRP Irp
  287. )
  288. /*++
  289. Routine Description:
  290. This routine is the main dispatch routine for the video port driver.
  291. It accepts an I/O Request Packet, transforms it to a video Request
  292. Packet, and forwards it to the appropriate miniport dispatch routine.
  293. Upon returning, it completes the request and return the appropriate
  294. status value.
  295. Arguments:
  296. DeviceObject - Pointer to the device object of the miniport driver to
  297. which the request must be sent.
  298. Irp - Pointer to the request packet representing the I/O request.
  299. Return Value:
  300. The function value os the status of the operation.
  301. --*/
  302. {
  303. PFDO_EXTENSION combinedExtension;
  304. PFDO_EXTENSION fdoExtension;
  305. PVOID HwDeviceExtension;
  306. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  307. PCHILD_PDO_EXTENSION pdoExtension = NULL;
  308. PIO_STACK_LOCATION irpStack;
  309. PVOID ioBuffer;
  310. ULONG inputBufferLength;
  311. ULONG outputBufferLength;
  312. PSTATUS_BLOCK statusBlock;
  313. NTSTATUS finalStatus = -1;
  314. ULONG ioControlCode;
  315. VIDEO_REQUEST_PACKET vrp;
  316. NTSTATUS status;
  317. PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
  318. ULONG ulACPIMethodParam1;
  319. ULONG ulACPIMethodParam2;
  320. HANDLE hkRegistry;
  321. UNICODE_STRING UnicodeString;
  322. OBJECT_ATTRIBUTES ObjectAttributes;
  323. #if _X86_
  324. PUCHAR BiosDataBuffer;
  325. #define BIOS_DATA_SIZE 256
  326. #endif
  327. //
  328. // Get pointer to the port driver's device extension.
  329. //
  330. combinedExtension = DeviceObject->DeviceExtension;
  331. HwDeviceExtension = combinedExtension->HwDeviceExtension;
  332. //
  333. // Get pointer to the port driver's device extension.
  334. //
  335. if (IS_PDO(DeviceObject->DeviceExtension)) {
  336. pdoExtension = DeviceObject->DeviceExtension;
  337. fdoExtension = pdoExtension->pFdoExtension;
  338. DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
  339. } else if (IS_FDO(DeviceObject->DeviceExtension)) {
  340. fdoExtension = DeviceObject->DeviceExtension;
  341. DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1);
  342. } else {
  343. DoSpecificExtension = DeviceObject->DeviceExtension;
  344. fdoExtension = DoSpecificExtension->pFdoExtension;
  345. combinedExtension = fdoExtension;
  346. }
  347. //
  348. // Get a pointer to the current location in the Irp. This is where
  349. // the function codes and parameters are located.
  350. //
  351. irpStack = IoGetCurrentIrpStackLocation(Irp);
  352. //
  353. // Get the pointer to the status buffer.
  354. // Assume SUCCESS for now.
  355. //
  356. statusBlock = (PSTATUS_BLOCK) &Irp->IoStatus;
  357. //
  358. // Synchronize execution of the dispatch routine by acquiring the device
  359. // event object. This ensures all request are serialized.
  360. // The synchronization must be done explicitly because the functions
  361. // executed in the dispatch routine use system services that cannot
  362. // be executed in the start I/O routine.
  363. //
  364. // The synchronization is done on the miniport's event so as not to
  365. // block commands coming in for another device.
  366. //
  367. #if REMOVE_LOCK_ENABLED
  368. status = IoAcquireRemoveLock(&combinedExtension->RemoveLock, Irp);
  369. if (NT_SUCCESS(status) == FALSE) {
  370. ASSERT(FALSE);
  371. Irp->IoStatus.Information = 0;
  372. Irp->IoStatus.Status = status;
  373. IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
  374. return status;
  375. }
  376. #endif
  377. ACQUIRE_DEVICE_LOCK(combinedExtension);
  378. //
  379. // Get the requestor mode.
  380. //
  381. combinedExtension->CurrentIrpRequestorMode = Irp->RequestorMode;
  382. ASSERT(irpStack->MajorFunction != IRP_MJ_PNP);
  383. ASSERT(irpStack->MajorFunction != IRP_MJ_POWER);
  384. //
  385. // Case on the function being requested.
  386. // If the function is operating specific, intercept the operation and
  387. // perform directly. Otherwise, pass it on to the appropriate miniport.
  388. //
  389. switch (irpStack->MajorFunction) {
  390. //
  391. // Called by the display driver *or a user-mode application*
  392. // to get exclusive access to the device.
  393. // This access is given by the I/O system (based on a bit set during the
  394. // IoCreateDevice() call).
  395. //
  396. case IRP_MJ_CREATE:
  397. pVideoDebugPrint((Trace, "VIDEOPRT: IRP_MJ_CREATE\n"));
  398. if (Irp->RequestorMode == UserMode)
  399. {
  400. statusBlock->Status = STATUS_SUCCESS;
  401. break;
  402. }
  403. //
  404. // Don't let an old driver start during the upgrade
  405. //
  406. if (fdoExtension->Flags & UPGRADE_FAIL_START)
  407. {
  408. statusBlock->Status = STATUS_ACCESS_DENIED;
  409. break;
  410. }
  411. //
  412. // Don't allow create's on children, unless they are a monitor
  413. // which will receive calls from the display driver
  414. //
  415. if (IS_PDO(pdoExtension)) {
  416. pVideoDebugPrint((Error, "VIDEOPRT: Create's on children devices not allowed.\n"));
  417. statusBlock->Status = STATUS_ACCESS_DENIED;
  418. break;
  419. }
  420. //
  421. // Special hack to succeed on Attach, but do nothing ...
  422. // If the device is already opened, do nothing.
  423. //
  424. if ((irpStack->Parameters.Create.SecurityContext->DesiredAccess ==
  425. FILE_READ_ATTRIBUTES) ||
  426. (DoSpecificExtension->DeviceOpened)) {
  427. statusBlock->Information = FILE_OPEN;
  428. statusBlock->Status = STATUS_SUCCESS;
  429. break;
  430. }
  431. //
  432. // If we haven't already done so, create our watchdog recovery event
  433. //
  434. if (VpThreadStuckEvent == NULL) {
  435. UNICODE_STRING strName;
  436. RtlInitUnicodeString(&strName, L"\\BaseNamedObjects\\StuckThreadEvent");
  437. VpThreadStuckEvent = IoCreateNotificationEvent(&strName, &VpThreadStuckEventHandle);
  438. if (VpThreadStuckEvent) {
  439. KeClearEvent(VpThreadStuckEvent);
  440. }
  441. }
  442. //
  443. // Get out of the special setup mode that we may be in
  444. //
  445. VpSetupType = 0;
  446. //
  447. // If hwInitialize has been called then the system is done
  448. // initializing and we are transitioning into gui mode.
  449. //
  450. VpSystemInitialized = TRUE;
  451. //
  452. // Now perform basic initialization to allow the Windows display
  453. // driver to set up the device appropriately.
  454. //
  455. statusBlock->Information = FILE_OPEN;
  456. //
  457. // If the address space has not been set up in the server yet, do it now.
  458. // NOTE: no need to map in IO ports since the server has IOPL
  459. //
  460. if (CsrProcess == NULL)
  461. {
  462. CsrProcess = PsGetCurrentProcess();
  463. ObReferenceObject(CsrProcess);
  464. }
  465. pVideoPortInitializeInt10(fdoExtension);
  466. if (!IsMirrorDriver(fdoExtension)) {
  467. //
  468. // Tell the kernel we are now taking ownership the display, but
  469. // only do so if this is not a mirroring driver.
  470. //
  471. InbvNotifyDisplayOwnershipLost(pVideoPortResetDisplay);
  472. }
  473. if ((fdoExtension->Flags & FINDADAPTER_SUCCEEDED) == 0) {
  474. statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  475. } else if ((fdoExtension->HwInitStatus == HwInitNotCalled) &&
  476. (fdoExtension->HwInitialize(fdoExtension->HwDeviceExtension) == FALSE))
  477. {
  478. statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  479. fdoExtension->HwInitStatus = HwInitFailed;
  480. } else if (fdoExtension->HwInitStatus == HwInitFailed) {
  481. statusBlock->Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  482. } else {
  483. fdoExtension->HwInitStatus = HwInitSucceeded;
  484. statusBlock->Status = STATUS_SUCCESS;
  485. }
  486. //
  487. // Mark the device as opened so we will fail future opens.
  488. //
  489. DoSpecificExtension->DeviceOpened = TRUE;
  490. //
  491. // We don't want GDI to use any drivers other than display
  492. // or boot drivers during upgrade setup.
  493. //
  494. if (fdoExtension->Flags & UPGRADE_FAIL_HWINIT) {
  495. statusBlock->Status = STATUS_ACCESS_DENIED;
  496. }
  497. break;
  498. //
  499. // Called when the display driver wishes to give up it's handle to the
  500. // device.
  501. //
  502. case IRP_MJ_CLOSE:
  503. pVideoDebugPrint((Trace, "VIDEOPRT: IRP_MJ_CLOSE\n"));
  504. statusBlock->Status = STATUS_SUCCESS;
  505. break;
  506. //
  507. // Device Controls are specific functions for the driver.
  508. // First check for calls that must be intercepted and hidden from the
  509. // miniport driver. These calls are hidden for simplicity.
  510. // The other control functions are passed down to the miniport after
  511. // the request structure has been filled out properly.
  512. //
  513. case IRP_MJ_DEVICE_CONTROL:
  514. //
  515. // Get the pointer to the input/output buffer and it's length
  516. //
  517. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  518. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  519. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  520. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  521. if (Irp->RequestorMode == UserMode)
  522. {
  523. statusBlock->Information = 0;
  524. if ((ioControlCode != IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS) &&
  525. (ioControlCode != IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS) &&
  526. (ioControlCode != IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS))
  527. {
  528. statusBlock->Status = STATUS_ACCESS_DENIED;
  529. break;
  530. }
  531. }
  532. #ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  533. //
  534. // Validate session usage
  535. //
  536. // Note: Some IOCTLs are acceptable to call from non-console sessions
  537. // These include all private IOCTLs which is completely under
  538. // the drivers' control and may happen even when the device is
  539. // disabled. IOCTL_VIDEO_REGISTER_VDM is also allowed since
  540. // it doesn't access any hardware.
  541. //
  542. if ((ioControlCode & CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)) == 0 &&
  543. ioControlCode != IOCTL_VIDEO_REGISTER_VDM)
  544. {
  545. if (DoSpecificExtension->SessionId != VIDEO_DEVICE_INVALID_SESSION &&
  546. PsGetCurrentProcessSessionId() != DoSpecificExtension->SessionId)
  547. {
  548. DbgPrint("VIDEOPRT: Trying to use display device in sessions %lu and %lu.\n",
  549. DoSpecificExtension->SessionId,
  550. PsGetCurrentProcessSessionId());
  551. //
  552. // We will also allow several other IOCTLs to be called from
  553. // a non-console session.
  554. // For simplicity we allow all IOCTLs for which the driver
  555. // provides support with the exception of
  556. // IOCTL_VIDEO_ENABLE_VDM.
  557. //
  558. if ((ioControlCode &
  559. CTL_CODE(0x7fff, 0x7ff, METHOD_BUFFERED, FILE_ANY_ACCESS)) <=
  560. IOCTL_VIDEO_USE_DEVICE_IN_SESSION)
  561. {
  562. ASSERT(FALSE);
  563. }
  564. else
  565. {
  566. DbgPrint("VIDEOPRT: Cross session use is acceptable in this case.\n");
  567. }
  568. }
  569. }
  570. #endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  571. //
  572. // Enabling or disabling the VDM is done only by the port driver.
  573. //
  574. if (ioControlCode == IOCTL_VIDEO_REGISTER_VDM) {
  575. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_REGISTER_VDM\n"));
  576. ASSERT(IS_PDO(pdoExtension) == FALSE);
  577. statusBlock->Status = pVideoPortRegisterVDM(fdoExtension,
  578. (PVIDEO_VDM) ioBuffer,
  579. inputBufferLength,
  580. (PVIDEO_REGISTER_VDM) ioBuffer,
  581. outputBufferLength,
  582. &statusBlock->Information);
  583. } else if (ioControlCode == IOCTL_VIDEO_DISABLE_VDM) {
  584. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_DISABLE_VDM"));
  585. ASSERT(IS_PDO(pdoExtension) == FALSE);
  586. statusBlock->Status = pVideoPortEnableVDM(fdoExtension,
  587. FALSE,
  588. (PVIDEO_VDM) ioBuffer,
  589. inputBufferLength);
  590. } else if ((ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE) ||
  591. (ioControlCode == IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE)) {
  592. //
  593. // This handles the case where ntuser has signalled that it wants
  594. // to change or detect the power state.
  595. //
  596. PCHILD_PDO_EXTENSION pChild;
  597. PPOWER_BLOCK powerCtx = NULL;
  598. ULONG count = 0;
  599. UCHAR mFnc =
  600. (ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE) ?
  601. IRP_MN_SET_POWER : IRP_MN_QUERY_POWER ;
  602. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_%s_OUTPUT_DEVICE_POWER_STATE\n",
  603. ioControlCode == IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE ? "SET" : "GET"));
  604. //
  605. // USER wants to set the power on the monitor, not the card.
  606. // So let's find our child monitor and send it the power management
  607. // function.
  608. // If there is no power manageable monitor, then we can just fail
  609. // the request right here.
  610. //
  611. ASSERT(IS_PDO(pdoExtension) == FALSE);
  612. if (fdoExtension->ChildPdoList)
  613. {
  614. //
  615. // Count the number of monitor devices so that the IRP will
  616. // be completed properly after a power IRP has been requested
  617. // for each.
  618. //
  619. for (pChild = fdoExtension->ChildPdoList;
  620. pChild;
  621. pChild = pChild->NextChild) {
  622. if (pChild->VideoChildDescriptor->Type == Monitor)
  623. count++;
  624. }
  625. for (pChild = fdoExtension->ChildPdoList;
  626. pChild;
  627. pChild = pChild->NextChild)
  628. {
  629. if (pChild->VideoChildDescriptor->Type == Monitor)
  630. {
  631. count--;
  632. //
  633. // Allocate memory for the IRP context.
  634. //
  635. powerCtx = ExAllocatePoolWithTag(NonPagedPool,
  636. sizeof(POWER_BLOCK),
  637. VP_TAG);
  638. if (!powerCtx) {
  639. pVideoDebugPrint ((Error, "VIDEOPRT: No memory for power context.\n"));
  640. finalStatus = statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
  641. break;
  642. }
  643. powerCtx->Irp = Irp;
  644. powerCtx->FinalFlag = FALSE;
  645. //
  646. // Since there is a least one monitor that a power IRP
  647. // will be requested for, mark this IRP as pending as
  648. // it will undoubtedly be returned with STATUS_PENDING.
  649. //
  650. IoMarkIrpPending(Irp);
  651. if (count == 0) {
  652. powerCtx->FinalFlag = TRUE;
  653. }
  654. //
  655. // Since PoRequestPowerIrp always returns STATUS_PENDING
  656. // if the IRP was sent, a double completion here is
  657. // impossible as at the bottom of this function
  658. // IoCompleteRequest will not be called if status is
  659. // STATUS_PENDING
  660. //
  661. finalStatus =
  662. PoRequestPowerIrp(pChild->ChildDeviceObject,
  663. mFnc,
  664. *(PPOWER_STATE)(ioBuffer),
  665. pVideoPortPowerCompletionIoctl,
  666. powerCtx,
  667. NULL);
  668. if (finalStatus != STATUS_PENDING) {
  669. break;
  670. }
  671. }
  672. }
  673. }
  674. } else if ((ioControlCode == IOCTL_VIDEO_SET_POWER_MANAGEMENT) ||
  675. (ioControlCode == IOCTL_VIDEO_GET_POWER_MANAGEMENT)) {
  676. statusBlock->Status = STATUS_SUCCESS;
  677. } else if (ioControlCode == IOCTL_VIDEO_ENUM_MONITOR_PDO) {
  678. ULONG szMonitorDevices;
  679. PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL, pMD;
  680. PCHILD_PDO_EXTENSION pChildDeviceExtension;
  681. PDEVICE_OBJECT pdo;
  682. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_ENUM_MONITOR_PDO\n"));
  683. szMonitorDevices = (fdoExtension->ChildPdoNumber+1)*sizeof(VIDEO_MONITOR_DEVICE);
  684. pMonitorDevices = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  685. szMonitorDevices,
  686. VP_TAG);
  687. if (pMonitorDevices == NULL) {
  688. statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
  689. } else {
  690. RtlZeroMemory(pMonitorDevices, szMonitorDevices);
  691. //
  692. // Walk our chain of children, and store them in the relations array.
  693. //
  694. pChildDeviceExtension = fdoExtension->ChildPdoList;
  695. pMD = pMonitorDevices;
  696. while (pChildDeviceExtension) {
  697. if (pChildDeviceExtension->bIsEnumerated &&
  698. pChildDeviceExtension->VideoChildDescriptor->Type == Monitor
  699. )
  700. {
  701. ULONG UId, flag = VIDEO_CHILD_ACTIVE;
  702. //
  703. // Refcount the ChildDeviceObject.
  704. //
  705. ObReferenceObject(pChildDeviceExtension->ChildDeviceObject);
  706. UId = pChildDeviceExtension->VideoChildDescriptor->UId;
  707. if (!NT_SUCCESS
  708. (pVideoMiniDeviceIoControl(DeviceObject,
  709. IOCTL_VIDEO_GET_CHILD_STATE,
  710. &UId,
  711. sizeof(ULONG),
  712. &flag,
  713. sizeof(ULONG) ) )
  714. )
  715. {
  716. //
  717. // If driver driver doesn't handle IOCTL_VIDEO_GET_CHILD_STATE, set to default value
  718. //
  719. flag = pCheckActiveMonitor(pChildDeviceExtension) ? VIDEO_CHILD_ACTIVE : 0;
  720. }
  721. pMD->flag = flag;
  722. pMD->pdo = pChildDeviceExtension->ChildDeviceObject;
  723. pMD->HwID = pChildDeviceExtension->VideoChildDescriptor->UId;
  724. pMD++;
  725. }
  726. pChildDeviceExtension = pChildDeviceExtension->NextChild;
  727. }
  728. //
  729. // Return the information to GDI. The array terminated by a zero unit.
  730. //
  731. *((PVOID *)ioBuffer) = pMonitorDevices;
  732. statusBlock->Status = STATUS_SUCCESS;
  733. statusBlock->Information = sizeof(PVOID);
  734. }
  735. } else if (ioControlCode == IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) {
  736. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n"));
  737. if (DoSpecificExtension->PhysDisp == NULL)
  738. {
  739. DoSpecificExtension->PhysDisp = ((PVIDEO_WIN32K_CALLBACKS)(ioBuffer))->PhysDisp;
  740. }
  741. if (Win32kCallout == NULL)
  742. {
  743. Win32kCallout = ((PVIDEO_WIN32K_CALLBACKS)(ioBuffer))->Callout;
  744. }
  745. ((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->bACPI = DoSpecificExtension->bACPI;
  746. ((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->pPhysDeviceObject = fdoExtension->PhysicalDeviceObject;
  747. ((PVIDEO_WIN32K_CALLBACKS)ioBuffer)->DualviewFlags = DoSpecificExtension->DualviewFlags;
  748. statusBlock->Status = STATUS_SUCCESS;
  749. statusBlock->Information = sizeof(VIDEO_WIN32K_CALLBACKS);
  750. } else if (ioControlCode == IOCTL_VIDEO_IS_VGA_DEVICE) {
  751. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_IS_VGA_DEVICE\n"));
  752. *((PBOOLEAN)(ioBuffer)) = (BOOLEAN)(DeviceObject == DeviceOwningVga);
  753. statusBlock->Status = STATUS_SUCCESS;
  754. statusBlock->Information = sizeof(BOOLEAN);
  755. } else if (ioControlCode == IOCTL_VIDEO_PREPARE_FOR_EARECOVERY) {
  756. KBUGCHECK_SECONDARY_DUMP_DATA DumpData;
  757. ULONG ulDumpSize = 0;
  758. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n"));
  759. //
  760. // Save basic minidump on the disk (if we have any problem later
  761. // during recovery we still will have something to work with)
  762. //
  763. if (VpDump) {
  764. ulDumpSize = min((ULONG)((PMEMORY_DUMP)VpDump)->Header.RequiredDumpSpace.QuadPart,
  765. TRIAGE_DUMP_SIZE);
  766. pVpWriteFile(L"\\SystemRoot\\MEMORY.DMP",
  767. VpDump,
  768. ulDumpSize);
  769. }
  770. //
  771. // As all the display devices to go into a mode where VGA works.
  772. //
  773. pVpGeneralBugcheckHandler(&DumpData);
  774. if (VpDump) {
  775. ULONG ulSize;
  776. ULONG BugcheckDataSize = (VpBugcheckDeviceObject) ?
  777. ((PFDO_EXTENSION)VpBugcheckDeviceObject->DeviceExtension)->BugcheckDataSize :
  778. 0;
  779. //
  780. // Dump file created already so just add driver specific data
  781. //
  782. ulSize = pVpAppendSecondaryMinidumpData(VpBugcheckData,
  783. BugcheckDataSize,
  784. VpDump);
  785. if (ulSize > ulDumpSize) {
  786. //
  787. // Write the data to disk
  788. //
  789. pVpWriteFile(L"\\SystemRoot\\MEMORY.DMP",
  790. VpDump,
  791. ulSize);
  792. }
  793. if (VpDump) {
  794. ExFreePool(VpDump);
  795. VpDump = NULL;
  796. }
  797. }
  798. pVideoPortResetDisplay(80,25);
  799. statusBlock->Status = STATUS_SUCCESS;
  800. statusBlock->Information = 0;
  801. #ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  802. } else if (ioControlCode == IOCTL_VIDEO_USE_DEVICE_IN_SESSION) {
  803. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n"));
  804. if (((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bEnable)
  805. {
  806. if (DoSpecificExtension->SessionId == VIDEO_DEVICE_INVALID_SESSION)
  807. {
  808. DoSpecificExtension->SessionId = PsGetCurrentProcessSessionId();
  809. ((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = TRUE;
  810. }
  811. else
  812. {
  813. ((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = FALSE;
  814. }
  815. }
  816. else
  817. {
  818. if (DoSpecificExtension->SessionId == PsGetCurrentProcessSessionId())
  819. {
  820. DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
  821. ((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = TRUE;
  822. }
  823. else
  824. {
  825. ((PVIDEO_DEVICE_SESSION_STATUS)ioBuffer)->bSuccess = FALSE;
  826. }
  827. }
  828. statusBlock->Status = STATUS_SUCCESS;
  829. statusBlock->Information = sizeof(VIDEO_DEVICE_SESSION_STATUS);
  830. #endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  831. //
  832. // The following three IOCTLs support LCD backlight control.
  833. //
  834. } else if (ioControlCode == IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS) {
  835. //
  836. // Note: this IOCTL must be called before:
  837. // IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
  838. //
  839. // This IOCTL will query the brightness capabilities
  840. // of the BIOS.
  841. //
  842. //
  843. // We expect a buffer size of 256 bytes.
  844. //
  845. ULONG ulNumReturnedLevels = 0;
  846. PDEVICE_OBJECT AttachedDevice = NULL;
  847. if (outputBufferLength < 256)
  848. {
  849. statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
  850. break;
  851. }
  852. //
  853. // Call VpQueryBacklightLevels to obtain the list of supported levels.
  854. //
  855. if (LCDPanelDevice) {
  856. AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
  857. }
  858. if (AttachedDevice) {
  859. statusBlock->Status = VpQueryBacklightLevels(
  860. AttachedDevice,
  861. (PUCHAR) ioBuffer,
  862. &ulNumReturnedLevels);
  863. ObDereferenceObject(AttachedDevice);
  864. }
  865. else {
  866. statusBlock->Status = ERROR_INVALID_PARAMETER;
  867. }
  868. if (!NT_SUCCESS(statusBlock->Status)) {
  869. break;
  870. }
  871. //
  872. // The new API is being used. If we haven't already read the applicable
  873. // levels from the registry (per pVpInit) then write the keys to the
  874. // registry and update pVpBacklightStatus as necessary.
  875. //
  876. if ((pVpBacklightStatus->bNewAPISupported == FALSE) ||
  877. (pVpBacklightStatus->bACBrightnessInRegistry == FALSE) ||
  878. (pVpBacklightStatus->bDCBrightnessInRegistry == FALSE)) {
  879. // ZwCreateKey
  880. RtlInitUnicodeString(&UnicodeString,
  881. L"\\Registry\\Machine\\System\\CurrentControlSet\\"
  882. L"Control\\Backlight");
  883. InitializeObjectAttributes(&ObjectAttributes,
  884. &UnicodeString,
  885. OBJ_CASE_INSENSITIVE,
  886. NULL,
  887. NULL);
  888. statusBlock->Status = ZwCreateKey(&hkRegistry,
  889. GENERIC_READ | GENERIC_WRITE,
  890. &ObjectAttributes,
  891. 0L,
  892. NULL,
  893. REG_OPTION_NON_VOLATILE,
  894. NULL);
  895. if (NT_SUCCESS(statusBlock->Status)) {
  896. ULONG ulRegData = 1;
  897. PVOID pvData;
  898. // NewAPISupported
  899. RtlInitUnicodeString(
  900. &UnicodeString,
  901. L"NewAPISupported"
  902. );
  903. pvData = &ulRegData;
  904. statusBlock->Status = ZwSetValueKey(
  905. hkRegistry,
  906. &UnicodeString,
  907. 0,
  908. REG_DWORD,
  909. pvData,
  910. 4
  911. );
  912. if (NT_SUCCESS(statusBlock->Status)) {
  913. pVpBacklightStatus->bNewAPISupported = TRUE;
  914. }
  915. // ACBacklightLevel, use BIOS default value
  916. RtlInitUnicodeString(
  917. &UnicodeString,
  918. L"ACBacklightLevel"
  919. );
  920. pVpBacklightStatus->ucACBrightness = pVpBacklightStatus->ucBIOSDefaultAC;
  921. ulRegData = (UCHAR) pVpBacklightStatus->ucACBrightness;
  922. pvData = &ulRegData;
  923. statusBlock->Status = ZwSetValueKey(
  924. hkRegistry,
  925. &UnicodeString,
  926. 0,
  927. REG_DWORD,
  928. pvData,
  929. 4
  930. );
  931. if (NT_SUCCESS(statusBlock->Status)) {
  932. pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
  933. }
  934. // DCBacklightLevel, use BIOS default value
  935. RtlInitUnicodeString(
  936. &UnicodeString,
  937. L"DCBacklightLevel"
  938. );
  939. pVpBacklightStatus->ucDCBrightness = pVpBacklightStatus->ucBIOSDefaultDC;
  940. ulRegData = (UCHAR) pVpBacklightStatus->ucDCBrightness;
  941. pvData = &ulRegData;
  942. statusBlock->Status = ZwSetValueKey(
  943. hkRegistry,
  944. &UnicodeString,
  945. 0,
  946. REG_DWORD,
  947. pvData,
  948. 4
  949. );
  950. if (NT_SUCCESS(statusBlock->Status)) {
  951. pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
  952. }
  953. ZwClose(hkRegistry);
  954. pVpBacklightStatus->bACBrightnessKnown = TRUE;
  955. pVpBacklightStatus->bDCBrightnessKnown = TRUE;
  956. }
  957. }
  958. pVpBacklightStatus->bQuerySupportedBrightnessCalled = TRUE;
  959. statusBlock->Status = STATUS_SUCCESS;
  960. statusBlock->Information = ulNumReturnedLevels;
  961. } else if (ioControlCode == IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS) {
  962. //
  963. // If the backlight level is known for the display policy queried,
  964. // it will be reported.
  965. //
  966. // No ACPI methods are used here. _BCL will be used in
  967. // IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS and _BCM will
  968. // be used in IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS.
  969. //
  970. PDISPLAY_BRIGHTNESS pDisplayBrightness;
  971. if (outputBufferLength < sizeof(DISPLAY_BRIGHTNESS))
  972. {
  973. statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
  974. break;
  975. }
  976. pDisplayBrightness = (PDISPLAY_BRIGHTNESS) ioBuffer;
  977. //
  978. // Report AC value if available.
  979. //
  980. // Note: Value ~should~ be known, even if we need to use
  981. // AC default.
  982. //
  983. if ((pVpBacklightStatus->bACBrightnessKnown == FALSE) &&
  984. (pVpBacklightStatus->bBIOSDefaultACKnown == FALSE))
  985. {
  986. statusBlock->Status = ERROR_INVALID_PARAMETER;
  987. break;
  988. }
  989. if (pVpBacklightStatus->bACBrightnessKnown == TRUE)
  990. {
  991. pDisplayBrightness->ucACBrightness = pVpBacklightStatus->ucACBrightness;
  992. }
  993. else
  994. {
  995. pDisplayBrightness->ucACBrightness = pVpBacklightStatus->ucBIOSDefaultAC;
  996. }
  997. //
  998. // Report DC value if available.
  999. //
  1000. // Note: Value ~should~ be known, even if we need to use
  1001. // DC default.
  1002. //
  1003. if ((pVpBacklightStatus->bDCBrightnessKnown == FALSE) &&
  1004. (pVpBacklightStatus->bBIOSDefaultDCKnown == FALSE))
  1005. {
  1006. statusBlock->Status = ERROR_INVALID_PARAMETER;
  1007. break;
  1008. }
  1009. if (pVpBacklightStatus->bDCBrightnessKnown == TRUE)
  1010. {
  1011. pDisplayBrightness->ucDCBrightness = pVpBacklightStatus->ucDCBrightness;
  1012. }
  1013. else
  1014. {
  1015. pDisplayBrightness->ucDCBrightness = pVpBacklightStatus->ucBIOSDefaultDC;
  1016. }
  1017. //
  1018. // Report the current power policy.
  1019. //
  1020. if (VpRunningOnAC == TRUE)
  1021. {
  1022. pDisplayBrightness->ucDisplayPolicy = DISPLAYPOLICY_AC;
  1023. }
  1024. else
  1025. {
  1026. pDisplayBrightness->ucDisplayPolicy = DISPLAYPOLICY_DC;
  1027. }
  1028. //
  1029. // No errors are expected here.
  1030. //
  1031. statusBlock->Status = STATUS_SUCCESS;
  1032. statusBlock->Information = sizeof(DISPLAY_BRIGHTNESS);
  1033. } else if (ioControlCode == IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS) {
  1034. //
  1035. // This IOCTL will set the current brightness level of
  1036. // the backlight.
  1037. //
  1038. // The _BCM ACPI method will be used.
  1039. //
  1040. PDISPLAY_BRIGHTNESS pDisplayBrightness;
  1041. PDEVICE_OBJECT AttachedDevice = NULL;
  1042. BOOLEAN bSetPanelBrightness = FALSE;
  1043. //
  1044. // Check buffer size and that Brightness capabilities
  1045. // have been queried.
  1046. //
  1047. if (inputBufferLength < sizeof(DISPLAY_BRIGHTNESS))
  1048. {
  1049. statusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
  1050. break;
  1051. }
  1052. //
  1053. // Videoprt insists that IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS
  1054. // be called first.
  1055. //
  1056. if (pVpBacklightStatus->bQuerySupportedBrightnessCalled == FALSE)
  1057. {
  1058. statusBlock->Status = ERROR_INVALID_FUNCTION;
  1059. break;
  1060. }
  1061. //
  1062. // Videoprt will ensure no crashes, but caller should ensure
  1063. // they are setting a valid value.
  1064. //
  1065. pDisplayBrightness = (PDISPLAY_BRIGHTNESS) ioBuffer;
  1066. //
  1067. // Set the AC/DC brightness level, if appropriate.
  1068. // The caller could conceivably ask us to set a value
  1069. // for a power policy that is not currenlty active.
  1070. //
  1071. ulACPIMethodParam2 = 0;
  1072. if ((VpRunningOnAC == TRUE) &&
  1073. ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_AC))
  1074. {
  1075. bSetPanelBrightness = TRUE;
  1076. ulACPIMethodParam1 = (ULONG) pDisplayBrightness->ucACBrightness;
  1077. }
  1078. else if ((VpRunningOnAC == FALSE) &&
  1079. ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_DC))
  1080. {
  1081. bSetPanelBrightness = TRUE;
  1082. ulACPIMethodParam1 = (ULONG) pDisplayBrightness->ucDCBrightness;
  1083. }
  1084. statusBlock->Status = STATUS_SUCCESS;
  1085. if (bSetPanelBrightness == TRUE)
  1086. {
  1087. if (LCDPanelDevice) {
  1088. AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice);
  1089. }
  1090. if (AttachedDevice) {
  1091. statusBlock->Status = pVideoPortACPIIoctl(
  1092. AttachedDevice,
  1093. (ULONG) ('MCB_'),
  1094. &ulACPIMethodParam1,
  1095. NULL,
  1096. 0,
  1097. NULL);
  1098. ObDereferenceObject(AttachedDevice);
  1099. }
  1100. else {
  1101. statusBlock->Status = ERROR_INVALID_PARAMETER;
  1102. }
  1103. }
  1104. if (!NT_SUCCESS(statusBlock->Status))
  1105. {
  1106. statusBlock->Status = ERROR_INVALID_PARAMETER;
  1107. break;
  1108. }
  1109. //
  1110. // Save the new brightness levels.
  1111. //
  1112. if ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_DC)
  1113. {
  1114. pVpBacklightStatus->ucDCBrightness = pDisplayBrightness->ucDCBrightness;
  1115. pVpBacklightStatus->bDCBrightnessKnown = TRUE;
  1116. }
  1117. if ((pDisplayBrightness->ucDisplayPolicy) & DISPLAYPOLICY_AC)
  1118. {
  1119. pVpBacklightStatus->ucACBrightness = pDisplayBrightness->ucACBrightness;
  1120. pVpBacklightStatus->bACBrightnessKnown = TRUE;
  1121. }
  1122. //
  1123. // Save the new AC / DC values in the Registry.
  1124. //
  1125. // ZwCreateKey
  1126. RtlInitUnicodeString(&UnicodeString,
  1127. L"\\Registry\\Machine\\System\\CurrentControlSet\\"
  1128. L"Control\\Backlight");
  1129. InitializeObjectAttributes(&ObjectAttributes,
  1130. &UnicodeString,
  1131. OBJ_CASE_INSENSITIVE,
  1132. NULL,
  1133. NULL);
  1134. statusBlock->Status = ZwCreateKey(&hkRegistry,
  1135. GENERIC_READ | GENERIC_WRITE,
  1136. &ObjectAttributes,
  1137. 0L,
  1138. NULL,
  1139. REG_OPTION_NON_VOLATILE,
  1140. NULL);
  1141. if (NT_SUCCESS(statusBlock->Status)) {
  1142. ULONG ulRegData = 0;
  1143. PVOID pvData;
  1144. // ACBacklightLevel
  1145. RtlInitUnicodeString(
  1146. &UnicodeString,
  1147. L"ACBacklightLevel"
  1148. );
  1149. ulRegData = (UCHAR) pVpBacklightStatus->ucACBrightness;
  1150. pvData = &ulRegData;
  1151. statusBlock->Status = ZwSetValueKey(
  1152. hkRegistry,
  1153. &UnicodeString,
  1154. 0,
  1155. REG_DWORD,
  1156. pvData,
  1157. 4
  1158. );
  1159. if (NT_SUCCESS(statusBlock->Status)) {
  1160. pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
  1161. }
  1162. // DCBacklightLevel
  1163. RtlInitUnicodeString(
  1164. &UnicodeString,
  1165. L"DCBacklightLevel"
  1166. );
  1167. ulRegData = (UCHAR) pVpBacklightStatus->ucDCBrightness;
  1168. pvData = &ulRegData;
  1169. statusBlock->Status = ZwSetValueKey(
  1170. hkRegistry,
  1171. &UnicodeString,
  1172. 0,
  1173. REG_DWORD,
  1174. pvData,
  1175. 4
  1176. );
  1177. if (NT_SUCCESS(statusBlock->Status)) {
  1178. pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
  1179. }
  1180. ZwClose(hkRegistry);
  1181. }
  1182. //
  1183. // No errors are expected here unless the caller asked us to set a
  1184. // level that is not available.
  1185. //
  1186. statusBlock->Status = STATUS_SUCCESS;
  1187. statusBlock->Information = 0;
  1188. } else {
  1189. //
  1190. // All other request need to be passed to the miniport driver.
  1191. //
  1192. statusBlock->Status = STATUS_SUCCESS;
  1193. switch (ioControlCode) {
  1194. case IOCTL_VIDEO_ENABLE_VDM:
  1195. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_ENABLE_VDM\n"));
  1196. ASSERT(IS_PDO(pdoExtension) == FALSE);
  1197. statusBlock->Status = pVideoPortEnableVDM(fdoExtension,
  1198. TRUE,
  1199. (PVIDEO_VDM) ioBuffer,
  1200. inputBufferLength);
  1201. #if DBG
  1202. if (statusBlock->Status == STATUS_CONFLICTING_ADDRESSES) {
  1203. pVideoDebugPrint((Trace, "VIDEOPRT: pVideoPortEnableVDM failed\n"));
  1204. }
  1205. #endif
  1206. break;
  1207. #if _X86_
  1208. case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
  1209. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_SAVE_HARDWARE_STATE\n"));
  1210. //
  1211. // allocate the memory required by the miniport driver so it can
  1212. // save its state to be returned to the caller.
  1213. //
  1214. ASSERT(IS_PDO(pdoExtension) == FALSE);
  1215. if (fdoExtension->HardwareStateSize == 0) {
  1216. statusBlock->Status = STATUS_NOT_IMPLEMENTED;
  1217. break;
  1218. }
  1219. //
  1220. // Must make sure the caller is a trusted subsystem with the
  1221. // appropriate privilege level before executing this call.
  1222. // If the calls returns FALSE we must return an error code.
  1223. //
  1224. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  1225. SE_TCB_PRIVILEGE),
  1226. fdoExtension->CurrentIrpRequestorMode)) {
  1227. statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
  1228. break;
  1229. }
  1230. ((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength =
  1231. fdoExtension->HardwareStateSize;
  1232. statusBlock->Status =
  1233. ZwAllocateVirtualMemory(NtCurrentProcess(),
  1234. (PVOID *) &(((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateHeader),
  1235. 0L,
  1236. &((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength,
  1237. MEM_COMMIT,
  1238. PAGE_READWRITE);
  1239. if(!NT_SUCCESS(statusBlock->Status))
  1240. break;
  1241. BiosDataBuffer = ExAllocatePoolWithTag(PagedPool,
  1242. BIOS_DATA_SIZE,
  1243. VP_TAG);
  1244. if (BiosDataBuffer == NULL) {
  1245. statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
  1246. } else {
  1247. statusBlock->Status =
  1248. pVideoPortGetVDMBiosData(fdoExtension,
  1249. BiosDataBuffer,
  1250. BIOS_DATA_SIZE);
  1251. if(!NT_SUCCESS(statusBlock->Status)) {
  1252. ExFreePool(BiosDataBuffer);
  1253. }
  1254. }
  1255. break;
  1256. #endif
  1257. case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
  1258. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES\n"));
  1259. //
  1260. // Must make sure the caller is a trusted subsystem with the
  1261. // appropriate privilege level before executing this call.
  1262. // If the calls returns FALSE we must return an error code.
  1263. //
  1264. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  1265. SE_TCB_PRIVILEGE),
  1266. fdoExtension->CurrentIrpRequestorMode)) {
  1267. statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
  1268. }
  1269. break;
  1270. case IOCTL_VIDEO_GET_CHILD_STATE:
  1271. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL_VIDEO_GET_CHILD_STATE\n"));
  1272. //
  1273. // If it's PDO, set the ID of the child device before letting it go
  1274. // to the miniports StartIo routine.
  1275. //
  1276. if (IS_PDO(pdoExtension)) {
  1277. if (outputBufferLength < sizeof (ULONG)) {
  1278. statusBlock->Status = STATUS_BUFFER_TOO_SMALL ;
  1279. break ;
  1280. }
  1281. *((PULONG)(ioBuffer)) = pdoExtension->ChildUId ;
  1282. }
  1283. break;
  1284. //
  1285. // The default case is when the port driver does not handle the
  1286. // request. We must then call the miniport driver.
  1287. //
  1288. default:
  1289. break;
  1290. } // switch (ioControlCode)
  1291. //
  1292. // All above cases call the miniport driver.
  1293. //
  1294. // only process it if no errors happened in the port driver
  1295. // processing.
  1296. //
  1297. if (NT_SUCCESS(statusBlock->Status)) {
  1298. pVideoDebugPrint((Trace, "VIDEOPRT: IOCTL fallthrough\n"));
  1299. vrp.IoControlCode = ioControlCode;
  1300. vrp.StatusBlock = statusBlock;
  1301. vrp.InputBuffer = ioBuffer;
  1302. vrp.InputBufferLength = inputBufferLength;
  1303. vrp.OutputBuffer = ioBuffer;
  1304. vrp.OutputBufferLength = outputBufferLength;
  1305. //
  1306. // Send the request to the miniport.
  1307. //
  1308. fdoExtension->HwStartIO(HwDeviceExtension, &vrp);
  1309. #if _X86_
  1310. if(ioControlCode == IOCTL_VIDEO_SAVE_HARDWARE_STATE) {
  1311. pVideoPortPutVDMBiosData(fdoExtension,
  1312. BiosDataBuffer,
  1313. BIOS_DATA_SIZE);
  1314. ExFreePool(BiosDataBuffer);
  1315. }
  1316. #endif
  1317. if (statusBlock->Status != NO_ERROR) {
  1318. //
  1319. // Make sure we don't tell the IO system to copy data
  1320. // on a real error.
  1321. //
  1322. if (statusBlock->Status != ERROR_MORE_DATA) {
  1323. statusBlock->Information = 0;
  1324. }
  1325. pVideoPortMapToNtStatus(statusBlock);
  1326. //
  1327. // !!! Compatibility:
  1328. // Do not require a miniport to support the REGISTER_VDM
  1329. // IOCTL, so if we get an error in that case, just
  1330. // return success.
  1331. //
  1332. // Do put up a message so people fix this.
  1333. //
  1334. if (ioControlCode == IOCTL_VIDEO_ENABLE_VDM) {
  1335. statusBlock->Status = STATUS_SUCCESS;
  1336. pVideoDebugPrint((Warn, "VIDEOPRT: The miniport driver does not support IOCTL_VIDEO_ENABLE_VDM. The video miniport driver *should* be fixed.\n"));
  1337. }
  1338. }
  1339. }
  1340. } // if (ioControlCode == ...
  1341. break;
  1342. case IRP_MJ_SHUTDOWN:
  1343. {
  1344. PEPROCESS csr;
  1345. //
  1346. // This little dance is just to make sure we never overdereference csr.
  1347. //
  1348. csr = InterlockedExchangePointer(&CsrProcess, NULL);
  1349. if (csr != NULL) {
  1350. ObDereferenceObject(csr);
  1351. }
  1352. //
  1353. // TODO: This is a temporary hack only till we get Nt/ZwQueryLastShutdownType()
  1354. // API implemented. On the next boot we need to know if the last shutdown was
  1355. // successful, and if not and if we have a watchdog event registered from that
  1356. // session we can assume the driver got stuck so we can notify user and
  1357. // optionally send a problem report to MS.
  1358. //
  1359. // N.B. This doesn't work for non-PnP devices (e.g. VGA) but it's still good
  1360. // enough, we're losing once piece of info but we'll still check for watchdog
  1361. // events from the last session.
  1362. //
  1363. {
  1364. #define VP_KEY_WATCHDOG L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog"
  1365. #define VP_KEY_WATCHDOG_DISPLAY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog\\Display"
  1366. static BOOLEAN shutdownRegistered = FALSE;
  1367. if (FALSE == shutdownRegistered)
  1368. {
  1369. NTSTATUS ntStatus;
  1370. shutdownRegistered = TRUE;
  1371. //
  1372. // Is Watchdog\Display key already there?
  1373. //
  1374. ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG_DISPLAY);
  1375. if (!NT_SUCCESS(ntStatus)) {
  1376. //
  1377. // Is Watchdog key already there?
  1378. //
  1379. ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG);
  1380. if (!NT_SUCCESS(ntStatus)) {
  1381. //
  1382. // Create a new key.
  1383. //
  1384. ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG);
  1385. }
  1386. if (NT_SUCCESS(ntStatus)) {
  1387. //
  1388. // Create a new key.
  1389. //
  1390. ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, VP_KEY_WATCHDOG_DISPLAY);
  1391. }
  1392. }
  1393. if (NT_SUCCESS(ntStatus)) {
  1394. ULONG shutdownFlag = 1;
  1395. ULONG shutdownCount;
  1396. ULONG defaultShutdownCount = 0;
  1397. RTL_QUERY_REGISTRY_TABLE queryTable[] =
  1398. {
  1399. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"ShutdownCount", &shutdownCount, REG_DWORD, &defaultShutdownCount, 4},
  1400. {NULL, 0, NULL}
  1401. };
  1402. //
  1403. // Get accumulated statistics from registry.
  1404. //
  1405. RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1406. VP_KEY_WATCHDOG_DISPLAY,
  1407. queryTable,
  1408. NULL,
  1409. NULL);
  1410. shutdownCount++;
  1411. //
  1412. // Update registry values.
  1413. //
  1414. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  1415. VP_KEY_WATCHDOG_DISPLAY,
  1416. L"ShutdownCount",
  1417. REG_DWORD,
  1418. &shutdownCount,
  1419. sizeof (ULONG));
  1420. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  1421. VP_KEY_WATCHDOG_DISPLAY,
  1422. L"Shutdown",
  1423. REG_DWORD,
  1424. &shutdownFlag,
  1425. sizeof (ULONG));
  1426. }
  1427. }
  1428. }
  1429. break;
  1430. }
  1431. //
  1432. // Other major entry points in the dispatch routine are not supported.
  1433. //
  1434. default:
  1435. statusBlock->Status = STATUS_SUCCESS;
  1436. break;
  1437. } // switch (irpStack->MajorFunction)
  1438. //
  1439. // save the final status so we can return it after the IRP is completed.
  1440. //
  1441. if (finalStatus == -1) {
  1442. finalStatus = statusBlock->Status;
  1443. }
  1444. RELEASE_DEVICE_LOCK(combinedExtension);
  1445. #if REMOVE_LOCK_ENABLED
  1446. IoReleaseRemoveLock(&combinedExtension->RemoveLock, Irp);
  1447. #endif
  1448. if (finalStatus == STATUS_PENDING) {
  1449. pVideoDebugPrint((Trace, "VIDEOPRT: Returned pending in pVideoPortDispatch.\n")) ;
  1450. return STATUS_PENDING ;
  1451. }
  1452. pVideoDebugPrint((Trace, "VIDEOPRT: IoCompleteRequest with Irp %x\n", Irp));
  1453. IoCompleteRequest(Irp,
  1454. IO_VIDEO_INCREMENT);
  1455. //
  1456. // We never have pending operation so always return the status code.
  1457. //
  1458. pVideoDebugPrint((Trace, "VIDEOPRT: final IOCTL status: %08lx\n",
  1459. finalStatus));
  1460. return finalStatus;
  1461. } // pVideoPortDispatch()
  1462. VOID
  1463. VideoPortFreeDeviceBase(
  1464. IN PVOID HwDeviceExtension,
  1465. IN PVOID MappedAddress
  1466. )
  1467. /*++
  1468. Routine Description:
  1469. VideoPortFreeDeviceBase frees a block of I/O addresses or memory space
  1470. previously mapped into the system address space by calling
  1471. VideoPortGetDeviceBase.
  1472. Arguments:
  1473. HwDeviceExtension - Points to the miniport driver's device extension.
  1474. MappedAddress - Specifies the base address of the block to be freed. This
  1475. value must be the same as the value returned by VideoPortGetDeviceBase.
  1476. Return Value:
  1477. None.
  1478. Environment:
  1479. This routine cannot be called from a miniport routine synchronized with
  1480. VideoPortSynchronizeRoutine or from an ISR.
  1481. --*/
  1482. {
  1483. pVideoPortFreeDeviceBase(HwDeviceExtension, MappedAddress);
  1484. return;
  1485. }
  1486. PVOID
  1487. pVideoPortFreeDeviceBase(
  1488. IN PVOID HwDeviceExtension,
  1489. IN PVOID MappedAddress
  1490. )
  1491. {
  1492. PMAPPED_ADDRESS nextMappedAddress;
  1493. PMAPPED_ADDRESS lastMappedAddress;
  1494. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1495. pVideoDebugPrint((Info, "VPFreeDeviceBase at mapped address is %08lx\n",
  1496. MappedAddress));
  1497. lastMappedAddress = NULL;
  1498. nextMappedAddress = fdoExtension->MappedAddressList;
  1499. while (nextMappedAddress) {
  1500. if (nextMappedAddress->MappedAddress == MappedAddress) {
  1501. //
  1502. // Count up how much memory a miniport driver is really taking
  1503. //
  1504. if (nextMappedAddress->bNeedsUnmapping) {
  1505. fdoExtension->MemoryPTEUsage -=
  1506. ADDRESS_AND_SIZE_TO_SPAN_PAGES(nextMappedAddress->MappedAddress,
  1507. nextMappedAddress->NumberOfUchars);
  1508. }
  1509. if (!(--nextMappedAddress->RefCount)) {
  1510. //
  1511. // Unmap address, if necessary.
  1512. //
  1513. if (nextMappedAddress->bNeedsUnmapping) {
  1514. if (nextMappedAddress->bLargePageRequest) {
  1515. MmUnmapVideoDisplay(nextMappedAddress->MappedAddress,
  1516. nextMappedAddress->NumberOfUchars);
  1517. } else {
  1518. MmUnmapIoSpace(nextMappedAddress->MappedAddress,
  1519. nextMappedAddress->NumberOfUchars);
  1520. }
  1521. }
  1522. //
  1523. // Remove mapped address from list.
  1524. //
  1525. if (lastMappedAddress == NULL) {
  1526. fdoExtension->MappedAddressList =
  1527. nextMappedAddress->NextMappedAddress;
  1528. } else {
  1529. lastMappedAddress->NextMappedAddress =
  1530. nextMappedAddress->NextMappedAddress;
  1531. }
  1532. ExFreePool(nextMappedAddress);
  1533. }
  1534. //
  1535. // We just return the value to show that the call succeeded.
  1536. //
  1537. return (nextMappedAddress);
  1538. } else {
  1539. lastMappedAddress = nextMappedAddress;
  1540. nextMappedAddress = nextMappedAddress->NextMappedAddress;
  1541. }
  1542. }
  1543. return NULL;
  1544. } // end VideoPortFreeDeviceBase()
  1545. PVOID
  1546. VideoPortGetDeviceBase(
  1547. IN PVOID HwDeviceExtension,
  1548. IN PHYSICAL_ADDRESS IoAddress,
  1549. IN ULONG NumberOfUchars,
  1550. IN UCHAR InIoSpace
  1551. )
  1552. /*++
  1553. Routine Description:
  1554. VideoPortGetDeviceBase maps a memory or I/O address range into the
  1555. system (kernel) address space. Access to this mapped address space
  1556. must follow these rules:
  1557. If the input value for InIoSpace is 1 (the address IS in I/O space),
  1558. the returned logical address should be used in conjunction with
  1559. VideoPort[Read/Write]Port[Uchar/Ushort/Ulong] functions.
  1560. ^^^^
  1561. If the input value for InIoSpace is 0 (the address IS NOT in I/O
  1562. space), the returned logical address should be used in conjunction
  1563. with VideoPort[Read/Write]Register[Uchar/Ushort/Ulong] functions.
  1564. ^^^^^^^^
  1565. Note that VideoPortFreeDeviceBase is used to unmap a previously mapped
  1566. range from the system address space.
  1567. Arguments:
  1568. HwDeviceExtension - Points to the miniport driver's device extension.
  1569. IoAddress - Specifies the base physical address of the range to be
  1570. mapped in the system address space.
  1571. NumberOfUchars - Specifies the number of bytes, starting at the base
  1572. address, to map in system space. The driver must not access
  1573. addresses outside this range.
  1574. InIoSpace - Specifies that the address is in the I/O space if 1.
  1575. Otherwise, the address is assumed to be in memory space.
  1576. Return Value:
  1577. This function returns a base address suitable for use by the hardware
  1578. access functions. VideoPortGetDeviceBase may be called several times
  1579. by the miniport driver.
  1580. Environment:
  1581. This routine cannot be called from a miniport routine synchronized with
  1582. VideoPortSynchronizeRoutine or from an ISR.
  1583. --*/
  1584. {
  1585. //
  1586. // We specify large page as FALSE for the default since the miniport could
  1587. // be using the address at raise IRQL in an ISR.
  1588. //
  1589. return pVideoPortGetDeviceBase(HwDeviceExtension,
  1590. IoAddress,
  1591. NumberOfUchars,
  1592. InIoSpace,
  1593. FALSE);
  1594. }
  1595. BOOLEAN
  1596. VpTranslateBusAddress(
  1597. IN PFDO_EXTENSION fdoExtension,
  1598. IN PPHYSICAL_ADDRESS IoAddress,
  1599. IN OUT PULONG addressSpace,
  1600. IN OUT PPHYSICAL_ADDRESS TranslatedAddress
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This routine finds the cpu relative address that matches the given
  1605. bus relative address.
  1606. Arguments:
  1607. fdoExtension - The device extension for the device in question.
  1608. IoAddress - The address which we mean to translate.
  1609. addressSpace - pointer to resource type (IO, memory, etc).
  1610. TranslatedAddress - a pointer to the location in which to store the
  1611. translated address.
  1612. Returns:
  1613. TRUE if successful,
  1614. FALSE otherwise.
  1615. --*/
  1616. {
  1617. BOOLEAN bStatus;
  1618. //
  1619. // We need to find a way to translate dense space before we can
  1620. // do this.
  1621. //
  1622. #if 0
  1623. if ((fdoExtension->Flags & LEGACY_DRIVER) != LEGACY_DRIVER) {
  1624. bStatus = VpTranslateResource(
  1625. fdoExtension,
  1626. addressSpace,
  1627. IoAddress,
  1628. TranslatedAddress);
  1629. } else {
  1630. #endif
  1631. bStatus = HalTranslateBusAddress(
  1632. fdoExtension->AdapterInterfaceType,
  1633. fdoExtension->SystemIoBusNumber,
  1634. *IoAddress,
  1635. addressSpace,
  1636. TranslatedAddress);
  1637. #if 0
  1638. }
  1639. #endif
  1640. return bStatus;
  1641. }
  1642. PVOID
  1643. pVideoPortGetDeviceBase(
  1644. IN PVOID HwDeviceExtension,
  1645. IN PHYSICAL_ADDRESS IoAddress,
  1646. IN ULONG NumberOfUchars,
  1647. IN UCHAR InIoSpace,
  1648. IN BOOLEAN bLargePage
  1649. )
  1650. {
  1651. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1652. PHYSICAL_ADDRESS cardAddress = IoAddress;
  1653. PVOID mappedAddress = NULL;
  1654. PMAPPED_ADDRESS newMappedAddress;
  1655. BOOLEAN bMapped;
  1656. ULONG addressSpace;
  1657. ULONG p6Caching = FALSE;
  1658. pVideoDebugPrint((Info, "VPGetDeviceBase reqested %08lx mem type. address is %08lx %08lx, length of %08lx\n",
  1659. InIoSpace, IoAddress.HighPart, IoAddress.LowPart, NumberOfUchars));
  1660. //
  1661. // Properly configure the flags for translation
  1662. //
  1663. addressSpace = InIoSpace & 0xFF;
  1664. p6Caching = addressSpace & VIDEO_MEMORY_SPACE_P6CACHE;
  1665. addressSpace &= ~VIDEO_MEMORY_SPACE_P6CACHE;
  1666. addressSpace &= ~VIDEO_MEMORY_SPACE_DENSE;
  1667. if (addressSpace & VIDEO_MEMORY_SPACE_USER_MODE) {
  1668. ASSERT(FALSE);
  1669. return NULL;
  1670. }
  1671. if ((((cardAddress.QuadPart >= 0x000C0000) && (cardAddress.QuadPart < 0x000C8000)) &&
  1672. (InIoSpace == 0) &&
  1673. (VpC0000Compatible == 2)) ||
  1674. VpTranslateBusAddress(fdoExtension,
  1675. &IoAddress,
  1676. &addressSpace,
  1677. &cardAddress)) {
  1678. //
  1679. // Use reference counting for addresses to support broken ATI !
  1680. // Return the previously mapped address if we find the same physical
  1681. // address.
  1682. //
  1683. PMAPPED_ADDRESS nextMappedAddress;
  1684. pVideoDebugPrint((Info, "VPGetDeviceBase requested %08lx mem type. physical address is %08lx %08lx, length of %08lx\n",
  1685. addressSpace, cardAddress.HighPart, cardAddress.LowPart, NumberOfUchars));
  1686. nextMappedAddress = fdoExtension->MappedAddressList;
  1687. while (nextMappedAddress) {
  1688. if ((nextMappedAddress->InIoSpace == InIoSpace) &&
  1689. (nextMappedAddress->NumberOfUchars == NumberOfUchars) &&
  1690. (nextMappedAddress->PhysicalAddress.QuadPart == cardAddress.QuadPart)) {
  1691. pVideoDebugPrint((Info, "VPGetDeviceBase : refCount hit on address %08lx \n",
  1692. nextMappedAddress->PhysicalAddress.LowPart));
  1693. nextMappedAddress->RefCount++;
  1694. //
  1695. // Count up how much memory a miniport driver is really taking
  1696. //
  1697. if (nextMappedAddress->bNeedsUnmapping) {
  1698. fdoExtension->MemoryPTEUsage +=
  1699. ADDRESS_AND_SIZE_TO_SPAN_PAGES(nextMappedAddress->MappedAddress,
  1700. nextMappedAddress->NumberOfUchars);
  1701. }
  1702. return (nextMappedAddress->MappedAddress);
  1703. } else {
  1704. nextMappedAddress = nextMappedAddress->NextMappedAddress;
  1705. }
  1706. }
  1707. //
  1708. // Allocate memory to store mapped address for unmap.
  1709. //
  1710. newMappedAddress = ExAllocatePoolWithTag(NonPagedPool,
  1711. sizeof(MAPPED_ADDRESS),
  1712. 'trpV');
  1713. if (!newMappedAddress) {
  1714. pVideoDebugPrint((Error, "VIDEOPRT: Not enough memory to cache mapped address! \n"));
  1715. return NULL;
  1716. }
  1717. //
  1718. // If the address is in IO space, don't do anything.
  1719. // If the address is in memory space, map it and save the information.
  1720. //
  1721. if (addressSpace & VIDEO_MEMORY_SPACE_IO) {
  1722. mappedAddress = (PVOID) cardAddress.QuadPart;
  1723. bMapped = FALSE;
  1724. } else {
  1725. //
  1726. // Map the device base address into the virtual address space
  1727. //
  1728. // NOTE: This routine is order dependant, and changing flags like
  1729. // bLargePage will affect the caching of address we do earlier
  1730. // on in this routine.
  1731. //
  1732. if (p6Caching && EnableUSWC) {
  1733. mappedAddress = MmMapIoSpace(cardAddress,
  1734. NumberOfUchars,
  1735. MmFrameBufferCached);
  1736. if (mappedAddress == NULL) {
  1737. mappedAddress = MmMapIoSpace(cardAddress,
  1738. NumberOfUchars,
  1739. FALSE);
  1740. }
  1741. } else if (bLargePage) {
  1742. mappedAddress = MmMapVideoDisplay(cardAddress,
  1743. NumberOfUchars,
  1744. 0);
  1745. } else {
  1746. mappedAddress = MmMapIoSpace(cardAddress,
  1747. NumberOfUchars,
  1748. FALSE);
  1749. }
  1750. if (mappedAddress == NULL) {
  1751. ExFreePool(newMappedAddress);
  1752. pVideoDebugPrint((Error, "VIDEOPRT: MmMapIoSpace FAILED\n"));
  1753. return NULL;
  1754. }
  1755. bMapped = TRUE;
  1756. fdoExtension->MemoryPTEUsage +=
  1757. ADDRESS_AND_SIZE_TO_SPAN_PAGES(mappedAddress,
  1758. NumberOfUchars);
  1759. }
  1760. //
  1761. // Save the reference
  1762. //
  1763. newMappedAddress->PhysicalAddress = cardAddress;
  1764. newMappedAddress->RefCount = 1;
  1765. newMappedAddress->MappedAddress = mappedAddress;
  1766. newMappedAddress->NumberOfUchars = NumberOfUchars;
  1767. newMappedAddress->InIoSpace = InIoSpace;
  1768. newMappedAddress->bNeedsUnmapping = bMapped;
  1769. newMappedAddress->bLargePageRequest = bLargePage;
  1770. //
  1771. // Link current list to new entry.
  1772. //
  1773. newMappedAddress->NextMappedAddress = fdoExtension->MappedAddressList;
  1774. //
  1775. // Point anchor at new list.
  1776. //
  1777. fdoExtension->MappedAddressList = newMappedAddress;
  1778. } else {
  1779. pVideoDebugPrint((Error, "VIDEOPRT: VpTranslateBusAddress failed\n"));
  1780. }
  1781. pVideoDebugPrint((Info, "VIDEOPRT: VideoPortGetDeviceBase mapped virtual address is %08lx\n",
  1782. mappedAddress));
  1783. return mappedAddress;
  1784. } // end VideoPortGetDeviceBase()
  1785. NTSTATUS
  1786. pVideoPortGetDeviceDataRegistry(
  1787. IN PVOID Context,
  1788. IN PUNICODE_STRING PathName,
  1789. IN INTERFACE_TYPE BusType,
  1790. IN ULONG BusNumber,
  1791. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  1792. IN CONFIGURATION_TYPE ControllerType,
  1793. IN ULONG ControllerNumber,
  1794. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  1795. IN CONFIGURATION_TYPE PeripheralType,
  1796. IN ULONG PeripheralNumber,
  1797. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. Arguments:
  1802. Return Value:
  1803. Environment:
  1804. This routine cannot be called from a miniport routine synchronized with
  1805. VideoPortSynchronizeRoutine or from an ISR.
  1806. --*/
  1807. {
  1808. //
  1809. // This macro should be in the io system header file.
  1810. //
  1811. #define GetIoQueryDeviceInfo(DeviceInfo, InfoType) \
  1812. ((PVOID) ( ((PUCHAR) (*(DeviceInfo + InfoType))) + \
  1813. ((ULONG_PTR) (*(DeviceInfo + InfoType))->DataOffset) ))
  1814. #define GetIoQueryDeviceInfoLength(DeviceInfo, InfoType) \
  1815. ((*(DeviceInfo + InfoType))->DataLength)
  1816. PVP_QUERY_DEVICE queryDevice = Context;
  1817. PKEY_VALUE_FULL_INFORMATION *deviceInformation;
  1818. PCM_FULL_RESOURCE_DESCRIPTOR configurationData;
  1819. switch (queryDevice->DeviceDataType) {
  1820. case VpBusData:
  1821. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: BusData\n"));
  1822. configurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)
  1823. GetIoQueryDeviceInfo(BusInformation,
  1824. IoQueryDeviceConfigurationData);
  1825. if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
  1826. queryDevice->CallbackRoutine)(
  1827. queryDevice->MiniportHwDeviceExtension,
  1828. queryDevice->MiniportContext,
  1829. queryDevice->DeviceDataType,
  1830. GetIoQueryDeviceInfo(BusInformation,
  1831. IoQueryDeviceIdentifier),
  1832. GetIoQueryDeviceInfoLength(BusInformation,
  1833. IoQueryDeviceIdentifier),
  1834. (PVOID) &(configurationData->PartialResourceList.PartialDescriptors[1]),
  1835. configurationData->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize,
  1836. GetIoQueryDeviceInfo(BusInformation,
  1837. IoQueryDeviceComponentInformation),
  1838. GetIoQueryDeviceInfoLength(BusInformation,
  1839. IoQueryDeviceComponentInformation)
  1840. )) {
  1841. return STATUS_SUCCESS;
  1842. } else {
  1843. return STATUS_DEVICE_DOES_NOT_EXIST;
  1844. }
  1845. break;
  1846. case VpControllerData:
  1847. deviceInformation = ControllerInformation;
  1848. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: ControllerData\n"));
  1849. //
  1850. // This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
  1851. //
  1852. if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
  1853. queryDevice->CallbackRoutine)(
  1854. queryDevice->MiniportHwDeviceExtension,
  1855. queryDevice->MiniportContext,
  1856. queryDevice->DeviceDataType,
  1857. GetIoQueryDeviceInfo(deviceInformation,
  1858. IoQueryDeviceIdentifier),
  1859. GetIoQueryDeviceInfoLength(deviceInformation,
  1860. IoQueryDeviceIdentifier),
  1861. GetIoQueryDeviceInfo(deviceInformation,
  1862. IoQueryDeviceConfigurationData),
  1863. GetIoQueryDeviceInfoLength(deviceInformation,
  1864. IoQueryDeviceConfigurationData),
  1865. GetIoQueryDeviceInfo(deviceInformation,
  1866. IoQueryDeviceComponentInformation),
  1867. GetIoQueryDeviceInfoLength(deviceInformation,
  1868. IoQueryDeviceComponentInformation)
  1869. )) {
  1870. return STATUS_SUCCESS;
  1871. } else {
  1872. return STATUS_DEVICE_DOES_NOT_EXIST;
  1873. }
  1874. break;
  1875. case VpMonitorData:
  1876. deviceInformation = PeripheralInformation;
  1877. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceDataCallback: MonitorData\n"));
  1878. //
  1879. // This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
  1880. //
  1881. if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
  1882. queryDevice->CallbackRoutine)(
  1883. queryDevice->MiniportHwDeviceExtension,
  1884. queryDevice->MiniportContext,
  1885. queryDevice->DeviceDataType,
  1886. GetIoQueryDeviceInfo(deviceInformation,
  1887. IoQueryDeviceIdentifier),
  1888. GetIoQueryDeviceInfoLength(deviceInformation,
  1889. IoQueryDeviceIdentifier),
  1890. GetIoQueryDeviceInfo(deviceInformation,
  1891. IoQueryDeviceConfigurationData),
  1892. GetIoQueryDeviceInfoLength(deviceInformation,
  1893. IoQueryDeviceConfigurationData),
  1894. GetIoQueryDeviceInfo(deviceInformation,
  1895. IoQueryDeviceComponentInformation),
  1896. GetIoQueryDeviceInfoLength(deviceInformation,
  1897. IoQueryDeviceComponentInformation)
  1898. )) {
  1899. return STATUS_SUCCESS;
  1900. } else {
  1901. return STATUS_DEVICE_DOES_NOT_EXIST;
  1902. }
  1903. break;
  1904. default:
  1905. ASSERT(FALSE);
  1906. return STATUS_UNSUCCESSFUL;
  1907. }
  1908. } // end pVideoPortGetDeviceDataRegistry()
  1909. VP_STATUS
  1910. VideoPortGetDeviceData(
  1911. PVOID HwDeviceExtension,
  1912. VIDEO_DEVICE_DATA_TYPE DeviceDataType,
  1913. PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
  1914. PVOID Context
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. VideoPortGetDeviceData retrieves information from the hardware hive in
  1919. the registry. The information retrieved from the registry is
  1920. bus-specific or hardware-specific.
  1921. Arguments:
  1922. HwDeviceExtension - Points to the miniport driver's device extension.
  1923. DeviceDataType - Specifies the type of data being requested (as indicated
  1924. in VIDEO_DEVICE_DATA_TYPE).
  1925. CallbackRoutine - Points to a function that should be called back with
  1926. the requested information.
  1927. Context - Specifies a context parameter passed to the callback function.
  1928. Return Value:
  1929. This function returns the final status of the operation.
  1930. Environment:
  1931. This routine cannot be called from a miniport routine synchronized with
  1932. VideoPortSynchronizeRoutine or from an ISR.
  1933. --*/
  1934. {
  1935. #define CMOS_MAX_DATA_SIZE 66000
  1936. NTSTATUS ntStatus;
  1937. VP_STATUS vpStatus;
  1938. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  1939. VP_QUERY_DEVICE queryDevice;
  1940. PUCHAR cmosData = NULL;
  1941. ULONG cmosDataSize;
  1942. ULONG exCmosDataSize;
  1943. UNICODE_STRING Identifier;
  1944. PULONG pConfiguration = NULL;
  1945. PULONG pComponent = NULL;
  1946. queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
  1947. queryDevice.DeviceDataType = DeviceDataType;
  1948. queryDevice.CallbackRoutine = CallbackRoutine;
  1949. queryDevice.MiniportStatus = NO_ERROR;
  1950. queryDevice.MiniportContext = Context;
  1951. switch (DeviceDataType) {
  1952. case VpMachineData:
  1953. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: MachineData\n"));
  1954. ntStatus = STATUS_UNSUCCESSFUL;
  1955. pConfiguration = ExAllocatePoolWithTag(PagedPool,
  1956. 0x1000,
  1957. VP_TAG);
  1958. pComponent = ExAllocatePoolWithTag(PagedPool,
  1959. 0x1000,
  1960. VP_TAG);
  1961. if (pConfiguration && pComponent)
  1962. {
  1963. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  1964. { NULL,
  1965. RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
  1966. L"Identifier",
  1967. &Identifier,
  1968. REG_NONE,
  1969. NULL,
  1970. 0
  1971. },
  1972. { NULL,
  1973. RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
  1974. L"Configuration Data",
  1975. pConfiguration,
  1976. REG_NONE,
  1977. NULL,
  1978. 0
  1979. },
  1980. { NULL,
  1981. RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
  1982. L"Component Information",
  1983. pComponent,
  1984. REG_NONE,
  1985. NULL,
  1986. 0
  1987. },
  1988. // Null entry to mark the end
  1989. { 0, 0, 0, 0, 0, 0, 0 }
  1990. };
  1991. //
  1992. // The first DWORD of the buffer contains the size of the buffer.
  1993. // Upon return, the first return contains the size of the data in the buffer.
  1994. //
  1995. // A NULL bufferint he UNICODE_STRING means the unicode string will be set up automatically
  1996. //
  1997. *pConfiguration = 0x1000 - 4;
  1998. *pComponent = 0x1000 - 4;
  1999. Identifier.Buffer = NULL;
  2000. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  2001. L"\\Registry\\Machine\\Hardware\\Description\\System",
  2002. QueryTable,
  2003. NULL,
  2004. NULL)))
  2005. {
  2006. vpStatus = ((PMINIPORT_QUERY_DEVICE_ROUTINE) CallbackRoutine)(
  2007. HwDeviceExtension,
  2008. Context,
  2009. DeviceDataType,
  2010. Identifier.Buffer,
  2011. Identifier.Length,
  2012. pConfiguration + 1,
  2013. *pConfiguration,
  2014. pComponent + 1,
  2015. *pComponent);
  2016. if (vpStatus == NO_ERROR)
  2017. {
  2018. ntStatus = STATUS_SUCCESS;
  2019. }
  2020. }
  2021. if (Identifier.Buffer)
  2022. {
  2023. ExFreePool(Identifier.Buffer);
  2024. }
  2025. }
  2026. //
  2027. // Free up the resources
  2028. //
  2029. if (pConfiguration)
  2030. {
  2031. ExFreePool(pConfiguration);
  2032. }
  2033. if (pComponent)
  2034. {
  2035. ExFreePool(pComponent);
  2036. }
  2037. break;
  2038. case VpCmosData:
  2039. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: CmosData - not implemented\n"));
  2040. #if !defined(NO_LEGACY_DRIVERS)
  2041. cmosData = ExAllocatePoolWithTag(PagedPool,
  2042. CMOS_MAX_DATA_SIZE,
  2043. VP_TAG);
  2044. //
  2045. // Allocate enough pool to store all the CMOS data.
  2046. //
  2047. if (!cmosData) {
  2048. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2049. break;
  2050. }
  2051. cmosDataSize = HalGetBusData(Cmos,
  2052. 0, // bus 0 returns standard Cmos info
  2053. 0, // no slot number
  2054. cmosData,
  2055. CMOS_MAX_DATA_SIZE);
  2056. exCmosDataSize = HalGetBusData(Cmos,
  2057. 1, // bus 1 returns extended Cmos info
  2058. 0, // no slot number
  2059. cmosData + cmosDataSize,
  2060. CMOS_MAX_DATA_SIZE - cmosDataSize);
  2061. //
  2062. // Call the miniport driver callback routine
  2063. //
  2064. if (NO_ERROR == CallbackRoutine(HwDeviceExtension,
  2065. Context,
  2066. DeviceDataType,
  2067. NULL,
  2068. 0,
  2069. cmosData,
  2070. cmosDataSize + exCmosDataSize,
  2071. NULL,
  2072. 0)) {
  2073. ntStatus = STATUS_SUCCESS;
  2074. } else {
  2075. ntStatus = STATUS_DEVICE_DOES_NOT_EXIST;
  2076. }
  2077. #endif // NO_LEGACY_DRIVERS
  2078. break;
  2079. break;
  2080. case VpBusData:
  2081. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: BusData\n"));
  2082. ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
  2083. &fdoExtension->SystemIoBusNumber,
  2084. NULL,
  2085. NULL,
  2086. NULL,
  2087. NULL,
  2088. &pVideoPortGetDeviceDataRegistry,
  2089. (PVOID)(&queryDevice));
  2090. break;
  2091. case VpControllerData:
  2092. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: ControllerData\n"));
  2093. //
  2094. // Increment the controller number since we want to get info on the
  2095. // new controller.
  2096. // We do a pre-increment since the number must remain the same for
  2097. // monitor queries.
  2098. //
  2099. VpQueryDeviceControllerNumber++;
  2100. ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
  2101. &fdoExtension->SystemIoBusNumber,
  2102. &VpQueryDeviceControllerType,
  2103. &VpQueryDeviceControllerNumber,
  2104. NULL,
  2105. NULL,
  2106. &pVideoPortGetDeviceDataRegistry,
  2107. (PVOID)(&queryDevice));
  2108. //
  2109. // Reset the Peripheral number to zero since we are working on a new
  2110. // Controller.
  2111. //
  2112. VpQueryDevicePeripheralNumber = 0;
  2113. break;
  2114. case VpMonitorData:
  2115. pVideoDebugPrint((Trace, "VIDEOPRT: VPGetDeviceData: MonitorData\n"));
  2116. ntStatus = IoQueryDeviceDescription(&fdoExtension->AdapterInterfaceType,
  2117. &fdoExtension->SystemIoBusNumber,
  2118. &VpQueryDeviceControllerType,
  2119. &VpQueryDeviceControllerNumber,
  2120. &VpQueryDevicePeripheralType,
  2121. &VpQueryDevicePeripheralNumber,
  2122. &pVideoPortGetDeviceDataRegistry,
  2123. (PVOID)(&queryDevice));
  2124. //
  2125. // Increment the peripheral number since we have the info on this
  2126. // monitor already.
  2127. //
  2128. VpQueryDevicePeripheralNumber++;
  2129. break;
  2130. default:
  2131. pVideoDebugPrint((Warn, "VIDEOPRT: VPGetDeviceData: invalid Data type\n"));
  2132. ASSERT(FALSE);
  2133. ntStatus = STATUS_UNSUCCESSFUL;
  2134. }
  2135. //
  2136. // Free the pool we may have allocated
  2137. //
  2138. if (cmosData) {
  2139. ExFreePool(cmosData);
  2140. }
  2141. if (NT_SUCCESS(ntStatus)) {
  2142. return NO_ERROR;
  2143. } else {
  2144. pVideoDebugPrint((Warn, "VPGetDeviceData failed: return status is %08lx\n", ntStatus));
  2145. return ERROR_INVALID_PARAMETER;
  2146. }
  2147. } // end VideoPortGetDeviceData()
  2148. NTSTATUS
  2149. pVideoPortGetRegistryCallback(
  2150. IN PWSTR ValueName,
  2151. IN ULONG ValueType,
  2152. IN PVOID ValueData,
  2153. IN ULONG ValueLength,
  2154. IN PVOID Context,
  2155. IN PVOID EntryContext
  2156. )
  2157. /*++
  2158. Routine Description:
  2159. This routine gets information from the system hive, user-specified
  2160. registry (as opposed to the information gathered by ntdetect.
  2161. Arguments:
  2162. ValueName - Pointer to a unicode String containing the name of the data
  2163. value being searched for.
  2164. ValueType - Type of the data value.
  2165. ValueData - Pointer to a buffer containing the information to be written
  2166. out to the registry.
  2167. ValueLength - Size of the data being written to the registry.
  2168. Context - Specifies a context parameter passed to the callback routine.
  2169. EntryContext - Specifies a second context parameter passed with the
  2170. request.
  2171. Return Value:
  2172. STATUS_SUCCESS
  2173. Environment:
  2174. This routine cannot be called from a miniport routine synchronized with
  2175. VideoPortSynchronizeRoutine or from an ISR.
  2176. --*/
  2177. {
  2178. PVP_QUERY_DEVICE queryDevice = Context;
  2179. UNICODE_STRING unicodeString;
  2180. OBJECT_ATTRIBUTES objectAttributes;
  2181. NTSTATUS ntStatus = STATUS_SUCCESS;
  2182. HANDLE fileHandle = NULL;
  2183. IO_STATUS_BLOCK ioStatusBlock;
  2184. FILE_STANDARD_INFORMATION fileStandardInfo;
  2185. PVOID fileBuffer = NULL;
  2186. LARGE_INTEGER byteOffset;
  2187. //
  2188. // If the parameter was a file to be opened, perform the operation
  2189. // here. Otherwise just return the data.
  2190. //
  2191. if (queryDevice->DeviceDataType == VP_GET_REGISTRY_FILE) {
  2192. //
  2193. // For the name of the file to be valid, we must first append
  2194. // \DosDevices in front of it.
  2195. //
  2196. RtlInitUnicodeString(&unicodeString,
  2197. ValueData);
  2198. InitializeObjectAttributes(&objectAttributes,
  2199. &unicodeString,
  2200. OBJ_CASE_INSENSITIVE,
  2201. (HANDLE) NULL,
  2202. (PSECURITY_DESCRIPTOR) NULL);
  2203. ntStatus = ZwOpenFile(&fileHandle,
  2204. FILE_GENERIC_READ | SYNCHRONIZE,
  2205. &objectAttributes,
  2206. &ioStatusBlock,
  2207. 0,
  2208. FILE_SYNCHRONOUS_IO_ALERT);
  2209. if (!NT_SUCCESS(ntStatus)) {
  2210. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not open file\n"));
  2211. goto EndRegistryCallback;
  2212. }
  2213. ntStatus = ZwQueryInformationFile(fileHandle,
  2214. &ioStatusBlock,
  2215. &fileStandardInfo,
  2216. sizeof(FILE_STANDARD_INFORMATION),
  2217. FileStandardInformation);
  2218. if (!NT_SUCCESS(ntStatus)) {
  2219. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not get size of file\n"));
  2220. goto EndRegistryCallback;
  2221. }
  2222. if (fileStandardInfo.EndOfFile.HighPart) {
  2223. //
  2224. // If file is too big, do not try to go further.
  2225. //
  2226. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2227. goto EndRegistryCallback;
  2228. }
  2229. ValueLength = fileStandardInfo.EndOfFile.LowPart;
  2230. fileBuffer = ExAllocatePoolWithTag(PagedPool,
  2231. ValueLength,
  2232. VP_TAG);
  2233. if (!fileBuffer) {
  2234. pVideoDebugPrint((Error, "VideoPortGetRegistryParameters: Could not allocate buffer to read file\n"));
  2235. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2236. goto EndRegistryCallback;
  2237. }
  2238. ValueData = fileBuffer;
  2239. //
  2240. // Read the entire file for the beginning.
  2241. //
  2242. byteOffset.QuadPart = 0;
  2243. ntStatus = ZwReadFile(fileHandle,
  2244. NULL,
  2245. NULL,
  2246. NULL,
  2247. &ioStatusBlock,
  2248. ValueData,
  2249. ValueLength,
  2250. &byteOffset,
  2251. NULL);
  2252. if (!NT_SUCCESS(ntStatus)) {
  2253. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortGetRegistryParameters: Could not read file\n"));
  2254. goto EndRegistryCallback;
  2255. }
  2256. }
  2257. //
  2258. // Call the miniport with the appropriate information.
  2259. //
  2260. queryDevice->MiniportStatus = ((PMINIPORT_GET_REGISTRY_ROUTINE)
  2261. queryDevice->CallbackRoutine) (queryDevice->MiniportHwDeviceExtension,
  2262. queryDevice->MiniportContext,
  2263. ValueName,
  2264. ValueData,
  2265. ValueLength);
  2266. EndRegistryCallback:
  2267. if (fileHandle) {
  2268. ZwClose(fileHandle);
  2269. }
  2270. if (fileBuffer) {
  2271. ExFreePool(fileBuffer);
  2272. }
  2273. return ntStatus;
  2274. } // end pVideoPortGetRegistryCallback()
  2275. VP_STATUS
  2276. VideoPortGetRegistryParameters(
  2277. PVOID HwDeviceExtension,
  2278. PWSTR ParameterName,
  2279. UCHAR IsParameterFileName,
  2280. PMINIPORT_GET_REGISTRY_ROUTINE CallbackRoutine,
  2281. PVOID Context
  2282. )
  2283. /*++
  2284. Routine Description:
  2285. VideoPortGetRegistryParameters retrieves information from the
  2286. CurrentControlSet in the registry. The function automatically searches
  2287. for the specified parameter name under the \Devicexxx key for the
  2288. current driver.
  2289. Arguments:
  2290. HwDeviceExtension - Points to the miniport driver's device extension.
  2291. ParameterName - Points to a Unicode string that contains the name of the
  2292. data value being searched for in the registry.
  2293. IsParameterFileName - If 1, the data retrieved from the requested
  2294. parameter name is treated as a file name. The contents of the file are
  2295. returned, instead of the parameter itself.
  2296. CallbackRoutine - Points to a function that should be called back with
  2297. the requested information.
  2298. Context - Specifies a context parameter passed to the callback routine.
  2299. Return Value:
  2300. This function returns the final status of the operation.
  2301. Environment:
  2302. This routine cannot be called from a miniport routine synchronized with
  2303. VideoPortSynchronizeRoutine or from an ISR.
  2304. --*/
  2305. {
  2306. VP_STATUS vpStatus = ERROR_INVALID_PARAMETER;
  2307. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
  2308. if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
  2309. vpStatus = VPGetRegistryParameters(HwDeviceExtension,
  2310. ParameterName,
  2311. IsParameterFileName,
  2312. CallbackRoutine,
  2313. Context,
  2314. DoSpecificExtension->DriverNewRegistryPath,
  2315. DoSpecificExtension->DriverNewRegistryPathLength);
  2316. } else {
  2317. vpStatus = VPGetRegistryParameters(HwDeviceExtension,
  2318. ParameterName,
  2319. IsParameterFileName,
  2320. CallbackRoutine,
  2321. Context,
  2322. DoSpecificExtension->DriverOldRegistryPath,
  2323. DoSpecificExtension->DriverOldRegistryPathLength);
  2324. }
  2325. return vpStatus;
  2326. }
  2327. VP_STATUS
  2328. VPGetRegistryParameters(
  2329. PVOID HwDeviceExtension,
  2330. PWSTR ParameterName,
  2331. UCHAR IsParameterFileName,
  2332. PMINIPORT_GET_REGISTRY_ROUTINE CallbackRoutine,
  2333. PVOID Context,
  2334. PWSTR RegistryPath,
  2335. ULONG RegistryPathLength
  2336. )
  2337. {
  2338. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  2339. NTSTATUS ntStatus;
  2340. VP_QUERY_DEVICE queryDevice;
  2341. LPWSTR RegPath;
  2342. LPWSTR lpstrStart, lpstrEnd;
  2343. ASSERT (ParameterName != NULL);
  2344. //
  2345. // Check if there are subkeys to be entered
  2346. //
  2347. RegPath = (LPWSTR) ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  2348. RegistryPathLength +
  2349. 2 * (wcslen(ParameterName) + sizeof(WCHAR)),
  2350. VP_TAG);
  2351. if (RegPath == NULL) {
  2352. return ERROR_NOT_ENOUGH_MEMORY;
  2353. }
  2354. wcscpy(RegPath, RegistryPath);
  2355. if (!IsParameterFileName)
  2356. {
  2357. lpstrStart = RegPath + (RegistryPathLength / 2);
  2358. while (lpstrEnd = wcschr(ParameterName, L'\\'))
  2359. {
  2360. //
  2361. // Concat the string
  2362. //
  2363. *(lpstrStart++) = L'\\';
  2364. while (ParameterName != lpstrEnd) {
  2365. *(lpstrStart++) = *(ParameterName++);
  2366. }
  2367. *lpstrStart = UNICODE_NULL;
  2368. ParameterName++;
  2369. }
  2370. }
  2371. queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
  2372. queryDevice.DeviceDataType = IsParameterFileName ? VP_GET_REGISTRY_FILE : VP_GET_REGISTRY_DATA;
  2373. queryDevice.CallbackRoutine = CallbackRoutine;
  2374. queryDevice.MiniportStatus = NO_ERROR;
  2375. queryDevice.MiniportContext = Context;
  2376. //
  2377. // Can be simplified now since we don't have to go down a directory.
  2378. // It can be just one call.
  2379. //
  2380. queryTable[0].QueryRoutine = pVideoPortGetRegistryCallback;
  2381. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  2382. queryTable[0].Name = ParameterName;
  2383. queryTable[0].EntryContext = NULL;
  2384. queryTable[0].DefaultType = REG_NONE;
  2385. queryTable[0].DefaultData = 0;
  2386. queryTable[0].DefaultLength = 0;
  2387. queryTable[1].QueryRoutine = NULL;
  2388. queryTable[1].Flags = 0;
  2389. queryTable[1].Name = NULL;
  2390. queryTable[1].EntryContext = NULL;
  2391. queryTable[1].DefaultType = REG_NONE;
  2392. queryTable[1].DefaultData = 0;
  2393. queryTable[1].DefaultLength = 0;
  2394. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  2395. RegPath,
  2396. queryTable,
  2397. &queryDevice,
  2398. NULL);
  2399. if (!NT_SUCCESS(ntStatus)) {
  2400. queryDevice.MiniportStatus = ERROR_INVALID_PARAMETER;
  2401. }
  2402. ExFreePool(RegPath);
  2403. return queryDevice.MiniportStatus;
  2404. } // end VideoPortGetRegistryParameters()
  2405. VOID
  2406. pVPInit(
  2407. VOID
  2408. )
  2409. /*++
  2410. Routine Description:
  2411. First time initialization of the video port.
  2412. Normally, this is the stuff we should put in the DriverEntry routine.
  2413. However, the video port is being loaded as a DLL, and the DriverEntry
  2414. is never called. It would just be too much work to add it back to the hive
  2415. and setup.
  2416. This little routine works just as well.
  2417. --*/
  2418. {
  2419. UNICODE_STRING UnicodeString;
  2420. OBJECT_ATTRIBUTES ObjectAttributes;
  2421. NTSTATUS ntStatus;
  2422. HANDLE hkRegistry;
  2423. UCHAR OptionsData[512];
  2424. HANDLE physicalMemoryHandle = NULL;
  2425. PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus;
  2426. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = NULL;
  2427. HAL_DISPLAY_BIOS_INFORMATION HalBiosInfo;
  2428. ULONG HalBiosInfoLen = sizeof(ULONG);
  2429. SYSTEM_BASIC_INFORMATION basicInfo;
  2430. //
  2431. // Check for USWC disabling
  2432. //
  2433. RtlInitUnicodeString(&UnicodeString,
  2434. L"\\Registry\\Machine\\System\\CurrentControlSet"
  2435. L"\\Control\\GraphicsDrivers\\DisableUSWC");
  2436. InitializeObjectAttributes(&ObjectAttributes,
  2437. &UnicodeString,
  2438. OBJ_CASE_INSENSITIVE,
  2439. NULL,
  2440. NULL);
  2441. ntStatus = ZwOpenKey(&hkRegistry,
  2442. GENERIC_READ | GENERIC_WRITE,
  2443. &ObjectAttributes);
  2444. if (NT_SUCCESS(ntStatus)) {
  2445. EnableUSWC = FALSE;
  2446. ZwClose(hkRegistry);
  2447. }
  2448. //
  2449. // Check for setup running
  2450. //
  2451. {
  2452. ULONG defaultValue = 0;
  2453. ULONG UpgradeInProgress = 0, SystemSetupInProgress = 0, MiniSetupInProgress = 0;
  2454. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  2455. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"SystemSetupInProgress",
  2456. &SystemSetupInProgress, REG_DWORD, &defaultValue, 4},
  2457. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"UpgradeInProgress",
  2458. &UpgradeInProgress, REG_DWORD, &defaultValue, 4},
  2459. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"MiniSetupInProgress",
  2460. &MiniSetupInProgress, REG_DWORD, &defaultValue, 4},
  2461. {NULL, 0, NULL}
  2462. };
  2463. RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  2464. L"\\Registry\\Machine\\System\\Setup",
  2465. &QueryTable[0],
  2466. NULL,
  2467. NULL);
  2468. // System is doing an upgrade.
  2469. if (UpgradeInProgress)
  2470. {
  2471. ASSERT(SystemSetupInProgress);
  2472. VpSetupType = SETUPTYPE_UPGRADE;
  2473. }
  2474. // System is doing a clean install.
  2475. else if (SystemSetupInProgress && !MiniSetupInProgress)
  2476. {
  2477. VpSetupType = SETUPTYPE_FULL;
  2478. }
  2479. else
  2480. {
  2481. VpSetupType = SETUPTYPE_NONE;
  2482. }
  2483. VpSetupTypeAtBoot = VpSetupType;
  2484. }
  2485. //
  2486. // Check for basevideo from the start options
  2487. //
  2488. RtlInitUnicodeString(&UnicodeString,
  2489. L"\\Registry\\Machine\\System\\CurrentControlSet"
  2490. L"\\Control");
  2491. InitializeObjectAttributes(&ObjectAttributes,
  2492. &UnicodeString,
  2493. OBJ_CASE_INSENSITIVE,
  2494. NULL,
  2495. NULL);
  2496. ntStatus = ZwOpenKey(&hkRegistry,
  2497. GENERIC_READ | GENERIC_WRITE,
  2498. &ObjectAttributes);
  2499. if (NT_SUCCESS(ntStatus)) {
  2500. PVOID pwszOptions;
  2501. ULONG returnSize;
  2502. RtlInitUnicodeString(&UnicodeString,
  2503. L"SystemStartOptions");
  2504. ntStatus = ZwQueryValueKey(hkRegistry,
  2505. &UnicodeString,
  2506. KeyValueFullInformation,
  2507. OptionsData,
  2508. sizeof(OptionsData),
  2509. &returnSize);
  2510. if ((NT_SUCCESS(ntStatus)) &&
  2511. (((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataLength) &&
  2512. (((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset)) {
  2513. pwszOptions = ((PUCHAR)OptionsData) +
  2514. ((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset;
  2515. if (wcsstr(pwszOptions, L"BASEVIDEO")) {
  2516. VpBaseVideo = TRUE;
  2517. }
  2518. }
  2519. ZwClose(hkRegistry);
  2520. }
  2521. if (VpBaseVideo == TRUE)
  2522. {
  2523. //
  2524. // If we are in Basevideo mode, then create a key and value in the
  2525. // currentcontrolset part of the hardware profile that USER will
  2526. // read to determine if the vga driver should be used or not.
  2527. //
  2528. RtlInitUnicodeString(&UnicodeString,
  2529. L"\\Registry\\Machine\\System\\CurrentControlSet\\"
  2530. L"Control\\GraphicsDrivers\\BaseVideo");
  2531. InitializeObjectAttributes(&ObjectAttributes,
  2532. &UnicodeString,
  2533. OBJ_CASE_INSENSITIVE,
  2534. NULL,
  2535. NULL);
  2536. ntStatus = ZwCreateKey(&hkRegistry,
  2537. GENERIC_READ | GENERIC_WRITE,
  2538. &ObjectAttributes,
  2539. 0L,
  2540. NULL,
  2541. REG_OPTION_VOLATILE,
  2542. NULL);
  2543. if (NT_SUCCESS(ntStatus)) {
  2544. ZwClose(hkRegistry);
  2545. } else {
  2546. ASSERT(FALSE);
  2547. }
  2548. }
  2549. //
  2550. // Determine if we have a VGA compatible machine
  2551. //
  2552. ntStatus = HalQuerySystemInformation(HalDisplayBiosInformation,
  2553. HalBiosInfoLen,
  2554. &HalBiosInfo,
  2555. &HalBiosInfoLen);
  2556. if (NT_SUCCESS(ntStatus)) {
  2557. if (HalBiosInfo == HalDisplayInt10Bios) {
  2558. VpC0000Compatible = 2;
  2559. } else {
  2560. // == HalDisplayEmulatedBios,
  2561. // == HalDisplayNoBios
  2562. VpC0000Compatible = 0;
  2563. }
  2564. } else {
  2565. //
  2566. // In case of an error in the API call, we just assume it's an old HAL
  2567. // and use the old behaviour of the video port which is to assume
  2568. // there is a BIOS at C000
  2569. //
  2570. VpC0000Compatible = 1;
  2571. }
  2572. //
  2573. // Lets open the physical memory section just once, for all drivers.
  2574. //
  2575. //
  2576. // Get a pointer to physical memory so we can map the
  2577. // video frame buffer (and possibly video registers) into
  2578. // the caller's address space whenever he needs it.
  2579. //
  2580. // - Create the name
  2581. // - Initialize the data to find the object
  2582. // - Open a handle to the oject and check the status
  2583. // - Get a pointer to the object
  2584. // - Free the handle
  2585. //
  2586. RtlInitUnicodeString(&UnicodeString,
  2587. L"\\Device\\PhysicalMemory");
  2588. InitializeObjectAttributes(&ObjectAttributes,
  2589. &UnicodeString,
  2590. OBJ_CASE_INSENSITIVE,
  2591. (HANDLE) NULL,
  2592. (PSECURITY_DESCRIPTOR) NULL);
  2593. ntStatus = ZwOpenSection(&physicalMemoryHandle,
  2594. SECTION_ALL_ACCESS,
  2595. &ObjectAttributes);
  2596. if (NT_SUCCESS(ntStatus)) {
  2597. ntStatus = ObReferenceObjectByHandle(physicalMemoryHandle,
  2598. SECTION_ALL_ACCESS,
  2599. (POBJECT_TYPE) NULL,
  2600. KernelMode,
  2601. &PhysicalMemorySection,
  2602. (POBJECT_HANDLE_INFORMATION) NULL);
  2603. if (!NT_SUCCESS(ntStatus)) {
  2604. pVideoDebugPrint((Warn, "VIDEOPRT: VPInit: Could not reference physical memory\n"));
  2605. ASSERT(PhysicalMemorySection == NULL);
  2606. }
  2607. ZwClose(physicalMemoryHandle);
  2608. }
  2609. VpSystemMemorySize = 0;
  2610. ntStatus = ZwQuerySystemInformation(SystemBasicInformation,
  2611. &basicInfo,
  2612. sizeof(basicInfo),
  2613. NULL);
  2614. if (NT_SUCCESS(ntStatus)) {
  2615. VpSystemMemorySize
  2616. = (ULONGLONG)basicInfo.NumberOfPhysicalPages * (ULONGLONG)basicInfo.PageSize;
  2617. }
  2618. //
  2619. // Initialize the fast mutex to protect the LCD Panel information
  2620. // Initialize the fast mutex to protect INT10
  2621. //
  2622. KeInitializeMutex (&LCDPanelMutex, 0);
  2623. KeInitializeMutex (&VpInt10Mutex, 0);
  2624. //
  2625. // Check if we should use the new way of generating the registry path
  2626. //
  2627. RtlInitUnicodeString(&UnicodeString,
  2628. SZ_USE_NEW_KEY);
  2629. InitializeObjectAttributes(&ObjectAttributes,
  2630. &UnicodeString,
  2631. OBJ_CASE_INSENSITIVE,
  2632. NULL,
  2633. NULL);
  2634. ntStatus = ZwOpenKey(&hkRegistry,
  2635. GENERIC_READ | GENERIC_WRITE,
  2636. &ObjectAttributes);
  2637. if (NT_SUCCESS(ntStatus)) {
  2638. EnableNewRegistryKey = TRUE;
  2639. ZwClose(hkRegistry);
  2640. }
  2641. //
  2642. // Initialize our structure which tracks the state of
  2643. // a backlight for the LCD (when present)
  2644. //
  2645. pVpBacklightStatus->bQuerySupportedBrightnessCalled = FALSE;
  2646. pVpBacklightStatus->bACBrightnessKnown = FALSE;
  2647. pVpBacklightStatus->bDCBrightnessKnown = FALSE;
  2648. pVpBacklightStatus->bBIOSDefaultACKnown = FALSE;
  2649. pVpBacklightStatus->bBIOSDefaultDCKnown = FALSE;
  2650. pVpBacklightStatus->bNewAPISupported = FALSE;
  2651. pVpBacklightStatus->bACBrightnessInRegistry = FALSE;
  2652. pVpBacklightStatus->bACBrightnessInRegistry = FALSE;
  2653. //
  2654. // Read the registry to find out if the new API is supported.
  2655. // If so, retreive the AC/DC brightness values and set the
  2656. // brightness as applicable (depending upon VpRunningOnAC).
  2657. //
  2658. // Note: We will store the Backlight info in the following
  2659. // location in the registry:
  2660. //
  2661. // HKLM\System\CurrentControlSet\Control\Backlight
  2662. //
  2663. // The values there will be:
  2664. //
  2665. // NewAPISupported REG_DWORD 0 Not Supported
  2666. // 1 Supported
  2667. //
  2668. //
  2669. // ACBacklightLevel REG_DWORD 0-255
  2670. //
  2671. // DCBacklightLevel REG_DWORD 0-255
  2672. //
  2673. pKeyValueInfo = ExAllocatePoolWithTag(PagedPool,
  2674. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
  2675. VP_TAG);
  2676. if (pKeyValueInfo == NULL) {
  2677. return;
  2678. }
  2679. RtlInitUnicodeString(&UnicodeString,
  2680. L"\\Registry\\Machine\\System\\CurrentControlSet"
  2681. L"\\Control\\Backlight");
  2682. InitializeObjectAttributes(&ObjectAttributes,
  2683. &UnicodeString,
  2684. OBJ_CASE_INSENSITIVE,
  2685. NULL,
  2686. NULL);
  2687. ntStatus = ZwOpenKey(&hkRegistry,
  2688. GENERIC_READ | GENERIC_WRITE,
  2689. &ObjectAttributes);
  2690. if (NT_SUCCESS(ntStatus)) {
  2691. //
  2692. // The key is there, read the 3 values listed above
  2693. //
  2694. ULONG ulReturnSize;
  2695. // NewAPISupported
  2696. RtlInitUnicodeString(&UnicodeString,
  2697. L"NewAPISupported");
  2698. ntStatus = ZwQueryValueKey(hkRegistry,
  2699. &UnicodeString,
  2700. KeyValuePartialInformation,
  2701. (PVOID) pKeyValueInfo,
  2702. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
  2703. &ulReturnSize);
  2704. if (NT_SUCCESS(ntStatus)) {
  2705. if ((UCHAR) *pKeyValueInfo->Data) {
  2706. pVpBacklightStatus->bNewAPISupported = TRUE;
  2707. }
  2708. // ACBacklightLevel
  2709. RtlInitUnicodeString(&UnicodeString,
  2710. L"ACBacklightLevel");
  2711. ntStatus = ZwQueryValueKey(hkRegistry,
  2712. &UnicodeString,
  2713. KeyValuePartialInformation,
  2714. (PVOID) pKeyValueInfo,
  2715. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
  2716. &ulReturnSize);
  2717. if (NT_SUCCESS(ntStatus)) {
  2718. pVpBacklightStatus->bACBrightnessInRegistry = TRUE;
  2719. pVpBacklightStatus->bACBrightnessKnown = TRUE;
  2720. pVpBacklightStatus->ucACBrightness = (UCHAR) *pKeyValueInfo->Data;
  2721. }
  2722. // DCBacklightLevel
  2723. RtlInitUnicodeString(&UnicodeString,
  2724. L"DCBacklightLevel");
  2725. ntStatus = ZwQueryValueKey(hkRegistry,
  2726. &UnicodeString,
  2727. KeyValuePartialInformation,
  2728. (PVOID) pKeyValueInfo,
  2729. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3,
  2730. &ulReturnSize);
  2731. if (NT_SUCCESS(ntStatus)) {
  2732. pVpBacklightStatus->bDCBrightnessInRegistry = TRUE;
  2733. pVpBacklightStatus->bDCBrightnessKnown = TRUE;
  2734. pVpBacklightStatus->ucDCBrightness = (UCHAR) *pKeyValueInfo->Data;
  2735. }
  2736. }
  2737. ZwClose(hkRegistry);
  2738. }
  2739. if (pKeyValueInfo) {
  2740. ExFreePool(pKeyValueInfo);
  2741. }
  2742. //
  2743. // Most laptops respond incorrectly to HwSetPowerState calls
  2744. // on lid close. By default, we will support the XP behavior
  2745. // and not notify the miniport on lid close.
  2746. //
  2747. // The driver will be called if the following registry key
  2748. // is present:
  2749. //
  2750. // HKLM\System\CurrentControlSet\Control\GraphicsDrivers\LidCloseSetPower"
  2751. //
  2752. RtlInitUnicodeString(&UnicodeString,
  2753. SZ_LIDCLOSE);
  2754. InitializeObjectAttributes(&ObjectAttributes,
  2755. &UnicodeString,
  2756. OBJ_CASE_INSENSITIVE,
  2757. NULL,
  2758. NULL);
  2759. ntStatus = ZwOpenKey(&hkRegistry,
  2760. GENERIC_READ | GENERIC_WRITE,
  2761. &ObjectAttributes);
  2762. if (NT_SUCCESS(ntStatus)) {
  2763. VpLidCloseSetPower = TRUE;
  2764. ZwClose(hkRegistry);
  2765. }
  2766. //
  2767. // Initialize the bugcheck callback record
  2768. //
  2769. KeInitializeCallbackRecord(&VpCallbackRecord);
  2770. //
  2771. // Regiter for bugcheck callbacks.
  2772. //
  2773. KeRegisterBugCheckReasonCallback(&VpCallbackRecord,
  2774. pVpBugcheckCallback,
  2775. KbCallbackSecondaryDumpData,
  2776. "Videoprt");
  2777. //
  2778. // Initialize the global video port mutex.
  2779. //
  2780. KeInitializeMutex(&VpGlobalLock, 0);
  2781. }
  2782. VOID
  2783. VpDriverUnload(
  2784. IN PDRIVER_OBJECT DriverObject
  2785. )
  2786. {
  2787. ULONG_PTR emptyList = 0;
  2788. BOOLEAN conflict;
  2789. //ULONG iReset;
  2790. //PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;
  2791. //
  2792. // Release the resource we put in the resourcemap (if any).
  2793. //
  2794. IoReportResourceUsage(&VideoClassName,
  2795. DriverObject,
  2796. NULL,
  2797. 0L,
  2798. NULL,
  2799. (PCM_RESOURCE_LIST) &emptyList,
  2800. sizeof(ULONG_PTR),
  2801. FALSE,
  2802. &conflict);
  2803. //
  2804. // Unregister LCD callbacks.
  2805. //
  2806. VpUnregisterLCDCallbacks();
  2807. //
  2808. // Unregister Dock/Undock callbacks.
  2809. //
  2810. if (DockCallbackHandle)
  2811. {
  2812. IoUnregisterPlugPlayNotification(DockCallbackHandle);
  2813. }
  2814. //
  2815. // Make absolutely certain there are no HwResetHw routines left
  2816. // for this devices controlled by this DriverObject.
  2817. //
  2818. //while (DeviceObject) {
  2819. //
  2820. // for (iReset=0; iReset<6; iReset++) {
  2821. //
  2822. // if (HwResetHw[iReset].HwDeviceExtension ==
  2823. // ((PDEVICE_EXTENSION)
  2824. // DeviceObject->DeviceExtension)->HwDeviceExtension) {
  2825. //
  2826. // HwResetHw[iReset].ResetFunction = NULL;
  2827. // break;
  2828. // }
  2829. // }
  2830. //
  2831. // DeviceObject = DeviceObject->NextDevice;
  2832. //}
  2833. // This is causing us to lose video on a number of systems
  2834. // during setup. This code can be used when the necessary
  2835. // additional checks are determined.
  2836. //
  2837. //if (CsrProcess) {
  2838. // ObDereferenceObject(CsrProcess);
  2839. // CsrProcess = NULL;
  2840. //}
  2841. //
  2842. // Unregister bugcheck callbacks
  2843. //
  2844. KeDeregisterBugCheckReasonCallback(&VpCallbackRecord);
  2845. return;
  2846. }
  2847. NTSTATUS
  2848. VpInitializeBusCallback(
  2849. IN PVOID Context,
  2850. IN PUNICODE_STRING PathName,
  2851. IN INTERFACE_TYPE BusType,
  2852. IN ULONG BusNumber,
  2853. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  2854. IN CONFIGURATION_TYPE ControllerType,
  2855. IN ULONG ControllerNumber,
  2856. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  2857. IN CONFIGURATION_TYPE PeripheralType,
  2858. IN ULONG PeripheralNumber,
  2859. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  2860. )
  2861. {
  2862. return STATUS_SUCCESS;
  2863. } // end VpInitializeBusCallback()
  2864. VP_STATUS
  2865. VpRegistryCallback(
  2866. PVOID HwDeviceExtension,
  2867. PVOID Context,
  2868. PWSTR ValueName,
  2869. PVOID ValueData,
  2870. ULONG ValueLength
  2871. )
  2872. {
  2873. if (ValueLength && ValueData) {
  2874. *((PULONG)Context) = *((PULONG)ValueData);
  2875. return NO_ERROR;
  2876. } else {
  2877. return ERROR_INVALID_PARAMETER;
  2878. }
  2879. }
  2880. NTSTATUS
  2881. VpAddDevice(
  2882. IN PDRIVER_OBJECT DriverObject,
  2883. IN PDEVICE_OBJECT PhysicalDeviceObject
  2884. )
  2885. {
  2886. NTSTATUS ntStatus;
  2887. PDEVICE_OBJECT functionalDeviceObject;
  2888. PDEVICE_OBJECT attachedTo;
  2889. PFDO_EXTENSION fdoExtension;
  2890. ULONG extensionAllocationSize;
  2891. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  2892. PVIDEO_HW_INITIALIZATION_DATA HwInitializationData;
  2893. pVideoDebugPrint((Trace, "VIDEOPRT: VpAddDevice\n"));
  2894. DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  2895. IoGetDriverObjectExtension(DriverObject,
  2896. DriverObject);
  2897. HwInitializationData = &DriverObjectExtension->HwInitData;
  2898. extensionAllocationSize = HwInitializationData->HwDeviceExtensionSize +
  2899. sizeof(FDO_EXTENSION) +
  2900. sizeof(DEVICE_SPECIFIC_EXTENSION);
  2901. ntStatus = VpCreateDevice(DriverObject,
  2902. extensionAllocationSize,
  2903. &functionalDeviceObject);
  2904. if (NT_SUCCESS(ntStatus)) {
  2905. PCHILD_PDO_EXTENSION PdoExtension = PhysicalDeviceObject->DeviceExtension;
  2906. VideoDeviceNumber++;
  2907. fdoExtension = (PFDO_EXTENSION)functionalDeviceObject->DeviceExtension;
  2908. //
  2909. // Set any deviceExtension fields here that are PnP specific
  2910. //
  2911. fdoExtension->ChildPdoNumber = 0;
  2912. fdoExtension->ChildPdoList = NULL;
  2913. fdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
  2914. //
  2915. // Since the pnp system is notifying us of our device, this is
  2916. // not a legacy device.
  2917. //
  2918. fdoExtension->Flags = PNP_ENABLED;
  2919. //
  2920. // Now attach to the PDO we were given.
  2921. //
  2922. attachedTo = IoAttachDeviceToDeviceStack(functionalDeviceObject,
  2923. PhysicalDeviceObject);
  2924. if (attachedTo == NULL) {
  2925. pVideoDebugPrint((Error, "VIDEOPRT: Could not attach in AddDevice.\n"));
  2926. ASSERT(attachedTo != NULL);
  2927. //
  2928. // Couldn't attach. Delete the FDO, and tear down anything that has
  2929. // been allocated so far.
  2930. //
  2931. VideoDeviceNumber--;
  2932. IoDeleteDevice (functionalDeviceObject);
  2933. return STATUS_NO_SUCH_DEVICE;
  2934. }
  2935. //
  2936. // Initialize the remove lock.
  2937. //
  2938. IoInitializeRemoveLock(&fdoExtension->RemoveLock, 0, 0, 256);
  2939. fdoExtension->AttachedDeviceObject = attachedTo;
  2940. fdoExtension->VpDmaAdapterHead = NULL ;
  2941. //
  2942. // Set the power management flag indicating that device mapping
  2943. // has not been done yet.
  2944. //
  2945. fdoExtension->IsMappingReady = FALSE ;
  2946. //
  2947. // Clear DO_DEVICE_INITIALIZING flag.
  2948. //
  2949. functionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  2950. functionalDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
  2951. //
  2952. // Save the function pointers to the new 5.0 miniport driver callbacks.
  2953. //
  2954. if (HwInitializationData->HwInitDataSize >
  2955. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) {
  2956. fdoExtension->HwSetPowerState = HwInitializationData->HwSetPowerState;
  2957. fdoExtension->HwGetPowerState = HwInitializationData->HwGetPowerState;
  2958. fdoExtension->HwQueryInterface = HwInitializationData->HwQueryInterface;
  2959. fdoExtension->HwGetVideoChildDescriptor = HwInitializationData->HwGetVideoChildDescriptor;
  2960. }
  2961. }
  2962. pVideoDebugPrint((Trace, "VIDEOPRT: VpAddDevice returned: 0x%x\n", ntStatus));
  2963. return ntStatus;
  2964. }
  2965. NTSTATUS
  2966. VpCreateDevice(
  2967. IN PDRIVER_OBJECT DriverObject,
  2968. IN ULONG DeviceExtensionSize,
  2969. OUT PDEVICE_OBJECT *FunctionalDeviceObject
  2970. )
  2971. {
  2972. WCHAR deviceNameBuffer[STRING_LENGTH];
  2973. UNICODE_STRING deviceNameUnicodeString;
  2974. NTSTATUS ntStatus;
  2975. PFDO_EXTENSION fdoExtension;
  2976. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  2977. ntStatus = pVideoPortCreateDeviceName(L"\\Device\\Video",
  2978. VideoDeviceNumber,
  2979. &deviceNameUnicodeString,
  2980. deviceNameBuffer);
  2981. //
  2982. // Create a device object to represent the Video Adapter.
  2983. //
  2984. if (NT_SUCCESS(ntStatus)) {
  2985. ntStatus = IoCreateDevice(DriverObject,
  2986. DeviceExtensionSize,
  2987. &deviceNameUnicodeString,
  2988. FILE_DEVICE_VIDEO,
  2989. 0,
  2990. TRUE,
  2991. FunctionalDeviceObject);
  2992. if (NT_SUCCESS(ntStatus)) {
  2993. ntStatus = IoRegisterShutdownNotification(*FunctionalDeviceObject);
  2994. if (!NT_SUCCESS(ntStatus)) {
  2995. IoDeleteDevice(*FunctionalDeviceObject);
  2996. *FunctionalDeviceObject = NULL;
  2997. } else {
  2998. (*FunctionalDeviceObject)->DeviceType = FILE_DEVICE_VIDEO;
  2999. fdoExtension = (*FunctionalDeviceObject)->DeviceExtension;
  3000. //
  3001. // Set any deviceExtension fields here
  3002. //
  3003. DoSpecificExtension = (PVOID)(fdoExtension + 1);
  3004. DoSpecificExtension->DeviceNumber = VideoDeviceNumber;
  3005. DoSpecificExtension->pFdoExtension = fdoExtension;
  3006. DoSpecificExtension->Signature = VP_TAG;
  3007. DoSpecificExtension->ExtensionType = TypeDeviceSpecificExtension;
  3008. DoSpecificExtension->HwDeviceExtension = (PVOID)(DoSpecificExtension + 1);
  3009. DoSpecificExtension->DualviewFlags = 0;
  3010. #ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  3011. DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
  3012. #endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  3013. fdoExtension->pFdoExtension = fdoExtension;
  3014. fdoExtension->Signature = VP_TAG;
  3015. fdoExtension->ExtensionType = TypeFdoExtension;
  3016. fdoExtension->FunctionalDeviceObject = *FunctionalDeviceObject;
  3017. fdoExtension->DriverObject = DriverObject;
  3018. KeInitializeMutex(&fdoExtension->SyncMutex,
  3019. 0);
  3020. }
  3021. }
  3022. }
  3023. return ntStatus;
  3024. }
  3025. ULONG
  3026. VideoPortInitialize(
  3027. IN PVOID Argument1, // DriverObject
  3028. IN PVOID Argument2, // RegistryPath
  3029. IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
  3030. IN PVOID HwContext
  3031. )
  3032. {
  3033. PDRIVER_OBJECT driverObject = Argument1;
  3034. NTSTATUS ntStatus;
  3035. PUNICODE_STRING registryPath = (PUNICODE_STRING) Argument2;
  3036. ULONG PnpFlags;
  3037. if (VPFirstTime)
  3038. {
  3039. VPFirstTime = FALSE;
  3040. pVPInit();
  3041. }
  3042. //
  3043. // Check if the size of the pointer, or the size of the data passed in
  3044. // are OK.
  3045. //
  3046. ASSERT(HwInitializationData != NULL);
  3047. if (HwInitializationData->HwInitDataSize >
  3048. sizeof(VIDEO_HW_INITIALIZATION_DATA) ) {
  3049. pVideoDebugPrint((Error, "VIDEOPRT: Invalid initialization data size\n"));
  3050. return ((ULONG) STATUS_REVISION_MISMATCH);
  3051. }
  3052. //
  3053. // Check that each required entry is not NULL.
  3054. //
  3055. if ((!HwInitializationData->HwFindAdapter) ||
  3056. (!HwInitializationData->HwInitialize) ||
  3057. (!HwInitializationData->HwStartIO)) {
  3058. pVideoDebugPrint((Error, "VIDEOPRT: Miniport missing required entry\n"));
  3059. return ((ULONG)STATUS_REVISION_MISMATCH);
  3060. }
  3061. //
  3062. // Check the registry for PnP Flags. Currently we recongnize the
  3063. // following values:
  3064. //
  3065. // PnPEnabled - If this value is set with a non-zero value, we
  3066. // will treat behave like a PnP driver.
  3067. //
  3068. // LegacyDetect - If this value is non-zero, we will report
  3069. // a non-pci device to the system via
  3070. // IoReportDetectedDevice.
  3071. //
  3072. // If we don't get the flags, we don't know how to run this driver.
  3073. // return failure
  3074. //
  3075. if (!(NT_SUCCESS(VpGetFlags(registryPath,
  3076. HwInitializationData,
  3077. &PnpFlags))))
  3078. {
  3079. return STATUS_UNSUCCESSFUL;
  3080. }
  3081. //
  3082. // During an upgrade don't allow a driver to start unless it was written
  3083. // for this version of Windows.
  3084. //
  3085. if ((VpSetupTypeAtBoot == SETUPTYPE_UPGRADE) &&
  3086. (HwInitializationData->HwInitDataSize < sizeof(VIDEO_HW_INITIALIZATION_DATA)))
  3087. {
  3088. pVideoDebugPrint((0, "We don't allow pre WinXP drivers to start during upgrade.\n"));
  3089. return STATUS_UNSUCCESSFUL;
  3090. }
  3091. //
  3092. // Set up the device driver entry points.
  3093. //
  3094. driverObject->DriverUnload = VpDriverUnload;
  3095. driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = pVideoPortDispatch;
  3096. driverObject->MajorFunction[IRP_MJ_CREATE] = pVideoPortDispatch;
  3097. driverObject->MajorFunction[IRP_MJ_CLOSE] = pVideoPortDispatch;
  3098. driverObject->MajorFunction[IRP_MJ_SHUTDOWN] = pVideoPortDispatch;
  3099. //
  3100. // Check that the device extension size is reasonable.
  3101. //
  3102. #if DBG
  3103. if (HwInitializationData->HwDeviceExtensionSize > 0x4000) {
  3104. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortInitialize:\n"
  3105. "Warning: Device Extension is stored in non-paged pool\n"
  3106. " Do you need a 0x%x byte device extension?\n",
  3107. HwInitializationData->HwDeviceExtensionSize));
  3108. }
  3109. #endif
  3110. //
  3111. // PnP drivers have new rules.
  3112. //
  3113. if (PnpFlags & PNP_ENABLED)
  3114. {
  3115. pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize with PNP_ENABLED\n"));
  3116. //
  3117. // We also can't be plug and play compatible if the driver passes
  3118. // info in HwContext. This is because we can't store this.
  3119. //
  3120. if ((PnpFlags & VGA_DRIVER) ||
  3121. (HwContext != NULL))
  3122. {
  3123. pVideoDebugPrint((Error, "VIDEOPRT: This video driver can not be "
  3124. "PNP due to passing info in HwContext.\n"));
  3125. ASSERT(FALSE);
  3126. return STATUS_INVALID_PARAMETER;
  3127. }
  3128. } else {
  3129. //
  3130. // Don't allow a non PnP driver to start after the system is up and
  3131. // running. Instead require a reboot first.
  3132. //
  3133. if (VpSystemInitialized) {
  3134. #if defined STATUS_REBOOT_REQUIRED
  3135. return STATUS_REBOOT_REQUIRED;
  3136. #else
  3137. return STATUS_INVALID_PARAMETER;
  3138. #endif
  3139. }
  3140. }
  3141. //
  3142. // Never do legacy detection of PnP drivers on the PCI Bus.
  3143. //
  3144. if (HwInitializationData->AdapterInterfaceType == PCIBus) {
  3145. pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize on PCI Bus\n"));
  3146. if ( (PnpFlags & PNP_ENABLED) &&
  3147. ((PnpFlags & LEGACY_DETECT) ||
  3148. (PnpFlags & REPORT_DEVICE)) ) {
  3149. pVideoDebugPrint((Error, "VIDEOPRT: Trying to detect PnP driver on PCI - fail\n"));
  3150. return STATUS_INVALID_PARAMETER;
  3151. }
  3152. }
  3153. //
  3154. // Set this information for all PnP Drivers
  3155. //
  3156. // Special !!! - we cannot do this in the LEGACY_DETECT because the system
  3157. // will think we failed to load and return a failure code.
  3158. //
  3159. if ( (PnpFlags & PNP_ENABLED) &&
  3160. (!(PnpFlags & LEGACY_DETECT)) )
  3161. {
  3162. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  3163. pVideoDebugPrint((Info, "VIDEOPRT: We have a PnP Device.\n"));
  3164. //
  3165. // Fill in the new PnP entry points.
  3166. //
  3167. driverObject->DriverExtension->AddDevice = VpAddDevice;
  3168. driverObject->MajorFunction[IRP_MJ_PNP] = pVideoPortPnpDispatch;
  3169. driverObject->MajorFunction[IRP_MJ_POWER] = pVideoPortPowerDispatch;
  3170. driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = pVideoPortSystemControl;
  3171. //
  3172. // we'll do findadapter during the START_DEVICE irp
  3173. //
  3174. // Store away arguments, so we can retrieve them when we need them.
  3175. //
  3176. // Try to create a DriverObjectExtension
  3177. //
  3178. if (DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  3179. IoGetDriverObjectExtension(driverObject,
  3180. driverObject))
  3181. {
  3182. DriverObjectExtension->HwInitData = *HwInitializationData;
  3183. ntStatus = STATUS_SUCCESS;
  3184. }
  3185. else if (NT_SUCCESS(IoAllocateDriverObjectExtension(
  3186. driverObject,
  3187. driverObject,
  3188. sizeof(VIDEO_PORT_DRIVER_EXTENSION),
  3189. &DriverObjectExtension)))
  3190. {
  3191. DriverObjectExtension->RegistryPath = *registryPath;
  3192. DriverObjectExtension->RegistryPath.MaximumLength += sizeof(WCHAR);
  3193. DriverObjectExtension->RegistryPath.Buffer =
  3194. ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  3195. DriverObjectExtension->RegistryPath.MaximumLength,
  3196. 'trpV');
  3197. ASSERT(DriverObjectExtension->RegistryPath.Buffer);
  3198. RtlCopyUnicodeString(&(DriverObjectExtension->RegistryPath),
  3199. registryPath);
  3200. DriverObjectExtension->HwInitData = *HwInitializationData;
  3201. ntStatus = STATUS_SUCCESS;
  3202. }
  3203. else
  3204. {
  3205. //
  3206. // Something went wrong. We should have a
  3207. // DriverObjectExtension by now.
  3208. //
  3209. pVideoDebugPrint((Error, "VIDEOPRT: IoAllocateDriverExtensionObject failed!\n"));
  3210. ASSERT(FALSE);
  3211. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3212. }
  3213. }
  3214. //
  3215. // If we are doing legacy detection or reporting, create the FDO
  3216. // right now ...
  3217. //
  3218. if ((!(PnpFlags & PNP_ENABLED)) ||
  3219. (PnpFlags & LEGACY_DETECT) ||
  3220. (PnpFlags & VGA_DRIVER) ||
  3221. (PnpFlags & REPORT_DEVICE) ||
  3222. (HwContext != NULL)) {
  3223. pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortInitialize on PCI Bus\n"));
  3224. pVideoDebugPrint((Info, "Legacy FindAdapter Interface %s\n",
  3225. BusType[HwInitializationData->AdapterInterfaceType]));
  3226. ntStatus = VideoPortLegacyFindAdapter(Argument1,
  3227. Argument2,
  3228. HwInitializationData,
  3229. HwContext,
  3230. PnpFlags);
  3231. }
  3232. return ntStatus;
  3233. }
  3234. VOID
  3235. UpdateRegValue(
  3236. IN PUNICODE_STRING RegistryPath,
  3237. IN PWCHAR RegValue,
  3238. IN ULONG Value
  3239. )
  3240. {
  3241. PWSTR Path;
  3242. Path = ExAllocatePoolWithTag(PagedPool,
  3243. RegistryPath->Length + sizeof(UNICODE_NULL),
  3244. VP_TAG);
  3245. if (Path) {
  3246. RtlCopyMemory(Path,
  3247. RegistryPath->Buffer,
  3248. RegistryPath->Length);
  3249. *(Path + (RegistryPath->Length / sizeof(UNICODE_NULL))) = UNICODE_NULL;
  3250. RtlWriteRegistryValue(
  3251. RTL_REGISTRY_ABSOLUTE,
  3252. Path,
  3253. RegValue,
  3254. REG_DWORD,
  3255. &Value,
  3256. sizeof(ULONG));
  3257. ExFreePool(Path);
  3258. }
  3259. }
  3260. ULONG
  3261. VideoPortLegacyFindAdapter(
  3262. IN PDRIVER_OBJECT DriverObject,
  3263. IN PVOID Argument2,
  3264. IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
  3265. IN PVOID HwContext,
  3266. IN ULONG PnpFlags
  3267. )
  3268. {
  3269. ULONG busNumber = 0;
  3270. ULONG extensionAllocationSize;
  3271. NTSTATUS ntStatus;
  3272. UCHAR nextMiniport;
  3273. ULONG registryIndex = 0;
  3274. //
  3275. // Reset the controller number used in IoQueryDeviceDescription to zero
  3276. // since we are restarting on a new type of bus.
  3277. // Note: PeripheralNumber is reset only when we find a new controller.
  3278. //
  3279. VpQueryDeviceControllerNumber = 0xFFFFFFFF;
  3280. //
  3281. // Determine size of the device extension to allocate.
  3282. //
  3283. extensionAllocationSize = sizeof(FDO_EXTENSION) +
  3284. sizeof(DEVICE_SPECIFIC_EXTENSION) +
  3285. HwInitializationData->HwDeviceExtensionSize;
  3286. //
  3287. // Check if we are on the right Bus Adapter type.
  3288. // If we are not, then return immediately.
  3289. //
  3290. ASSERT (HwInitializationData->AdapterInterfaceType < MaximumInterfaceType);
  3291. //
  3292. // Assume we are going to fail this the IoQueryDeviceDescription call
  3293. // and that no device is found.
  3294. //
  3295. ntStatus = STATUS_NO_SUCH_DEVICE;
  3296. pVideoDebugPrint((Trace, "Legacy FindAdapter Interface %s, Bus %d\n",
  3297. BusType[HwInitializationData->AdapterInterfaceType],
  3298. busNumber));
  3299. while (NT_SUCCESS(IoQueryDeviceDescription(
  3300. &HwInitializationData->AdapterInterfaceType,
  3301. &busNumber,
  3302. NULL,
  3303. NULL,
  3304. NULL,
  3305. NULL,
  3306. &VpInitializeBusCallback,
  3307. NULL))) {
  3308. //
  3309. // This is to support the multiple initialization as described by the
  3310. // again paramter in HwFindAdapter.
  3311. // We must repeat almost everything in this function until FALSE is
  3312. // returned by the miniport. This is why we test for the condition at
  3313. // the end. Freeing of data structure has to be done also since we want
  3314. // to delete a device object for a device that did not load properly.
  3315. //
  3316. do {
  3317. PDEVICE_OBJECT deviceObject = NULL;
  3318. PDEVICE_OBJECT PnPDeviceObject = NULL;
  3319. PFDO_EXTENSION fdoExtension;
  3320. UNICODE_STRING tmpString;
  3321. nextMiniport = FALSE;
  3322. //
  3323. // Allocate the buffer in which the miniport driver will store all the
  3324. // configuration information.
  3325. //
  3326. ntStatus = VpCreateDevice(DriverObject,
  3327. extensionAllocationSize,
  3328. &deviceObject);
  3329. if (!NT_SUCCESS(ntStatus)) {
  3330. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortLegacyFindAdapter: Could not create device object\n"));
  3331. return (ULONG)ntStatus;
  3332. }
  3333. fdoExtension = deviceObject->DeviceExtension;
  3334. fdoExtension->SystemIoBusNumber = busNumber;
  3335. fdoExtension->AdapterInterfaceType =
  3336. HwInitializationData->AdapterInterfaceType;
  3337. fdoExtension->RegistryIndex = registryIndex;
  3338. //
  3339. // Initialize the remove lock.
  3340. //
  3341. IoInitializeRemoveLock(&fdoExtension->RemoveLock, 0, 0, 256);
  3342. //
  3343. // If we came through this code path, we are a legacy device
  3344. //
  3345. fdoExtension->Flags = PnpFlags | LEGACY_DRIVER;
  3346. fdoExtension->VpDmaAdapterHead = NULL ;
  3347. //
  3348. // Make the VGA driver report resources "for detection" during
  3349. // FindAdapter. Later we'll remove the "LEGACY_DETECT" flag and
  3350. // try to claim the resources for real.
  3351. //
  3352. if (fdoExtension->Flags & VGA_DRIVER) {
  3353. fdoExtension->Flags |= VGA_DETECT;
  3354. }
  3355. ntStatus = VideoPortFindAdapter(DriverObject,
  3356. Argument2,
  3357. HwInitializationData,
  3358. HwContext,
  3359. deviceObject,
  3360. &nextMiniport);
  3361. if (fdoExtension->Flags & VGA_DRIVER) {
  3362. fdoExtension->Flags &= ~VGA_DETECT;
  3363. }
  3364. pVideoDebugPrint((Info, "VIDEOPRT: Legacy VideoPortFindAdapter status = %08lx\n", ntStatus));
  3365. pVideoDebugPrint((Info, "VIDEOPRT: Legacy VideoPortFindAdapter nextMiniport = %d\n", nextMiniport));
  3366. if ((NT_SUCCESS(ntStatus) == FALSE) || (PnpFlags & LEGACY_DETECT))
  3367. {
  3368. pVideoDebugPrint((1, "Deleting Device Object.\n"));
  3369. IoDeleteDevice(deviceObject);
  3370. }
  3371. if (NT_SUCCESS(ntStatus))
  3372. {
  3373. //
  3374. // We use this variable to know if at least one of the tries at
  3375. // loading the device succeded.
  3376. //
  3377. registryIndex++;
  3378. }
  3379. else
  3380. {
  3381. continue;
  3382. }
  3383. //
  3384. // If this is the VGA driver, store this device extension for
  3385. // us to play around with the resources later on (so we can release
  3386. // the resources if we install a driver on the fly).
  3387. //
  3388. // Otherwise, determine if we want to report it to the IO system
  3389. // so it can be used as a PNP device later on.
  3390. // ... Never report a device found on the PCI bus.
  3391. //
  3392. if (PnpFlags & VGA_DRIVER)
  3393. {
  3394. VgaHwDeviceExtension = fdoExtension->HwDeviceExtension;
  3395. if (NT_SUCCESS(ntStatus)) {
  3396. //
  3397. // Claim the VGA resources again without the
  3398. // VGA_DETECT flag.
  3399. //
  3400. VideoPortVerifyAccessRanges(VgaHwDeviceExtension,
  3401. NumVgaAccessRanges,
  3402. VgaAccessRanges);
  3403. }
  3404. }
  3405. else if (PnpFlags & REPORT_DEVICE)
  3406. {
  3407. ULONG_PTR emptyList = 0;
  3408. BOOLEAN conflict;
  3409. PDEVICE_OBJECT attachedTo;
  3410. ASSERT (HwInitializationData->AdapterInterfaceType != PCIBus);
  3411. //
  3412. // Release the resource we put in the resourcemap (if any).
  3413. //
  3414. IoReportResourceUsage(&VideoClassName,
  3415. DriverObject,
  3416. NULL,
  3417. 0L,
  3418. deviceObject,
  3419. (PCM_RESOURCE_LIST) &emptyList,
  3420. sizeof(ULONG_PTR),
  3421. FALSE,
  3422. &conflict);
  3423. pVideoDebugPrint((Info, "VIDEOPRT: Reporting new device to the system.\n"));
  3424. pVideoDebugPrint((Info, "VIDEOPRT: ResourceList...\n"));
  3425. if (fdoExtension->ResourceList) {
  3426. #if DBG
  3427. DumpResourceList(fdoExtension->ResourceList);
  3428. #endif
  3429. } else {
  3430. pVideoDebugPrint((Info, "\tnone.\n"));
  3431. }
  3432. ntStatus = IoReportDetectedDevice(
  3433. DriverObject,
  3434. InterfaceTypeUndefined,
  3435. -1,
  3436. -1,
  3437. fdoExtension->ResourceList,
  3438. NULL,
  3439. FALSE,
  3440. &PnPDeviceObject);
  3441. pVideoDebugPrint((Info, "VIDEOPRT: New device reported ntStatus %08lx\n", ntStatus));
  3442. ASSERT(NT_SUCCESS(ntStatus));
  3443. //
  3444. // Now we can release the memory used to hold
  3445. // the resources pointed to by ResourceList.
  3446. //
  3447. if (fdoExtension->ResourceList) {
  3448. ExFreePool(fdoExtension->ResourceList);
  3449. fdoExtension->ResourceList = NULL;
  3450. }
  3451. attachedTo = IoAttachDeviceToDeviceStack(deviceObject,
  3452. PnPDeviceObject);
  3453. ASSERT(attachedTo != NULL);
  3454. fdoExtension->AttachedDeviceObject = attachedTo;
  3455. fdoExtension->PhysicalDeviceObject = PnPDeviceObject;
  3456. //
  3457. // Clear the ReportDevice value in the registry so
  3458. // that we don't try to report the device again in
  3459. // the future.
  3460. //
  3461. UpdateRegValue(Argument2, L"ReportDevice", FALSE);
  3462. }
  3463. } while (nextMiniport);
  3464. //
  3465. // We finished finding all the device on the current bus
  3466. // Go on to the next bus.
  3467. //
  3468. busNumber++;
  3469. }
  3470. //
  3471. // If at least one device loaded, then return success, otherwise return
  3472. // the last available error message.
  3473. //
  3474. if (registryIndex > 0) {
  3475. return STATUS_SUCCESS;
  3476. } else {
  3477. return ((ULONG)ntStatus);
  3478. }
  3479. }
  3480. NTSTATUS
  3481. VideoPortFindAdapter(
  3482. IN PDRIVER_OBJECT DriverObject,
  3483. IN PVOID Argument2,
  3484. IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
  3485. IN PVOID HwContext,
  3486. PDEVICE_OBJECT DeviceObject,
  3487. PUCHAR nextMiniport
  3488. )
  3489. {
  3490. NTSTATUS status;
  3491. PVOID vgaDE = VgaHwDeviceExtension;
  3492. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  3493. POWER_STATE state;
  3494. //
  3495. // During boot of upgrade install, only let VGA,
  3496. // boot video drivers start. Other types of drivers don't get
  3497. // a chance to start until after the vga or a boot driver tries'
  3498. // to start.
  3499. //
  3500. // The logic relies on the fact that today PNP drivers try to
  3501. // start before legacy drivers (including our system vga driver).a3844
  3502. //
  3503. // All other drivers are disabled so we have a chance of
  3504. // 1) booting the machine
  3505. // 2) installing the PnP drivers
  3506. //
  3507. if ((VpSetupType == SETUPTYPE_UPGRADE) &&
  3508. ((fdoExtension->Flags & (BOOT_DRIVER | VGA_DRIVER)) == 0) &&
  3509. (VpSetupAllowDriversToStart == FALSE))
  3510. {
  3511. status = STATUS_NO_SUCH_DEVICE;
  3512. }
  3513. else
  3514. {
  3515. //
  3516. // If we get here during setup we may be trying to start the
  3517. // vga driver. As soon as it is started we will allow othere
  3518. // devices to start.
  3519. //
  3520. VpSetupAllowDriversToStart = TRUE;
  3521. //
  3522. // Allow PNP adapters to start so that we can enumerate their
  3523. // children. But don't let IRP_MJ_CREATE succeed, so GDI
  3524. // won't try to use the device during gui mode setup.
  3525. //
  3526. if ((VpSetupType == SETUPTYPE_UPGRADE) &&
  3527. (fdoExtension->Flags & PNP_ENABLED)) {
  3528. fdoExtension->Flags |= UPGRADE_FAIL_HWINIT;
  3529. }
  3530. //
  3531. // If the VGA driver has the VGA resources, unclaim them temporarily
  3532. //
  3533. if (vgaDE) {
  3534. pVideoDebugPrint((Info, "VIDEOPRT: Freeing VGA resources\n"));
  3535. VpReleaseResources(GET_FDO_EXT(vgaDE));
  3536. }
  3537. status = VideoPortFindAdapter2(DriverObject,
  3538. Argument2,
  3539. HwInitializationData,
  3540. HwContext,
  3541. DeviceObject,
  3542. nextMiniport);
  3543. //
  3544. // Try to reclaim the vga ports. FYI, may not get them
  3545. // back if the new driver claimed them.
  3546. //
  3547. if (vgaDE) {
  3548. pVideoDebugPrint((Info, "VIDEOPRT: Try to allocate back vga resources.\n"));
  3549. if (((DeviceObject == DeviceOwningVga) && NT_SUCCESS(status)) ||
  3550. VideoPortVerifyAccessRanges(vgaDE,
  3551. NumVgaAccessRanges,
  3552. VgaAccessRanges) != NO_ERROR) {
  3553. //
  3554. // We couldn't reclaim the vga resources, so another driver
  3555. // must have claimed them. Lets release our resources.
  3556. //
  3557. if (VgaAccessRanges) {
  3558. ExFreePool(VgaAccessRanges);
  3559. }
  3560. VgaHwDeviceExtension = NULL;
  3561. VgaAccessRanges = NULL;
  3562. NumVgaAccessRanges = 0;
  3563. pVideoDebugPrint((Warn, "VIDEOPRT: Resource re-allocation failed.\n"));
  3564. }
  3565. }
  3566. }
  3567. if (NT_SUCCESS(status))
  3568. {
  3569. //
  3570. // Initialize Power stuff.
  3571. // Set the devices current power state.
  3572. // NOTE - we assume the device is on at this point in time ...
  3573. //
  3574. fdoExtension->DevicePowerState = PowerDeviceD0;
  3575. state.DeviceState = fdoExtension->DevicePowerState;
  3576. state = PoSetPowerState(DeviceObject,
  3577. DevicePowerState,
  3578. state);
  3579. //
  3580. // Register and enable the interface
  3581. //
  3582. VpEnableAdapterInterface((PDEVICE_SPECIFIC_EXTENSION)
  3583. (fdoExtension + 1));
  3584. //
  3585. // Mark this object as supporting buffered I/O so that the I/O system
  3586. // will only supply simple buffers in IRPs.
  3587. //
  3588. // Set and clear the two power fields to ensure we only get called
  3589. // as passive level to do power management operations.
  3590. //
  3591. // Finally, tell the system we are done with Device Initialization
  3592. //
  3593. DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  3594. DeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
  3595. fdoExtension->Flags |= FINDADAPTER_SUCCEEDED;
  3596. //
  3597. // Track the number of started devices (don't count mirroring drivers)
  3598. //
  3599. if (!IsMirrorDriver(fdoExtension)) {
  3600. NumDevicesStarted++;
  3601. }
  3602. }
  3603. return status;
  3604. }
  3605. NTSTATUS
  3606. VideoPortFindAdapter2(
  3607. IN PDRIVER_OBJECT DriverObject,
  3608. IN PVOID Argument2,
  3609. IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
  3610. IN PVOID HwContext,
  3611. PDEVICE_OBJECT DeviceObject,
  3612. PUCHAR nextMiniport
  3613. )
  3614. {
  3615. WCHAR deviceNameBuffer[STRING_LENGTH];
  3616. POBJECT_NAME_INFORMATION deviceName;
  3617. ULONG strLength;
  3618. NTSTATUS ntStatus;
  3619. WCHAR deviceSubpathBuffer[STRING_LENGTH];
  3620. UNICODE_STRING deviceSubpathUnicodeString;
  3621. WCHAR deviceLinkBuffer[STRING_LENGTH];
  3622. UNICODE_STRING deviceLinkUnicodeString;
  3623. KAFFINITY affinity;
  3624. PVIDEO_PORT_CONFIG_INFO miniportConfigInfo = NULL;
  3625. PDEVICE_OBJECT deviceObject;
  3626. PFDO_EXTENSION fdoExtension;
  3627. VP_STATUS findAdapterStatus = ERROR_DEV_NOT_EXIST;
  3628. ULONG driverKeySize;
  3629. PWSTR driverKeyName = NULL;
  3630. BOOLEAN symbolicLinkCreated = FALSE;
  3631. ULONG MaxObjectNumber;
  3632. PDEVICE_OBJECT pdo;
  3633. BOOLEAN ChildObject=FALSE;
  3634. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  3635. ntStatus = STATUS_NO_SUCH_DEVICE;
  3636. deviceObject = DeviceObject;
  3637. fdoExtension = deviceObject->DeviceExtension;
  3638. DoSpecificExtension = (PVOID)(fdoExtension + 1);
  3639. pdo = fdoExtension->PhysicalDeviceObject;
  3640. deviceName = (POBJECT_NAME_INFORMATION) deviceNameBuffer;
  3641. ObQueryNameString(deviceObject,
  3642. deviceName,
  3643. STRING_LENGTH * sizeof(WCHAR),
  3644. &strLength);
  3645. //
  3646. // Allocate the buffer in which the miniport driver will store all the
  3647. // configuration information.
  3648. //
  3649. miniportConfigInfo = (PVIDEO_PORT_CONFIG_INFO)
  3650. ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  3651. sizeof(VIDEO_PORT_CONFIG_INFO),
  3652. VP_TAG);
  3653. if (miniportConfigInfo == NULL) {
  3654. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3655. goto EndOfInitialization;
  3656. }
  3657. RtlZeroMemory((PVOID) miniportConfigInfo,
  3658. sizeof(VIDEO_PORT_CONFIG_INFO));
  3659. miniportConfigInfo->Length = sizeof(VIDEO_PORT_CONFIG_INFO);
  3660. //
  3661. // Put in the BusType specified within the HW_INITIALIZATION_DATA
  3662. // structure by the miniport and the bus number inthe miniport config info.
  3663. //
  3664. miniportConfigInfo->SystemIoBusNumber = fdoExtension->SystemIoBusNumber;
  3665. miniportConfigInfo->AdapterInterfaceType = fdoExtension->AdapterInterfaceType;
  3666. //
  3667. // Initialize the pointer to VpGetProcAddress.
  3668. //
  3669. miniportConfigInfo->VideoPortGetProcAddress = VpGetProcAddress;
  3670. //
  3671. // Initialize the type of interrupt based on the bus type.
  3672. //
  3673. switch (miniportConfigInfo->AdapterInterfaceType) {
  3674. case Internal:
  3675. case MicroChannel:
  3676. case PCIBus:
  3677. miniportConfigInfo->InterruptMode = LevelSensitive;
  3678. break;
  3679. default:
  3680. miniportConfigInfo->InterruptMode = Latched;
  3681. break;
  3682. }
  3683. //
  3684. // Set up device extension pointers and sizes
  3685. //
  3686. fdoExtension->HwDeviceExtension = (PVOID)((ULONG_PTR)(fdoExtension) +
  3687. sizeof(FDO_EXTENSION) + sizeof(DEVICE_SPECIFIC_EXTENSION));
  3688. fdoExtension->HwDeviceExtensionSize =
  3689. HwInitializationData->HwDeviceExtensionSize;
  3690. fdoExtension->MiniportConfigInfo = miniportConfigInfo;
  3691. //
  3692. // Save the dependent driver routines in the device extension.
  3693. //
  3694. fdoExtension->HwFindAdapter = HwInitializationData->HwFindAdapter;
  3695. fdoExtension->HwInitialize = HwInitializationData->HwInitialize;
  3696. fdoExtension->HwInterrupt = HwInitializationData->HwInterrupt;
  3697. fdoExtension->HwStartIO = HwInitializationData->HwStartIO;
  3698. if (HwInitializationData->HwInitDataSize >
  3699. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) {
  3700. fdoExtension->HwLegacyResourceList = HwInitializationData->HwLegacyResourceList;
  3701. fdoExtension->HwLegacyResourceCount = HwInitializationData->HwLegacyResourceCount;
  3702. }
  3703. if (HwInitializationData->HwInitDataSize >
  3704. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, AllowEarlyEnumeration)) {
  3705. fdoExtension->AllowEarlyEnumeration = HwInitializationData->AllowEarlyEnumeration;
  3706. }
  3707. //
  3708. // Create the name we will be storing in the \DeviceMap.
  3709. // This name is a PWSTR, not a unicode string
  3710. // This is the name of the driver with an appended device number
  3711. //
  3712. if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\Device",
  3713. HwInitializationData->StartingDeviceNumber,
  3714. &deviceSubpathUnicodeString,
  3715. deviceSubpathBuffer))) {
  3716. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not create device subpath number\n"));
  3717. goto EndOfInitialization;
  3718. }
  3719. DoSpecificExtension->DriverOldRegistryPathLength =
  3720. ((PUNICODE_STRING)Argument2)->Length +
  3721. deviceSubpathUnicodeString.Length;
  3722. driverKeySize =
  3723. DoSpecificExtension->DriverOldRegistryPathLength +
  3724. 2 * sizeof(UNICODE_NULL);
  3725. if ( (driverKeyName = (PWSTR) ExAllocatePoolWithTag(PagedPool,
  3726. driverKeySize,
  3727. VP_TAG) ) == NULL) {
  3728. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3729. goto EndOfInitialization;
  3730. }
  3731. RtlMoveMemory(driverKeyName,
  3732. ((PUNICODE_STRING)Argument2)->Buffer,
  3733. ((PUNICODE_STRING)Argument2)->Length);
  3734. RtlMoveMemory((PWSTR)( (ULONG_PTR)driverKeyName +
  3735. ((PUNICODE_STRING)Argument2)->Length ),
  3736. deviceSubpathBuffer,
  3737. deviceSubpathUnicodeString.Length);
  3738. //
  3739. // Put two NULLs at the end so we can play around with the string later.
  3740. //
  3741. *((PWSTR) ((ULONG_PTR)driverKeyName +
  3742. DoSpecificExtension->DriverOldRegistryPathLength))
  3743. = UNICODE_NULL;
  3744. *((PWSTR) ((ULONG_PTR)driverKeyName +
  3745. DoSpecificExtension->DriverOldRegistryPathLength
  3746. + sizeof(UNICODE_NULL))) = UNICODE_NULL;
  3747. //
  3748. // There is a bug in Lotus Screen Cam where it will only work if our
  3749. // reg path is \REGISTRY\Machine\System not \REGISTRY\MACHINE\SYSTEM.
  3750. // so replace the appropriate strings.
  3751. //
  3752. if (wcsstr(driverKeyName, L"MACHINE")) {
  3753. wcsncpy(wcsstr(driverKeyName, L"MACHINE"), L"Machine", sizeof("Machine")-1);
  3754. }
  3755. if (wcsstr(driverKeyName, L"SYSTEM")) {
  3756. wcsncpy(wcsstr(driverKeyName, L"SYSTEM"), L"System", sizeof("System")-1);
  3757. }
  3758. //
  3759. // Store the old key
  3760. //
  3761. DoSpecificExtension->DriverOldRegistryPath = driverKeyName;
  3762. //
  3763. // Store the new key
  3764. // If this is not a Whistler driver, then use the old key.
  3765. //
  3766. if (EnableNewRegistryKey) {
  3767. #if _X86_
  3768. if (HwInitializationData->HwInitDataSize > SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA)
  3769. #endif // _X86_
  3770. VpEnableNewRegistryKey(fdoExtension,
  3771. DoSpecificExtension,
  3772. (PUNICODE_STRING)Argument2,
  3773. fdoExtension->RegistryIndex);
  3774. }
  3775. //
  3776. // Store the path name of the location of the driver in the registry.
  3777. //
  3778. if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
  3779. DoSpecificExtension->DriverRegistryPath =
  3780. DoSpecificExtension->DriverNewRegistryPath;
  3781. DoSpecificExtension->DriverRegistryPathLength =
  3782. DoSpecificExtension->DriverNewRegistryPathLength;
  3783. } else {
  3784. DoSpecificExtension->DriverRegistryPath =
  3785. DoSpecificExtension->DriverOldRegistryPath;
  3786. DoSpecificExtension->DriverRegistryPathLength =
  3787. DoSpecificExtension->DriverOldRegistryPathLength;
  3788. }
  3789. miniportConfigInfo->DriverRegistryPath = DoSpecificExtension->DriverRegistryPath;
  3790. //
  3791. // Let the driver know how much system memory is present.
  3792. //
  3793. miniportConfigInfo->SystemMemorySize = VpSystemMemorySize;
  3794. //
  3795. // Initialize the DPC object used for error logging.
  3796. //
  3797. KeInitializeDpc(&fdoExtension->ErrorLogDpc,
  3798. pVideoPortLogErrorEntryDPC,
  3799. deviceObject);
  3800. //
  3801. // If the machine is using a Intel 450NX PCIset with a
  3802. // 82451NX Memory & I/O Controller (MIOC) then we must
  3803. // disable write combining to work around a bug in the
  3804. // chipset.
  3805. //
  3806. // We also want to disable USWC on the Compaq fiat
  3807. // chipset.
  3808. //
  3809. if (EnableUSWC) {
  3810. if ((VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x8086, 0x84CA, 0, 0, 0, 0)) ||
  3811. (VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x0E11, 0x6010, 0, 0, 0, 0)) ||
  3812. (VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x1166, 0x0009, 0, 0, 0, 0))) {
  3813. pVideoDebugPrint((Warn, "VIDEOPRT: USWC disabled due to to MIOC bug.\n"));
  3814. EnableUSWC = FALSE;
  3815. }
  3816. //
  3817. // Disable USWC on HPs 6 way box.
  3818. //
  3819. if (VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x1166, 0x0008, 0, 0, 0, 0) &&
  3820. (VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x103C, 0x1219, 0, 0, 0, 0) ||
  3821. VideoPortCheckForDeviceExistence(fdoExtension->HwDeviceExtension, 0x103C, 0x121A, 0, 0, 0, 0))) {
  3822. pVideoDebugPrint((Warn, "USWC disabled due to to RCC USWC bug on HP 6-way system.\n"));
  3823. EnableUSWC = FALSE;
  3824. }
  3825. }
  3826. //
  3827. // Turn on the debug level based on the miniport driver entry
  3828. //
  3829. VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
  3830. L"VideoDebugLevel",
  3831. FALSE,
  3832. VpRegistryCallback,
  3833. &VideoDebugLevel);
  3834. if (VpAllowFindAdapter(fdoExtension)) {
  3835. ACQUIRE_DEVICE_LOCK(fdoExtension);
  3836. //
  3837. // Notify the boot driver that we will be accessing the display
  3838. // hardware.
  3839. //
  3840. VpEnableDisplay(fdoExtension, FALSE);
  3841. findAdapterStatus =
  3842. fdoExtension->HwFindAdapter(fdoExtension->HwDeviceExtension,
  3843. HwContext,
  3844. NULL,
  3845. miniportConfigInfo,
  3846. nextMiniport);
  3847. VpEnableDisplay(fdoExtension, TRUE);
  3848. RELEASE_DEVICE_LOCK(fdoExtension);
  3849. }
  3850. //
  3851. // If the adapter is not found, display an error.
  3852. //
  3853. if (findAdapterStatus != NO_ERROR) {
  3854. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: Find adapter failed\n"));
  3855. ntStatus = STATUS_UNSUCCESSFUL;
  3856. goto EndOfInitialization;
  3857. }
  3858. //
  3859. // Store the emulator data in the device extension so we can use it
  3860. // later.
  3861. //
  3862. fdoExtension->NumEmulatorAccessEntries =
  3863. miniportConfigInfo->NumEmulatorAccessEntries;
  3864. fdoExtension->EmulatorAccessEntries =
  3865. miniportConfigInfo->EmulatorAccessEntries;
  3866. fdoExtension->EmulatorAccessEntriesContext =
  3867. miniportConfigInfo->EmulatorAccessEntriesContext;
  3868. fdoExtension->VdmPhysicalVideoMemoryAddress =
  3869. miniportConfigInfo->VdmPhysicalVideoMemoryAddress;
  3870. fdoExtension->VdmPhysicalVideoMemoryLength =
  3871. miniportConfigInfo->VdmPhysicalVideoMemoryLength;
  3872. //
  3873. // Store the required information in the device extension for later use.
  3874. //
  3875. fdoExtension->HardwareStateSize =
  3876. miniportConfigInfo->HardwareStateSize;
  3877. //
  3878. // If the device supplies an interrupt service routine, we must
  3879. // set up all the structures to support interrupts. Otherwise,
  3880. // they can be ignored.
  3881. //
  3882. if (fdoExtension->HwInterrupt) {
  3883. if ((miniportConfigInfo->BusInterruptLevel != 0) ||
  3884. (miniportConfigInfo->BusInterruptVector != 0)) {
  3885. #if defined(NO_LEGACY_DRIVERS)
  3886. affinity = fdoExtension->InterruptAffinity;
  3887. #else
  3888. if (fdoExtension->Flags & LEGACY_DRIVER) {
  3889. //
  3890. // Note: the spinlock for the interrupt object is created
  3891. // internally by the IoConnectInterrupt() call. It is also
  3892. // used internally by KeSynchronizeExecution.
  3893. //
  3894. fdoExtension->InterruptVector =
  3895. HalGetInterruptVector(fdoExtension->AdapterInterfaceType,
  3896. fdoExtension->SystemIoBusNumber,
  3897. miniportConfigInfo->BusInterruptLevel,
  3898. miniportConfigInfo->BusInterruptVector,
  3899. &fdoExtension->InterruptIrql,
  3900. &affinity);
  3901. } else {
  3902. affinity = fdoExtension->InterruptAffinity;
  3903. }
  3904. #endif
  3905. fdoExtension->InterruptMode = miniportConfigInfo->InterruptMode;
  3906. fdoExtension->InterruptsEnabled = TRUE;
  3907. ntStatus = IoConnectInterrupt(&fdoExtension->InterruptObject,
  3908. (PKSERVICE_ROUTINE) pVideoPortInterrupt,
  3909. deviceObject,
  3910. NULL,
  3911. fdoExtension->InterruptVector,
  3912. fdoExtension->InterruptIrql,
  3913. fdoExtension->InterruptIrql,
  3914. fdoExtension->InterruptMode,
  3915. (BOOLEAN) ((miniportConfigInfo->InterruptMode ==
  3916. LevelSensitive) ? TRUE : FALSE),
  3917. affinity,
  3918. FALSE);
  3919. if (!NT_SUCCESS(ntStatus)) {
  3920. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Can't connect interrupt\n"));
  3921. goto EndOfInitialization;
  3922. }
  3923. } else {
  3924. pVideoDebugPrint((Warn, "VIDEOPRT: Warning: No interrupt resources assigned to this device.\n"));
  3925. }
  3926. } else {
  3927. fdoExtension->HwInterrupt = NULL;
  3928. }
  3929. //
  3930. // Initialize DPC Support
  3931. //
  3932. KeInitializeDpc(&fdoExtension->Dpc,
  3933. pVideoPortDpcDispatcher,
  3934. fdoExtension->HwDeviceExtension);
  3935. //
  3936. // DMA support
  3937. //
  3938. if (HwInitializationData->HwInitDataSize >
  3939. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwStartDma)) {
  3940. fdoExtension->HwStartDma = HwInitializationData->HwStartDma;
  3941. //
  3942. // Determine if a Dma Adapter must be allocated.
  3943. //
  3944. if (fdoExtension->DmaAdapterObject == NULL &&
  3945. (miniportConfigInfo->Master ||
  3946. miniportConfigInfo->DmaChannel != 0)) {
  3947. DEVICE_DESCRIPTION deviceDescription;
  3948. ULONG numberOfMapRegisters;
  3949. //
  3950. // Get the adapter object for this card.
  3951. //
  3952. RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
  3953. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  3954. deviceDescription.DmaChannel = miniportConfigInfo->DmaChannel;
  3955. deviceDescription.BusNumber = miniportConfigInfo->SystemIoBusNumber;
  3956. deviceDescription.DmaWidth = miniportConfigInfo->DmaWidth;
  3957. deviceDescription.DmaSpeed = miniportConfigInfo->DmaSpeed;
  3958. deviceDescription.ScatterGather = miniportConfigInfo->ScatterGather;
  3959. deviceDescription.Master = miniportConfigInfo->Master;
  3960. deviceDescription.DmaPort = miniportConfigInfo->DmaPort;
  3961. deviceDescription.AutoInitialize = FALSE;
  3962. deviceDescription.DemandMode = miniportConfigInfo->DemandMode;
  3963. deviceDescription.MaximumLength = miniportConfigInfo->MaximumTransferLength;
  3964. deviceDescription.InterfaceType = fdoExtension->AdapterInterfaceType;
  3965. fdoExtension->DmaAdapterObject =
  3966. IoGetDmaAdapter(fdoExtension->PhysicalDeviceObject,
  3967. &deviceDescription,
  3968. &numberOfMapRegisters);
  3969. ASSERT(fdoExtension->DmaAdapterObject);
  3970. }
  3971. } // end if HW_DATA_SIZE > ... HWStartDma
  3972. //
  3973. // New, Optional.
  3974. // Setup the timer if it is specified by a driver.
  3975. //
  3976. if (HwInitializationData->HwInitDataSize >
  3977. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwTimer)){
  3978. fdoExtension->HwTimer = HwInitializationData->HwTimer;
  3979. if (fdoExtension->HwTimer) {
  3980. ntStatus = IoInitializeTimer(deviceObject,
  3981. pVideoPortHwTimer,
  3982. NULL);
  3983. //
  3984. // If we fail forget about the timer !
  3985. //
  3986. if (!NT_SUCCESS(ntStatus)) {
  3987. ASSERT(FALSE);
  3988. fdoExtension->HwTimer = NULL;
  3989. }
  3990. }
  3991. }
  3992. //
  3993. // New, Optional.
  3994. // Reset Hw function.
  3995. //
  3996. if (HwInitializationData->HwInitDataSize >
  3997. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwResetHw)) {
  3998. ULONG iReset;
  3999. for (iReset=0; iReset<6; iReset++) {
  4000. if (HwResetHw[iReset].ResetFunction == NULL) {
  4001. HwResetHw[iReset].ResetFunction = HwInitializationData->HwResetHw;
  4002. HwResetHw[iReset].HwDeviceExtension = fdoExtension->HwDeviceExtension;
  4003. break;
  4004. }
  4005. }
  4006. }
  4007. //
  4008. // The FdoList is for debugging purpose
  4009. //
  4010. {
  4011. ULONG i;
  4012. for(i = 0; i < 8; i++) {
  4013. if(FdoList[i] == NULL) {
  4014. FdoList[i] = fdoExtension;
  4015. break;
  4016. }
  4017. }
  4018. }
  4019. fdoExtension->NextFdoExtension = FdoHead;
  4020. FdoHead = fdoExtension;
  4021. //
  4022. // NOTE:
  4023. //
  4024. // We only want to reinitialize the device once the Boot sequence has
  4025. // been completed and the HAL does not need to access the device again.
  4026. // So the initialization entry point will be called when the device is
  4027. // opened.
  4028. //
  4029. if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\DosDevices\\DISPLAY",
  4030. DoSpecificExtension->DeviceNumber + 1,
  4031. &deviceLinkUnicodeString,
  4032. deviceLinkBuffer))) {
  4033. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not create device subpath number\n"));
  4034. goto EndOfInitialization;
  4035. }
  4036. ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
  4037. &deviceName->Name);
  4038. if (!NT_SUCCESS(ntStatus)) {
  4039. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: SymbolicLink Creation failed\n"));
  4040. goto EndOfInitialization;
  4041. }
  4042. symbolicLinkCreated = TRUE;
  4043. //
  4044. // Once initialization is finished, load the required information in the
  4045. // registry so that the appropriate display drivers can be loaded.
  4046. //
  4047. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  4048. VideoClassString,
  4049. deviceName->Name.Buffer,
  4050. REG_SZ,
  4051. DoSpecificExtension->DriverRegistryPath,
  4052. DoSpecificExtension->DriverRegistryPathLength +
  4053. sizeof(UNICODE_NULL));
  4054. if (!NT_SUCCESS(ntStatus)) {
  4055. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not store name in DeviceMap\n"));
  4056. }
  4057. if (fdoExtension->Flags & LEGACY_DRIVER) {
  4058. //
  4059. // If we successfully found a legacy driver, increment the
  4060. // global device number.
  4061. //
  4062. VideoDeviceNumber++;
  4063. }
  4064. //
  4065. // Tell win32k how many objects to try to open
  4066. //
  4067. MaxObjectNumber = VideoDeviceNumber - 1;
  4068. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  4069. VideoClassString,
  4070. L"MaxObjectNumber",
  4071. REG_DWORD,
  4072. &MaxObjectNumber,
  4073. sizeof(ULONG));
  4074. if (!NT_SUCCESS(ntStatus)) {
  4075. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortFindAdapter: Could not store name in DeviceMap\n"));
  4076. } else {
  4077. pVideoDebugPrint((Info, "VIDEOPRT: VideoPortFindAdapter: %d is stored in MaxObjectNumber of DeviceMap\n",
  4078. MaxObjectNumber));
  4079. }
  4080. //
  4081. // Save the function pointers to the new 5.0 miniport driver callbacks.
  4082. //
  4083. if (HwInitializationData->HwInitDataSize >
  4084. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) {
  4085. fdoExtension->HwSetPowerState = HwInitializationData->HwSetPowerState;
  4086. fdoExtension->HwGetPowerState = HwInitializationData->HwGetPowerState;
  4087. fdoExtension->HwQueryInterface = HwInitializationData->HwQueryInterface;
  4088. if (!ChildObject)
  4089. {
  4090. fdoExtension->HwGetVideoChildDescriptor = HwInitializationData->HwGetVideoChildDescriptor;
  4091. }
  4092. }
  4093. //
  4094. // Check if the minitor should always be D0 or D3
  4095. //
  4096. {
  4097. ULONG OverrideMonitorPower = 0;
  4098. VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
  4099. L"OverrideMonitorPower",
  4100. FALSE,
  4101. VpRegistryCallback,
  4102. &OverrideMonitorPower);
  4103. fdoExtension->OverrideMonitorPower = (OverrideMonitorPower != 0);
  4104. }
  4105. EndOfInitialization:
  4106. //
  4107. // If we are doing detection, then don't save all of these objects.
  4108. // We just want to see if the driver would load or not
  4109. //
  4110. if ( (fdoExtension->Flags & LEGACY_DETECT) ||
  4111. (!NT_SUCCESS(ntStatus)) )
  4112. {
  4113. //
  4114. // Free the miniport config info buffer.
  4115. //
  4116. if (miniportConfigInfo) {
  4117. ExFreePool(miniportConfigInfo);
  4118. }
  4119. //
  4120. // Free the rom image if we grabbed one.
  4121. //
  4122. if (fdoExtension->RomImage) {
  4123. ExFreePool(fdoExtension->RomImage);
  4124. fdoExtension->RomImage = NULL;
  4125. }
  4126. //
  4127. // Release the resource we put in the resourcemap (if any).
  4128. //
  4129. if ((fdoExtension->Flags & LEGACY_DETECT) ||
  4130. (findAdapterStatus != NO_ERROR)) {
  4131. ULONG_PTR emptyList = 0;
  4132. BOOLEAN conflict;
  4133. IoReportResourceUsage(&VideoClassName,
  4134. DriverObject,
  4135. NULL,
  4136. 0L,
  4137. deviceObject,
  4138. (PCM_RESOURCE_LIST) &emptyList, // an empty resource list
  4139. sizeof(ULONG_PTR),
  4140. FALSE,
  4141. &conflict);
  4142. }
  4143. //
  4144. // These are the things we want to delete if they were created and
  4145. // the initialization *FAILED* at a later time.
  4146. //
  4147. if (fdoExtension->InterruptObject) {
  4148. IoDisconnectInterrupt(fdoExtension->InterruptObject);
  4149. }
  4150. if (driverKeyName) {
  4151. ExFreePool(driverKeyName);
  4152. DoSpecificExtension->DriverOldRegistryPath = NULL;
  4153. }
  4154. if (DoSpecificExtension->DriverNewRegistryPath) {
  4155. ExFreePool(DoSpecificExtension->DriverNewRegistryPath);
  4156. DoSpecificExtension->DriverNewRegistryPath = NULL;
  4157. }
  4158. DoSpecificExtension->DriverRegistryPath = NULL;
  4159. if (symbolicLinkCreated) {
  4160. IoDeleteSymbolicLink(&deviceLinkUnicodeString);
  4161. }
  4162. //
  4163. // Free up any memory mapped in by the miniport using
  4164. // VideoPort GetDeviceBase.
  4165. //
  4166. while (fdoExtension->MappedAddressList != NULL)
  4167. {
  4168. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: unfreed address %08lx, physical %08lx, size %08lx\n",
  4169. fdoExtension->MappedAddressList->MappedAddress,
  4170. fdoExtension->MappedAddressList->PhysicalAddress.LowPart,
  4171. fdoExtension->MappedAddressList->NumberOfUchars));
  4172. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortFindAdapter: unfreed refcount %d, unmapping %d\n\n",
  4173. fdoExtension->MappedAddressList->RefCount,
  4174. fdoExtension->MappedAddressList->bNeedsUnmapping));
  4175. VideoPortFreeDeviceBase(fdoExtension->HwDeviceExtension,
  4176. fdoExtension->MappedAddressList->MappedAddress);
  4177. }
  4178. //
  4179. // Remove any HwResetHw function we may have added for this device.
  4180. //
  4181. if (HwInitializationData->HwInitDataSize >
  4182. FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwResetHw)) {
  4183. ULONG iReset;
  4184. for (iReset=0; iReset<6; iReset++) {
  4185. if (HwResetHw[iReset].HwDeviceExtension ==
  4186. fdoExtension->HwDeviceExtension) {
  4187. HwResetHw[iReset].ResetFunction = NULL;
  4188. break;
  4189. }
  4190. }
  4191. }
  4192. } else {
  4193. HwInitializationData->StartingDeviceNumber++;
  4194. }
  4195. return ntStatus;
  4196. }
  4197. BOOLEAN
  4198. pVideoPortInterrupt(
  4199. IN PKINTERRUPT Interrupt,
  4200. IN PDEVICE_OBJECT DeviceObject
  4201. )
  4202. /*++
  4203. Routine Description:
  4204. This function is the main interrupt service routine. If finds which
  4205. miniport driver the interrupt was for and forwards it.
  4206. Arguments:
  4207. Interrupt -
  4208. DeviceObject -
  4209. Return Value:
  4210. Returns TRUE if the interrupt was expected.
  4211. --*/
  4212. {
  4213. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  4214. BOOLEAN bRet;
  4215. UNREFERENCED_PARAMETER(Interrupt);
  4216. //
  4217. // If there is no interrupt routine, fail the assertion
  4218. //
  4219. ASSERT (fdoExtension->HwInterrupt);
  4220. if (fdoExtension->InterruptsEnabled) {
  4221. bRet = fdoExtension->HwInterrupt(fdoExtension->HwDeviceExtension);
  4222. } else {
  4223. bRet = FALSE; // this device did not handle the interrupt
  4224. }
  4225. return bRet;
  4226. } // pVideoPortInterrupt()
  4227. VOID
  4228. VideoPortLogError(
  4229. IN PVOID HwDeviceExtension,
  4230. IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
  4231. IN VP_STATUS ErrorCode,
  4232. IN ULONG UniqueId
  4233. )
  4234. /*++
  4235. Routine Description:
  4236. This routine saves the error log information so it can be processed at
  4237. any IRQL.
  4238. Arguments:
  4239. HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
  4240. Vrp - Supplies an optional pointer to a video request packet if there is
  4241. one.
  4242. ErrorCode - Supplies an error code indicating the type of error.
  4243. UniqueId - Supplies a unique identifier for the error.
  4244. Return Value:
  4245. None.
  4246. --*/
  4247. {
  4248. VP_ERROR_LOG_ENTRY errorLogEntry;
  4249. //
  4250. // Save the information in a local errorLogEntry structure.
  4251. //
  4252. errorLogEntry.DeviceExtension = GET_FDO_EXT(HwDeviceExtension);
  4253. if (Vrp != NULL) {
  4254. errorLogEntry.IoControlCode = Vrp->IoControlCode;
  4255. } else {
  4256. errorLogEntry.IoControlCode = 0;
  4257. }
  4258. errorLogEntry.ErrorCode = ErrorCode;
  4259. errorLogEntry.UniqueId = UniqueId;
  4260. //
  4261. // Call the sync routine so we are synchronized when writting in
  4262. // the device extension.
  4263. //
  4264. pVideoPortSynchronizeExecution(HwDeviceExtension,
  4265. VpMediumPriority,
  4266. pVideoPortLogErrorEntry,
  4267. &errorLogEntry);
  4268. return;
  4269. } // end VideoPortLogError()
  4270. BOOLEAN
  4271. pVideoPortLogErrorEntry(
  4272. IN PVOID Context
  4273. )
  4274. /*++
  4275. Routine Description:
  4276. This function is the synchronized LogError functions.
  4277. Arguments:
  4278. Context - Context value used here as the VP_ERROR_LOG_ENTRY for this
  4279. particular error
  4280. Return Value:
  4281. None.
  4282. --*/
  4283. {
  4284. PVP_ERROR_LOG_ENTRY logEntry = Context;
  4285. PFDO_EXTENSION fdoExtension = logEntry->DeviceExtension;
  4286. //
  4287. // If the error log entry is already full, then dump the error.
  4288. //
  4289. if (fdoExtension->InterruptFlags & VP_ERROR_LOGGED) {
  4290. pVideoDebugPrint((Trace, "VIDEOPRT: VideoPortLogError: Dumping video error log packet.\n"));
  4291. pVideoDebugPrint((Info, "\tControlCode = %x, ErrorCode = %x, UniqueId = %x.\n",
  4292. logEntry->IoControlCode, logEntry->ErrorCode,
  4293. logEntry->UniqueId));
  4294. return TRUE;
  4295. }
  4296. //
  4297. // Indicate that the error log entry is in use.
  4298. //
  4299. fdoExtension->InterruptFlags |= VP_ERROR_LOGGED;
  4300. fdoExtension->ErrorLogEntry = *logEntry;
  4301. //
  4302. // Now queue a DPC so we can process the error.
  4303. //
  4304. KeInsertQueueDpc(&fdoExtension->ErrorLogDpc,
  4305. NULL,
  4306. NULL);
  4307. return TRUE;
  4308. } // end pVideoPortLogErrorEntry();
  4309. VOID
  4310. pVideoPortLogErrorEntryDPC(
  4311. IN PKDPC Dpc,
  4312. IN PVOID DeferredContext,
  4313. IN PVOID SystemArgument1,
  4314. IN PVOID SystemArgument2
  4315. )
  4316. /*++
  4317. Routine Description:
  4318. This function allocates an I/O error log record, fills it in and writes it
  4319. to the I/O error log.
  4320. Arguments:
  4321. Dpc - Pointer to the DPC object.
  4322. DeferredContext - Context parameter that was passed to the DPC
  4323. initialization routine. It contains a pointer to the deviceObject.
  4324. SystemArgument1 - Unused.
  4325. SystemArgument2 - Unused.
  4326. Return Value:
  4327. None.
  4328. --*/
  4329. {
  4330. PDEVICE_OBJECT DeviceObject = DeferredContext;
  4331. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  4332. PIO_ERROR_LOG_PACKET errorLogPacket;
  4333. errorLogPacket = (PIO_ERROR_LOG_PACKET)
  4334. IoAllocateErrorLogEntry(DeviceObject,
  4335. sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
  4336. if (errorLogPacket != NULL) {
  4337. errorLogPacket->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL;
  4338. errorLogPacket->RetryCount = 0;
  4339. errorLogPacket->NumberOfStrings = 0;
  4340. errorLogPacket->StringOffset = 0;
  4341. errorLogPacket->EventCategory = 0;
  4342. //
  4343. // Translate the miniport error code into the NT I\O driver.
  4344. //
  4345. switch (fdoExtension->ErrorLogEntry.ErrorCode) {
  4346. case ERROR_INVALID_FUNCTION:
  4347. case ERROR_INVALID_PARAMETER:
  4348. errorLogPacket->ErrorCode = IO_ERR_INVALID_REQUEST;
  4349. break;
  4350. case ERROR_NOT_ENOUGH_MEMORY:
  4351. case ERROR_INSUFFICIENT_BUFFER:
  4352. errorLogPacket->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
  4353. break;
  4354. case ERROR_DEV_NOT_EXIST:
  4355. errorLogPacket->ErrorCode = IO_ERR_CONFIGURATION_ERROR;
  4356. break;
  4357. case ERROR_IO_PENDING:
  4358. ASSERT(FALSE);
  4359. case ERROR_MORE_DATA:
  4360. case NO_ERROR:
  4361. errorLogPacket->ErrorCode = 0;
  4362. break;
  4363. //
  4364. // If it is another error code, than assume it is private to the
  4365. // driver and just pass as-is.
  4366. //
  4367. default:
  4368. errorLogPacket->ErrorCode =
  4369. fdoExtension->ErrorLogEntry.ErrorCode;
  4370. break;
  4371. }
  4372. errorLogPacket->UniqueErrorValue =
  4373. fdoExtension->ErrorLogEntry.UniqueId;
  4374. errorLogPacket->FinalStatus = STATUS_SUCCESS;
  4375. errorLogPacket->SequenceNumber = 0;
  4376. errorLogPacket->IoControlCode =
  4377. fdoExtension->ErrorLogEntry.IoControlCode;
  4378. errorLogPacket->DumpDataSize = sizeof(ULONG);
  4379. errorLogPacket->DumpData[0] =
  4380. fdoExtension->ErrorLogEntry.ErrorCode;
  4381. IoWriteErrorLogEntry(errorLogPacket);
  4382. }
  4383. fdoExtension->InterruptFlags &= ~VP_ERROR_LOGGED;
  4384. } // end pVideoPortLogErrorEntry();
  4385. VOID
  4386. pVideoPortMapToNtStatus(
  4387. IN PSTATUS_BLOCK StatusBlock
  4388. )
  4389. /*++
  4390. Routine Description:
  4391. This function maps a Win32 error code to an NT error code, making sure
  4392. the inverse translation will map back to the original status code.
  4393. Arguments:
  4394. StatusBlock - Pointer to the status block
  4395. Return Value:
  4396. None.
  4397. --*/
  4398. {
  4399. PNTSTATUS status = &StatusBlock->Status;
  4400. switch (*status) {
  4401. case ERROR_INVALID_FUNCTION:
  4402. *status = STATUS_NOT_IMPLEMENTED;
  4403. break;
  4404. case ERROR_NOT_ENOUGH_MEMORY:
  4405. *status = STATUS_INSUFFICIENT_RESOURCES;
  4406. break;
  4407. case ERROR_INVALID_PARAMETER:
  4408. *status = STATUS_INVALID_PARAMETER;
  4409. break;
  4410. case ERROR_INSUFFICIENT_BUFFER:
  4411. *status = STATUS_BUFFER_TOO_SMALL;
  4412. //
  4413. // Make sure we zero out the information block if we get an
  4414. // insufficient buffer.
  4415. //
  4416. StatusBlock->Information = 0;
  4417. break;
  4418. case ERROR_MORE_DATA:
  4419. *status = STATUS_BUFFER_OVERFLOW;
  4420. break;
  4421. case ERROR_DEV_NOT_EXIST:
  4422. *status = STATUS_DEVICE_DOES_NOT_EXIST;
  4423. break;
  4424. case ERROR_IO_PENDING:
  4425. ASSERT(FALSE);
  4426. // Fall through.
  4427. case NO_ERROR:
  4428. *status = STATUS_SUCCESS;
  4429. break;
  4430. default:
  4431. pVideoDebugPrint((Error, "VIDEOPRT: Invalid return value from HwStartIo!\n"));
  4432. ASSERT(FALSE);
  4433. //
  4434. // Since the driver did not see fit to follow the
  4435. // rules about returning correct error codes. Videoprt will do it for
  4436. // them.
  4437. //
  4438. *status = STATUS_UNSUCCESSFUL;
  4439. break;
  4440. }
  4441. return;
  4442. } // end pVideoPortMapToNtStatus()
  4443. NTSTATUS
  4444. pVideoPortMapUserPhysicalMem(
  4445. IN PFDO_EXTENSION FdoExtension,
  4446. IN HANDLE ProcessHandle OPTIONAL,
  4447. IN PHYSICAL_ADDRESS PhysicalAddress,
  4448. IN OUT PULONG Length,
  4449. IN OUT PULONG InIoSpace,
  4450. IN OUT PVOID *VirtualAddress
  4451. )
  4452. /*++
  4453. Routine Description:
  4454. This function maps a view of a block of physical memory into a process'
  4455. virtual address space.
  4456. Arguments:
  4457. HwDeviceExtension - Pointer to the miniport driver's device extension.
  4458. ProcessHandle - Optional handle to the process into which the memory must
  4459. be mapped.
  4460. PhysicalAddress - Offset from the beginning of physical memory, in bytes.
  4461. Length - Pointer to a variable that will receive that actual size in
  4462. bytes of the view. The length is rounded to a page boundary. THe
  4463. length may not be zero.
  4464. InIoSpace - Specifies if the address is in the IO space if TRUE; otherwise,
  4465. the address is assumed to be in memory space.
  4466. VirtualAddress - Pointer to a variable that will receive the base
  4467. address of the view. If the initial value is not NULL, then the view
  4468. will be allocated starting at teh specified virtual address rounded
  4469. down to the next 64kb addess boundary.
  4470. Return Value:
  4471. STATUS_UNSUCCESSFUL if the length was zero.
  4472. STATUS_SUCCESS otherwise.
  4473. Environment:
  4474. This routine cannot be called from a miniport routine synchronized with
  4475. VideoPortSynchronizeRoutine or from an ISR.
  4476. --*/
  4477. {
  4478. NTSTATUS ntStatus;
  4479. HANDLE physicalMemoryHandle;
  4480. PHYSICAL_ADDRESS physicalAddressBase;
  4481. PHYSICAL_ADDRESS physicalAddressEnd;
  4482. PHYSICAL_ADDRESS viewBase;
  4483. PHYSICAL_ADDRESS mappedLength;
  4484. HANDLE processHandle;
  4485. BOOLEAN translateBaseAddress;
  4486. BOOLEAN translateEndAddress;
  4487. ULONG inIoSpace2;
  4488. ULONG inIoSpace1;
  4489. ULONG MapViewFlags;
  4490. //
  4491. // Check for a length of zero. If it is, the entire physical memory
  4492. // would be mapped into the process' address space. An error is returned
  4493. // in this case.
  4494. //
  4495. if (!*Length) {
  4496. return STATUS_INVALID_PARAMETER_4;
  4497. }
  4498. if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)) {
  4499. return STATUS_INVALID_PARAMETER_5;
  4500. }
  4501. //
  4502. // Get a handle to the physical memory section using our pointer.
  4503. // If this fails, return.
  4504. //
  4505. ntStatus = ObOpenObjectByPointer(PhysicalMemorySection,
  4506. 0L,
  4507. (PACCESS_STATE) NULL,
  4508. SECTION_ALL_ACCESS,
  4509. (POBJECT_TYPE) NULL,
  4510. KernelMode,
  4511. &physicalMemoryHandle);
  4512. if (!NT_SUCCESS(ntStatus)) {
  4513. return ntStatus;
  4514. }
  4515. //
  4516. // No flags are used in translation
  4517. //
  4518. inIoSpace1 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
  4519. inIoSpace2 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
  4520. //
  4521. // Initialize the physical addresses that will be translated
  4522. //
  4523. physicalAddressEnd.QuadPart = PhysicalAddress.QuadPart + (*Length - 1);
  4524. //
  4525. // Translate the physical addresses.
  4526. //
  4527. translateBaseAddress =
  4528. VpTranslateBusAddress(FdoExtension,
  4529. &PhysicalAddress,
  4530. &inIoSpace1,
  4531. &physicalAddressBase);
  4532. translateEndAddress =
  4533. VpTranslateBusAddress(FdoExtension,
  4534. &physicalAddressEnd,
  4535. &inIoSpace2,
  4536. &physicalAddressEnd);
  4537. if ( !(translateBaseAddress && translateEndAddress) ) {
  4538. ZwClose(physicalMemoryHandle);
  4539. return STATUS_DEVICE_CONFIGURATION_ERROR;
  4540. }
  4541. ASSERT(inIoSpace1 == inIoSpace2);
  4542. //
  4543. // Calcualte the length of the memory to be mapped
  4544. //
  4545. mappedLength.QuadPart = physicalAddressEnd.QuadPart -
  4546. physicalAddressBase.QuadPart + 1;
  4547. //
  4548. // If the mappedlength is zero, somthing very weird happened in the HAL
  4549. // since the Length was checked against zero.
  4550. //
  4551. ASSERT (mappedLength.QuadPart != 0);
  4552. //
  4553. // If the address is in io space, just return the address, otherwise
  4554. // go through the mapping mechanism
  4555. //
  4556. if ( (*InIoSpace) & (ULONG)0x01 ) {
  4557. (ULONG_PTR) *VirtualAddress = (ULONG_PTR) physicalAddressBase.QuadPart;
  4558. } else {
  4559. //
  4560. // If no process handle was passed, get the handle to the current
  4561. // process.
  4562. //
  4563. if (ProcessHandle) {
  4564. processHandle = ProcessHandle;
  4565. } else {
  4566. processHandle = NtCurrentProcess();
  4567. }
  4568. //
  4569. // initialize view base that will receive the physical mapped
  4570. // address after the MapViewOfSection call.
  4571. //
  4572. viewBase = physicalAddressBase;
  4573. //
  4574. // Map the section
  4575. //
  4576. if ((*InIoSpace) & VIDEO_MEMORY_SPACE_P6CACHE) {
  4577. MapViewFlags = PAGE_READWRITE | PAGE_WRITECOMBINE;
  4578. } else {
  4579. MapViewFlags = PAGE_READWRITE | PAGE_NOCACHE;
  4580. }
  4581. ntStatus = ZwMapViewOfSection(physicalMemoryHandle,
  4582. processHandle,
  4583. VirtualAddress,
  4584. 0L,
  4585. (ULONG_PTR) mappedLength.QuadPart,
  4586. &viewBase,
  4587. (PULONG_PTR) (&(mappedLength.QuadPart)),
  4588. ViewUnmap,
  4589. 0,
  4590. MapViewFlags);
  4591. //
  4592. // Close the handle since we only keep the pointer reference to the
  4593. // section.
  4594. //
  4595. ZwClose(physicalMemoryHandle);
  4596. //
  4597. // Mapping the section above rounded the physical address down to the
  4598. // nearest 64 K boundary. Now return a virtual address that sits where
  4599. // we wnat by adding in the offset from the beginning of the section.
  4600. //
  4601. (ULONG_PTR) *VirtualAddress += (ULONG_PTR) (physicalAddressBase.QuadPart -
  4602. viewBase.QuadPart);
  4603. }
  4604. //
  4605. // Restore all the other FLAGS
  4606. //
  4607. *InIoSpace = inIoSpace1 | *InIoSpace & ~VIDEO_MEMORY_SPACE_IO;
  4608. *Length = mappedLength.LowPart;
  4609. return ntStatus;
  4610. } // end pVideoPortMapUserPhysicalMem()
  4611. PVOID
  4612. VideoPortAllocatePool(
  4613. IN PVOID HwDeviceExtension,
  4614. IN VP_POOL_TYPE PoolType,
  4615. IN SIZE_T NumberOfBytes,
  4616. IN ULONG Tag)
  4617. /*++
  4618. Routine Description:
  4619. Allocates Memory
  4620. Arguments:
  4621. HwDeviceExtension - pointer to the miniports device extension
  4622. VpPoolType - The type of pool to allocate:
  4623. VpNonPagedPool
  4624. VpPagedPool
  4625. VpNonPagedPoolCacheAligned
  4626. VpPagedPoolCacheAligned
  4627. NumberOfBytes - Supplies the number of bytes to allocate.
  4628. Tag - Supplies the caller's identifying tag.
  4629. Return Value:
  4630. NULL - The memory allocation failed.
  4631. NON-NULL - Returns a pointer to the allocated pool.
  4632. --*/
  4633. {
  4634. ASSERT(HwDeviceExtension != NULL);
  4635. return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
  4636. }
  4637. VOID
  4638. VideoPortFreePool(
  4639. IN PVOID HwDeviceExtension,
  4640. IN PVOID Ptr
  4641. )
  4642. /*++
  4643. Routine Description:
  4644. Free's allocated memory
  4645. Arguments:
  4646. HwDeviceExtension - pointer to the miniports device extension
  4647. Ptr - pointer to the memory to free
  4648. Return Value:
  4649. none
  4650. --*/
  4651. {
  4652. ASSERT(HwDeviceExtension != NULL);
  4653. ASSERT(Ptr != NULL);
  4654. ExFreePool(Ptr);
  4655. }
  4656. VP_STATUS
  4657. VideoPortAllocateBuffer(
  4658. IN PVOID HwDeviceExtension,
  4659. IN ULONG Size,
  4660. OUT PVOID *Buffer
  4661. )
  4662. {
  4663. pVideoDebugPrint((1, "Obsolete function: Please use VideoPortAllocatePool instead\n"));
  4664. *Buffer = VideoPortAllocatePool(HwDeviceExtension, VpPagedPool, Size, ' pmV');
  4665. if (*Buffer) {
  4666. return NO_ERROR;
  4667. } else {
  4668. return ERROR_NOT_ENOUGH_MEMORY;
  4669. }
  4670. }
  4671. VOID
  4672. VideoPortReleaseBuffer(
  4673. IN PVOID HwDeviceExtension,
  4674. IN PVOID Buffer
  4675. )
  4676. {
  4677. pVideoDebugPrint((1, "Obsolete function: Please use VideoPortFreePool instead\n"));
  4678. VideoPortFreePool(HwDeviceExtension, Buffer);
  4679. }
  4680. VP_STATUS
  4681. VideoPortMapBankedMemory(
  4682. PVOID HwDeviceExtension,
  4683. PHYSICAL_ADDRESS PhysicalAddress,
  4684. PULONG Length,
  4685. PULONG InIoSpace,
  4686. PVOID *VirtualAddress,
  4687. ULONG BankLength,
  4688. UCHAR ReadWriteBank,
  4689. PBANKED_SECTION_ROUTINE BankRoutine,
  4690. PVOID Context
  4691. )
  4692. /*++
  4693. Routine Description:
  4694. VideoPortMapMemory allows the miniport driver to map a section of
  4695. physical memory (either memory or registers) into the calling process'
  4696. address space (eventhough we are in kernel mode, this function is
  4697. executed within the same context as the user-mode process that initiated
  4698. the call).
  4699. Arguments:
  4700. HwDeviceExtension - Points to the miniport driver's device extension.
  4701. PhysicalAddress - Specifies the physical address to be mapped.
  4702. Length - Points to the number of bytes of physical memory to be mapped.
  4703. This argument returns the actual amount of memory mapped.
  4704. InIoSpace - Points to a variable that is 1 if the address is in I/O
  4705. space. Otherwise, the address is assumed to be in memory space.
  4706. VirtualAddress - A pointer to a location containing:
  4707. on input: An optional handle to the process in which the memory must
  4708. be mapped. 0 must be used to map the memory for the display
  4709. driver (in the context of the windows server process).
  4710. on output: The return value is the virtual address at which the
  4711. physical address has been mapped.
  4712. BankLength - Size of the bank on the device.
  4713. ReadWriteBank - TRUE is the bank is READ\WRITE, FALSE if there are
  4714. two independent READ and WRITE banks.
  4715. BankRoutine - Pointer to the banking routine.
  4716. Context - Context parameter passed in by the miniport supplied on
  4717. each callback to the miniport.
  4718. Return Value:
  4719. VideoPortMapBankedMemory returns the status of the operation.
  4720. Environment:
  4721. This routine cannot be called from a miniport routine synchronized with
  4722. VideoPortSynchronizeRoutine or from an ISR.
  4723. --*/
  4724. {
  4725. VP_STATUS status;
  4726. HANDLE processHandle;
  4727. //
  4728. // Save the process ID, but don't change it since MapMemory relies
  4729. // on it also
  4730. //
  4731. if (*VirtualAddress == NULL) {
  4732. processHandle = NtCurrentProcess();
  4733. } else {
  4734. processHandle = (HANDLE) *VirtualAddress;
  4735. }
  4736. status = VideoPortMapMemory(HwDeviceExtension,
  4737. PhysicalAddress,
  4738. Length,
  4739. InIoSpace,
  4740. VirtualAddress);
  4741. if (status == NO_ERROR) {
  4742. NTSTATUS ntstatus;
  4743. ntstatus = MmSetBankedSection(processHandle,
  4744. *VirtualAddress,
  4745. BankLength,
  4746. ReadWriteBank,
  4747. BankRoutine,
  4748. Context);
  4749. if (!NT_SUCCESS(ntstatus)) {
  4750. ASSERT (FALSE);
  4751. status = ERROR_INVALID_PARAMETER;
  4752. }
  4753. }
  4754. return status;
  4755. } // end VideoPortMapBankedMemory()
  4756. VP_STATUS
  4757. VideoPortMapMemory(
  4758. PVOID HwDeviceExtension,
  4759. PHYSICAL_ADDRESS PhysicalAddress,
  4760. PULONG Length,
  4761. PULONG InIoSpace,
  4762. PVOID *VirtualAddress
  4763. )
  4764. /*++
  4765. Routine Description:
  4766. VideoPortMapMemory allows the miniport driver to map a section of
  4767. physical memory (either memory or registers) into the calling process'
  4768. address space (eventhough we are in kernel mode, this function is
  4769. executed within the same context as the user-mode process that initiated
  4770. the call).
  4771. Arguments:
  4772. HwDeviceExtension - Points to the miniport driver's device extension.
  4773. PhysicalAddress - Specifies the physical address to be mapped.
  4774. Length - Points to the number of bytes of physical memory to be mapped.
  4775. This argument returns the actual amount of memory mapped.
  4776. InIoSpace - Points to a variable that is 1 if the address is in I/O
  4777. space. Otherwise, the address is assumed to be in memory space.
  4778. VirtualAddress - A pointer to a location containing:
  4779. on input: An optional handle to the process in which the memory must
  4780. be mapped. 0 must be used to map the memory for the display
  4781. driver (in the context of the windows server process).
  4782. on output: The return value is the virtual address at which the
  4783. physical address has been mapped.
  4784. Return Value:
  4785. VideoPortMapMemory returns the status of the operation.
  4786. Environment:
  4787. This routine cannot be called from a miniport routine synchronized with
  4788. VideoPortSynchronizeRoutine or from an ISR.
  4789. --*/
  4790. {
  4791. NTSTATUS ntStatus;
  4792. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  4793. HANDLE processHandle;
  4794. //
  4795. // Check for valid pointers.
  4796. //
  4797. if (!(ARGUMENT_PRESENT(Length)) ||
  4798. !(ARGUMENT_PRESENT(InIoSpace)) ||
  4799. !(ARGUMENT_PRESENT(VirtualAddress)) ) {
  4800. ASSERT(FALSE);
  4801. return ERROR_INVALID_PARAMETER;
  4802. }
  4803. //
  4804. // Let's handle the special memory types here.
  4805. //
  4806. // NOTE
  4807. // Large pages is automatic - the caller need not specify this attribute
  4808. // since it does not affect the device.
  4809. //
  4810. // Save the process handle and zero out the Virtual address field
  4811. //
  4812. if (*VirtualAddress == NULL) {
  4813. if (*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)
  4814. {
  4815. ASSERT(FALSE);
  4816. return ERROR_INVALID_PARAMETER;
  4817. }
  4818. ntStatus = STATUS_SUCCESS;
  4819. //
  4820. // We specify TRUE for large pages since we know the addrses will only
  4821. // be used in the context of the display driver, at normal IRQL.
  4822. //
  4823. *VirtualAddress = pVideoPortGetDeviceBase(HwDeviceExtension,
  4824. PhysicalAddress,
  4825. *Length,
  4826. (UCHAR) (*InIoSpace),
  4827. TRUE);
  4828. //
  4829. // Zero can only be success if the driver is calling to MAP
  4830. // address 0. Otherwise, it is an error.
  4831. //
  4832. if (*VirtualAddress == NULL) {
  4833. //
  4834. // Only on X86 can the logical address also be 0.
  4835. //
  4836. #if defined (_X86_) || defined(_IA64_)
  4837. if (PhysicalAddress.QuadPart != 0)
  4838. #endif
  4839. ntStatus = STATUS_INVALID_PARAMETER;
  4840. }
  4841. } else {
  4842. if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE))
  4843. {
  4844. //
  4845. // We can not assert since this is an existing path and old
  4846. // drivers will not have this flag set.
  4847. //
  4848. // ASSERT(FALSE);
  4849. // return ERROR_INVALID_PARAMETER;
  4850. //
  4851. *InIoSpace |= VIDEO_MEMORY_SPACE_USER_MODE;
  4852. }
  4853. processHandle = (HANDLE) *VirtualAddress;
  4854. *VirtualAddress = NULL;
  4855. ntStatus = pVideoPortMapUserPhysicalMem(fdoExtension,
  4856. processHandle,
  4857. PhysicalAddress,
  4858. Length,
  4859. InIoSpace,
  4860. VirtualAddress);
  4861. }
  4862. if (!NT_SUCCESS(ntStatus)) {
  4863. pVideoDebugPrint((Error,
  4864. "VIDEOPRT: VideoPortMapMemory failed with NtStatus = %08lx\n",
  4865. ntStatus));
  4866. pVideoDebugPrint((Error, "*VirtualAddress = 0x%x\n", *VirtualAddress));
  4867. pVideoDebugPrint((Error, "Length = 0x%x\n", *Length));
  4868. pVideoDebugPrint((Error,
  4869. "PhysicalAddress.LowPart = 0x%08lx, PhysicalAddress.HighPart = 0x%08lx\n",
  4870. PhysicalAddress.LowPart, PhysicalAddress.HighPart));
  4871. *VirtualAddress = NULL;
  4872. return ERROR_INVALID_PARAMETER;
  4873. } else {
  4874. return NO_ERROR;
  4875. }
  4876. } // end VideoPortMapMemory()
  4877. VOID
  4878. pVideoPortPowerCompletionIoctl(
  4879. IN PDEVICE_OBJECT DeviceObject,
  4880. IN UCHAR MinorFunction,
  4881. IN POWER_STATE PowerState,
  4882. IN PVOID Context,
  4883. IN PIO_STATUS_BLOCK IoStatus
  4884. )
  4885. /*++
  4886. Routine Description:
  4887. Completion routine that is called when one of our power irps has been
  4888. comeplted. This allows us to fill out the status code for the request.
  4889. Arguments:
  4890. DeviceObject - Pointer to the device object
  4891. MinorFunction - Minor function of the IRP
  4892. PowerState - Power state that was set
  4893. Context - Context paramter
  4894. IoStatus - Status block for that IRP
  4895. Return Value:
  4896. VOID
  4897. Environment:
  4898. --*/
  4899. {
  4900. PPOWER_BLOCK powerContext = (PPOWER_BLOCK) Context;
  4901. if (powerContext->FinalFlag == TRUE) {
  4902. powerContext->Irp->IoStatus.Status = IoStatus->Status;
  4903. IoCompleteRequest (powerContext->Irp, IO_VIDEO_INCREMENT);
  4904. }
  4905. ExFreePool(Context);
  4906. return;
  4907. }
  4908. BOOLEAN
  4909. pVideoPortResetDisplay(
  4910. IN ULONG Columns,
  4911. IN ULONG Rows
  4912. )
  4913. /*++
  4914. Routine Description:
  4915. Callback for the HAL that calls the miniport driver.
  4916. Arguments:
  4917. Columns - The number of columns of the video mode.
  4918. Rows - The number of rows for the video mode.
  4919. Return Value:
  4920. We always return FALSE so the HAL will always reste the mode afterwards.
  4921. Environment:
  4922. Non-paged only.
  4923. Used in BugCheck and soft-reset calls.
  4924. --*/
  4925. {
  4926. ULONG iReset;
  4927. BOOLEAN bRetVal = FALSE;
  4928. for (iReset=0;
  4929. (iReset < 6) && (HwResetHw[iReset].HwDeviceExtension);
  4930. iReset++) {
  4931. PFDO_EXTENSION fdoExtension =
  4932. GET_FDO_EXT(HwResetHw[iReset].HwDeviceExtension);
  4933. //
  4934. // We can only reset devices which are on the hibernation path, otherwise
  4935. // we are running into the risk that IO / MMIO decode has been disabled
  4936. // by PCI.SYS for that device during power management cycle.
  4937. //
  4938. if (HwResetHw[iReset].ResetFunction &&
  4939. (fdoExtension->HwInitStatus == HwInitSucceeded) &&
  4940. (fdoExtension->OnHibernationPath == TRUE)) {
  4941. bRetVal &= HwResetHw[iReset].ResetFunction(HwResetHw[iReset].HwDeviceExtension,
  4942. Columns,
  4943. Rows);
  4944. }
  4945. }
  4946. return bRetVal;
  4947. } // end pVideoPortResetDisplay()
  4948. BOOLEAN
  4949. VideoPortScanRom(
  4950. PVOID HwDeviceExtension,
  4951. PUCHAR RomBase,
  4952. ULONG RomLength,
  4953. PUCHAR String
  4954. )
  4955. /*++
  4956. Routine Description:
  4957. Does a case *SENSITIVE* search for a string in the ROM.
  4958. Arguments:
  4959. HwDeviceExtension - Points to the miniport driver's device extension.
  4960. RomBase - Base address at which the search should start.
  4961. RomLength - Size, in bytes, of the ROM area in which to perform the
  4962. search.
  4963. String - String to search for
  4964. Return Value:
  4965. Returns TRUE if the string was found.
  4966. Returns FALSE if it was not found.
  4967. Environment:
  4968. This routine cannot be called from a miniport routine synchronized with
  4969. VideoPortSynchronizeRoutine or from an ISR.
  4970. --*/
  4971. {
  4972. ULONG stringLength, length;
  4973. ULONG_PTR startOffset;
  4974. PUCHAR string1, string2;
  4975. BOOLEAN match;
  4976. UNREFERENCED_PARAMETER(HwDeviceExtension);
  4977. stringLength = strlen(String);
  4978. for (startOffset = 0;
  4979. startOffset < RomLength - stringLength + 1;
  4980. startOffset++) {
  4981. length = stringLength;
  4982. string1 = RomBase + startOffset;
  4983. string2 = String;
  4984. match = TRUE;
  4985. while (length--) {
  4986. if (READ_REGISTER_UCHAR(string1++) - (*string2++)) {
  4987. match = FALSE;
  4988. break;
  4989. }
  4990. }
  4991. if (match) {
  4992. return TRUE;
  4993. }
  4994. }
  4995. return FALSE;
  4996. } // end VideoPortScanRom()
  4997. VP_STATUS
  4998. VideoPortSetRegistryParameters(
  4999. PVOID HwDeviceExtension,
  5000. PWSTR ValueName,
  5001. PVOID ValueData,
  5002. ULONG ValueLength
  5003. )
  5004. /*++
  5005. Routine Description:
  5006. VideoPortSetRegistryParameters writes information to the CurrentControlSet
  5007. in the registry. The function automatically searches for or creates the
  5008. specified parameter name under the parameter key of the current driver.
  5009. Arguments:
  5010. HwDeviceExtension - Points to the miniport driver's device extension.
  5011. ValueName - Points to a Unicode string that contains the name of the
  5012. data value being written in the registry.
  5013. ValueData - Points to a buffer containing the information to be written
  5014. to the registry.
  5015. ValueLength - Specifies the size of the data being written to the registry.
  5016. Return Value:
  5017. This function returns the final status of the operation.
  5018. Environment:
  5019. This routine cannot be called from a miniport routine synchronized with
  5020. VideoPortSynchronizeRoutine or from an ISR.
  5021. --*/
  5022. {
  5023. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  5024. VP_STATUS vpStatus;
  5025. ASSERT (ValueName != NULL);
  5026. DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
  5027. if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
  5028. vpStatus = VPSetRegistryParameters(HwDeviceExtension,
  5029. ValueName,
  5030. ValueData,
  5031. ValueLength,
  5032. DoSpecificExtension->DriverNewRegistryPath,
  5033. DoSpecificExtension->DriverNewRegistryPathLength);
  5034. } else {
  5035. vpStatus = VPSetRegistryParameters(HwDeviceExtension,
  5036. ValueName,
  5037. ValueData,
  5038. ValueLength,
  5039. DoSpecificExtension->DriverOldRegistryPath,
  5040. DoSpecificExtension->DriverOldRegistryPathLength);
  5041. }
  5042. return vpStatus;
  5043. }
  5044. VP_STATUS
  5045. VPSetRegistryParameters(
  5046. PVOID HwDeviceExtension,
  5047. PWSTR ValueName,
  5048. PVOID ValueData,
  5049. ULONG ValueLength,
  5050. PWSTR RegistryPath,
  5051. ULONG RegistryPathLength
  5052. )
  5053. {
  5054. NTSTATUS ntStatus;
  5055. LPWSTR RegPath;
  5056. LPWSTR lpstrStart, lpstrEnd;
  5057. //
  5058. // Check if there are subkeys need to be created
  5059. //
  5060. RegPath = (LPWSTR) ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  5061. RegistryPathLength +
  5062. 2 * (wcslen(ValueName) + sizeof(WCHAR)),
  5063. VP_TAG);
  5064. if (RegPath == NULL) {
  5065. return ERROR_NOT_ENOUGH_MEMORY;
  5066. }
  5067. wcscpy(RegPath, RegistryPath);
  5068. lpstrStart = RegPath + (RegistryPathLength / 2);
  5069. while (lpstrEnd = wcschr(ValueName, L'\\'))
  5070. {
  5071. //
  5072. // Concat the string
  5073. //
  5074. *(lpstrStart++) = L'\\';
  5075. while (ValueName != lpstrEnd) {
  5076. *(lpstrStart++) = *(ValueName++);
  5077. }
  5078. *lpstrStart = UNICODE_NULL;
  5079. //
  5080. // Create the Key.
  5081. //
  5082. ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, RegPath);
  5083. if (!NT_SUCCESS(ntStatus)) {
  5084. ExFreePool(RegPath);
  5085. return ERROR_INVALID_PARAMETER;
  5086. }
  5087. ValueName++;
  5088. }
  5089. //
  5090. // Don't let people store as DefaultSettings anymore ...
  5091. // Must still work for older drivers through.
  5092. //
  5093. if (wcsncmp(ValueName,
  5094. L"DefaultSettings.",
  5095. sizeof(L"DefaultSettings.")) == 0) {
  5096. ASSERT(FALSE);
  5097. //
  5098. // check for NT 5.0
  5099. //
  5100. if (GET_FDO_EXT(HwDeviceExtension)->Flags & PNP_ENABLED) {
  5101. ExFreePool(RegPath);
  5102. return ERROR_INVALID_PARAMETER;
  5103. }
  5104. }
  5105. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5106. RegPath,
  5107. ValueName,
  5108. REG_BINARY,
  5109. ValueData,
  5110. ValueLength);
  5111. ExFreePool(RegPath);
  5112. if (!NT_SUCCESS(ntStatus)) {
  5113. return ERROR_INVALID_PARAMETER;
  5114. }
  5115. return NO_ERROR;
  5116. } // end VideoPortSetRegistryParamaters()
  5117. VP_STATUS
  5118. VideoPortFlushRegistry(
  5119. PVOID HwDeviceExtension
  5120. )
  5121. /*++
  5122. Routine Description:
  5123. This routine will flush the registry keys and values associated with
  5124. the given miniport driver.
  5125. Arguments:
  5126. HwDeviceExtension - Pointer to the miniport device extension.
  5127. Return Value:
  5128. Status Code.
  5129. --*/
  5130. {
  5131. OBJECT_ATTRIBUTES ObjectAttributes;
  5132. UNICODE_STRING KeyName;
  5133. HANDLE RegKey;
  5134. NTSTATUS Status;
  5135. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  5136. DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
  5137. if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
  5138. KeyName.Length = (USHORT)DoSpecificExtension->DriverNewRegistryPathLength;
  5139. KeyName.MaximumLength = (USHORT)DoSpecificExtension->DriverNewRegistryPathLength;
  5140. KeyName.Buffer = DoSpecificExtension->DriverNewRegistryPath;
  5141. } else {
  5142. KeyName.Length = (USHORT)DoSpecificExtension->DriverOldRegistryPathLength;
  5143. KeyName.MaximumLength = (USHORT)DoSpecificExtension->DriverOldRegistryPathLength;
  5144. KeyName.Buffer = DoSpecificExtension->DriverOldRegistryPath;
  5145. }
  5146. //
  5147. // Flush the registry key
  5148. //
  5149. InitializeObjectAttributes(&ObjectAttributes,
  5150. &KeyName,
  5151. OBJ_CASE_INSENSITIVE,
  5152. NULL,
  5153. NULL);
  5154. Status = ZwOpenKey(&RegKey,
  5155. KEY_READ | KEY_WRITE,
  5156. &ObjectAttributes);
  5157. if (NT_SUCCESS(Status)) {
  5158. ZwFlushKey(RegKey);
  5159. ZwClose(RegKey);
  5160. }
  5161. return NO_ERROR;
  5162. }
  5163. VOID
  5164. pVideoPortHwTimer(
  5165. IN PDEVICE_OBJECT DeviceObject,
  5166. PVOID Context
  5167. )
  5168. /*++
  5169. Routine Description:
  5170. This function is the main entry point for the timer routine that we then
  5171. forward to the miniport driver.
  5172. Arguments:
  5173. DeviceObject -
  5174. Context - Not needed
  5175. Return Value:
  5176. None.
  5177. --*/
  5178. {
  5179. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  5180. UNREFERENCED_PARAMETER(Context);
  5181. fdoExtension->HwTimer(fdoExtension->HwDeviceExtension);
  5182. return;
  5183. } // pVideoPortInterrupt()
  5184. VOID
  5185. VideoPortStartTimer(
  5186. PVOID HwDeviceExtension
  5187. )
  5188. /*++
  5189. Routine Description:
  5190. Enables the timer specified in the HW_INITIALIZATION_DATA structure
  5191. passed to the video port driver at init time.
  5192. Arguments:
  5193. HwDeviceExtension - Points to the miniport driver's device extension.
  5194. Return Value:
  5195. None
  5196. --*/
  5197. {
  5198. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  5199. if (fdoExtension->HwTimer == NULL) {
  5200. ASSERT(fdoExtension->HwTimer != NULL);
  5201. } else {
  5202. IoStartTimer(fdoExtension->FunctionalDeviceObject);
  5203. }
  5204. return;
  5205. }
  5206. VOID
  5207. VideoPortStopTimer(
  5208. PVOID HwDeviceExtension
  5209. )
  5210. /*++
  5211. Routine Description:
  5212. Disables the timer specified in the HW_INITIALIZATION_DATA structure
  5213. passed to the video port driver at init time.
  5214. Arguments:
  5215. HwDeviceExtension - Points to the miniport driver's device extension.
  5216. Return Value:
  5217. None
  5218. --*/
  5219. {
  5220. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  5221. if (fdoExtension->HwTimer == NULL) {
  5222. ASSERT(fdoExtension->HwTimer != NULL);
  5223. } else {
  5224. IoStopTimer(fdoExtension->FunctionalDeviceObject);
  5225. }
  5226. return;
  5227. }
  5228. BOOLEAN
  5229. VideoPortSynchronizeExecution(
  5230. PVOID HwDeviceExtension,
  5231. VIDEO_SYNCHRONIZE_PRIORITY Priority,
  5232. PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
  5233. PVOID Context
  5234. )
  5235. /*++
  5236. Stub so we can allow the miniports to link directly
  5237. --*/
  5238. {
  5239. return pVideoPortSynchronizeExecution(HwDeviceExtension,
  5240. Priority,
  5241. SynchronizeRoutine,
  5242. Context);
  5243. } // end VideoPortSynchronizeExecution()
  5244. BOOLEAN
  5245. pVideoPortSynchronizeExecution(
  5246. PVOID HwDeviceExtension,
  5247. VIDEO_SYNCHRONIZE_PRIORITY Priority,
  5248. PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
  5249. PVOID Context
  5250. )
  5251. /*++
  5252. Routine Description:
  5253. VideoPortSynchronizeExecution synchronizes the execution of a miniport
  5254. driver function in the following manner:
  5255. - If Priority is equal to VpLowPriority, the current thread is
  5256. raised to the highest non-interrupt-masking priority. In
  5257. other words, the current thread can only be pre-empted by an ISR.
  5258. - If Priority is equal to VpMediumPriority and there is an
  5259. ISR associated with the video device, then the function specified
  5260. by SynchronizeRoutine is synchronized with the ISR.
  5261. If no ISR is connected, synchronization is made at VpHighPriority
  5262. level.
  5263. - If Priority is equal to VpHighPriority, the current IRQL is
  5264. raised to HIGH_LEVEL, which effectively masks out ALL interrupts
  5265. in the system. This should be done sparingly and for very short
  5266. periods -- it will completely freeze up the entire system.
  5267. Arguments:
  5268. HwDeviceExtension - Points to the miniport driver's device extension.
  5269. Priority - Specifies the type of priority at which the SynchronizeRoutine
  5270. must be executed (found in VIDEO_SYNCHRONIZE_PRIORITY).
  5271. SynchronizeRoutine - Points to the miniport driver function to be
  5272. synchronized.
  5273. Context - Specifies a context parameter to be passed to the miniport's
  5274. SynchronizeRoutine.
  5275. Return Value:
  5276. This function returns TRUE if the operation is successful. Otherwise, it
  5277. returns FALSE.
  5278. --*/
  5279. {
  5280. BOOLEAN status;
  5281. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  5282. KIRQL oldIrql;
  5283. //
  5284. // Switch on which type of priority.
  5285. //
  5286. switch (Priority) {
  5287. case VpMediumPriority:
  5288. case VpHighPriority:
  5289. //
  5290. // This is synchronized with the interrupt object
  5291. //
  5292. if (fdoExtension->InterruptObject) {
  5293. status = KeSynchronizeExecution(fdoExtension->InterruptObject,
  5294. (PKSYNCHRONIZE_ROUTINE)
  5295. SynchronizeRoutine,
  5296. Context);
  5297. return status;
  5298. }
  5299. //
  5300. // Fall through for Medium Priority
  5301. //
  5302. case VpLowPriority:
  5303. //
  5304. // Just normal level
  5305. //
  5306. status = SynchronizeRoutine(Context);
  5307. return status;
  5308. default:
  5309. return FALSE;
  5310. }
  5311. }
  5312. VP_STATUS
  5313. VideoPortUnmapMemory(
  5314. PVOID HwDeviceExtension,
  5315. PVOID VirtualAddress,
  5316. HANDLE ProcessHandle
  5317. )
  5318. /*++
  5319. Routine Description:
  5320. VideoPortUnmapMemory allows the miniport driver to unmap a physical
  5321. address range previously mapped into the calling process' address space
  5322. using the VideoPortMapMemory function.
  5323. Arguments:
  5324. HwDeviceExtension - Points to the miniport driver's device extension.
  5325. VirtualAddress - Points to the virtual address to unmap from the
  5326. address space of the caller.
  5327. // InIoSpace - Specifies whether the address is in I/O space (1) or memory
  5328. // space (0).
  5329. ProcessHandle - Handle to the process from which memory must be unmapped.
  5330. Return Value:
  5331. This function returns a status code of NO_ERROR if the operation succeeds.
  5332. It returns ERROR_INVALID_PARAMETER if an error occurs.
  5333. Environment:
  5334. This routine cannot be called from a miniport routine synchronized with
  5335. VideoPortSynchronizeRoutine or from an ISR.
  5336. --*/
  5337. {
  5338. NTSTATUS ntstatus;
  5339. VP_STATUS vpStatus = NO_ERROR;
  5340. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  5341. //
  5342. // Backwards compatibility to when the ProcessHandle was actually
  5343. // ULONG InIoSpace.
  5344. //
  5345. if (((ULONG_PTR)(ProcessHandle)) == 1) {
  5346. pVideoDebugPrint((Warn,"VIDEOPRT: VideoPortUnmapMemory - interface change, must pass in process handle\n\n"));
  5347. ASSERT(FALSE);
  5348. return NO_ERROR;
  5349. }
  5350. if (((ULONG_PTR)(ProcessHandle)) == 0) {
  5351. //
  5352. // If the process handle is zero, it means it was mapped by the display
  5353. // driver and is therefore in kernel mode address space.
  5354. //
  5355. if (!pVideoPortFreeDeviceBase(HwDeviceExtension, VirtualAddress)) {
  5356. ASSERT(FALSE);
  5357. vpStatus = ERROR_INVALID_PARAMETER;
  5358. }
  5359. } else {
  5360. //
  5361. // A process handle is passed in.
  5362. // This ms it was mapped for use by an application (DCI \ DirectDraw).
  5363. //
  5364. ntstatus = ZwUnmapViewOfSection ( ProcessHandle,
  5365. (PVOID) ( ((ULONG_PTR)VirtualAddress) & (~(PAGE_SIZE - 1)) ) );
  5366. if ( (!NT_SUCCESS(ntstatus)) &&
  5367. (ntstatus != STATUS_PROCESS_IS_TERMINATING) ) {
  5368. ASSERT(FALSE);
  5369. vpStatus = ERROR_INVALID_PARAMETER;
  5370. }
  5371. }
  5372. return NO_ERROR;
  5373. } // end VideoPortUnmapMemory()
  5374. BOOLEAN
  5375. VideoPortSignalDmaComplete(
  5376. IN PVOID HwDeviceExtension,
  5377. IN PDMA pDmaHandle
  5378. )
  5379. /*++
  5380. Routine Description:
  5381. This function is obsolete.
  5382. --*/
  5383. {
  5384. return FALSE;
  5385. }
  5386. VP_STATUS
  5387. VideoPortCreateSecondaryDisplay(
  5388. IN PVOID HwDeviceExtension,
  5389. IN OUT PVOID *SecondaryDeviceExtension,
  5390. IN ULONG ulFlag
  5391. )
  5392. /*++
  5393. Routine Description:
  5394. This routine creates a secondary device object for the given device. This
  5395. will allow for dual-view support.
  5396. Arguments:
  5397. HwDeviceExtension - The HwDeviceExtension for the device which wants to
  5398. create additional output devices.
  5399. SecondaryDeviceExtension - The location in which to store the
  5400. HwDeviceExtension for the secondary display.
  5401. Returns:
  5402. VP_STATUS
  5403. --*/
  5404. {
  5405. WCHAR deviceNameBuffer[STRING_LENGTH];
  5406. POBJECT_NAME_INFORMATION deviceName;
  5407. ULONG strLength;
  5408. UNICODE_STRING deviceNameUnicodeString;
  5409. PDEVICE_OBJECT DeviceObject;
  5410. NTSTATUS ntStatus;
  5411. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
  5412. PFDO_EXTENSION FdoExtension = GET_FDO_EXT(HwDeviceExtension);
  5413. PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension;
  5414. PUNICODE_STRING RegistryPath;
  5415. WCHAR deviceSubpathBuffer[STRING_LENGTH];
  5416. UNICODE_STRING deviceSubpathUnicodeString;
  5417. WCHAR deviceLinkBuffer[STRING_LENGTH];
  5418. UNICODE_STRING deviceLinkUnicodeString;
  5419. ULONG driverKeySize;
  5420. PWSTR driverKeyName = NULL;
  5421. ULONG MaxObjectNumber;
  5422. //
  5423. // Retrieve the data we cached away during VideoPortInitialize.
  5424. //
  5425. DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION)
  5426. IoGetDriverObjectExtension(
  5427. FdoExtension->DriverObject,
  5428. FdoExtension->DriverObject);
  5429. ASSERT(DriverObjectExtension);
  5430. ASSERT(SecondaryDeviceExtension != NULL);
  5431. RegistryPath = &DriverObjectExtension->RegistryPath;
  5432. ntStatus = pVideoPortCreateDeviceName(L"\\Device\\Video",
  5433. VideoDeviceNumber,
  5434. &deviceNameUnicodeString,
  5435. deviceNameBuffer);
  5436. //
  5437. // Create a device object to represent the Video Adapter.
  5438. //
  5439. if (NT_SUCCESS(ntStatus)) {
  5440. ntStatus = IoCreateDevice(FdoExtension->DriverObject,
  5441. sizeof(DEVICE_SPECIFIC_EXTENSION) +
  5442. FdoExtension->HwDeviceExtensionSize,
  5443. &deviceNameUnicodeString,
  5444. FILE_DEVICE_VIDEO,
  5445. 0,
  5446. TRUE,
  5447. &DeviceObject);
  5448. if (NT_SUCCESS(ntStatus)) {
  5449. DeviceObject->DeviceType = FILE_DEVICE_VIDEO;
  5450. DoSpecificExtension = DeviceObject->DeviceExtension;
  5451. //
  5452. // Initialize DeviceSpecificExtension
  5453. //
  5454. DoSpecificExtension->DeviceNumber = VideoDeviceNumber;
  5455. DoSpecificExtension->pFdoExtension = FdoExtension;
  5456. DoSpecificExtension->Signature = VP_TAG;
  5457. DoSpecificExtension->ExtensionType = TypeDeviceSpecificExtension;
  5458. DoSpecificExtension->HwDeviceExtension = (PVOID)(DoSpecificExtension + 1);
  5459. DoSpecificExtension->DualviewFlags = ulFlag | VIDEO_DUALVIEW_SECONDARY;
  5460. #ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  5461. DoSpecificExtension->SessionId = VIDEO_DEVICE_INVALID_SESSION;
  5462. #endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  5463. deviceName = (POBJECT_NAME_INFORMATION) deviceNameBuffer;
  5464. ObQueryNameString(DeviceObject,
  5465. deviceName,
  5466. STRING_LENGTH * sizeof(WCHAR),
  5467. &strLength);
  5468. //
  5469. // Create the name we will be storing in the \DeviceMap.
  5470. // This name is a PWSTR, not a unicode string
  5471. // This is the name of the driver with an appended device number
  5472. //
  5473. if (!NT_SUCCESS(pVideoPortCreateDeviceName(
  5474. L"\\Device",
  5475. DriverObjectExtension->HwInitData.StartingDeviceNumber + 1,
  5476. &deviceSubpathUnicodeString,
  5477. deviceSubpathBuffer)))
  5478. {
  5479. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not create device subpath number\n"));
  5480. IoDeleteDevice(DeviceObject);
  5481. return STATUS_INSUFFICIENT_RESOURCES;
  5482. }
  5483. DoSpecificExtension->DriverOldRegistryPathLength =
  5484. RegistryPath->Length +
  5485. deviceSubpathUnicodeString.Length;
  5486. driverKeySize =
  5487. DoSpecificExtension->DriverOldRegistryPathLength +
  5488. 2 * sizeof(UNICODE_NULL);
  5489. if ( (driverKeyName = (PWSTR) ExAllocatePoolWithTag(PagedPool,
  5490. driverKeySize,
  5491. VP_TAG) ) == NULL)
  5492. {
  5493. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Fail to allocate driverKeyName\n"));
  5494. IoDeleteDevice(DeviceObject);
  5495. return STATUS_INSUFFICIENT_RESOURCES;
  5496. }
  5497. RtlMoveMemory(driverKeyName,
  5498. RegistryPath->Buffer,
  5499. RegistryPath->Length);
  5500. RtlMoveMemory((PWSTR)((ULONG_PTR)driverKeyName +
  5501. RegistryPath->Length),
  5502. deviceSubpathBuffer,
  5503. deviceSubpathUnicodeString.Length);
  5504. //
  5505. // Put two NULLs at the end so we can play around with the string later.
  5506. //
  5507. *((PWSTR) ((ULONG_PTR)driverKeyName +
  5508. DoSpecificExtension->DriverOldRegistryPathLength))
  5509. = UNICODE_NULL;
  5510. *((PWSTR) ((ULONG_PTR)driverKeyName +
  5511. (DoSpecificExtension->DriverOldRegistryPathLength
  5512. + sizeof(UNICODE_NULL)))) = UNICODE_NULL;
  5513. //
  5514. // There is a bug in Lotus Screen Cam where it will only work if our
  5515. // reg path is \REGISTRY\Machine\System not \REGISTRY\MACHINE\SYSTEM.
  5516. // so replace the appropriate strings.
  5517. //
  5518. if (wcsstr(driverKeyName, L"MACHINE")) {
  5519. wcsncpy(wcsstr(driverKeyName, L"MACHINE"), L"Machine", sizeof("Machine")-1);
  5520. }
  5521. if (wcsstr(driverKeyName, L"SYSTEM")) {
  5522. wcsncpy(wcsstr(driverKeyName, L"SYSTEM"), L"System", sizeof("System")-1);
  5523. }
  5524. //
  5525. // Store the old key
  5526. //
  5527. DoSpecificExtension->DriverOldRegistryPath = driverKeyName;
  5528. //
  5529. // Store the new key
  5530. // If this is not a Whistler driver, then use the old key.
  5531. //
  5532. if (EnableNewRegistryKey) {
  5533. #if _X86_
  5534. if (DriverObjectExtension->HwInitData.HwInitDataSize > SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA)
  5535. #endif // _X86_
  5536. VpEnableNewRegistryKey(FdoExtension,
  5537. DoSpecificExtension,
  5538. RegistryPath,
  5539. FdoExtension->RegistryIndex + 1);
  5540. }
  5541. //
  5542. // Store the path name of the location of the driver in the registry.
  5543. //
  5544. if (DoSpecificExtension->DriverNewRegistryPath != NULL) {
  5545. DoSpecificExtension->DriverRegistryPath =
  5546. DoSpecificExtension->DriverNewRegistryPath;
  5547. DoSpecificExtension->DriverRegistryPathLength =
  5548. DoSpecificExtension->DriverNewRegistryPathLength;
  5549. } else {
  5550. DoSpecificExtension->DriverRegistryPath =
  5551. DoSpecificExtension->DriverOldRegistryPath;
  5552. DoSpecificExtension->DriverRegistryPathLength =
  5553. DoSpecificExtension->DriverOldRegistryPathLength;
  5554. }
  5555. //
  5556. // NOTE:
  5557. //
  5558. // We only want to reinitialize the device once the Boot sequence has
  5559. // been completed and the HAL does not need to access the device again.
  5560. // So the initialization entry point will be called when the device is
  5561. // opened.
  5562. //
  5563. if (!NT_SUCCESS(pVideoPortCreateDeviceName(L"\\DosDevices\\DISPLAY",
  5564. DoSpecificExtension->DeviceNumber + 1,
  5565. &deviceLinkUnicodeString,
  5566. deviceLinkBuffer)))
  5567. {
  5568. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not create device subpath number\n"));
  5569. ExFreePool(driverKeyName);
  5570. IoDeleteDevice(DeviceObject);
  5571. return STATUS_INSUFFICIENT_RESOURCES;
  5572. }
  5573. ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
  5574. &deviceName->Name);
  5575. if (!NT_SUCCESS(ntStatus)) {
  5576. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: SymbolicLink Creation failed\n"));
  5577. ExFreePool(driverKeyName);
  5578. IoDeleteDevice(DeviceObject);
  5579. return STATUS_INSUFFICIENT_RESOURCES;
  5580. }
  5581. //
  5582. // Once initialization is finished, load the required information in the
  5583. // registry so that the appropriate display drivers can be loaded.
  5584. //
  5585. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  5586. VideoClassString,
  5587. deviceName->Name.Buffer,
  5588. REG_SZ,
  5589. DoSpecificExtension->DriverRegistryPath,
  5590. DoSpecificExtension->DriverRegistryPathLength +
  5591. sizeof(UNICODE_NULL));
  5592. if (!NT_SUCCESS(ntStatus)) {
  5593. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not store name in DeviceMap\n"));
  5594. }
  5595. //
  5596. // Tell win32k how many objects to try to open
  5597. //
  5598. MaxObjectNumber = VideoDeviceNumber - 1;
  5599. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  5600. VideoClassString,
  5601. L"MaxObjectNumber",
  5602. REG_DWORD,
  5603. &MaxObjectNumber,
  5604. sizeof(ULONG));
  5605. if (!NT_SUCCESS(ntStatus)) {
  5606. pVideoDebugPrint((Error, "VIDEOPRT: VideoPortCreateSecondaryDisplay: Could not store name in DeviceMap\n"));
  5607. }
  5608. //
  5609. // Register and enable the interface
  5610. //
  5611. VpEnableAdapterInterface(DoSpecificExtension);
  5612. //
  5613. // Finally, tell the system we are done with Device Initialization
  5614. //
  5615. DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  5616. DeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING | DO_POWER_INRUSH);
  5617. VideoDeviceNumber++;
  5618. FdoExtension->RegistryIndex++;
  5619. }
  5620. }
  5621. if (NT_SUCCESS(ntStatus)) {
  5622. *SecondaryDeviceExtension = (PVOID)(DoSpecificExtension + 1);
  5623. DriverObjectExtension->HwInitData.StartingDeviceNumber++;
  5624. //
  5625. // Mark the primary view
  5626. //
  5627. ((PDEVICE_SPECIFIC_EXTENSION)(FdoExtension + 1))->DualviewFlags = VIDEO_DUALVIEW_PRIMARY;
  5628. }
  5629. return ntStatus;
  5630. }
  5631. #if DBG
  5632. PIO_RESOURCE_REQUIREMENTS_LIST
  5633. BuildRequirements(
  5634. PCM_RESOURCE_LIST pcmResourceList
  5635. )
  5636. {
  5637. ULONG i;
  5638. PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
  5639. PIO_RESOURCE_REQUIREMENTS_LIST Requirements;
  5640. PIO_RESOURCE_DESCRIPTOR pioDescript;
  5641. ULONG RequirementsListSize;
  5642. ULONG RequirementCount;
  5643. pVideoDebugPrint((Trace, "VIDEOPRT: BuildRequirements()\n"));
  5644. RequirementCount = pcmResourceList->List[0].PartialResourceList.Count;
  5645. RequirementsListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  5646. ((RequirementCount - 1) *
  5647. sizeof(IO_RESOURCE_DESCRIPTOR));
  5648. Requirements = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(
  5649. PagedPool,
  5650. RequirementsListSize);
  5651. Requirements->ListSize = RequirementsListSize;
  5652. Requirements->InterfaceType = pcmResourceList->List[0].InterfaceType;
  5653. Requirements->BusNumber = pcmResourceList->List[0].BusNumber;
  5654. Requirements->SlotNumber = -1; // ???
  5655. Requirements->AlternativeLists = 0; // ???
  5656. Requirements->List[0].Version = pcmResourceList->List[0].PartialResourceList.Version;
  5657. Requirements->List[0].Revision = pcmResourceList->List[0].PartialResourceList.Revision;
  5658. Requirements->List[0].Count = RequirementCount;
  5659. pcmDescript = &(pcmResourceList->List[0].PartialResourceList.PartialDescriptors[0]);
  5660. pioDescript = &(Requirements->List[0].Descriptors[0]);
  5661. for (i=0; i<RequirementCount; i++) {
  5662. pioDescript->Option = IO_RESOURCE_PREFERRED;
  5663. pioDescript->Type = pcmDescript->Type;
  5664. pioDescript->ShareDisposition = pcmDescript->ShareDisposition;
  5665. pioDescript->Flags = pcmDescript->Flags;
  5666. switch (pcmDescript->Type) {
  5667. case CmResourceTypePort:
  5668. pioDescript->u.Port.Length = pcmDescript->u.Port.Length;
  5669. pioDescript->u.Port.Alignment = 1;
  5670. pioDescript->u.Port.MinimumAddress =
  5671. pioDescript->u.Port.MaximumAddress = pcmDescript->u.Port.Start;
  5672. break;
  5673. case CmResourceTypeMemory:
  5674. pioDescript->u.Memory.Length = pcmDescript->u.Memory.Length;
  5675. pioDescript->u.Memory.Alignment = 1;
  5676. pioDescript->u.Memory.MinimumAddress =
  5677. pioDescript->u.Memory.MaximumAddress = pcmDescript->u.Memory.Start;
  5678. break;
  5679. default:
  5680. //
  5681. // We don't have to handle the other stuff, because we only
  5682. // want to report Ports and Memory to the system.
  5683. //
  5684. break;
  5685. }
  5686. pioDescript++;
  5687. pcmDescript++;
  5688. }
  5689. return Requirements;
  5690. }
  5691. VOID
  5692. DumpRequirements(
  5693. PIO_RESOURCE_REQUIREMENTS_LIST Requirements
  5694. )
  5695. {
  5696. ULONG i;
  5697. PIO_RESOURCE_DESCRIPTOR pioDescript;
  5698. ULONG RequirementsListSize;
  5699. ULONG RequirementCount = Requirements->List[0].Count;
  5700. char *Table[] = { "Internal",
  5701. "Isa",
  5702. "Eisa",
  5703. "MicroChannel",
  5704. "TurboChannel",
  5705. "PCIBus",
  5706. "VMEBus",
  5707. "NuBus",
  5708. "PCMCIABus",
  5709. "CBus",
  5710. "MPIBus",
  5711. "MPSABus",
  5712. "ProcessorInternal",
  5713. "InternalPowerBus",
  5714. "PNPISABus",
  5715. "MaximumInterfaceType"
  5716. };
  5717. pVideoDebugPrint((Info, "VIDEOPRT: Beginning dump of requirements list:\n"));
  5718. pVideoDebugPrint((Info, "ListSize: 0x%x\n"
  5719. "InterfaceType: %s\n"
  5720. "BusNumber: 0x%x\n"
  5721. "SlotNumber: 0x%x\n"
  5722. "AlternativeLists: 0x%x\n",
  5723. Requirements->ListSize,
  5724. Table[Requirements->InterfaceType],
  5725. Requirements->BusNumber,
  5726. Requirements->SlotNumber,
  5727. Requirements->AlternativeLists));
  5728. pVideoDebugPrint((Info, "List[0].Version: 0x%x\n"
  5729. "List[0].Revision: 0x%x\n"
  5730. "List[0].Count: 0x%x\n",
  5731. Requirements->List[0].Version,
  5732. Requirements->List[0].Revision,
  5733. Requirements->List[0].Count));
  5734. pioDescript = &(Requirements->List[0].Descriptors[0]);
  5735. for (i=0; i<RequirementCount; i++) {
  5736. pVideoDebugPrint((Info, "\n"
  5737. "Option: 0x%x\n"
  5738. "Type: 0x%x\n"
  5739. "ShareDisposition: 0x%x\n"
  5740. "Flags: 0x%x\n",
  5741. pioDescript->Option,
  5742. pioDescript->Type,
  5743. pioDescript->ShareDisposition,
  5744. pioDescript->Flags));
  5745. switch (pioDescript->Type) {
  5746. case CmResourceTypePort:
  5747. pVideoDebugPrint((Info, "\nPort...\n"
  5748. "\tLength: 0x%x\n"
  5749. "\tAlignment: 0x%x\n"
  5750. "\tMinimumAddress: 0x%x\n"
  5751. "\tMaximumAddress: 0x%x\n",
  5752. pioDescript->u.Port.Length,
  5753. pioDescript->u.Port.Alignment,
  5754. pioDescript->u.Port.MinimumAddress,
  5755. pioDescript->u.Port.MaximumAddress));
  5756. break;
  5757. case CmResourceTypeMemory:
  5758. pVideoDebugPrint((Info, "\nMemory...\n"
  5759. "\tLength: 0x%x\n"
  5760. "\tAlignment: 0x%x\n"
  5761. "\tMinimumAddress: 0x%x\n"
  5762. "\tMaximumAddress: 0x%x\n",
  5763. pioDescript->u.Memory.Length,
  5764. pioDescript->u.Memory.Alignment,
  5765. pioDescript->u.Memory.MinimumAddress,
  5766. pioDescript->u.Memory.MaximumAddress));
  5767. break;
  5768. case CmResourceTypeInterrupt:
  5769. pVideoDebugPrint((Info, "\nInterrupt...\n"
  5770. "\tMinimum Vector: 0x%x\n"
  5771. "\tMaximum Vector: 0x%x\n",
  5772. pioDescript->u.Interrupt.MinimumVector,
  5773. pioDescript->u.Interrupt.MaximumVector));
  5774. break;
  5775. default:
  5776. //
  5777. // We don't have to handle the other stuff, because we only
  5778. // want to report Ports and Memory to the system.
  5779. //
  5780. break;
  5781. }
  5782. pioDescript++;
  5783. }
  5784. return;
  5785. }
  5786. VOID
  5787. DumpResourceList(
  5788. PCM_RESOURCE_LIST pcmResourceList)
  5789. {
  5790. ULONG i, j;
  5791. PCM_FULL_RESOURCE_DESCRIPTOR pcmFull;
  5792. PCM_PARTIAL_RESOURCE_LIST pcmPartial;
  5793. PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
  5794. pVideoDebugPrint((Trace, "VIDEOPRT: Beginning dump of resource list:\n"));
  5795. pcmFull = &(pcmResourceList->List[0]);
  5796. for (i=0; i<pcmResourceList->Count; i++) {
  5797. pVideoDebugPrint((Info, "List[%d]\n", i));
  5798. pVideoDebugPrint((Info, "InterfaceType = 0x%x\n", pcmFull->InterfaceType));
  5799. pVideoDebugPrint((Info, "BusNumber = 0x%x\n", pcmFull->BusNumber));
  5800. pcmPartial = &(pcmFull->PartialResourceList);
  5801. pVideoDebugPrint((Info, "Version = 0x%x\n", pcmPartial->Version));
  5802. pVideoDebugPrint((Info, "Revision = 0x%x\n", pcmPartial->Revision));
  5803. pcmDescript = &(pcmPartial->PartialDescriptors[0]);
  5804. for (j=0; j<pcmPartial->Count; j++) {
  5805. switch (pcmDescript->Type) {
  5806. case CmResourceTypePort:
  5807. pVideoDebugPrint((Info, "Port: 0x%x Length: 0x%x\n",
  5808. pcmDescript->u.Port.Start.LowPart,
  5809. pcmDescript->u.Port.Length));
  5810. break;
  5811. case CmResourceTypeInterrupt:
  5812. pVideoDebugPrint((Info, "Interrupt: 0x%x Level: 0x%x\n",
  5813. pcmDescript->u.Interrupt.Vector,
  5814. pcmDescript->u.Interrupt.Level));
  5815. break;
  5816. case CmResourceTypeMemory:
  5817. pVideoDebugPrint((Info, "Start: 0x%x Length: 0x%x\n",
  5818. pcmDescript->u.Memory.Start.LowPart,
  5819. pcmDescript->u.Memory.Length));
  5820. break;
  5821. case CmResourceTypeDma:
  5822. pVideoDebugPrint((Info, "Dma Channel: 0x%x Port: 0x%x\n",
  5823. pcmDescript->u.Dma.Channel,
  5824. pcmDescript->u.Dma.Port));
  5825. break;
  5826. }
  5827. pcmDescript++;
  5828. }
  5829. pcmFull = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescript;
  5830. }
  5831. pVideoDebugPrint((Info, "VIDEOPRT: EndResourceList\n"));
  5832. }
  5833. VOID
  5834. DumpUnicodeString(
  5835. IN PUNICODE_STRING p
  5836. )
  5837. {
  5838. PUSHORT pus = p->Buffer;
  5839. UCHAR buffer[256]; // the string better not be longer than 255 chars!
  5840. PUCHAR puc = buffer;
  5841. ULONG i;
  5842. for (i = 0; i < p->Length; i++) {
  5843. *puc++ = (UCHAR) *pus++;
  5844. }
  5845. *puc = 0; // null terminate the string
  5846. pVideoDebugPrint((Info, "VIDEOPRT: UNICODE STRING: %s\n", buffer));
  5847. }
  5848. #endif
  5849. VP_STATUS
  5850. VideoPortEnumerateChildren(
  5851. IN PVOID HwDeviceExtension,
  5852. IN PVOID Reserved
  5853. )
  5854. /*++
  5855. Routine Description:
  5856. Allows a miniport to force a re-enumeration of it's children.
  5857. Arguments:
  5858. HwDeviceExtension - The miniports device extension
  5859. Reserved - Not currently used, should be NULL.
  5860. Returns:
  5861. Status
  5862. --*/
  5863. {
  5864. PFDO_EXTENSION fdoExtension = GET_FDO_EXT (HwDeviceExtension);
  5865. PDEVICE_OBJECT pFDO = fdoExtension->FunctionalDeviceObject;
  5866. PDEVICE_OBJECT pPDO = fdoExtension->PhysicalDeviceObject;
  5867. ASSERT(Reserved == NULL);
  5868. IoInvalidateDeviceRelations(pPDO, BusRelations);
  5869. return NO_ERROR;
  5870. }
  5871. VIDEOPORT_API
  5872. VP_STATUS
  5873. VideoPortQueryServices(
  5874. IN PVOID pHwDeviceExtension,
  5875. IN VIDEO_PORT_SERVICES servicesType,
  5876. IN OUT PINTERFACE pInterface
  5877. )
  5878. /*++
  5879. Routine Description:
  5880. This routine exposes interfaces to services supported by the videoprt.
  5881. Arguments:
  5882. pHwDeviceExtension - Points to per-adapter device extension.
  5883. servicesType - Requested services type.
  5884. pInterface - Points to services interface structure.
  5885. Returns:
  5886. NO_ERROR - Valid interface in the pInterface.
  5887. Error code - Unsupported / unavailable services.
  5888. --*/
  5889. {
  5890. VP_STATUS vpStatus;
  5891. PAGED_CODE();
  5892. ASSERT(NULL != pHwDeviceExtension);
  5893. ASSERT(NULL != pInterface);
  5894. ASSERT(IS_HW_DEVICE_EXTENSION(pHwDeviceExtension) == TRUE);
  5895. if (VideoPortServicesAGP == servicesType)
  5896. {
  5897. if ((pInterface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_2) &&
  5898. (pInterface->Size == sizeof (VIDEO_PORT_AGP_INTERFACE_2)))
  5899. {
  5900. PVIDEO_PORT_AGP_INTERFACE_2 pAgpInterface = (PVIDEO_PORT_AGP_INTERFACE_2)pInterface;
  5901. vpStatus = VpGetAgpServices2(pHwDeviceExtension, pAgpInterface);
  5902. }
  5903. else if ((pInterface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1) &&
  5904. (pInterface->Size == sizeof (VIDEO_PORT_AGP_INTERFACE)))
  5905. {
  5906. PVIDEO_PORT_AGP_INTERFACE pAgpInterface = (PVIDEO_PORT_AGP_INTERFACE)pInterface;
  5907. pAgpInterface->Context = pHwDeviceExtension;
  5908. pAgpInterface->InterfaceReference = VpInterfaceDefaultReference;
  5909. pAgpInterface->InterfaceDereference = VpInterfaceDefaultDereference;
  5910. if (VideoPortGetAgpServices(pHwDeviceExtension,
  5911. (PVIDEO_PORT_AGP_SERVICES)&(pAgpInterface->AgpReservePhysical)) == TRUE)
  5912. {
  5913. //
  5914. // Reference the interface before handing it out.
  5915. //
  5916. pAgpInterface->InterfaceReference(pAgpInterface->Context);
  5917. vpStatus = NO_ERROR;
  5918. }
  5919. else
  5920. {
  5921. vpStatus = ERROR_DEV_NOT_EXIST;
  5922. }
  5923. }
  5924. else
  5925. {
  5926. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
  5927. vpStatus = ERROR_INVALID_PARAMETER;
  5928. }
  5929. }
  5930. else if (VideoPortServicesI2C == servicesType)
  5931. {
  5932. if ((pInterface->Version == VIDEO_PORT_I2C_INTERFACE_VERSION_2) &&
  5933. (pInterface->Size == sizeof (VIDEO_PORT_I2C_INTERFACE_2)))
  5934. {
  5935. PVIDEO_PORT_I2C_INTERFACE_2 pI2CInterface = (PVIDEO_PORT_I2C_INTERFACE_2)pInterface;
  5936. pI2CInterface->Context = pHwDeviceExtension;
  5937. pI2CInterface->InterfaceReference = VpInterfaceDefaultReference;
  5938. pI2CInterface->InterfaceDereference = VpInterfaceDefaultDereference;
  5939. pI2CInterface->I2CStart = I2CStart2;
  5940. pI2CInterface->I2CStop = I2CStop2;
  5941. pI2CInterface->I2CWrite = I2CWrite2;
  5942. pI2CInterface->I2CRead = I2CRead2;
  5943. //
  5944. // Reference the interface before handing it out.
  5945. //
  5946. pI2CInterface->InterfaceReference(pI2CInterface->Context);
  5947. vpStatus = NO_ERROR;
  5948. }
  5949. else if ((pInterface->Version == VIDEO_PORT_I2C_INTERFACE_VERSION_1) &&
  5950. (pInterface->Size == sizeof (VIDEO_PORT_I2C_INTERFACE)))
  5951. {
  5952. PVIDEO_PORT_I2C_INTERFACE pI2CInterface = (PVIDEO_PORT_I2C_INTERFACE)pInterface;
  5953. pI2CInterface->Context = pHwDeviceExtension;
  5954. pI2CInterface->InterfaceReference = VpInterfaceDefaultReference;
  5955. pI2CInterface->InterfaceDereference = VpInterfaceDefaultDereference;
  5956. pI2CInterface->I2CStart = I2CStart;
  5957. pI2CInterface->I2CStop = I2CStop;
  5958. pI2CInterface->I2CWrite = I2CWrite;
  5959. pI2CInterface->I2CRead = I2CRead;
  5960. //
  5961. // Reference the interface before handing it out.
  5962. //
  5963. pI2CInterface->InterfaceReference(pI2CInterface->Context);
  5964. vpStatus = NO_ERROR;
  5965. }
  5966. else
  5967. {
  5968. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
  5969. vpStatus = ERROR_INVALID_PARAMETER;
  5970. }
  5971. }
  5972. else if (VideoPortServicesInt10 == servicesType)
  5973. {
  5974. if ((pInterface->Version == VIDEO_PORT_INT10_INTERFACE_VERSION_1) &&
  5975. (pInterface->Size == sizeof(VIDEO_PORT_INT10_INTERFACE)))
  5976. {
  5977. PVIDEO_PORT_INT10_INTERFACE pInt10 = (PVIDEO_PORT_INT10_INTERFACE)pInterface;
  5978. pInt10->Context = pHwDeviceExtension;
  5979. pInt10->InterfaceReference = VpInterfaceDefaultReference;
  5980. pInt10->InterfaceDereference = VpInterfaceDefaultDereference;
  5981. pInt10->Int10AllocateBuffer = VpInt10AllocateBuffer;
  5982. pInt10->Int10FreeBuffer = VpInt10FreeBuffer;
  5983. pInt10->Int10ReadMemory = VpInt10ReadMemory;
  5984. pInt10->Int10WriteMemory = VpInt10WriteMemory;
  5985. pInt10->Int10CallBios = VpInt10CallBios;
  5986. //
  5987. // Reference the interface before handing it out.
  5988. //
  5989. pInt10->InterfaceReference(pInt10->Context);
  5990. vpStatus = NO_ERROR;
  5991. }
  5992. else
  5993. {
  5994. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported interface version\n"));
  5995. vpStatus = ERROR_INVALID_PARAMETER;
  5996. }
  5997. }
  5998. else
  5999. {
  6000. pVideoDebugPrint((Warn, "VIDEOPRT: VideoPortQueryServices: Unsupported service type\n"));
  6001. vpStatus = ERROR_INVALID_PARAMETER;
  6002. }
  6003. return vpStatus;
  6004. } // VideoPortQueryServices()
  6005. VIDEOPORT_API
  6006. LONGLONG
  6007. VideoPortQueryPerformanceCounter(
  6008. IN PVOID pHwDeviceExtension,
  6009. OUT PLONGLONG pllPerformanceFrequency OPTIONAL
  6010. )
  6011. /*++
  6012. Routine Description:
  6013. This routine provides the finest grained running count available in the system.
  6014. Use this routine as infrequently as possible. Depending on the platform,
  6015. VideoPortQueryPerformanceCounter can disable system-wide interrupts for a minimal interval.
  6016. Consequently, calling this routine frequently or repeatedly, as in an iteration, defeats its
  6017. purpose of returning very fine-grained, running time-stamp information. Calling this routine
  6018. too frequently can degrade I/O performance for the calling driver and for the system as a whole.
  6019. Arguments:
  6020. pHwDeviceExtension - Points to per-adapter device extension.
  6021. pllPerformanceFrequency - Specifies an optional pointer to a variable that is to receive the
  6022. performance counter frequency.
  6023. Returns:
  6024. The performance counter value in units of ticks.
  6025. --*/
  6026. {
  6027. LARGE_INTEGER li;
  6028. //
  6029. // No ASSERT() allowed - nonpagable code.
  6030. //
  6031. li = KeQueryPerformanceCounter((PLARGE_INTEGER)pllPerformanceFrequency);
  6032. return *((PLONGLONG) &li);
  6033. } // VideoPortQueryPerformanceCounter()
  6034. VOID
  6035. VpInterfaceDefaultReference(
  6036. IN PVOID pContext
  6037. )
  6038. /*++
  6039. Routine Description:
  6040. This routine is default callback for interfaces exposed from the videoprt.
  6041. Should be called by the client before it starts using an interface.
  6042. Arguments:
  6043. pContext - Context returned by the VideoPortQueryServices() in the
  6044. pInterface->Context field.
  6045. --*/
  6046. {
  6047. UNREFERENCED_PARAMETER(pContext);
  6048. PAGED_CODE();
  6049. } // VpInterfaceDefaultReference()
  6050. VOID
  6051. VpInterfaceDefaultDereference(
  6052. IN PVOID pContext
  6053. )
  6054. /*++
  6055. Routine Description:
  6056. This routine is default callback for interfaces exposed from the videoprt.
  6057. Should be called by the client when it stops using an interface.
  6058. Arguments:
  6059. pContext - Context returned by the VideoPortQueryServices() in the
  6060. pInterface->Context field.
  6061. --*/
  6062. {
  6063. UNREFERENCED_PARAMETER(pContext);
  6064. PAGED_CODE();
  6065. } // VpInterfaceDefaultDereference()
  6066. BOOLEAN
  6067. VpEnableAdapterInterface(
  6068. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension
  6069. )
  6070. /*++
  6071. Routine Description:
  6072. This routine registers and enables a display adapter interface.
  6073. It also writes the interface name to the registry.
  6074. Arguments:
  6075. DoSpecificExtension - Pointer to the functional device object
  6076. specific extension.
  6077. --*/
  6078. {
  6079. PFDO_EXTENSION fdoExtension = NULL;
  6080. UNICODE_STRING SymbolicLinkName;
  6081. BOOLEAN Success = FALSE;
  6082. UNICODE_STRING VolatileSettingsString;
  6083. OBJECT_ATTRIBUTES VolatileSettingsAttributes;
  6084. HANDLE VolatileSettingsKey;
  6085. PAGED_CODE();
  6086. ASSERT ((DoSpecificExtension != NULL) &&
  6087. (DoSpecificExtension->ExtensionType == TypeDeviceSpecificExtension));
  6088. VolatileSettingsString.Buffer = NULL;
  6089. fdoExtension = DoSpecificExtension->pFdoExtension;
  6090. ASSERT (IS_FDO(fdoExtension));
  6091. if (fdoExtension->PhysicalDeviceObject == NULL) {
  6092. //
  6093. // This fdo doesn't have a physical device object (e.g. vga).
  6094. // In this case, we can't create an interface.
  6095. //
  6096. goto Fallout;
  6097. }
  6098. //
  6099. // Register the interface
  6100. //
  6101. if (IoRegisterDeviceInterface(fdoExtension->PhysicalDeviceObject,
  6102. &GUID_DISPLAY_ADAPTER_INTERFACE,
  6103. NULL,
  6104. &SymbolicLinkName) != STATUS_SUCCESS) {
  6105. goto Fallout;
  6106. }
  6107. //
  6108. // Enable the interface
  6109. //
  6110. if (IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE) != STATUS_SUCCESS) {
  6111. goto Cleanup;
  6112. }
  6113. //
  6114. // Write the interface name to registry
  6115. //
  6116. ASSERT (DoSpecificExtension->DriverRegistryPath != NULL);
  6117. VolatileSettingsString.Length = 0;
  6118. VolatileSettingsString.MaximumLength =
  6119. (USHORT)DoSpecificExtension->DriverRegistryPathLength + 40;
  6120. VolatileSettingsString.Buffer = ExAllocatePoolWithTag(
  6121. PagedPool | POOL_COLD_ALLOCATION,
  6122. VolatileSettingsString.MaximumLength,
  6123. VP_TAG);
  6124. if (VolatileSettingsString.Buffer == NULL) {
  6125. goto Cleanup;
  6126. }
  6127. if (RtlAppendUnicodeToString(&VolatileSettingsString,
  6128. DoSpecificExtension->DriverRegistryPath) != STATUS_SUCCESS) {
  6129. goto Cleanup;
  6130. }
  6131. if (RtlAppendUnicodeToString(&VolatileSettingsString,
  6132. L"\\VolatileSettings") != STATUS_SUCCESS) {
  6133. goto Cleanup;
  6134. }
  6135. InitializeObjectAttributes(&VolatileSettingsAttributes,
  6136. &VolatileSettingsString,
  6137. OBJ_CASE_INSENSITIVE,
  6138. NULL,
  6139. NULL);
  6140. if (ZwCreateKey(&VolatileSettingsKey,
  6141. GENERIC_READ | GENERIC_WRITE,
  6142. &VolatileSettingsAttributes,
  6143. 0L,
  6144. NULL,
  6145. REG_OPTION_VOLATILE,
  6146. NULL) != STATUS_SUCCESS) {
  6147. goto Cleanup;
  6148. }
  6149. if (RtlWriteRegistryValue(
  6150. RTL_REGISTRY_ABSOLUTE,
  6151. VolatileSettingsString.Buffer,
  6152. L"{5b45201d-f2f2-4f3b-85bb-30ff1f953599}",
  6153. REG_BINARY,
  6154. (PVOID)SymbolicLinkName.Buffer,
  6155. SymbolicLinkName.Length) == STATUS_SUCCESS) {
  6156. Success = TRUE;
  6157. }
  6158. Cleanup:
  6159. if (VolatileSettingsString.Buffer != NULL) {
  6160. ExFreePool(VolatileSettingsString.Buffer);
  6161. }
  6162. RtlFreeUnicodeString(&SymbolicLinkName);
  6163. Fallout:
  6164. if (Success) {
  6165. pVideoDebugPrint((Trace, "VideoPort - Device interface ok.\n"));
  6166. } else {
  6167. pVideoDebugPrint((Warn,
  6168. "VideoPort - Couldn't register, enable or save the device interface.\n"));
  6169. }
  6170. return Success;
  6171. } // VpEnableAdapterInterface
  6172. VOID
  6173. VpDisableAdapterInterface(
  6174. PFDO_EXTENSION fdoExtension
  6175. )
  6176. /*++
  6177. Routine Description:
  6178. This routine disables the display adapter interface.
  6179. Arguments:
  6180. fdoExtension - Pointer to the functional device object extension.
  6181. --*/
  6182. {
  6183. PWSTR SymbolicLinkList = NULL;
  6184. UNICODE_STRING SymbolicLinkName;
  6185. PAGED_CODE();
  6186. ASSERT ((fdoExtension != NULL) && IS_FDO(fdoExtension));
  6187. if (fdoExtension->PhysicalDeviceObject == NULL) {
  6188. //
  6189. // This fdo doesn't have a physical device object (e.g. vga ...).
  6190. // In this case, we didn't create any interface so there is
  6191. // nothing to disable.
  6192. //
  6193. return;
  6194. }
  6195. //
  6196. // There is no need to remove the InterfaceName from the registry
  6197. // as the parent key is volatile.
  6198. //
  6199. //
  6200. // Disable the interface
  6201. //
  6202. if (IoGetDeviceInterfaces(&GUID_DISPLAY_ADAPTER_INTERFACE,
  6203. fdoExtension->PhysicalDeviceObject,
  6204. 0,
  6205. &SymbolicLinkList) != STATUS_SUCCESS) {
  6206. pVideoDebugPrint((Warn,
  6207. "VideoPort - Could not find any enabled device interfaces.\n"));
  6208. return;
  6209. }
  6210. RtlInitUnicodeString(&SymbolicLinkName, SymbolicLinkList);
  6211. if (SymbolicLinkName.Length > 0) {
  6212. if (IoSetDeviceInterfaceState(&SymbolicLinkName,
  6213. FALSE) != STATUS_SUCCESS) {
  6214. pVideoDebugPrint((Warn,
  6215. "VideoPort - Could not disable the device interface.\n"));
  6216. }
  6217. }
  6218. ExFreePool((PVOID)SymbolicLinkList);
  6219. } // VpDisableAdapterInterface
  6220. VOID
  6221. VpEnableNewRegistryKey(
  6222. PFDO_EXTENSION FdoExtension,
  6223. PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension,
  6224. PUNICODE_STRING RegistryPath,
  6225. ULONG RegistryIndex
  6226. )
  6227. {
  6228. PKEY_VALUE_PARTIAL_INFORMATION GUIDBuffer = NULL;
  6229. ULONG GUIDLength = 0;
  6230. LPWSTR Buffer = NULL;
  6231. HANDLE GuidKey = NULL;
  6232. HANDLE NewDeviceKey = NULL;
  6233. HANDLE ServiceSubKey = NULL;
  6234. UNICODE_STRING UnicodeString, newGuidStr;
  6235. OBJECT_ATTRIBUTES ObjectAttributes;
  6236. ULONG Len;
  6237. GUID newGuid;
  6238. BOOLEAN IsLegacy = FALSE;
  6239. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  6240. BOOLEAN IsNewKey = FALSE;
  6241. PWSTR pService = NULL;
  6242. ULONG ServiceLen = 0;
  6243. ASSERT((DoSpecificExtension->DriverNewRegistryPath == NULL) &&
  6244. (DoSpecificExtension->DriverNewRegistryPathLength == 0));
  6245. ASSERT(DoSpecificExtension->DriverOldRegistryPath != NULL);
  6246. ASSERT(EnableNewRegistryKey);
  6247. newGuidStr.Buffer = NULL;
  6248. //
  6249. // Get the service name
  6250. //
  6251. pService = RegistryPath->Buffer +
  6252. (RegistryPath->Length / sizeof(WCHAR)) - 1;
  6253. while ((pService > RegistryPath->Buffer) &&
  6254. (*pService != L'\\')) {
  6255. pService--;
  6256. ServiceLen++;
  6257. }
  6258. ASSERT (*pService == L'\\');
  6259. pService++;
  6260. Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  6261. (ServiceLen + 1) * sizeof(WCHAR),
  6262. VP_TAG);
  6263. if (Buffer == NULL) {
  6264. pVideoDebugPrint((Error,
  6265. "VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
  6266. goto Fallout;
  6267. }
  6268. RtlZeroMemory(Buffer, (ServiceLen + 1) * sizeof(WCHAR));
  6269. wcsncpy(Buffer, pService, ServiceLen);
  6270. pService = Buffer;
  6271. Buffer = NULL;
  6272. //
  6273. // Try to open the PnP device key
  6274. //
  6275. if ((FdoExtension->PhysicalDeviceObject == NULL) ||
  6276. (IoOpenDeviceRegistryKey(FdoExtension->PhysicalDeviceObject,
  6277. PLUGPLAY_REGKEY_DEVICE,
  6278. KEY_READ | KEY_WRITE,
  6279. &GuidKey) != STATUS_SUCCESS)) {
  6280. //
  6281. // We failed to open the PnP device key.
  6282. // Try to open the service subkey instead.
  6283. //
  6284. if (!VpGetServiceSubkey(RegistryPath,
  6285. &GuidKey)) {
  6286. GuidKey = NULL;
  6287. goto Fallout;
  6288. }
  6289. IsLegacy = TRUE;
  6290. }
  6291. //
  6292. // Is the GUID there?
  6293. //
  6294. RtlInitUnicodeString(&UnicodeString, SZ_GUID);
  6295. ntStatus = ZwQueryValueKey(GuidKey,
  6296. &UnicodeString,
  6297. KeyValuePartialInformation,
  6298. (PVOID)NULL,
  6299. 0,
  6300. &GUIDLength);
  6301. if ((ntStatus == STATUS_BUFFER_OVERFLOW) ||
  6302. (ntStatus == STATUS_BUFFER_TOO_SMALL)) {
  6303. //
  6304. // The GUID is there.
  6305. // Allocate a buffer large enough to contain the entire key data value.
  6306. //
  6307. GUIDBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  6308. GUIDLength,
  6309. VP_TAG);
  6310. if (GUIDBuffer == NULL) {
  6311. pVideoDebugPrint((Error,
  6312. "VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
  6313. goto Fallout;
  6314. }
  6315. //
  6316. // Get the GUID from the registry
  6317. //
  6318. ntStatus = ZwQueryValueKey(GuidKey,
  6319. &UnicodeString,
  6320. KeyValuePartialInformation,
  6321. GUIDBuffer,
  6322. GUIDLength,
  6323. &GUIDLength);
  6324. if (!NT_SUCCESS(ntStatus)) {
  6325. pVideoDebugPrint((Error,
  6326. "VIDEOPRT: VpEnableNewRegistryKey: failed to get the GUID from the registry.\n"));
  6327. goto Fallout;
  6328. }
  6329. //
  6330. // Build the new registry path
  6331. //
  6332. Len = (wcslen(SZ_VIDEO_DEVICES) + 8) * sizeof(WCHAR) + GUIDBuffer->DataLength;
  6333. Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  6334. Len,
  6335. VP_TAG);
  6336. if (Buffer == NULL) {
  6337. pVideoDebugPrint((Error,
  6338. "VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
  6339. goto Fallout;
  6340. }
  6341. RtlZeroMemory(Buffer, Len);
  6342. wcscpy(Buffer, SZ_VIDEO_DEVICES);
  6343. wcscat(Buffer, L"\\");
  6344. wcsncpy(Buffer + wcslen(Buffer),
  6345. (LPWSTR)GUIDBuffer->Data,
  6346. GUIDBuffer->DataLength / sizeof(WCHAR));
  6347. ASSERT (RegistryIndex <= 9999);
  6348. swprintf(Buffer + wcslen(Buffer), L"\\%04d", RegistryIndex);
  6349. //
  6350. // Is the key already there?
  6351. //
  6352. if (RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6353. Buffer) != STATUS_SUCCESS) {
  6354. //
  6355. // Create the new key
  6356. //
  6357. if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6358. Buffer) != STATUS_SUCCESS) {
  6359. pVideoDebugPrint((Error,
  6360. "VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
  6361. goto Fallout;
  6362. }
  6363. //
  6364. // Initialize the key
  6365. //
  6366. if (IsLegacy) {
  6367. VpInitializeLegacyKey(DoSpecificExtension->DriverOldRegistryPath,
  6368. Buffer);
  6369. } else {
  6370. VpInitializeKey(FdoExtension->PhysicalDeviceObject,
  6371. Buffer);
  6372. }
  6373. }
  6374. } else {
  6375. //
  6376. // The GUID is not there so allocate a new one
  6377. //
  6378. // !!! Add special case for VGA, MNMDD & RDPCDD
  6379. //
  6380. ntStatus = ExUuidCreate(&newGuid);
  6381. if ((ntStatus != STATUS_SUCCESS) &&
  6382. (ntStatus != RPC_NT_UUID_LOCAL_ONLY)) {
  6383. pVideoDebugPrint((Error,
  6384. "VIDEOPRT: VpEnableNewRegistryKey: failed to create a new GUID.\n"));
  6385. goto Fallout;
  6386. }
  6387. if (RtlStringFromGUID(&newGuid, &newGuidStr) != STATUS_SUCCESS) {
  6388. pVideoDebugPrint((Error,
  6389. "VIDEOPRT: VpEnableNewRegistryKey: failed to convert the GUID to a string.\n"));
  6390. newGuidStr.Buffer = NULL;
  6391. goto Fallout;
  6392. }
  6393. //
  6394. // Upcase the string
  6395. //
  6396. RtlUpcaseUnicodeString(&newGuidStr, &newGuidStr, FALSE);
  6397. //
  6398. // Build the new registry path
  6399. //
  6400. Len = (wcslen(SZ_VIDEO_DEVICES) +
  6401. wcslen(newGuidStr.Buffer) +
  6402. wcslen(SZ_COMMON_SUBKEY) + 8) * sizeof(WCHAR);
  6403. Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
  6404. Len,
  6405. VP_TAG);
  6406. if (Buffer == NULL) {
  6407. pVideoDebugPrint((Error,
  6408. "VIDEOPRT: VpEnableNewRegistryKey: failed to allocate memory.\n"));
  6409. goto Fallout;
  6410. }
  6411. RtlZeroMemory(Buffer, Len);
  6412. wcscpy(Buffer, SZ_VIDEO_DEVICES);
  6413. if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6414. Buffer) != STATUS_SUCCESS) {
  6415. pVideoDebugPrint((Error,
  6416. "VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
  6417. goto Fallout;
  6418. }
  6419. wcscat(Buffer, L"\\");
  6420. wcscat(Buffer, newGuidStr.Buffer);
  6421. if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6422. Buffer) != STATUS_SUCCESS) {
  6423. pVideoDebugPrint((Error,
  6424. "VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
  6425. goto Fallout;
  6426. }
  6427. //
  6428. // Save the service name
  6429. //
  6430. Len = wcslen(Buffer);
  6431. wcscat(Buffer, L"\\");
  6432. wcscat(Buffer, SZ_COMMON_SUBKEY);
  6433. if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6434. Buffer) != STATUS_SUCCESS) {
  6435. pVideoDebugPrint((Error,
  6436. "VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
  6437. goto Fallout;
  6438. }
  6439. if (RtlWriteRegistryValue(
  6440. RTL_REGISTRY_ABSOLUTE,
  6441. Buffer,
  6442. SZ_SERVICE,
  6443. REG_SZ,
  6444. (PVOID)pService,
  6445. (ServiceLen + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
  6446. pVideoDebugPrint((Error,
  6447. "VIDEOPRT: VpEnableNewRegistryKey: failed to save the service name.\n"));
  6448. goto Fallout;
  6449. }
  6450. if (IsLegacy) {
  6451. ServiceSubKey = GuidKey;
  6452. } else {
  6453. if (!VpGetServiceSubkey(RegistryPath,
  6454. &ServiceSubKey)) {
  6455. ServiceSubKey = NULL;
  6456. }
  6457. }
  6458. if (ServiceSubKey != NULL) {
  6459. if (RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  6460. ServiceSubKey,
  6461. SZ_SERVICE,
  6462. REG_SZ,
  6463. (PVOID)pService,
  6464. (ServiceLen + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
  6465. pVideoDebugPrint((Error,
  6466. "VIDEOPRT: VpEnableNewRegistryKey: failed to save the service name.\n"));
  6467. goto Fallout;
  6468. }
  6469. }
  6470. //
  6471. // Create the 000X subkey
  6472. //
  6473. Buffer[Len] = 0;
  6474. ASSERT (RegistryIndex == 0);
  6475. wcscat(Buffer, L"\\0000");
  6476. if (RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  6477. Buffer) != STATUS_SUCCESS) {
  6478. pVideoDebugPrint((Error,
  6479. "VIDEOPRT: VpEnableNewRegistryKey: failed to create the new key.\n"));
  6480. goto Fallout;
  6481. }
  6482. //
  6483. // Save the new key under the PnP device key or the service subkey
  6484. //
  6485. if (RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  6486. GuidKey,
  6487. SZ_GUID,
  6488. REG_SZ,
  6489. (PVOID)newGuidStr.Buffer,
  6490. (wcslen(newGuidStr.Buffer) + 1) * sizeof(WCHAR)) != STATUS_SUCCESS) {
  6491. pVideoDebugPrint((Error,
  6492. "VIDEOPRT: VpEnableNewRegistryKey: failed to write the new GUID to the registry.\n"));
  6493. goto Fallout;
  6494. }
  6495. //
  6496. // The key was not there, so initialize it.
  6497. //
  6498. if (IsLegacy) {
  6499. VpInitializeLegacyKey(DoSpecificExtension->DriverOldRegistryPath,
  6500. Buffer);
  6501. } else {
  6502. VpInitializeKey(FdoExtension->PhysicalDeviceObject,
  6503. Buffer);
  6504. }
  6505. }
  6506. pVideoDebugPrint((Info, "VIDEOPRT: VpEnableNewRegistryKey: %ws\n", Buffer));
  6507. //
  6508. // Initialize the new registry path fields
  6509. //
  6510. DoSpecificExtension->DriverNewRegistryPath = Buffer;
  6511. DoSpecificExtension->DriverNewRegistryPathLength = wcslen(Buffer) * sizeof(WCHAR);
  6512. Fallout:
  6513. //
  6514. // Cleanup
  6515. //
  6516. if (GUIDBuffer != NULL) {
  6517. ExFreePool(GUIDBuffer);
  6518. }
  6519. if (newGuidStr.Buffer != NULL) {
  6520. RtlFreeUnicodeString(&newGuidStr);
  6521. }
  6522. if ((DoSpecificExtension->DriverNewRegistryPath == NULL) &&
  6523. (Buffer != NULL)) {
  6524. ExFreePool(Buffer);
  6525. }
  6526. if (GuidKey != NULL) {
  6527. ZwClose(GuidKey);
  6528. }
  6529. if (!IsLegacy && (ServiceSubKey != NULL)) {
  6530. ZwClose(ServiceSubKey);
  6531. }
  6532. if (pService != NULL) {
  6533. ExFreePool(pService);
  6534. }
  6535. return;
  6536. } // VpEnableNewRegistryKey
  6537. VOID
  6538. VpInitializeKey(
  6539. PDEVICE_OBJECT PhysicalDeviceObject,
  6540. PWSTR NewRegistryPath
  6541. )
  6542. {
  6543. HANDLE NewDeviceKey = NULL;
  6544. HANDLE DriverKey = NULL;
  6545. HANDLE DriverSettingsKey = NULL;
  6546. UNICODE_STRING UnicodeString;
  6547. OBJECT_ATTRIBUTES ObjectAttributes;
  6548. ASSERT (PhysicalDeviceObject != NULL);
  6549. ASSERT (NewRegistryPath != NULL);
  6550. //
  6551. // Open the new key
  6552. //
  6553. RtlInitUnicodeString(&UnicodeString, NewRegistryPath);
  6554. InitializeObjectAttributes(&ObjectAttributes,
  6555. &UnicodeString,
  6556. OBJ_CASE_INSENSITIVE,
  6557. NULL,
  6558. NULL);
  6559. if (ZwOpenKey(&NewDeviceKey,
  6560. KEY_ALL_ACCESS,
  6561. &ObjectAttributes) != STATUS_SUCCESS) {
  6562. pVideoDebugPrint((Error,
  6563. "VIDEOPRT: VpInitializeKey: failed to open the new key.\n"));
  6564. NewDeviceKey = NULL;
  6565. goto Fallout;
  6566. }
  6567. //
  6568. // Open the PnP driver key
  6569. //
  6570. if (IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  6571. PLUGPLAY_REGKEY_DRIVER,
  6572. KEY_READ | KEY_WRITE,
  6573. &DriverKey) != STATUS_SUCCESS) {
  6574. pVideoDebugPrint((Error,
  6575. "VIDEOPRT: VpInitializeKey: could not open the driver key.\n"));
  6576. DriverKey = NULL;
  6577. goto Fallout;
  6578. }
  6579. RtlInitUnicodeString(&UnicodeString, SZ_INITIAL_SETTINGS);
  6580. InitializeObjectAttributes(&ObjectAttributes,
  6581. &UnicodeString,
  6582. OBJ_CASE_INSENSITIVE,
  6583. DriverKey,
  6584. NULL);
  6585. //
  6586. // Open the "Settings" key.
  6587. // The class installer saved the initial settings there.
  6588. //
  6589. if (ZwOpenKey(&DriverSettingsKey,
  6590. GENERIC_READ | GENERIC_WRITE,
  6591. &ObjectAttributes) != STATUS_SUCCESS) {
  6592. pVideoDebugPrint((Error,
  6593. "VIDEOPRT: VpInitializeKey: failed to open the driver settings key.\n"));
  6594. DriverSettingsKey = NULL;
  6595. goto Fallout;
  6596. }
  6597. //
  6598. // Copy the settings
  6599. //
  6600. VpCopyRegistry(DriverSettingsKey,
  6601. NewDeviceKey,
  6602. NULL,
  6603. NULL);
  6604. Fallout:
  6605. if (DriverSettingsKey != NULL) {
  6606. ZwClose(DriverSettingsKey);
  6607. }
  6608. if (DriverKey != NULL) {
  6609. ZwClose(DriverKey);
  6610. }
  6611. if (NewDeviceKey != NULL) {
  6612. ZwClose(NewDeviceKey);
  6613. }
  6614. } // VpInitializeKey
  6615. VOID
  6616. VpInitializeLegacyKey(
  6617. PWSTR OldRegistryPath,
  6618. PWSTR NewRegistryPath
  6619. )
  6620. {
  6621. HANDLE NewDeviceKey = NULL;
  6622. HANDLE OldDeviceKey = NULL;
  6623. UNICODE_STRING UnicodeString;
  6624. OBJECT_ATTRIBUTES ObjectAttributes;
  6625. ASSERT (NewRegistryPath != NULL);
  6626. //
  6627. // Open the new key
  6628. //
  6629. RtlInitUnicodeString(&UnicodeString, NewRegistryPath);
  6630. InitializeObjectAttributes(&ObjectAttributes,
  6631. &UnicodeString,
  6632. OBJ_CASE_INSENSITIVE,
  6633. NULL,
  6634. NULL);
  6635. if (ZwOpenKey(&NewDeviceKey,
  6636. KEY_ALL_ACCESS,
  6637. &ObjectAttributes) != STATUS_SUCCESS) {
  6638. pVideoDebugPrint((Error,
  6639. "VIDEOPRT: VpInitializeLegacyKey: failed to open the new key.\n"));
  6640. NewDeviceKey = NULL;
  6641. goto Fallout;
  6642. }
  6643. //
  6644. // Open the old key
  6645. //
  6646. RtlInitUnicodeString(&UnicodeString,
  6647. OldRegistryPath);
  6648. InitializeObjectAttributes(&ObjectAttributes,
  6649. &UnicodeString,
  6650. OBJ_CASE_INSENSITIVE,
  6651. NULL,
  6652. NULL);
  6653. if (ZwOpenKey(&OldDeviceKey,
  6654. GENERIC_READ | GENERIC_WRITE,
  6655. &ObjectAttributes) != STATUS_SUCCESS) {
  6656. pVideoDebugPrint((Error,
  6657. "VIDEOPRT: VpInitializeLegacyKey: failed to open the old key.\n"));
  6658. OldDeviceKey = NULL;
  6659. goto Fallout;
  6660. }
  6661. //
  6662. // Copy the settings
  6663. //
  6664. VpCopyRegistry(OldDeviceKey,
  6665. NewDeviceKey,
  6666. NULL,
  6667. NULL);
  6668. Fallout:
  6669. if (NewDeviceKey != NULL) {
  6670. ZwClose(NewDeviceKey);
  6671. }
  6672. if (OldDeviceKey != NULL) {
  6673. ZwClose(OldDeviceKey);
  6674. }
  6675. } // VpInitializeLegacyKey
  6676. NTSTATUS
  6677. VpCopyRegistry(
  6678. HANDLE hKeyRootSrc,
  6679. HANDLE hKeyRootDst,
  6680. PWSTR SrcKeyPath,
  6681. PWSTR DstKeyPath
  6682. )
  6683. /*++
  6684. Routine Description:
  6685. This routine recursively copies a src key to a destination key.
  6686. Arguments:
  6687. hKeyRootSrc: Handle to root src key
  6688. hKeyRootDst: Handle to root dst key
  6689. SrcKeyPath: src root key relative path to the subkey which needs to be
  6690. recursively copied. if this is null SourceKey is the key
  6691. from which the recursive copy is to be done.
  6692. DstKeyPath: dst root key relative path to the subkey which needs to be
  6693. recursively copied. if this is null DestinationKey is the key
  6694. from which the recursive copy is to be done.
  6695. Return Value:
  6696. Status is returned.
  6697. --*/
  6698. {
  6699. NTSTATUS Status = STATUS_SUCCESS;
  6700. OBJECT_ATTRIBUTES ObjectAttributes;
  6701. UNICODE_STRING UnicodeString;
  6702. HANDLE hKeySrc = NULL, hKeyDst = NULL;
  6703. ULONG ResultLength, Index;
  6704. PKEY_BASIC_INFORMATION KeyInfo;
  6705. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  6706. PWSTR ValueName;
  6707. ULONG BufferSize = 512;
  6708. PVOID Buffer = NULL;
  6709. //
  6710. // Get a handle to the source key
  6711. //
  6712. if(SrcKeyPath == NULL) {
  6713. hKeySrc = hKeyRootSrc;
  6714. } else {
  6715. //
  6716. // Open the Src key
  6717. //
  6718. RtlInitUnicodeString(&UnicodeString, SrcKeyPath);
  6719. InitializeObjectAttributes(&ObjectAttributes,
  6720. &UnicodeString,
  6721. OBJ_CASE_INSENSITIVE,
  6722. hKeyRootSrc,
  6723. NULL);
  6724. Status = ZwOpenKey(&hKeySrc,
  6725. KEY_READ,
  6726. &ObjectAttributes);
  6727. if(!NT_SUCCESS(Status)) {
  6728. pVideoDebugPrint((Error,
  6729. "VIDEOPRT: VpCopyRegistry: failed to open the source key.\n"));
  6730. hKeySrc = NULL;
  6731. goto Fallout;
  6732. }
  6733. }
  6734. //
  6735. // Get a handle to the destination key
  6736. //
  6737. if(DstKeyPath == NULL) {
  6738. hKeyDst = hKeyRootDst;
  6739. } else {
  6740. //
  6741. // Create the destination key.
  6742. //
  6743. RtlInitUnicodeString(&UnicodeString, DstKeyPath);
  6744. InitializeObjectAttributes(&ObjectAttributes,
  6745. &UnicodeString,
  6746. OBJ_CASE_INSENSITIVE,
  6747. hKeyRootDst,
  6748. NULL);
  6749. Status = ZwCreateKey(&hKeyDst,
  6750. GENERIC_READ | GENERIC_WRITE,
  6751. &ObjectAttributes,
  6752. 0,
  6753. NULL,
  6754. REG_OPTION_NON_VOLATILE,
  6755. NULL);
  6756. if (!NT_SUCCESS(Status)) {
  6757. pVideoDebugPrint((Error,
  6758. "VIDEOPRT: VpCopyRegistry: failed to create the destination key.\n"));
  6759. hKeyDst = NULL;
  6760. goto Fallout;
  6761. }
  6762. }
  6763. //
  6764. // Enumerate all keys in the source key and recursively
  6765. // create all subkeys
  6766. //
  6767. for (Index = 0; ;Index++) {
  6768. do {
  6769. if (Buffer == NULL) {
  6770. Buffer = ExAllocatePoolWithTag(PagedPool,
  6771. BufferSize,
  6772. VP_TAG);
  6773. if (Buffer == NULL) {
  6774. pVideoDebugPrint((Error,
  6775. "VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
  6776. goto Fallout;
  6777. }
  6778. }
  6779. Status = ZwEnumerateKey(hKeySrc,
  6780. Index,
  6781. KeyBasicInformation,
  6782. Buffer,
  6783. BufferSize - sizeof(WCHAR),
  6784. &ResultLength);
  6785. if (Status == STATUS_BUFFER_TOO_SMALL) {
  6786. ExFreePool(Buffer);
  6787. Buffer = NULL;
  6788. BufferSize = ResultLength + sizeof(WCHAR);
  6789. }
  6790. } while (Status == STATUS_BUFFER_TOO_SMALL);
  6791. KeyInfo = (PKEY_BASIC_INFORMATION)Buffer;
  6792. if (!NT_SUCCESS(Status)) {
  6793. if(Status == STATUS_NO_MORE_ENTRIES) {
  6794. Status = STATUS_SUCCESS;
  6795. } else {
  6796. pVideoDebugPrint((Error,
  6797. "VIDEOPRT: VpCopyRegistry: failed to enumerate the subkeys.\n"));
  6798. }
  6799. break;
  6800. }
  6801. //
  6802. // Zero-terminate the subkey name
  6803. //
  6804. KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
  6805. //
  6806. // Copy the subkey
  6807. //
  6808. Status = VpCopyRegistry(hKeySrc,
  6809. hKeyDst,
  6810. KeyInfo->Name,
  6811. KeyInfo->Name);
  6812. }
  6813. //
  6814. // Enumerate all values in the source key and create all the values
  6815. // in the destination key
  6816. //
  6817. for(Index = 0; ;Index++) {
  6818. do {
  6819. if (Buffer == NULL) {
  6820. Buffer = ExAllocatePoolWithTag(PagedPool,
  6821. BufferSize,
  6822. VP_TAG);
  6823. if (Buffer == NULL) {
  6824. pVideoDebugPrint((Error,
  6825. "VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
  6826. goto Fallout;
  6827. }
  6828. }
  6829. Status = ZwEnumerateValueKey(hKeySrc,
  6830. Index,
  6831. KeyValueFullInformation,
  6832. Buffer,
  6833. BufferSize,
  6834. &ResultLength);
  6835. if (Status == STATUS_BUFFER_TOO_SMALL) {
  6836. ExFreePool(Buffer);
  6837. Buffer = NULL;
  6838. BufferSize = ResultLength;
  6839. }
  6840. } while (Status == STATUS_BUFFER_TOO_SMALL);
  6841. ValueInfo = (PKEY_VALUE_FULL_INFORMATION)Buffer;
  6842. if(!NT_SUCCESS(Status)) {
  6843. if(Status == STATUS_NO_MORE_ENTRIES) {
  6844. Status = STATUS_SUCCESS;
  6845. } else {
  6846. pVideoDebugPrint((Error,
  6847. "VIDEOPRT: VpCopyRegistry: failed to enumerate the values.\n"));
  6848. }
  6849. break;
  6850. }
  6851. //
  6852. // Process the value found and create the value in the destination key
  6853. //
  6854. ValueName = (PWSTR)
  6855. ExAllocatePoolWithTag(PagedPool,
  6856. ValueInfo->NameLength + sizeof(WCHAR),
  6857. VP_TAG);
  6858. if (ValueName == NULL) {
  6859. pVideoDebugPrint((Error,
  6860. "VIDEOPRT: VpCopyRegistry: failed to allocate memory.\n"));
  6861. goto Fallout;
  6862. }
  6863. wcsncpy(ValueName,
  6864. ValueInfo->Name,
  6865. (ValueInfo->NameLength)/sizeof(WCHAR));
  6866. ValueName[(ValueInfo->NameLength)/sizeof(WCHAR)] = 0;
  6867. RtlInitUnicodeString(&UnicodeString, ValueName);
  6868. Status = ZwSetValueKey(hKeyDst,
  6869. &UnicodeString,
  6870. ValueInfo->TitleIndex,
  6871. ValueInfo->Type,
  6872. (PVOID)((PUCHAR)ValueInfo + ValueInfo->DataOffset),
  6873. ValueInfo->DataLength);
  6874. if(!NT_SUCCESS(Status)) {
  6875. pVideoDebugPrint((Error,
  6876. "VIDEOPRT: VpCopyRegistry: failed to set the value.\n"));
  6877. }
  6878. ExFreePool(ValueName);
  6879. }
  6880. Fallout:
  6881. //
  6882. // Cleanup
  6883. //
  6884. if (Buffer != NULL) {
  6885. ExFreePool(Buffer);
  6886. }
  6887. if ((hKeySrc != NULL) && (hKeySrc != hKeyRootSrc)) {
  6888. ZwClose(hKeySrc);
  6889. }
  6890. if ((hKeyDst != NULL) && (hKeyDst != hKeyRootDst)) {
  6891. ZwClose(hKeyDst);
  6892. }
  6893. return(Status);
  6894. } // VpCopyRegistry
  6895. BOOLEAN
  6896. VpGetServiceSubkey(
  6897. PUNICODE_STRING RegistryPath,
  6898. HANDLE* pServiceSubKey
  6899. )
  6900. {
  6901. LPWSTR Buffer = NULL;
  6902. USHORT Len = 0;
  6903. OBJECT_ATTRIBUTES ObjectAttributes;
  6904. UNICODE_STRING UnicodeString;
  6905. BOOLEAN bSuccess = FALSE;
  6906. Len = RegistryPath->Length + (wcslen(SZ_COMMON_SUBKEY) + 2) * sizeof(WCHAR);
  6907. Buffer = (LPWSTR)ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, Len, VP_TAG);
  6908. if (Buffer == NULL) {
  6909. pVideoDebugPrint((Error,
  6910. "VIDEOPRT: VpGetServiceSubkey: failed to allocate memory.\n"));
  6911. goto Fallout;
  6912. }
  6913. RtlZeroMemory(Buffer, Len);
  6914. wcsncpy(Buffer,
  6915. RegistryPath->Buffer,
  6916. RegistryPath->Length / sizeof(WCHAR));
  6917. wcscat(Buffer, L"\\");
  6918. wcscat(Buffer, SZ_COMMON_SUBKEY);
  6919. RtlInitUnicodeString(&UnicodeString, Buffer);
  6920. InitializeObjectAttributes(&ObjectAttributes,
  6921. &UnicodeString,
  6922. OBJ_CASE_INSENSITIVE,
  6923. NULL,
  6924. NULL);
  6925. if (ZwCreateKey(pServiceSubKey,
  6926. GENERIC_READ | GENERIC_WRITE,
  6927. &ObjectAttributes,
  6928. 0,
  6929. NULL,
  6930. REG_OPTION_NON_VOLATILE,
  6931. NULL) != STATUS_SUCCESS) {
  6932. pVideoDebugPrint((Error,
  6933. "VIDEOPRT: VpGetServiceSubkey: could not create the service subkey.\n"));
  6934. goto Fallout;
  6935. }
  6936. bSuccess = TRUE;
  6937. Fallout:
  6938. if (Buffer != NULL) {
  6939. ExFreePool(Buffer);
  6940. }
  6941. return bSuccess;
  6942. } // VpGetServiceSubkey
  6943. VP_STATUS
  6944. VideoPortGetVersion(
  6945. PVOID HwDeviceExtension,
  6946. PVPOSVERSIONINFO pVpOsVersionInfo
  6947. )
  6948. {
  6949. RTL_OSVERSIONINFOEXW VersionInformation;
  6950. UNREFERENCED_PARAMETER(HwDeviceExtension);
  6951. if(pVpOsVersionInfo->Size < sizeof(VPOSVERSIONINFO)) {
  6952. return ERROR_INVALID_PARAMETER;
  6953. }
  6954. RtlZeroMemory ((PVOID)(&VersionInformation), sizeof(RTL_OSVERSIONINFOEXW));
  6955. VersionInformation.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
  6956. if ( STATUS_SUCCESS !=
  6957. RtlGetVersion( (PRTL_OSVERSIONINFOW) (&VersionInformation)) ) {
  6958. return ERROR_INVALID_PARAMETER;
  6959. }
  6960. pVpOsVersionInfo->MajorVersion = VersionInformation.dwMajorVersion;
  6961. pVpOsVersionInfo->MinorVersion = VersionInformation.dwMinorVersion;
  6962. pVpOsVersionInfo->BuildNumber = VersionInformation.dwBuildNumber;
  6963. pVpOsVersionInfo->ServicePackMajor = VersionInformation.wServicePackMajor;
  6964. pVpOsVersionInfo->ServicePackMinor = VersionInformation.wServicePackMinor;
  6965. return NO_ERROR;
  6966. }