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

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