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.

16670 lines
561 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: drvsup.c *
  3. * *
  4. * Copyright (c) 1990-1999 Microsoft Corporation *
  5. * *
  6. * Display Driver management routines *
  7. * *
  8. * Andre Vachon -Andreva- *
  9. \**************************************************************************/
  10. #include "precomp.hxx"
  11. // The declaration of AlignRects has been removed from usergdi.h
  12. // and has been explicitly added here. [dchinn]
  13. extern "C" {
  14. BOOL
  15. AlignRects(
  16. IN OUT LPRECT arc,
  17. IN DWORD cCount,
  18. IN DWORD iPrimary,
  19. IN DWORD dwFlags);
  20. }
  21. extern
  22. VOID APIENTRY GreSuspendDirectDrawEx(
  23. HDEV hdev,
  24. ULONG fl
  25. );
  26. extern
  27. VOID APIENTRY GreResumeDirectDrawEx(
  28. HDEV hdev,
  29. ULONG fl
  30. );
  31. #pragma hdrstop
  32. #include <wdmguid.h> // for GUID_DEVICE_INTERFACE_ARRIVAL/REMOVAL
  33. #define INITGUID
  34. #include <initguid.h>
  35. #include "ntddvdeo.h"
  36. #ifdef _HYDRA_
  37. #include <regapi.h>
  38. #include <winDDIts.h>
  39. #include "muclean.hxx"
  40. #include "winstaw.h"
  41. extern PFILE_OBJECT G_RemoteVideoFileObject;
  42. extern PFILE_OBJECT G_RemoteConnectionFileObject;
  43. extern HANDLE G_RemoteConnectionChannel;
  44. extern PBYTE G_PerformanceStatistics;
  45. extern BOOL G_fConsole;
  46. extern BOOL G_fDoubleDpi;
  47. extern LPWSTR G_DisplayDriverNames;
  48. #endif
  49. #if TEXTURE_DEMO
  50. /*
  51. * Texture Demo
  52. */
  53. ULONG gcTextures; // Count of textures
  54. HDEV gahdevTexture[8]; // Array of texture PDEVs
  55. BOOL gbTexture = FALSE; // TRUE if we're to do the texture demo
  56. HDEV ghdevTextureParent; // Non-NULL if doing texture demo
  57. LONG gcxTexture; // Texture size of TexEnablePDEV
  58. LONG gcyTexture;
  59. #define INDEX_DrvDemoTexture INDEX_DrvMovePanning
  60. typedef struct _DEMOCOORDINATE
  61. {
  62. float fX;
  63. float fY;
  64. float fW;
  65. float fU;
  66. float fV;
  67. float fZ;
  68. } DEMOCOORDINATE;
  69. typedef struct _DEMOQUAD
  70. {
  71. DEMOCOORDINATE V0;
  72. DEMOCOORDINATE V1;
  73. DEMOCOORDINATE V2;
  74. DEMOCOORDINATE V3;
  75. } DEMOQUAD;
  76. BOOL APIENTRY DrvDemoTexture(
  77. SURFOBJ *psoDst,
  78. SURFOBJ *psoSrc,
  79. CLIPOBJ *pco,
  80. DEMOQUAD *pQuads,
  81. ULONG cQuads
  82. );
  83. typedef BOOL (*PFN_DrvDemoTexture)(SURFOBJ*,SURFOBJ*,CLIPOBJ*,DEMOQUAD*,ULONG);
  84. #endif // TEXTURE_DEMO
  85. typedef enum _DISP_DRIVER_LOG {
  86. MsgInvalidConfiguration = 1,
  87. MsgInvalidDisplayDriver,
  88. MsgInvalidOldDriver,
  89. MsgInvalidDisplayMode,
  90. MsgInvalidDisplay16Colors,
  91. MsgInvalidUsingDefaultMode,
  92. } DISP_DRIVER_LOG;
  93. typedef enum _DISP_DRIVER_REGISTRY_TYPE {
  94. DispDriverRegGlobal,
  95. DispDriverRegHardwareProfile,
  96. DispDriverRegHardwareProfileCreate,
  97. DispDriverRegKey
  98. } DISP_DRIVER_REGISTRY_TYPE;
  99. typedef enum _GRAPHICS_STATE {
  100. GraphicsStateFull = 1,
  101. GraphicsStateNoAttach,
  102. GraphicsStateAttachDisconnect
  103. } GRAPHICS_STATE;
  104. #define DM_INTERNAL_VALID_FLAGS \
  105. (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | \
  106. DM_DISPLAYFLAGS | DM_LOGPIXELS | DM_PANNINGWIDTH | DM_PANNINGHEIGHT | \
  107. DM_DISPLAYORIENTATION )
  108. #define DDML_DRIVER -4
  109. BOOL gbBaseVideo;
  110. BOOL gbUpdateMonitor;
  111. BOOL gbInvalidateDualView;
  112. USHORT gdmLogPixels;
  113. ULONG gcNextGlobalDeviceNumber;
  114. ULONG gcNextGlobalPhysicalOutputNumber;
  115. ULONG gcNextGlobalVirtualOutputNumber;
  116. PGRAPHICS_DEVICE gpGraphicsDeviceList;
  117. PGRAPHICS_DEVICE gpGraphicsDeviceListLast;
  118. PGRAPHICS_DEVICE gPhysDispVGA; // VGA driver hack
  119. GRAPHICS_DEVICE gFullscreenGraphicsDevice;
  120. GRAPHICS_DEVICE gFeFullscreenGraphicsDevice;
  121. // #if DBG
  122. ULONG gcFailedModeChanges = 0;
  123. // #endif
  124. PPALETTE DrvRealizeHalftonePalette(HDEV hdevPalette, BOOL bForce);
  125. BOOL
  126. DrvSetDisconnectedGraphicsDevice(
  127. BOOL bLocal);
  128. VOID
  129. DrvCleanupOneGraphicsDevice(PGRAPHICS_DEVICE pGraphicsDeviceList);
  130. BOOL
  131. DrvIsProtocolAlreadyKnown(VOID);
  132. extern "C" USHORT gProtocolType;
  133. ULONG gcRemoteNextGlobalDeviceNumber;
  134. ULONG gcLocalNextGlobalDeviceNumber;
  135. PGRAPHICS_DEVICE gpRemoteGraphicsDeviceList;
  136. PGRAPHICS_DEVICE gpLocalGraphicsDeviceList;
  137. PGRAPHICS_DEVICE gpRemoteGraphicsDeviceListLast;
  138. PGRAPHICS_DEVICE gpLocalGraphicsDeviceListLast;
  139. PGRAPHICS_DEVICE gpRemoteDiscGraphicsDevice;
  140. PGRAPHICS_DEVICE gpLocalDiscGraphicsDevice;
  141. ULONG gcLocalNextGlobalPhysicalOutputNumber = 1;
  142. ULONG gcLocalNextGlobalVirtualOutputNumber = 1;
  143. ULONG gcRemoteNextGlobalPhysicalOutputNumber = 1;
  144. ULONG gcRemoteNextGlobalVirtualOutputNumber = 1;
  145. #if MDEV_STACK_TRACE_LENGTH
  146. LONG glMDEVTrace = 0;
  147. MDEVRECORD gMDEVTrace[32];
  148. const LONG gcMDEVTraceLength = sizeof(gMDEVTrace)/sizeof(gMDEVTrace[0]);
  149. #endif
  150. //
  151. // Global driver list. This pointer points to the first driver in a
  152. // singly linked list of drivers.
  153. //
  154. // We use this list to determine when we are called to load a driver to
  155. // determine if the the driver image is already loaded.
  156. // If the image is already loaded, we will just increment the reference count
  157. // and then create a new PDEV.
  158. //
  159. PLDEV gpldevDrivers;
  160. #if DBG
  161. #define TRACE_SWITCH(str) { if (GreTraceDisplayDriverLoad) { KdPrint(str); } }
  162. #else
  163. #define TRACE_SWITCH(str)
  164. #endif
  165. PUCHAR gpFullscreenFrameBufPtr;
  166. ULONG gpFullscreenFrameBufLength = 0;
  167. LONG CModeChangeInProgress::lInModeChange = 0;
  168. LONG CModeChangeInProgress::lNeedSyncFlush = 0;
  169. LONG CModeChangeInProgress::lNeedTimerFlush = 0;
  170. int
  171. ConvertOutputToOem(
  172. IN LPWSTR Source,
  173. IN int SourceLength, // in chars
  174. OUT LPSTR Target,
  175. IN int TargetLength // in chars
  176. )
  177. /*
  178. Converts SourceLength Unicode characters from Source into
  179. not more than TargetLength Codepage characters at Target.
  180. Returns the number characters put in Target. (0 if failure)
  181. [ntcon\server\misc.c]
  182. */
  183. {
  184. NTSTATUS Status;
  185. ULONG Length;
  186. // Can do this in place
  187. Status = RtlUnicodeToOemN(Target,
  188. TargetLength,
  189. &Length,
  190. Source,
  191. SourceLength * sizeof(WCHAR)
  192. );
  193. if (NT_SUCCESS(Status)) {
  194. return Length;
  195. } else {
  196. return 0;
  197. }
  198. }
  199. /***************************************************************************\
  200. * TranslateOutputToOem
  201. *
  202. * routine to translate console PCHAR_INFO to the ASCII from Unicode
  203. *
  204. * [ntcon\server\fe\direct2.c]
  205. \***************************************************************************/
  206. NTSTATUS
  207. TranslateOutputToOem(
  208. OUT PCHAR_INFO OutputBuffer,
  209. IN PCHAR_INFO InputBuffer,
  210. IN DWORD Length
  211. )
  212. {
  213. CHAR AsciiDbcs[2];
  214. ULONG NumBytes;
  215. while (Length--)
  216. {
  217. if (InputBuffer->Attributes & COMMON_LVB_LEADING_BYTE)
  218. {
  219. if (Length >= 2) // Safe DBCS in buffer ?
  220. {
  221. Length--;
  222. NumBytes = sizeof(AsciiDbcs);
  223. NumBytes = ConvertOutputToOem(&InputBuffer->Char.UnicodeChar,
  224. 1,
  225. &AsciiDbcs[0],
  226. NumBytes);
  227. OutputBuffer->Char.AsciiChar = AsciiDbcs[0];
  228. OutputBuffer->Attributes = InputBuffer->Attributes;
  229. OutputBuffer++;
  230. InputBuffer++;
  231. OutputBuffer->Char.AsciiChar = AsciiDbcs[1];
  232. OutputBuffer->Attributes = InputBuffer->Attributes;
  233. OutputBuffer++;
  234. InputBuffer++;
  235. }
  236. else
  237. {
  238. OutputBuffer->Char.AsciiChar = ' ';
  239. OutputBuffer->Attributes = InputBuffer->Attributes & ~COMMON_LVB_SBCSDBCS;
  240. OutputBuffer++;
  241. InputBuffer++;
  242. }
  243. }
  244. else if (! (InputBuffer->Attributes & COMMON_LVB_SBCSDBCS))
  245. {
  246. ConvertOutputToOem(&InputBuffer->Char.UnicodeChar,
  247. 1,
  248. &OutputBuffer->Char.AsciiChar,
  249. 1);
  250. OutputBuffer->Attributes = InputBuffer->Attributes;
  251. OutputBuffer++;
  252. InputBuffer++;
  253. }
  254. }
  255. return STATUS_SUCCESS;
  256. }
  257. /***************************************************************************\
  258. * NtGdiFullscreenControl
  259. *
  260. * routine to support console calls to the video driver
  261. *
  262. * 01-Sep-1995 andreva Created
  263. \***************************************************************************/
  264. NTSTATUS
  265. NtGdiFullscreenControl(
  266. IN FULLSCREENCONTROL FullscreenCommand,
  267. PVOID FullscreenInput,
  268. DWORD FullscreenInputLength,
  269. PVOID FullscreenOutput,
  270. PULONG FullscreenOutputLength)
  271. {
  272. NTSTATUS Status = STATUS_SUCCESS;
  273. ULONG BytesReturned;
  274. PVOID pCapBuffer = NULL;
  275. ULONG cCapBuffer = 0;
  276. ULONG ioctl = 0;
  277. #define VERIFY_RANGE(base, length, max_length) \
  278. (((ULONG_PTR)base < (ULONG_PTR)max_length) && \
  279. ((ULONG_PTR)length < (ULONG_PTR)max_length) && \
  280. (((ULONG_PTR)base + (ULONG_PTR)length) < (ULONG_PTR)max_length))
  281. //
  282. // If this is not CSR, then fail the API call.
  283. //
  284. if (PsGetCurrentProcess() != gpepCSRSS)
  285. {
  286. return STATUS_PRIVILEGE_NOT_HELD;
  287. }
  288. //
  289. // First validate the ioctl
  290. //
  291. switch(FullscreenCommand) {
  292. case FullscreenControlEnable:
  293. ioctl = IOCTL_VIDEO_ENABLE_VDM;
  294. TRACE_SWITCH(("Switching: FullscreenControlEnable\n"));
  295. break;
  296. case FullscreenControlDisable:
  297. ioctl = IOCTL_VIDEO_DISABLE_VDM;
  298. TRACE_SWITCH(("Switching: FullscreenControlDisable\n"));
  299. break;
  300. case FullscreenControlSetCursorPosition:
  301. if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL)
  302. {
  303. ioctl = IOCTL_FSVIDEO_SET_CURSOR_POSITION;
  304. }
  305. else
  306. {
  307. ioctl = IOCTL_VIDEO_SET_CURSOR_POSITION;
  308. }
  309. TRACE_SWITCH(("Switching: FullscreenControlSetCursorPosition\n"));
  310. break;
  311. case FullscreenControlSetCursorAttributes:
  312. ioctl = IOCTL_VIDEO_SET_CURSOR_ATTR;
  313. TRACE_SWITCH(("Switching: FullscreenControlSetCursorAttributes\n"));
  314. break;
  315. case FullscreenControlRegisterVdm:
  316. ioctl = IOCTL_VIDEO_REGISTER_VDM;
  317. TRACE_SWITCH(("Switching: FullscreenControlRegisterVdm\n"));
  318. break;
  319. case FullscreenControlSetPalette:
  320. ioctl = IOCTL_VIDEO_SET_PALETTE_REGISTERS;
  321. TRACE_SWITCH(("Switching: FullscreenControlSetPalette\n"));
  322. break;
  323. case FullscreenControlSetColors:
  324. ioctl = IOCTL_VIDEO_SET_COLOR_REGISTERS;
  325. TRACE_SWITCH(("Switching: FullscreenControlSetColors\n"));
  326. break;
  327. case FullscreenControlLoadFont:
  328. ioctl = IOCTL_VIDEO_LOAD_AND_SET_FONT;
  329. TRACE_SWITCH(("Switching: FullscreenControlLoadFont\n"));
  330. break;
  331. case FullscreenControlRestoreHardwareState:
  332. ioctl = IOCTL_VIDEO_RESTORE_HARDWARE_STATE;
  333. TRACE_SWITCH(("Switching: FullscreenControlRestoreHardwareState\n"));
  334. break;
  335. case FullscreenControlSaveHardwareState:
  336. ioctl = IOCTL_VIDEO_SAVE_HARDWARE_STATE;
  337. TRACE_SWITCH(("Switching: FullscreenControlSaveHardwareState\n"));
  338. break;
  339. case FullscreenControlCopyFrameBuffer:
  340. case FullscreenControlReadFromFrameBuffer:
  341. case FullscreenControlWriteToFrameBuffer:
  342. case FullscreenControlReverseMousePointer:
  343. case FullscreenControlCopyFrameBufferDB:
  344. case FullscreenControlWriteToFrameBufferDB:
  345. case FullscreenControlReverseMousePointerDB:
  346. // TRACE_SWITCH(("Switching: Fullscreen output command\n"));
  347. if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL)
  348. {
  349. /*
  350. * Console Full Screen Video driver is available.
  351. */
  352. switch(FullscreenCommand)
  353. {
  354. case FullscreenControlCopyFrameBufferDB:
  355. ioctl = IOCTL_FSVIDEO_COPY_FRAME_BUFFER;
  356. break;
  357. case FullscreenControlWriteToFrameBufferDB:
  358. ioctl = IOCTL_FSVIDEO_WRITE_TO_FRAME_BUFFER;
  359. break;
  360. case FullscreenControlReverseMousePointerDB:
  361. ioctl = IOCTL_FSVIDEO_REVERSE_MOUSE_POINTER;
  362. break;
  363. }
  364. }
  365. break;
  366. case FullscreenControlSetMode:
  367. TRACE_SWITCH(("Switching: Fullscreen setmode command\n"));
  368. break;
  369. case FullscreenControlSetScreenInformation:
  370. if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL)
  371. {
  372. ioctl = IOCTL_FSVIDEO_SET_SCREEN_INFORMATION;
  373. }
  374. else
  375. {
  376. return STATUS_NOT_IMPLEMENTED;
  377. }
  378. break;
  379. case FullscreenControlSpecificVideoControl: // for specific NEC PC-98
  380. __try
  381. {
  382. ProbeForRead(FullscreenInput, sizeof(DWORD), sizeof(DWORD));
  383. RtlCopyMemory(&ioctl, FullscreenInput, sizeof(DWORD));
  384. FullscreenInput = (PVOID)((PBYTE)FullscreenInput + sizeof(DWORD));
  385. FullscreenInputLength -= sizeof(DWORD);
  386. }
  387. __except (EXCEPTION_EXECUTE_HANDLER)
  388. {
  389. RIP("FullscreenControlSpecificVideoControl - error processing input buffer\n");
  390. return STATUS_NOT_IMPLEMENTED;
  391. }
  392. break;
  393. default:
  394. RIP("NtUserFullscreenControl: invalid IOCTL\n");
  395. return STATUS_NOT_IMPLEMENTED;
  396. }
  397. //
  398. // If this is a frame buffer function, that we can just deal with the
  399. // device directly, and not send any IOCTL to the device.
  400. //
  401. if (ioctl == 0)
  402. {
  403. CHAR Attribute;
  404. //
  405. // First get the frame buffer pointer for the device.
  406. //
  407. PUCHAR pFrameBuf = gpFullscreenFrameBufPtr;
  408. ULONG_PTR FrameBufLen = (ULONG_PTR)gpFullscreenFrameBufLength;
  409. PCHAR_INFO pCharInfo;
  410. PCHAR_IMAGE_INFO pCharImageInfo;
  411. LPDEVMODEW pDevmode = gFullscreenGraphicsDevice.devmodeInfo;
  412. VIDEO_MODE VideoMode;
  413. BOOLEAN modeFound = FALSE;
  414. ULONG BytesReturned;
  415. ULONG i;
  416. DEVMODEW capturedDevMode;
  417. //
  418. // Assume success for all these operations.
  419. //
  420. Status = STATUS_SUCCESS;
  421. switch(FullscreenCommand) {
  422. case FullscreenControlSetMode:
  423. //
  424. // Fullscreen VGA modes require us to call the miniport driver
  425. // directly.
  426. //
  427. // Lets check the VGA Device handle, which is in the first entry
  428. //
  429. __try
  430. {
  431. ProbeForRead(FullscreenInput, sizeof(DEVMODEW), sizeof(USHORT));
  432. RtlCopyMemory(&capturedDevMode, FullscreenInput, sizeof(DEVMODEW));
  433. }
  434. __except (EXCEPTION_EXECUTE_HANDLER)
  435. {
  436. RIP("Fullscreen control - error processing input/output buffer\n");
  437. Status = STATUS_UNSUCCESSFUL;
  438. }
  439. if ((Status != STATUS_SUCCESS) ||
  440. (gFullscreenGraphicsDevice.pDeviceHandle == NULL))
  441. {
  442. Status = STATUS_UNSUCCESSFUL;
  443. }
  444. else
  445. {
  446. //
  447. // NOTE We know that if there is a vgacompatible device, then
  448. // there are some text modes for it.
  449. //
  450. // NOTE !!!
  451. // As a hack, lets use the mode number we stored in the DEVMODE
  452. // a field we don't use
  453. //
  454. for (i = 0;
  455. i < gFullscreenGraphicsDevice.cbdevmodeInfo;
  456. i += sizeof(DEVMODEW), pDevmode += 1) {
  457. //
  458. // Check if this is the resolustion we are looking for.
  459. //
  460. if ((pDevmode->dmPelsWidth == capturedDevMode.dmPelsWidth) &&
  461. (pDevmode->dmPelsHeight == capturedDevMode.dmPelsHeight) &&
  462. (pDevmode->dmDisplayFlags == capturedDevMode.dmDisplayFlags) &&
  463. (pDevmode->dmBitsPerPel == capturedDevMode.dmBitsPerPel)
  464. )
  465. {
  466. //
  467. // FullscreenInput->dwOrientation is 0.
  468. //
  469. VideoMode.RequestedMode = (ULONG) pDevmode->dmOrientation;
  470. modeFound = TRUE;
  471. break;
  472. }
  473. }
  474. if (modeFound == FALSE)
  475. {
  476. RIP("ChangeDisplaySettings: Console passed in bad DEVMODE\n");
  477. Status = STATUS_UNSUCCESSFUL;
  478. }
  479. else
  480. {
  481. //
  482. // We have the mode number.
  483. // Call the driver to set the mode
  484. //
  485. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  486. IOCTL_VIDEO_SET_CURRENT_MODE,
  487. &VideoMode,
  488. sizeof(VideoMode),
  489. NULL,
  490. 0,
  491. &BytesReturned);
  492. if (NT_SUCCESS(Status))
  493. {
  494. //
  495. // We also map the memory so we can use it to
  496. // process string commands from the console
  497. //
  498. VIDEO_MEMORY FrameBufferMap;
  499. VIDEO_MEMORY_INFORMATION FrameBufferInfo;
  500. FrameBufferMap.RequestedVirtualAddress = NULL;
  501. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  502. IOCTL_VIDEO_MAP_VIDEO_MEMORY,
  503. &FrameBufferMap,
  504. sizeof(FrameBufferMap),
  505. &FrameBufferInfo,
  506. sizeof(FrameBufferInfo),
  507. &BytesReturned);
  508. if (NT_SUCCESS(Status))
  509. {
  510. //
  511. // get address of frame buffer
  512. //
  513. gpFullscreenFrameBufPtr = (PUCHAR) FrameBufferInfo.FrameBufferBase;
  514. gpFullscreenFrameBufLength = FrameBufferInfo.FrameBufferLength;
  515. if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL)
  516. {
  517. FSVIDEO_MODE_INFORMATION FsVideoMode;
  518. //
  519. // get current video mode
  520. //
  521. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  522. IOCTL_VIDEO_QUERY_CURRENT_MODE,
  523. NULL,
  524. 0,
  525. &FsVideoMode.VideoMode,
  526. sizeof(FsVideoMode.VideoMode),
  527. &BytesReturned);
  528. if (NT_SUCCESS(Status))
  529. {
  530. FsVideoMode.VideoMemory = FrameBufferInfo;
  531. //
  532. // set current vide mode to full screen video driver
  533. //
  534. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  535. IOCTL_FSVIDEO_SET_CURRENT_MODE,
  536. &FsVideoMode,
  537. sizeof(FsVideoMode),
  538. NULL,
  539. 0,
  540. &BytesReturned);
  541. if (NT_SUCCESS(Status))
  542. {
  543. }
  544. else
  545. {
  546. RIP("FSVGA setmode: fullscreen MODESET failed\n");
  547. Status = STATUS_UNSUCCESSFUL;
  548. }
  549. }
  550. }
  551. }
  552. else
  553. {
  554. RIP("Fullscreen setmode: memory mapping failed\n");
  555. Status = STATUS_UNSUCCESSFUL;
  556. }
  557. }
  558. else
  559. {
  560. RIP("Fullscreen setmode: fullscreen MODESET failed\n");
  561. Status = STATUS_UNSUCCESSFUL;
  562. }
  563. }
  564. }
  565. break;
  566. case FullscreenControlCopyFrameBuffer:
  567. TRACE_SWITCH(("Switching: FullscreenControlCopyFrameBuffer\n"));
  568. if ( VERIFY_RANGE(FullscreenInput, FullscreenInputLength, FrameBufLen) &&
  569. VERIFY_RANGE(FullscreenOutput, FullscreenInputLength, FrameBufLen))
  570. {
  571. RtlMoveMemory(pFrameBuf + (ULONG_PTR)FullscreenOutput,
  572. pFrameBuf + (ULONG_PTR)FullscreenInput,
  573. FullscreenInputLength);
  574. }
  575. else
  576. {
  577. RIP("Fullscreen control - error processing input/output buffer\n");
  578. }
  579. break;
  580. case FullscreenControlCopyFrameBufferDB:
  581. TRACE_SWITCH(("Switching: FullscreenControlCopyFrameBufferDB\n"));
  582. {
  583. FSCNTL_SCREEN_INFO FsCntlSrc;
  584. FSCNTL_SCREEN_INFO FsCntlDest;
  585. ULONG_PTR offsetSrc, offsetDst, len;
  586. __try
  587. {
  588. ProbeForRead(FullscreenInput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  589. RtlCopyMemory(&FsCntlSrc, FullscreenInput, sizeof(FSCNTL_SCREEN_INFO));
  590. ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  591. RtlCopyMemory(&FsCntlDest, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO));
  592. }
  593. __except (EXCEPTION_EXECUTE_HANDLER)
  594. {
  595. RIP("Fullscreen control - error processing input/output buffer\n");
  596. }
  597. offsetDst = SCREEN_BUFFER_POINTER(0, FsCntlDest.Position.Y, FsCntlDest.ScreenSize.X, sizeof(VGA_CHAR));
  598. offsetSrc = SCREEN_BUFFER_POINTER(0, FsCntlSrc.Position.Y, FsCntlSrc.ScreenSize.X, sizeof(VGA_CHAR));
  599. len = FsCntlSrc.nNumberOfChars * sizeof(VGA_CHAR);
  600. if ( VERIFY_RANGE(offsetDst, len, FrameBufLen) &&
  601. VERIFY_RANGE(offsetSrc, len, FrameBufLen))
  602. {
  603. RtlMoveMemory(pFrameBuf + offsetDst,
  604. pFrameBuf + offsetSrc,
  605. len);
  606. }
  607. else
  608. {
  609. RIP("Fullscreen control - error processing input/output buffer\n");
  610. }
  611. }
  612. break;
  613. case FullscreenControlReadFromFrameBuffer:
  614. TRACE_SWITCH(("Switching: FullscreenControlReadFromFrameBuffer\n"));
  615. FullscreenInputLength = (FullscreenInputLength / 2) * 2;
  616. if (VERIFY_RANGE(FullscreenInput, FullscreenInputLength, FrameBufLen))
  617. {
  618. __try
  619. {
  620. ProbeForWrite(FullscreenOutput, sizeof(CHAR_INFO) * FullscreenInputLength/2, sizeof(UCHAR));
  621. pFrameBuf += (ULONG_PTR) FullscreenInput;
  622. pCharInfo = (PCHAR_INFO) FullscreenOutput;
  623. while (FullscreenInputLength)
  624. {
  625. pCharInfo->Char.AsciiChar = *pFrameBuf++;
  626. pCharInfo->Attributes = *pFrameBuf++;
  627. FullscreenInputLength -= 2;
  628. pCharInfo++;
  629. }
  630. }
  631. __except (EXCEPTION_EXECUTE_HANDLER)
  632. {
  633. RIP("Fullscreen control - error processing input/output buffer\n");
  634. }
  635. }
  636. else
  637. {
  638. RIP("Fullscreen control - error processing input/output buffer\n");
  639. }
  640. break;
  641. case FullscreenControlWriteToFrameBuffer:
  642. TRACE_SWITCH(("Switching: FullscreenControlWriteToFrameBuffer\n"));
  643. FullscreenInputLength = (FullscreenInputLength / 4) * 4;
  644. if (VERIFY_RANGE(FullscreenOutput, FullscreenInputLength/2, FrameBufLen))
  645. {
  646. __try
  647. {
  648. ProbeForRead(FullscreenInput, sizeof(CHAR_INFO) * FullscreenInputLength/4, sizeof(UCHAR));
  649. pFrameBuf += (ULONG_PTR) FullscreenOutput;
  650. pCharInfo = (PCHAR_INFO) FullscreenInput;
  651. while (FullscreenInputLength)
  652. {
  653. *pFrameBuf++ = pCharInfo->Char.AsciiChar;
  654. *pFrameBuf++ = (UCHAR) (pCharInfo->Attributes);
  655. FullscreenInputLength -= 4;
  656. pCharInfo++;
  657. }
  658. }
  659. __except (EXCEPTION_EXECUTE_HANDLER)
  660. {
  661. RIP("Fullscreen control - error processing input/output buffer\n");
  662. }
  663. }
  664. else
  665. {
  666. RIP("Fullscreen control - error processing input/output buffer\n");
  667. }
  668. break;
  669. case FullscreenControlWriteToFrameBufferDB:
  670. TRACE_SWITCH(("Switching: FullscreenControlWriteToFrameBufferDB\n"));
  671. {
  672. FSCNTL_SCREEN_INFO FsCntl;
  673. ULONG_PTR offset;
  674. __try
  675. {
  676. ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  677. RtlCopyMemory(&FsCntl, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO));
  678. ProbeForRead(FullscreenInput, sizeof(CHAR_IMAGE_INFO) * FsCntl.nNumberOfChars, sizeof(USHORT));
  679. }
  680. __except (EXCEPTION_EXECUTE_HANDLER)
  681. {
  682. RIP("Fullscreen control - error processing input/output buffer\n");
  683. }
  684. offset = SCREEN_BUFFER_POINTER(FsCntl.Position.X,
  685. FsCntl.Position.Y,
  686. FsCntl.ScreenSize.X,
  687. sizeof(VGA_CHAR));
  688. if (VERIFY_RANGE(offset, FsCntl.nNumberOfChars*2, FrameBufLen))
  689. {
  690. pFrameBuf += offset;
  691. pCharImageInfo = (PCHAR_IMAGE_INFO) FullscreenInput;
  692. while (FsCntl.nNumberOfChars)
  693. {
  694. TranslateOutputToOem(&pCharImageInfo->CharInfo,
  695. &pCharImageInfo->CharInfo,
  696. 1);
  697. *pFrameBuf++ = pCharImageInfo->CharInfo.Char.AsciiChar;
  698. *pFrameBuf++ = (UCHAR) (pCharImageInfo->CharInfo.Attributes);
  699. FsCntl.nNumberOfChars--;
  700. pCharImageInfo++;
  701. }
  702. }
  703. else
  704. {
  705. RIP("Fullscreen control - error processing input/output buffer\n");
  706. }
  707. }
  708. break;
  709. case FullscreenControlReverseMousePointer:
  710. TRACE_SWITCH(("Switching: FullscreenControlReverseMousePointer\n"));
  711. if (VERIFY_RANGE(FullscreenInput, 1, FrameBufLen))
  712. {
  713. pFrameBuf += (ULONG_PTR) FullscreenInput;
  714. Attribute = (*(pFrameBuf + 1) & 0xF0) >> 4;
  715. Attribute |= (*(pFrameBuf + 1) & 0x0F) << 4;
  716. *(pFrameBuf + 1) = Attribute;
  717. }
  718. else
  719. {
  720. RIP("Fullscreen control - error processing input/output buffer\n");
  721. }
  722. break;
  723. case FullscreenControlReverseMousePointerDB:
  724. TRACE_SWITCH(("Switching: FullscreenControlReverseMousePointerDB\n"));
  725. {
  726. FSVIDEO_REVERSE_MOUSE_POINTER MousePointer;
  727. ULONG_PTR offset;
  728. __try
  729. {
  730. ProbeForRead(FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER), sizeof(USHORT));
  731. RtlCopyMemory(&MousePointer, FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER));
  732. }
  733. __except (EXCEPTION_EXECUTE_HANDLER)
  734. {
  735. RIP("Fullscreen control - error processing input/output buffer\n");
  736. }
  737. offset = SCREEN_BUFFER_POINTER(MousePointer.Screen.Position.X,
  738. MousePointer.Screen.Position.Y,
  739. MousePointer.Screen.ScreenSize.X,
  740. sizeof(VGA_CHAR));
  741. if (VERIFY_RANGE(offset, 1, FrameBufLen))
  742. {
  743. pFrameBuf += offset;
  744. Attribute = (*(pFrameBuf + 1) & 0xF0) >> 4;
  745. Attribute |= (*(pFrameBuf + 1) & 0x0F) << 4;
  746. *(pFrameBuf + 1) = Attribute;
  747. }
  748. else
  749. {
  750. RIP("Fullscreen control - error processing input/output buffer\n");
  751. }
  752. }
  753. break;
  754. }
  755. }
  756. else
  757. if (ioctl == IOCTL_FSVIDEO_COPY_FRAME_BUFFER)
  758. {
  759. PFSVIDEO_COPY_FRAME_BUFFER CopyFrameBuffer;
  760. cCapBuffer = sizeof(FSVIDEO_COPY_FRAME_BUFFER);
  761. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  762. if (!pCapBuffer)
  763. {
  764. Status = STATUS_INSUFFICIENT_RESOURCES;
  765. }
  766. else
  767. {
  768. CopyFrameBuffer = (PFSVIDEO_COPY_FRAME_BUFFER) pCapBuffer;
  769. __try
  770. {
  771. ProbeForRead(FullscreenInput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  772. RtlCopyMemory(&CopyFrameBuffer->SrcScreen, FullscreenInput, sizeof(FSCNTL_SCREEN_INFO));
  773. ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  774. RtlCopyMemory(&CopyFrameBuffer->DestScreen, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO));
  775. }
  776. __except (EXCEPTION_EXECUTE_HANDLER)
  777. {
  778. RIP("Fullscreen control - error processing input/output buffer\n");
  779. }
  780. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  781. ioctl,
  782. pCapBuffer,
  783. cCapBuffer,
  784. NULL,
  785. 0,
  786. &BytesReturned);
  787. }
  788. }
  789. else
  790. if (ioctl == IOCTL_FSVIDEO_WRITE_TO_FRAME_BUFFER)
  791. {
  792. PFSVIDEO_WRITE_TO_FRAME_BUFFER WriteFrameBuffer;
  793. cCapBuffer = sizeof(FSVIDEO_WRITE_TO_FRAME_BUFFER) + FullscreenInputLength;
  794. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  795. if (!pCapBuffer)
  796. {
  797. Status = STATUS_INSUFFICIENT_RESOURCES;
  798. }
  799. else
  800. {
  801. WriteFrameBuffer = (PFSVIDEO_WRITE_TO_FRAME_BUFFER) pCapBuffer;
  802. __try
  803. {
  804. ProbeForRead(FullscreenInput, FullscreenInputLength, sizeof(USHORT));
  805. WriteFrameBuffer->SrcBuffer =
  806. (PCHAR_IMAGE_INFO)((PBYTE)pCapBuffer + sizeof(FSVIDEO_WRITE_TO_FRAME_BUFFER));
  807. RtlCopyMemory(WriteFrameBuffer->SrcBuffer, FullscreenInput, FullscreenInputLength);
  808. ProbeForRead(FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO), sizeof(USHORT));
  809. RtlCopyMemory(&WriteFrameBuffer->DestScreen, FullscreenOutput, sizeof(FSCNTL_SCREEN_INFO));
  810. }
  811. __except (EXCEPTION_EXECUTE_HANDLER)
  812. {
  813. RIP("Fullscreen control - error processing input/output buffer\n");
  814. }
  815. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  816. ioctl,
  817. pCapBuffer,
  818. cCapBuffer,
  819. NULL,
  820. 0,
  821. &BytesReturned);
  822. }
  823. }
  824. else
  825. if (ioctl == IOCTL_FSVIDEO_REVERSE_MOUSE_POINTER)
  826. {
  827. PFSVIDEO_REVERSE_MOUSE_POINTER MouseFrameBuffer;
  828. cCapBuffer = sizeof(FSVIDEO_REVERSE_MOUSE_POINTER);
  829. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  830. if (!pCapBuffer)
  831. {
  832. Status = STATUS_INSUFFICIENT_RESOURCES;
  833. }
  834. else
  835. {
  836. MouseFrameBuffer = (PFSVIDEO_REVERSE_MOUSE_POINTER) pCapBuffer;
  837. __try
  838. {
  839. ProbeForRead(FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER), sizeof(USHORT));
  840. RtlCopyMemory(MouseFrameBuffer, FullscreenInput, sizeof(FSVIDEO_REVERSE_MOUSE_POINTER));
  841. }
  842. __except (EXCEPTION_EXECUTE_HANDLER)
  843. {
  844. RIP("Fullscreen control - error processing input/output buffer\n");
  845. }
  846. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  847. ioctl,
  848. pCapBuffer,
  849. cCapBuffer,
  850. NULL,
  851. 0,
  852. &BytesReturned);
  853. }
  854. }
  855. else
  856. if (ioctl == IOCTL_FSVIDEO_SET_SCREEN_INFORMATION)
  857. {
  858. PFSVIDEO_SCREEN_INFORMATION ScreenInformation;
  859. cCapBuffer = sizeof(FSVIDEO_SCREEN_INFORMATION);
  860. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  861. if (!pCapBuffer)
  862. {
  863. Status = STATUS_INSUFFICIENT_RESOURCES;
  864. }
  865. else
  866. {
  867. ScreenInformation = (PFSVIDEO_SCREEN_INFORMATION) pCapBuffer;
  868. __try
  869. {
  870. ProbeForRead(FullscreenInput, sizeof(FSVIDEO_SCREEN_INFORMATION), sizeof(USHORT));
  871. RtlCopyMemory(ScreenInformation, FullscreenInput, sizeof(FSVIDEO_SCREEN_INFORMATION));
  872. }
  873. __except (EXCEPTION_EXECUTE_HANDLER)
  874. {
  875. RIP("Fullscreen control - error processing input/output buffer\n");
  876. }
  877. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  878. ioctl,
  879. pCapBuffer,
  880. cCapBuffer,
  881. NULL,
  882. 0,
  883. &BytesReturned);
  884. }
  885. }
  886. else
  887. if (ioctl == IOCTL_FSVIDEO_SET_CURSOR_POSITION)
  888. {
  889. PFSVIDEO_CURSOR_POSITION FsCursorPosition;
  890. cCapBuffer = sizeof(FSVIDEO_CURSOR_POSITION);
  891. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  892. if (!pCapBuffer)
  893. {
  894. Status = STATUS_INSUFFICIENT_RESOURCES;
  895. }
  896. else
  897. {
  898. FsCursorPosition = (PFSVIDEO_CURSOR_POSITION) pCapBuffer;
  899. __try
  900. {
  901. ProbeForRead(FullscreenInput, sizeof(FSVIDEO_CURSOR_POSITION), sizeof(USHORT));
  902. RtlCopyMemory(FsCursorPosition, FullscreenInput, sizeof(FSVIDEO_CURSOR_POSITION));
  903. }
  904. __except (EXCEPTION_EXECUTE_HANDLER)
  905. {
  906. RIP("Fullscreen control - error processing input/output buffer\n");
  907. }
  908. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  909. ioctl,
  910. pCapBuffer,
  911. cCapBuffer,
  912. pCapBuffer,
  913. cCapBuffer,
  914. &BytesReturned);
  915. if (!NT_SUCCESS(Status))
  916. {
  917. /*
  918. * If full screen video driver returns error,
  919. * do calls VGA mini port driver on this.
  920. */
  921. ioctl = IOCTL_VIDEO_SET_CURSOR_POSITION;
  922. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  923. ioctl,
  924. &FsCursorPosition->Coord,
  925. sizeof(VIDEO_CURSOR_POSITION),
  926. &FsCursorPosition->Coord,
  927. sizeof(VIDEO_CURSOR_POSITION),
  928. &BytesReturned);
  929. }
  930. if (cCapBuffer && FullscreenOutputLength && NT_SUCCESS(Status))
  931. {
  932. __try
  933. {
  934. ProbeForWrite(FullscreenOutputLength, sizeof(ULONG), sizeof(UCHAR));
  935. *FullscreenOutputLength = BytesReturned;
  936. ProbeForWrite(FullscreenOutput, BytesReturned, sizeof(UCHAR));
  937. RtlCopyMemory(FullscreenOutput, pCapBuffer, BytesReturned);
  938. }
  939. __except (EXCEPTION_EXECUTE_HANDLER)
  940. {
  941. RIP("Fullscreen control - error processing output buffer\n");
  942. }
  943. }
  944. }
  945. }
  946. else
  947. {
  948. //
  949. // For all real operations, check the output buffer parameters
  950. //
  951. if ((FullscreenOutput == NULL) != (FullscreenOutputLength == NULL))
  952. {
  953. RIP("Fullscreen control - inconsistent output buffer information\n");
  954. Status = STATUS_INVALID_PARAMETER_4;
  955. }
  956. else
  957. {
  958. //
  959. // We must now capture the buffers so they can be safely passed down to the
  960. // video miniport driver
  961. //
  962. cCapBuffer = FullscreenInputLength;
  963. if (FullscreenOutputLength)
  964. {
  965. __try
  966. {
  967. ProbeForRead(FullscreenOutputLength, sizeof(ULONG), sizeof(UCHAR));
  968. cCapBuffer = max(cCapBuffer,*FullscreenOutputLength);
  969. }
  970. __except (EXCEPTION_EXECUTE_HANDLER)
  971. {
  972. RIP("Fullscreen control - error processing input buffer\n");
  973. }
  974. }
  975. if (cCapBuffer)
  976. {
  977. pCapBuffer = PALLOCNOZ(cCapBuffer, GDITAG_FULLSCREEN);
  978. if (!pCapBuffer)
  979. {
  980. Status = STATUS_INSUFFICIENT_RESOURCES;
  981. }
  982. else
  983. {
  984. __try
  985. {
  986. ProbeForRead(FullscreenInput, FullscreenInputLength, sizeof(UCHAR));
  987. RtlCopyMemory(pCapBuffer, FullscreenInput, FullscreenInputLength);
  988. }
  989. __except (EXCEPTION_EXECUTE_HANDLER)
  990. {
  991. RIP("Fullscreen control - error processing input buffer\n");
  992. }
  993. }
  994. }
  995. //
  996. // For now, the IOCTL will always be sent to the VGA compatible device.
  997. // We have a global for the handle to this device.
  998. //
  999. if (NT_SUCCESS(Status))
  1000. {
  1001. if (gFeFullscreenGraphicsDevice.pDeviceHandle != NULL &&
  1002. ioctl == IOCTL_VIDEO_SET_CURSOR_ATTR)
  1003. {
  1004. Status = GreDeviceIoControl(gFeFullscreenGraphicsDevice.pDeviceHandle,
  1005. ioctl,
  1006. pCapBuffer,
  1007. cCapBuffer,
  1008. pCapBuffer,
  1009. cCapBuffer,
  1010. &BytesReturned);
  1011. if (!NT_SUCCESS(Status))
  1012. {
  1013. /*
  1014. * If full screen video driver returns error,
  1015. * do calls VGA mini port driver on this.
  1016. */
  1017. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  1018. ioctl,
  1019. pCapBuffer,
  1020. cCapBuffer,
  1021. pCapBuffer,
  1022. cCapBuffer,
  1023. &BytesReturned);
  1024. }
  1025. }
  1026. else
  1027. {
  1028. Status = GreDeviceIoControl(gFullscreenGraphicsDevice.pDeviceHandle,
  1029. ioctl,
  1030. pCapBuffer,
  1031. cCapBuffer,
  1032. pCapBuffer,
  1033. cCapBuffer,
  1034. &BytesReturned);
  1035. TRACE_SWITCH(("Switching: FullscreenControl: IOCTL status is %08lx\n",
  1036. Status));
  1037. if (cCapBuffer && FullscreenOutputLength && NT_SUCCESS(Status))
  1038. {
  1039. __try
  1040. {
  1041. *FullscreenOutputLength = BytesReturned;
  1042. ProbeForWrite(FullscreenOutput, BytesReturned, sizeof(UCHAR));
  1043. RtlCopyMemory(FullscreenOutput, pCapBuffer, BytesReturned);
  1044. }
  1045. __except (EXCEPTION_EXECUTE_HANDLER)
  1046. {
  1047. RIP("Fullscreen control - error processing output buffer\n");
  1048. }
  1049. }
  1050. }
  1051. }
  1052. }
  1053. }
  1054. if (pCapBuffer)
  1055. {
  1056. VFREEMEM(pCapBuffer);
  1057. }
  1058. return (Status);
  1059. }
  1060. /**************************************************************************\
  1061. * DrvLogDisplayDriverEvent
  1062. *
  1063. * We will save a piece of data in the registry so that winlogon can find
  1064. * it and put up a popup if an error occured.
  1065. *
  1066. * CRIT not needed
  1067. *
  1068. * 03-Mar-1993 andreva created
  1069. \**************************************************************************/
  1070. VOID
  1071. DrvLogDisplayDriverEvent(
  1072. DISP_DRIVER_LOG MsgType
  1073. )
  1074. {
  1075. HANDLE hkRegistry;
  1076. OBJECT_ATTRIBUTES ObjectAttributes;
  1077. UNICODE_STRING RegistryPath;
  1078. UNICODE_STRING UnicodeString;
  1079. NTSTATUS Status;
  1080. DWORD dwValue = 1;
  1081. #ifdef _HYDRA_
  1082. /*
  1083. * Whatever happens on a Session, don't affect the console.
  1084. */
  1085. if ( !G_fConsole )
  1086. return;
  1087. #endif
  1088. RtlInitUnicodeString(&UnicodeString, L"");
  1089. switch (MsgType)
  1090. {
  1091. case MsgInvalidUsingDefaultMode:
  1092. //RtlInitUnicodeString(&UnicodeString, L"DefaultMode");
  1093. break;
  1094. case MsgInvalidDisplayDriver:
  1095. //RtlInitUnicodeString(&UnicodeString, L"MissingDisplayDriver");
  1096. break;
  1097. case MsgInvalidOldDriver:
  1098. RtlInitUnicodeString(&UnicodeString, L"OldDisplayDriver");
  1099. break;
  1100. case MsgInvalidDisplay16Colors:
  1101. //RtlInitUnicodeString(&UnicodeString, L"16ColorMode");
  1102. break;
  1103. case MsgInvalidDisplayMode:
  1104. //RtlInitUnicodeString(&UnicodeString, L"BadMode");
  1105. break;
  1106. case MsgInvalidConfiguration:
  1107. //RtlInitUnicodeString(&UnicodeString, L"InvalidConfiguration");
  1108. break;
  1109. default:
  1110. WARNING("DrvLogDisplayDriverEvent: Invalid error message\n");
  1111. return;
  1112. }
  1113. if (UnicodeString.Length != 0) {
  1114. RtlInitUnicodeString(&RegistryPath,
  1115. L"\\Registry\\Machine\\System\\CurrentControlSet\\"
  1116. L"Control\\GraphicsDrivers\\InvalidDisplay");
  1117. InitializeObjectAttributes(&ObjectAttributes,
  1118. &RegistryPath,
  1119. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  1120. NULL,
  1121. NULL);
  1122. Status = ZwCreateKey(&hkRegistry,
  1123. MAXIMUM_ALLOWED,
  1124. &ObjectAttributes,
  1125. 0L,
  1126. NULL,
  1127. REG_OPTION_VOLATILE,
  1128. NULL);
  1129. if (NT_SUCCESS(Status))
  1130. {
  1131. //
  1132. // Write the optional data value under the key.
  1133. //
  1134. (VOID) ZwSetValueKey(hkRegistry,
  1135. &UnicodeString,
  1136. 0,
  1137. REG_DWORD,
  1138. &dwValue,
  1139. sizeof(DWORD));
  1140. (VOID)ZwCloseKey(hkRegistry);
  1141. }
  1142. }
  1143. }
  1144. /******************************Member*Function*****************************\
  1145. * bEARecovery
  1146. *
  1147. * This function checks to see if the EA Recovery mechanism is enabled
  1148. * in the registry.
  1149. *
  1150. \**************************************************************************/
  1151. #define EARecovery L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Watchdog\\Display"
  1152. BOOL bEARecovery(VOID)
  1153. {
  1154. ULONG ulDefault = 0;
  1155. ULONG ulEaRecovery = 0;
  1156. ULONG ulFullRecovery = 0;
  1157. RTL_QUERY_REGISTRY_TABLE queryTable[] =
  1158. {
  1159. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"EaRecovery", &ulEaRecovery, REG_DWORD, &ulDefault, sizeof(ULONG)},
  1160. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"FullRecovery", &ulFullRecovery, REG_DWORD, &ulDefault, sizeof(ULONG)},
  1161. {NULL, 0, NULL}
  1162. };
  1163. RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1164. EARecovery,
  1165. queryTable,
  1166. NULL,
  1167. NULL);
  1168. return ulEaRecovery;
  1169. }
  1170. extern PFN WatchdogTable[INDEX_LAST];
  1171. /******************************Member*Function*****************************\
  1172. * bFillFunctionTable
  1173. *
  1174. * Fills the dispatch table called by the system with a set of routines
  1175. * which wrap the final driver entry points. This is done to allow us to
  1176. * hook each of these calls.
  1177. *
  1178. \**************************************************************************/
  1179. BOOL bFillWatchdogTable(
  1180. PFN *Dst,
  1181. PFN *Src,
  1182. LDEVTYPE ldevType)
  1183. {
  1184. ULONG i;
  1185. //
  1186. // This is required. At least for the final entries in the
  1187. // array which are the DX entry points.
  1188. //
  1189. RtlZeroMemory(Dst, INDEX_DD_LAST * sizeof(PFN));
  1190. //
  1191. // If EA recovery is enabled, and this is a display driver then
  1192. // add the watchdog hooking code. Note, we really don't want to
  1193. // hook remote drivers such as RDPDD. Unfortunately we don't know
  1194. // what driver is a remote driver and what isn't. There is a
  1195. // GCAPS2_REMOTEDRIVER flag that indicates this at DrvEnablePDEV time,
  1196. // but that is really to late.
  1197. //
  1198. // Fortunately this flag currently just indicates whether or not it
  1199. // is safe to hook DrvNineGrid. So I could just check for the existance
  1200. // of the DrvNineGrid function, and use that as a "remote driver" flag.
  1201. //
  1202. // Theoretically no "real" display driver is supposed to hook this
  1203. // function, so we shouldn't have to worry about a non-remote driver
  1204. // losing EA recovery support.
  1205. //
  1206. if (bEARecovery() &&
  1207. (ldevType == LDEV_DEVICE_DISPLAY) &&
  1208. (Src[INDEX_DrvNineGrid] == NULL)) {
  1209. for (i=0; i<INDEX_LAST; i++) {
  1210. if (*Src && WatchdogTable[i]) {
  1211. *Dst = WatchdogTable[i];
  1212. } else {
  1213. *Dst = *Src;
  1214. }
  1215. Src++;
  1216. Dst++;
  1217. }
  1218. } else {
  1219. RtlCopyMemory(Dst, Src, INDEX_LAST * sizeof(PFN));
  1220. }
  1221. return TRUE;
  1222. }
  1223. /******************************Member*Function*****************************\
  1224. * bFillFunctionTable
  1225. *
  1226. * Fills the dispatch table of the LDEV with function pointers from the
  1227. * driver.
  1228. *
  1229. \**************************************************************************/
  1230. BOOL bFillFunctionTable(
  1231. PDRVFN pdrvfn,
  1232. ULONG cdrvfn,
  1233. PFN* ppfnTable)
  1234. {
  1235. //
  1236. // fill with zero pointers to avoid possibility of accessing
  1237. // incorrect fields later
  1238. //
  1239. RtlZeroMemory(ppfnTable, INDEX_LAST*sizeof(PFN));
  1240. //
  1241. // Copy driver functions into our table.
  1242. //
  1243. while (cdrvfn--)
  1244. {
  1245. //
  1246. // Check the range of the index.
  1247. //
  1248. if (pdrvfn->iFunc >= INDEX_LAST)
  1249. {
  1250. return(FALSE);
  1251. }
  1252. //
  1253. // Copy the pointer.
  1254. //
  1255. ppfnTable[pdrvfn->iFunc] = pdrvfn->pfn;
  1256. pdrvfn++;
  1257. }
  1258. return(TRUE);
  1259. }
  1260. /******************************Member*Function*****************************\
  1261. * ldevbFillTable (ded)
  1262. *
  1263. * Fills the dispatch table of the LDEV with function pointers from the
  1264. * driver. Checks that the required functions are present.
  1265. *
  1266. \**************************************************************************/
  1267. static const ULONG aiFuncRequired[] =
  1268. {
  1269. INDEX_DrvEnablePDEV,
  1270. INDEX_DrvCompletePDEV,
  1271. INDEX_DrvDisablePDEV,
  1272. };
  1273. static const ULONG aiFuncPairs[][2] =
  1274. {
  1275. {INDEX_DrvCreateDeviceBitmap, INDEX_DrvDeleteDeviceBitmap},
  1276. {INDEX_DrvMovePointer, INDEX_DrvSetPointerShape}
  1277. };
  1278. static const ULONG aiFuncRequiredFD[] =
  1279. {
  1280. INDEX_DrvQueryFont,
  1281. INDEX_DrvQueryFontTree,
  1282. INDEX_DrvQueryFontData,
  1283. INDEX_DrvQueryFontCaps,
  1284. INDEX_DrvLoadFontFile,
  1285. INDEX_DrvUnloadFontFile,
  1286. INDEX_DrvQueryFontFile
  1287. };
  1288. BOOL
  1289. ldevFillTable(
  1290. PLDEV pldev,
  1291. DRVENABLEDATA *pded,
  1292. LDEVTYPE ldt)
  1293. {
  1294. //
  1295. // Get local copies of ded info and a pointer to the dispatch table.
  1296. //
  1297. ULONG cLeft = pded->c;
  1298. PDRVFN pdrvfn = pded->pdrvfn;
  1299. PFN *ppfnTable = pldev->apfnDriver;
  1300. //
  1301. // Store the driver version in the LDEV
  1302. //
  1303. pldev->ulDriverVersion = pded->iDriverVersion;
  1304. if (!bFillFunctionTable(pdrvfn, cLeft, ppfnTable))
  1305. {
  1306. ASSERTGDI(FALSE,"ldevFillTable: bogus function index\n");
  1307. return(FALSE);
  1308. }
  1309. //
  1310. // Check for required driver functions.
  1311. //
  1312. cLeft = sizeof(aiFuncRequired) / sizeof(ULONG);
  1313. while (cLeft--)
  1314. {
  1315. if (ppfnTable[aiFuncRequired[cLeft]] == (PFN) NULL)
  1316. {
  1317. ASSERTGDI(FALSE,"ldevFillTable: a required function is missing from driver\n");
  1318. return(FALSE);
  1319. }
  1320. }
  1321. //
  1322. // Check for required font functions.
  1323. //
  1324. if (pldev->ldevType == LDEV_FONT)
  1325. {
  1326. cLeft = sizeof(aiFuncRequiredFD) / sizeof(ULONG);
  1327. while (cLeft--)
  1328. {
  1329. if (ppfnTable[aiFuncRequiredFD[cLeft]] == (PFN) NULL)
  1330. {
  1331. ASSERTGDI(FALSE,"FillTable(): a required FD function is missing\n");
  1332. return(FALSE);
  1333. }
  1334. }
  1335. }
  1336. //
  1337. // Check for functions that come in pairs.
  1338. //
  1339. cLeft = sizeof(aiFuncPairs) / sizeof(ULONG) / 2;
  1340. while (cLeft--)
  1341. {
  1342. //
  1343. // Make sure that either both functions are hooked or both functions
  1344. // are not hooked.
  1345. //
  1346. if ((ppfnTable[aiFuncPairs[cLeft][0]] == (PFN) NULL)
  1347. != (ppfnTable[aiFuncPairs[cLeft][1]] == (PFN) NULL))
  1348. {
  1349. ASSERTGDI(FALSE,"ldevFillTable: one of pair of functions is missing from driver\n");
  1350. return(FALSE);
  1351. }
  1352. }
  1353. //
  1354. // The driver supplied function table looks good. Create another
  1355. // table which mirrors this one with new functions that can add
  1356. // monitoring code.
  1357. //
  1358. if (!bFillWatchdogTable((PFN*)&pldev->apfn, (PFN*)&pldev->apfnDriver, ldt)) {
  1359. return FALSE;
  1360. }
  1361. return(TRUE);
  1362. }
  1363. /******************************Member*Function*****************************\
  1364. * ldevLoadInternal
  1365. *
  1366. * Enable one of the statically linked font drivers via the LDEV.
  1367. *
  1368. \**************************************************************************/
  1369. PLDEV
  1370. ldevLoadInternal(
  1371. PFN pfnEnable,
  1372. LDEVTYPE ldt)
  1373. {
  1374. GDIFunctionID(ldevLoadInternal);
  1375. PLDEV pldev;
  1376. TRACE_INIT(("ldevLoadInternal ENTERING\n"));
  1377. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  1378. //
  1379. // Allocate memory for the LDEV.
  1380. //
  1381. pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV);
  1382. if (pldev)
  1383. {
  1384. //
  1385. // Call the Enable entry point.
  1386. //
  1387. DRVENABLEDATA ded;
  1388. if ((!((* (PFN_DrvEnableDriver) pfnEnable) (ENGINE_VERSION,
  1389. sizeof(DRVENABLEDATA),
  1390. &ded))) ||
  1391. (!ldevFillTable(pldev, &ded, ldt)))
  1392. {
  1393. VFREEMEM(pldev);
  1394. pldev = NULL;
  1395. }
  1396. else
  1397. {
  1398. pldev->ldevType = ldt;
  1399. pldev->cldevRefs = 1;
  1400. pldev->bThreadStuck = FALSE;
  1401. //
  1402. // Initialize the rest of the LDEV.
  1403. //
  1404. if (gpldevDrivers)
  1405. {
  1406. gpldevDrivers->pldevPrev = pldev;
  1407. }
  1408. pldev->pldevNext = gpldevDrivers;
  1409. pldev->pldevPrev = NULL;
  1410. gpldevDrivers = pldev;
  1411. //
  1412. // Since this driver is statically linked in, there is no name or
  1413. // MODOBJ.
  1414. //
  1415. pldev->pGdiDriverInfo = NULL;
  1416. TRACE_INIT(("ldevLoadInternal: SUCCESS loaded static driver (font or DDML)\n"));
  1417. }
  1418. }
  1419. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1420. return pldev;
  1421. }
  1422. /******************************Member*Function*****************************\
  1423. * ldevLoadImage
  1424. *
  1425. * Examines the list of loaded drivers and returns library handles (if any).
  1426. *
  1427. * Updates the ref cnt on driver usage.
  1428. *
  1429. * If the driver is not already loaded, a node is created and the dll is
  1430. * loaded in the kernel.
  1431. \**************************************************************************/
  1432. PLDEV
  1433. ldevLoadImage(
  1434. LPWSTR pwszDriver,
  1435. BOOL bImage,
  1436. PBOOL pbAlreadyLoaded,
  1437. BOOL LoadInSessionSpace)
  1438. {
  1439. PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo = NULL;
  1440. PLDEV pldev = NULL;
  1441. UNICODE_STRING usDriverName;
  1442. PLDEV pldevList;
  1443. NTSTATUS Status;
  1444. BOOLEAN OldHardErrorMode;
  1445. BOOL bSearchAgain, bLoadAgain;
  1446. BOOL bResetDriverNameToSystem32;
  1447. TRACE_INIT(("ldevLoadImage called on Image %ws\n", pwszDriver));
  1448. *pbAlreadyLoaded = FALSE;
  1449. //
  1450. // Only append the .dll if it's NOT an image.
  1451. //
  1452. if (MakeSystemRelativePath(pwszDriver,
  1453. &usDriverName,
  1454. !bImage))
  1455. {
  1456. bSearchAgain = TRUE;
  1457. searchagain:
  1458. //
  1459. // Check both lists of drivers.
  1460. //
  1461. pldevList = gpldevDrivers;
  1462. TRACE_INIT(("ldevLoadImage - search for existing image %ws\n",
  1463. usDriverName.Buffer));
  1464. while (pldevList != NULL)
  1465. {
  1466. //
  1467. // If there is a valid driver image, and if the types are compatible.
  1468. // bImage == TRUE means load an image, while bImage == FALSE means
  1469. // anything else (for now)
  1470. //
  1471. if ((pldevList->pGdiDriverInfo) &&
  1472. ((pldevList->ldevType == LDEV_IMAGE) == bImage))
  1473. {
  1474. //
  1475. // Do a case insensitive compare since the printer driver name
  1476. // can come from different locations.
  1477. //
  1478. if (RtlEqualUnicodeString(&(pldevList->pGdiDriverInfo->DriverName),
  1479. &usDriverName,
  1480. TRUE))
  1481. {
  1482. //
  1483. // If it's already loaded, increment the ref count
  1484. // and return that pointer.
  1485. //
  1486. TRACE_INIT(("ldevLoadImage found image. Inc ref count\n"));
  1487. pldevList->cldevRefs += 1;
  1488. *pbAlreadyLoaded = TRUE;
  1489. pldev = pldevList;
  1490. break;
  1491. }
  1492. }
  1493. pldevList = pldevList->pldevNext;
  1494. }
  1495. if (pldev == NULL)
  1496. {
  1497. if (!LoadInSessionSpace)
  1498. {
  1499. // If not a session load see if the Driver is from the
  1500. // \SystemRoot\System32\Drivers subdir. Ex dxapi.sys
  1501. if (bSearchAgain)
  1502. {
  1503. bSearchAgain = FALSE;
  1504. PWSTR pOldBuffer = usDriverName.Buffer;
  1505. bResetDriverNameToSystem32 = FALSE;
  1506. if (MakeSystemDriversRelativePath(pwszDriver,
  1507. &usDriverName,
  1508. !bImage))
  1509. {
  1510. bResetDriverNameToSystem32 = TRUE;
  1511. VFREEMEM(pOldBuffer);
  1512. goto searchagain;
  1513. }
  1514. }
  1515. if (bResetDriverNameToSystem32)
  1516. {
  1517. PWSTR pOldBuffer = usDriverName.Buffer;
  1518. if (!MakeSystemRelativePath(pwszDriver,
  1519. &usDriverName,
  1520. !bImage))
  1521. {
  1522. goto done;
  1523. }
  1524. VFREEMEM(pOldBuffer);
  1525. }
  1526. }
  1527. TRACE_INIT(("ldevLoadImage - attempting to load new image\n"));
  1528. pGdiDriverInfo = (PSYSTEM_GDI_DRIVER_INFORMATION)
  1529. PALLOCNOZ(sizeof(SYSTEM_GDI_DRIVER_INFORMATION), GDITAG_LDEV);
  1530. pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV);
  1531. bLoadAgain = TRUE;
  1532. if (pGdiDriverInfo && pldev)
  1533. {
  1534. loadagain:
  1535. pGdiDriverInfo->DriverName = usDriverName;
  1536. if (LoadInSessionSpace) {
  1537. Status = ZwSetSystemInformation(SystemLoadGdiDriverInformation,
  1538. pGdiDriverInfo,
  1539. sizeof(SYSTEM_GDI_DRIVER_INFORMATION));
  1540. } else {
  1541. Status = ZwSetSystemInformation(SystemLoadGdiDriverInSystemSpace,
  1542. pGdiDriverInfo,
  1543. sizeof(SYSTEM_GDI_DRIVER_INFORMATION));
  1544. }
  1545. //
  1546. // If we get an OBJECT_NAME_NOT_FOUND we handle it the
  1547. // following way:
  1548. //
  1549. // (1) If its a session load then its an error.
  1550. //
  1551. // (2) If it is a non session load then we try again to load
  1552. // the driver from System32\Drivers subdirectory. We do
  1553. // this because DX can ask us to load dxapi.sys and
  1554. // it lives in drivers subdir.
  1555. //
  1556. // In general we should never get IMAGE_ALREADY_LOADED because
  1557. // we check for loaded images above.
  1558. //
  1559. // If we do get this status we handle them in the following
  1560. // manner:
  1561. //
  1562. // (1) If we get IMAGE_ALREADY_LOADED when LoadInSessionSpace
  1563. // is true it is an error. We fail the ldev creation. Why ?
  1564. // because the image may be loaded in another session
  1565. // space and not in ours.
  1566. //
  1567. // (2) If we get IMAGE_ALREADY_LOADED when LoadInSessionSpace
  1568. // is false (i.e load in non session space) we will fail
  1569. // to create the ldev for modules (dll/sys) that win32k.sys
  1570. // does not statically link to. Why ? because such modules
  1571. // can get unloaded without win32k.sys knowing about it.
  1572. // By makeing sure we succeed only statically linked
  1573. // modules we are gauranteed they wont get unloaded
  1574. // behind our back because of our static link dependancy.
  1575. // This also means for such ldevs we cant unload them
  1576. // in ldevUnloadImage's ZwSetSystemInformation. A
  1577. // bStaticImportLink BOOL has been added to the LDEV to
  1578. // handle this case.
  1579. //
  1580. if ((NT_SUCCESS( Status )))
  1581. {
  1582. addstaticimport:
  1583. TRACE_INIT(("ldevLoadImage SUCCESS with HANDLE %08lx\n",
  1584. (ULONG_PTR)pGdiDriverInfo));
  1585. pldev->pGdiDriverInfo = pGdiDriverInfo;
  1586. pldev->bArtificialIncrement = FALSE;
  1587. pldev->cldevRefs = 1;
  1588. pldev->bThreadStuck = FALSE;
  1589. // Assume image for now.
  1590. pldev->ldevType = LDEV_IMAGE;
  1591. pldev->ulDriverVersion = (ULONG) -1;
  1592. if (gpldevDrivers)
  1593. {
  1594. gpldevDrivers->pldevPrev = pldev;
  1595. }
  1596. pldev->pldevNext = gpldevDrivers;
  1597. pldev->pldevPrev = NULL;
  1598. gpldevDrivers = pldev;
  1599. //
  1600. // We exit with all resources allocated, after leaving the
  1601. // semaphore.
  1602. //
  1603. return (pldev);
  1604. }
  1605. else
  1606. {
  1607. if (!LoadInSessionSpace)
  1608. {
  1609. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1610. {
  1611. if(bLoadAgain)
  1612. {
  1613. bLoadAgain = FALSE;
  1614. PWSTR pOldBuffer = usDriverName.Buffer;
  1615. if (MakeSystemDriversRelativePath(pwszDriver,
  1616. &usDriverName,
  1617. !bImage))
  1618. {
  1619. VFREEMEM(pOldBuffer);
  1620. goto loadagain;
  1621. }
  1622. }
  1623. }
  1624. if (Status == STATUS_IMAGE_ALREADY_LOADED)
  1625. {
  1626. //
  1627. // We allow this load to work only if the module is
  1628. // in win32k.sys static import lib list.
  1629. //
  1630. RTL_PROCESS_MODULES ModuleInformation;
  1631. DWORD cbModuleInformation;
  1632. DWORD ReturnedLength;
  1633. PRTL_PROCESS_MODULES pModuleInformation = 0;
  1634. DWORD i;
  1635. ANSI_STRING asDriver;
  1636. UNICODE_STRING uTmp;
  1637. BOOL bFoundDriver = FALSE;
  1638. BOOL bFreeAsDriver = FALSE;
  1639. WCHAR *pwszDriverFileName = 0;
  1640. pwszDriverFileName = wcsrchr(pwszDriver,L'\\');
  1641. if (pwszDriverFileName)
  1642. pwszDriverFileName++;
  1643. else
  1644. pwszDriverFileName = pwszDriver;
  1645. RtlInitUnicodeString(&uTmp, pwszDriverFileName);
  1646. Status = RtlUnicodeStringToAnsiString(&asDriver,&uTmp,TRUE);
  1647. //
  1648. // 1) Locate asDriver name in system Module list:
  1649. //
  1650. if (NT_SUCCESS(Status))
  1651. {
  1652. bFreeAsDriver = TRUE;
  1653. Status = ZwQuerySystemInformation(SystemModuleInformation,
  1654. &ModuleInformation,
  1655. sizeof(ModuleInformation),
  1656. &ReturnedLength);
  1657. if (NT_SUCCESS(Status) || (Status == STATUS_INFO_LENGTH_MISMATCH))
  1658. {
  1659. cbModuleInformation = offsetof(RTL_PROCESS_MODULES, Modules);
  1660. cbModuleInformation += ModuleInformation.NumberOfModules * sizeof(RTL_PROCESS_MODULE_INFORMATION);
  1661. pModuleInformation = (PRTL_PROCESS_MODULES)PALLOCNOZ(cbModuleInformation, 'pmtG');
  1662. if (pModuleInformation)
  1663. {
  1664. Status = ZwQuerySystemInformation(SystemModuleInformation,
  1665. pModuleInformation,
  1666. cbModuleInformation,
  1667. &ReturnedLength);
  1668. if (NT_SUCCESS(Status))
  1669. {
  1670. for (i = 0; i < ModuleInformation.NumberOfModules; i++)
  1671. {
  1672. CHAR *FullPathName = (CHAR*)(pModuleInformation->Modules[i].FullPathName);
  1673. USHORT OffsetToFileName = pModuleInformation->Modules[i].OffsetToFileName;
  1674. if(!_strnicmp(&FullPathName[OffsetToFileName],
  1675. asDriver.Buffer,
  1676. asDriver.Length))
  1677. {
  1678. bFoundDriver = TRUE;
  1679. break;
  1680. }
  1681. }
  1682. }
  1683. }
  1684. }
  1685. }
  1686. //
  1687. // 2) Found it in System Module list? then locate it in win32k.sys static import list
  1688. //
  1689. if (bFoundDriver)
  1690. {
  1691. bFoundDriver = FALSE;
  1692. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  1693. ULONG ImportSize;
  1694. PSZ ImportName;
  1695. ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)
  1696. RtlImageDirectoryEntryToData(gpvWin32kImageBase,
  1697. TRUE,
  1698. IMAGE_DIRECTORY_ENTRY_IMPORT,
  1699. &ImportSize);
  1700. while (ImportDescriptor &&
  1701. ImportDescriptor->Name &&
  1702. ImportDescriptor->OriginalFirstThunk)
  1703. {
  1704. ImportName = (PSZ)((PCHAR)gpvWin32kImageBase +
  1705. ImportDescriptor->Name);
  1706. if (!_strnicmp(ImportName,
  1707. asDriver.Buffer,
  1708. asDriver.Length))
  1709. {
  1710. bFoundDriver = TRUE;
  1711. break;
  1712. }
  1713. ImportDescriptor += 1;
  1714. }
  1715. }
  1716. //
  1717. // 3) Found it in both system Module list and win32k.sys static import list ?
  1718. // then gather GDISystemInformation and add pldev to gpLdevList:
  1719. if (bFoundDriver)
  1720. {
  1721. PVOID ImageBaseAddress = pModuleInformation->Modules[i].ImageBase;
  1722. ULONG_PTR EntryPoint;
  1723. ULONG Size;
  1724. pGdiDriverInfo->ExportSectionPointer = (PIMAGE_EXPORT_DIRECTORY)
  1725. RtlImageDirectoryEntryToData(ImageBaseAddress,
  1726. TRUE,
  1727. IMAGE_DIRECTORY_ENTRY_EXPORT,
  1728. &Size);
  1729. PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ImageBaseAddress);
  1730. EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint;
  1731. EntryPoint += (ULONG_PTR)ImageBaseAddress;
  1732. pGdiDriverInfo->ImageAddress = ImageBaseAddress;
  1733. pGdiDriverInfo->SectionPointer = 0;
  1734. pGdiDriverInfo->EntryPoint = (PVOID)EntryPoint;
  1735. }
  1736. if (pModuleInformation)
  1737. VFREEMEM(pModuleInformation);
  1738. if (bFreeAsDriver)
  1739. RtlFreeAnsiString(&asDriver);
  1740. if (bFoundDriver)
  1741. {
  1742. pldev->bStaticImportLink = TRUE;
  1743. goto addstaticimport;
  1744. }
  1745. }
  1746. }
  1747. //
  1748. // If MmLoadSystemImage failed to load the driver because
  1749. // of unresolved imports, this is likely an old driver
  1750. // being linked against something other than win32k.sys.
  1751. // Call user to log the error.
  1752. if (Status == STATUS_PROCEDURE_NOT_FOUND)
  1753. {
  1754. DrvLogDisplayDriverEvent(MsgInvalidOldDriver);
  1755. }
  1756. }
  1757. }
  1758. //
  1759. // Either success due to a cached entry, or failure.
  1760. // In either case, we can free all the resources we allocatred.
  1761. //
  1762. if (pGdiDriverInfo)
  1763. VFREEMEM(pGdiDriverInfo);
  1764. if (pldev)
  1765. VFREEMEM(pldev);
  1766. pldev = NULL;
  1767. }
  1768. done:
  1769. VFREEMEM(usDriverName.Buffer);
  1770. }
  1771. TRACE_INIT(("ldevLoadImage %ws with HANDLE %08lx\n",
  1772. pldev ? L"SUCCESS" : L"FAILED", pldev));
  1773. return (pldev);
  1774. }
  1775. /******************************Member*Function*****************************\
  1776. * ldevUnloadImage()
  1777. *
  1778. * Decrements the refcnt on driver usage.
  1779. * If the refcnt is zero {
  1780. * Deletes an LDEV. Disables and unloads the driver.
  1781. * }
  1782. \**************************************************************************/
  1783. VOID
  1784. ldevUnloadImage(
  1785. PLDEV pldev)
  1786. {
  1787. GDIFunctionID(ldevUnloadImage);
  1788. LPWSTR pDriverFile = NULL, pCopyDriverFile = NULL;
  1789. ULONG cbDriverFile;
  1790. //
  1791. // Hold the LDEV semaphore until after the module is unloaded.
  1792. //
  1793. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  1794. if (--pldev->cldevRefs == 0)
  1795. {
  1796. //
  1797. // Make sure that there is exactly one reference to this LDEV.
  1798. //
  1799. TRACE_INIT(("ldevUnloadImage: ENTERING\n"));
  1800. //
  1801. // Call the driver unload routine if it exists.
  1802. //
  1803. PFN_DrvDisableDriver pfnDisableDriver =
  1804. (PFN_DrvDisableDriver) pldev->apfn[INDEX_DrvDisableDriver];
  1805. if (pfnDisableDriver)
  1806. {
  1807. (*pfnDisableDriver)();
  1808. }
  1809. //
  1810. // If the module handle exists, we need to unload the module. (Does not exist
  1811. // for the statically linked font drivers).
  1812. //
  1813. if (pldev->pGdiDriverInfo)
  1814. {
  1815. //
  1816. // Tell the module to unload.
  1817. //
  1818. TRACE_INIT(("ldevUnloadImage called on Image %08lx, %ws\n",
  1819. (ULONG_PTR) pldev, pldev->pGdiDriverInfo->DriverName.Buffer));
  1820. if (!(pldev->bStaticImportLink))
  1821. {
  1822. ZwSetSystemInformation(SystemUnloadGdiDriverInformation,
  1823. &(pldev->pGdiDriverInfo->SectionPointer),
  1824. sizeof(ULONG_PTR));
  1825. }
  1826. //
  1827. // If a printer driver is being unloaded, the spooler must be informed
  1828. // so that it may perform driver upgrades.
  1829. //
  1830. if ((pldev->ldevType == LDEV_DEVICE_PRINTER) &&
  1831. (pldev->bArtificialIncrement == FALSE))
  1832. {
  1833. // Copy the driver file name into a temp buffer
  1834. // This will be used to notify the spooler of the driver unload
  1835. // from outside the semaphore
  1836. pDriverFile = pldev->pGdiDriverInfo->DriverName.Buffer;
  1837. // Check for invalid printer driver names.
  1838. if (pDriverFile && *pDriverFile)
  1839. {
  1840. // Copy the driver name into another buffer.
  1841. cbDriverFile = (wcslen(pDriverFile) + 1) * sizeof(WCHAR);
  1842. pCopyDriverFile = (LPWSTR) PALLOCMEM(cbDriverFile, 'lpsG');
  1843. if (pCopyDriverFile) {
  1844. memcpy(pCopyDriverFile, pDriverFile, cbDriverFile);
  1845. }
  1846. }
  1847. }
  1848. }
  1849. //
  1850. // Remove the ldev from the linker list.
  1851. //
  1852. if (pldev->pldevNext)
  1853. {
  1854. pldev->pldevNext->pldevPrev = pldev->pldevPrev;
  1855. }
  1856. if (pldev->pldevPrev)
  1857. {
  1858. pldev->pldevPrev->pldevNext = pldev->pldevNext;
  1859. }
  1860. else
  1861. {
  1862. gpldevDrivers = pldev->pldevNext;
  1863. }
  1864. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1865. //
  1866. // Free the ldev
  1867. //
  1868. if (pldev->pGdiDriverInfo)
  1869. {
  1870. //
  1871. // Free the memory associated with the module.
  1872. //
  1873. VFREEMEM(pldev->pGdiDriverInfo->DriverName.Buffer);
  1874. VFREEMEM(pldev->pGdiDriverInfo);
  1875. }
  1876. VFREEMEM(pldev);
  1877. }
  1878. else
  1879. {
  1880. TRACE_INIT(("ldevUnloadImage - refcount decremented\n"));
  1881. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1882. }
  1883. if (pCopyDriverFile)
  1884. {
  1885. GrePrinterDriverUnloadW(pCopyDriverFile);
  1886. VFREEMEM(pCopyDriverFile);
  1887. }
  1888. return;
  1889. }
  1890. /******************************Member*Function*****************************\
  1891. * ldevLoadDriver
  1892. *
  1893. * Locate an existing driver or load a new one. Increase its reference
  1894. * count.
  1895. *
  1896. \**************************************************************************/
  1897. PLDEV
  1898. ldevLoadDriver(
  1899. LPWSTR pwszDriver,
  1900. LDEVTYPE ldt)
  1901. {
  1902. GDIFunctionID(ldevLoadDriver);
  1903. NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  1904. PLDEV pldev;
  1905. BOOL bLoaded;
  1906. //
  1907. // Check for a bogus driver name.
  1908. //
  1909. if ((pwszDriver == NULL) ||
  1910. (*pwszDriver == L'\0'))
  1911. {
  1912. WARNING("ldevLoadDriver: bogus driver name\n");
  1913. return NULL;
  1914. }
  1915. #if DBG
  1916. //
  1917. // Check for bogus driver type
  1918. //
  1919. if ((ldt != LDEV_FONT) &&
  1920. (ldt != LDEV_DEVICE_DISPLAY) &&
  1921. (ldt != LDEV_DEVICE_PRINTER) &&
  1922. (ldt != LDEV_DEVICE_MIRROR))
  1923. {
  1924. WARNING("ldevLoadDriver: bad LDEVTYPE\n");
  1925. return NULL;
  1926. }
  1927. #endif
  1928. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  1929. pldev = ldevLoadImage(pwszDriver, FALSE, &bLoaded, TRUE);
  1930. if (pldev)
  1931. {
  1932. if (bLoaded)
  1933. {
  1934. TRACE_INIT(("ldevLoadDriver: SUCCESS, Driver already loaded\n"));
  1935. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1936. }
  1937. else
  1938. {
  1939. DRVENABLEDATA ded = {0,0,(DRVFN *) NULL};
  1940. if ((pldev->pGdiDriverInfo->EntryPoint != NULL) &&
  1941. ((PFN_DrvEnableDriver) pldev->pGdiDriverInfo->EntryPoint)(
  1942. ENGINE_VERSION, sizeof(DRVENABLEDATA), &ded) &&
  1943. (ded.iDriverVersion <= ENGINE_VERSION) &&
  1944. (ded.iDriverVersion >= ENGINE_VERSIONSUR) &&
  1945. ldevFillTable(pldev, &ded, ldt))
  1946. {
  1947. //
  1948. // Make sure the name and type of the ldev is initialized
  1949. //
  1950. pldev->ldevType = ldt;
  1951. //
  1952. // For printer drivers increment the refcnt to 2. This will keep
  1953. // the drivers loaded until they are upgraded by the spooler. The
  1954. // artificial increment will be undone when the spooler sends the
  1955. // appropriate message.
  1956. //
  1957. if (ldt == LDEV_DEVICE_PRINTER)
  1958. {
  1959. if (!pldev->bArtificialIncrement)
  1960. {
  1961. pldev->cldevRefs += 1;
  1962. pldev->bArtificialIncrement = TRUE;
  1963. }
  1964. }
  1965. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1966. #ifdef _HYDRA_
  1967. /*
  1968. * For remote video driver, call connect entry point to pass the
  1969. * Client data and the thinwire cache data area pointer.
  1970. *
  1971. * Only do this once. We don't support multiple drivers.
  1972. */
  1973. PFN_DrvConnect pConnectCall;
  1974. pConnectCall = (PFN_DrvConnect)((pldev->apfn[INDEX_DrvConnect]));
  1975. if ( pConnectCall ) {
  1976. ASSERT(gProtocolType != PROTOCOL_DISCONNECT);
  1977. BOOL Result;
  1978. Result = (*pConnectCall) (
  1979. G_RemoteConnectionChannel,
  1980. G_RemoteConnectionFileObject,
  1981. G_RemoteVideoFileObject,
  1982. G_PerformanceStatistics );
  1983. if ( !Result ) {
  1984. //
  1985. // Error exit path
  1986. //
  1987. ldevUnloadImage(pldev);
  1988. pldev = NULL;
  1989. TRACE_INIT(("LDEVREF::LDEVREF: CONNECT FAILIURE\n"));
  1990. return pldev;
  1991. }
  1992. }
  1993. #endif
  1994. TRACE_INIT(("ldevLoadDriver: SUCCESS\n"));
  1995. }
  1996. else
  1997. {
  1998. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  1999. //
  2000. // Error exit path
  2001. //
  2002. ldevUnloadImage(pldev);
  2003. pldev = NULL;
  2004. TRACE_INIT(("ldevLoadDriver: FAILURE\n"));
  2005. }
  2006. }
  2007. }
  2008. else
  2009. {
  2010. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  2011. }
  2012. return pldev;
  2013. }
  2014. /******************************Member*Function*****************************\
  2015. * ldevArtificialDecrement
  2016. *
  2017. * Removes the artificial increment on printer drivers.
  2018. *
  2019. \**************************************************************************/
  2020. BOOL
  2021. ldevArtificialDecrement(
  2022. LPWSTR pwszDriver)
  2023. {
  2024. GDIFunctionID(ldevArtificialDecrement);
  2025. PLDEV pldev = NULL, pldevList;
  2026. BOOL bReturn = FALSE;
  2027. UNICODE_STRING usDriverName;
  2028. PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo = NULL;
  2029. //
  2030. // Check for invalid driver name.
  2031. //
  2032. if (!pwszDriver || !*pwszDriver)
  2033. {
  2034. return bReturn;
  2035. }
  2036. TRACE_INIT(("ldevArtificialDecrement called on Image %ws\n", pwszDriver));
  2037. //
  2038. // Append .dll for printer drivers
  2039. //
  2040. if (MakeSystemRelativePath(pwszDriver,
  2041. &usDriverName,
  2042. TRUE))
  2043. {
  2044. //
  2045. // Check both list of drivers.
  2046. //
  2047. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  2048. pldevList = gpldevDrivers;
  2049. TRACE_INIT(("ldevArtificialDecrement - search for existing image %ws\n",
  2050. usDriverName.Buffer));
  2051. while (pldevList != NULL)
  2052. {
  2053. //
  2054. // Check for loaded printer drivers.
  2055. //
  2056. if ((pldevList->pGdiDriverInfo) &&
  2057. (pldevList->ldevType == LDEV_DEVICE_PRINTER))
  2058. {
  2059. //
  2060. // Do a case insensitive compare since the printer driver name
  2061. // can come from different locations.
  2062. //
  2063. if (RtlEqualUnicodeString(&(pldevList->pGdiDriverInfo->DriverName),
  2064. &usDriverName,
  2065. TRUE))
  2066. {
  2067. //
  2068. // If the driver is found and has an artificial increment on it,
  2069. // call ldevUnloadImage once and reset the bArtificialIncrement
  2070. // flag.
  2071. //
  2072. TRACE_INIT(("ldevArtificialIncrement found the driver.\n"));
  2073. if (pldevList->bArtificialIncrement)
  2074. {
  2075. pldev = pldevList;
  2076. pldev->bArtificialIncrement = FALSE;
  2077. }
  2078. break;
  2079. }
  2080. }
  2081. pldevList = pldevList->pldevNext;
  2082. }
  2083. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  2084. VFREEMEM(usDriverName.Buffer);
  2085. }
  2086. if (pldev)
  2087. {
  2088. // Spooler will be sent a message when the driver is unloaded.
  2089. ldevUnloadImage(pldev);
  2090. }
  2091. else
  2092. {
  2093. // Return TRUE if the driver is not loaded.
  2094. bReturn = TRUE;
  2095. }
  2096. return bReturn;
  2097. }
  2098. /******************************Public*Routine******************************\
  2099. * EngLoadImage
  2100. *
  2101. * Loads an image that a display of printers driver can then call to execute
  2102. * code
  2103. *
  2104. \**************************************************************************/
  2105. HANDLE
  2106. APIENTRY
  2107. EngLoadImage(
  2108. LPWSTR pwszDriver
  2109. )
  2110. {
  2111. GDIFunctionID(EngLoadImage);
  2112. BOOL bLoaded;
  2113. HANDLE h;
  2114. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  2115. h = ldevLoadImage(pwszDriver, TRUE, &bLoaded, TRUE);
  2116. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  2117. return h;
  2118. }
  2119. /******************************Public*Routine******************************\
  2120. * EngFindImageProcAddress
  2121. *
  2122. * Returns the address of the specified functions in the module.
  2123. * Special DrvEnableDriver since it is the entry point.
  2124. *
  2125. \**************************************************************************/
  2126. typedef struct _NEWPROCADDRESS {
  2127. LPSTR lpstrName;
  2128. PVOID pvAddress;
  2129. } NEWPROCADDRESS;
  2130. // The following define expands 'NEWPROC(x)' to '"x", x':
  2131. #define NEWPROC(x) #x, x
  2132. // Table of Eng functions that are new since NT 4.0:
  2133. NEWPROCADDRESS gaNewProcAddresses[] = {
  2134. NEWPROC(EngQueryPalette),
  2135. NEWPROC(EngSaveFloatingPointState),
  2136. NEWPROC(EngRestoreFloatingPointState),
  2137. NEWPROC(EngSetPointerShape),
  2138. NEWPROC(EngMovePointer),
  2139. NEWPROC(EngSetPointerTag),
  2140. NEWPROC(EngCreateEvent),
  2141. NEWPROC(EngDeleteEvent),
  2142. NEWPROC(EngMapEvent),
  2143. NEWPROC(EngUnmapEvent),
  2144. NEWPROC(EngSetEvent),
  2145. NEWPROC(EngClearEvent),
  2146. NEWPROC(EngReadStateEvent),
  2147. NEWPROC(EngWaitForSingleObject),
  2148. NEWPROC(EngDeleteWnd),
  2149. NEWPROC(EngInitializeSafeSemaphore),
  2150. NEWPROC(EngDeleteSafeSemaphore),
  2151. NEWPROC(HeapVidMemAllocAligned),
  2152. NEWPROC(VidMemFree),
  2153. NEWPROC(EngAlphaBlend),
  2154. NEWPROC(EngGradientFill),
  2155. NEWPROC(EngStretchBltROP),
  2156. NEWPROC(EngPlgBlt),
  2157. NEWPROC(EngTransparentBlt),
  2158. NEWPROC(EngControlSprites),
  2159. NEWPROC(EngLockDirectDrawSurface),
  2160. NEWPROC(EngUnlockDirectDrawSurface),
  2161. NEWPROC(EngMapFile),
  2162. NEWPROC(EngUnmapFile),
  2163. NEWPROC(EngDeleteFile),
  2164. NEWPROC(EngLpkInstalled),
  2165. NEWPROC(BRUSHOBJ_hGetColorTransform),
  2166. NEWPROC(XLATEOBJ_hGetColorTransform),
  2167. NEWPROC(FONTOBJ_pjOpenTypeTablePointer),
  2168. NEWPROC(FONTOBJ_pwszFontFilePaths),
  2169. NEWPROC(FONTOBJ_pfdg),
  2170. NEWPROC(FONTOBJ_pQueryGlyphAttrs),
  2171. NEWPROC(STROBJ_fxCharacterExtra),
  2172. NEWPROC(STROBJ_fxBreakExtra),
  2173. NEWPROC(STROBJ_bGetAdvanceWidths),
  2174. NEWPROC(STROBJ_bEnumPositionsOnly),
  2175. NEWPROC(EngGetPrinterDriver),
  2176. NEWPROC(EngMapFontFileFD),
  2177. NEWPROC(EngUnmapFontFileFD),
  2178. NEWPROC(EngQuerySystemAttribute),
  2179. NEWPROC(HT_Get8BPPMaskPalette),
  2180. #if !defined(_GDIPLUS_)
  2181. NEWPROC(EngGetTickCount),
  2182. NEWPROC(EngFileWrite),
  2183. NEWPROC(EngFileIoControl),
  2184. #endif
  2185. NEWPROC(EngDitherColor),
  2186. NEWPROC(EngModifySurface),
  2187. NEWPROC(EngQueryDeviceAttribute),
  2188. NEWPROC(EngHangNotification),
  2189. NEWPROC(EngNineGrid),
  2190. NEWPROC(EngBugCheckEx),
  2191. };
  2192. PVOID
  2193. APIENTRY
  2194. EngFindImageProcAddress(
  2195. HANDLE hModule,
  2196. LPSTR lpProcName
  2197. )
  2198. {
  2199. PSYSTEM_GDI_DRIVER_INFORMATION pGdiDriverInfo;
  2200. PULONG NameTableBase;
  2201. USHORT OrdinalNumber;
  2202. PUSHORT NameOrdinalTableBase;
  2203. ULONG NumberOfNames;
  2204. PULONG AddressTableBase;
  2205. ULONG i;
  2206. if (!hModule)
  2207. {
  2208. // An 'hModule' of zero means that the driver wants to find
  2209. // the address of a GDI 'Eng' function. Note that this didn't
  2210. // work in the final release of NT 4.0 (this routine would
  2211. // access violate if passed an 'hModule' of zero), so drivers
  2212. // must check GDI's engine version to make sure it's not 4.0,
  2213. // before calling this function.
  2214. //
  2215. // Unfortunately, the Base can't handle loading of 'win32k.sys'
  2216. // at the time of this writing, so we'll just special-case here
  2217. // all the Eng functions that are new since 4.0. This allows
  2218. // drivers to take advantage of NT 4.0 SP3 call-backs when
  2219. // running on SP3, but to still load and run NT 4.0 SP2.
  2220. for (i=0; i < sizeof(gaNewProcAddresses)/sizeof(NEWPROCADDRESS); i++)
  2221. {
  2222. if (!strcmp(lpProcName, gaNewProcAddresses[i].lpstrName))
  2223. {
  2224. return gaNewProcAddresses[i].pvAddress;
  2225. }
  2226. }
  2227. return NULL;
  2228. } else {
  2229. pGdiDriverInfo = ((PLDEV)hModule)->pGdiDriverInfo;
  2230. }
  2231. if (!strncmp(lpProcName,
  2232. "DrvEnableDriver",
  2233. strlen(lpProcName)))
  2234. {
  2235. return (pGdiDriverInfo->EntryPoint);
  2236. }
  2237. if (pGdiDriverInfo->ExportSectionPointer)
  2238. {
  2239. NameTableBase = (PULONG)((ULONG_PTR)pGdiDriverInfo->ImageAddress +
  2240. (ULONG)pGdiDriverInfo->ExportSectionPointer->AddressOfNames);
  2241. NameOrdinalTableBase = (PUSHORT)((ULONG_PTR)pGdiDriverInfo->ImageAddress +
  2242. (ULONG)pGdiDriverInfo->ExportSectionPointer->AddressOfNameOrdinals);
  2243. NumberOfNames = pGdiDriverInfo->ExportSectionPointer->NumberOfNames;
  2244. AddressTableBase = (PULONG)((ULONG_PTR)pGdiDriverInfo->ImageAddress +
  2245. (ULONG_PTR)pGdiDriverInfo->ExportSectionPointer->AddressOfFunctions);
  2246. for (i=0; i < NumberOfNames; i++)
  2247. {
  2248. if (!strncmp(lpProcName,
  2249. (PCHAR) (NameTableBase[i] + (ULONG_PTR)pGdiDriverInfo->ImageAddress),
  2250. strlen(lpProcName)))
  2251. {
  2252. OrdinalNumber = NameOrdinalTableBase[i];
  2253. return ((PVOID) ((ULONG_PTR)pGdiDriverInfo->ImageAddress +
  2254. AddressTableBase[OrdinalNumber]));
  2255. }
  2256. }
  2257. }
  2258. return NULL;
  2259. }
  2260. /******************************Public*Routine******************************\
  2261. * EngUnloadImage
  2262. *
  2263. * Unloads an image loaded using EngLoadImage.
  2264. *
  2265. \**************************************************************************/
  2266. VOID
  2267. APIENTRY
  2268. EngUnloadImage(
  2269. HANDLE hModule
  2270. )
  2271. {
  2272. ldevUnloadImage((PLDEV)hModule);
  2273. }
  2274. /******************************Public*Routine******************************\
  2275. * EngHangNotification
  2276. *
  2277. * This is the engine entry point to notify system that the given device
  2278. * is no longer operable or responsive.
  2279. *
  2280. * hDev must always be a valid device.
  2281. *
  2282. * This call will return EHN_RESTORED if the device has been restored to
  2283. * working order or EHN_ERROR otherwise.
  2284. *
  2285. *
  2286. * History:
  2287. * 12-Sep-2000 -by- Jason Hartman jasonha
  2288. * Wrote it.
  2289. \**************************************************************************/
  2290. ULONG
  2291. APIENTRY
  2292. EngHangNotification(
  2293. HDEV hdev,
  2294. PVOID Reserved
  2295. )
  2296. {
  2297. GDIFunctionID(EngHangNotification);
  2298. ULONG Result = EHN_ERROR;
  2299. PDEVOBJ pdo(hdev);
  2300. if (pdo.bValid())
  2301. {
  2302. PGRAPHICS_DEVICE PhysDisp = pdo.ppdev->pGraphicsDevice;
  2303. PIO_ERROR_LOG_PACKET perrLogEntry;
  2304. PCWSTR pwszDevice, pwszDesc;
  2305. ULONG cbDevice, cbDesc;
  2306. if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER ||
  2307. PhysDisp == NULL)
  2308. {
  2309. RIP("Invalid HDEV.\n");
  2310. return Result;
  2311. }
  2312. DbgPrint("GDI: EngHangNotification: %ls is not responding.\n", PhysDisp->szWinDeviceName);
  2313. pwszDevice = PhysDisp->szNtDeviceName;
  2314. cbDevice = (wcslen(pwszDevice)+1)*sizeof(WCHAR);
  2315. pwszDesc = PhysDisp->DeviceDescription;
  2316. cbDesc = (wcslen(pwszDesc)+1)*sizeof(WCHAR);
  2317. /*
  2318. * Allocate an error packet, fill it out, and write it to the log.
  2319. */
  2320. perrLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(gpWin32kDriverObject,
  2321. (UCHAR)(cbDevice + cbDesc + FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)));
  2322. if (perrLogEntry)
  2323. {
  2324. perrLogEntry->ErrorCode = STATUS_INVALID_DEVICE_STATE;
  2325. perrLogEntry->NumberOfStrings = 2;
  2326. perrLogEntry->StringOffset = FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
  2327. RtlCopyMemory(perrLogEntry->DumpData, pwszDevice, cbDevice);
  2328. RtlCopyMemory((PBYTE)perrLogEntry->DumpData + cbDevice, pwszDesc, cbDesc);
  2329. IoWriteErrorLogEntry(perrLogEntry);
  2330. }
  2331. else
  2332. {
  2333. WARNING("Failed to create error log entry.\n");
  2334. }
  2335. if (PPFNVALID(pdo,ResetDevice) &&
  2336. (*PPFNDRV(pdo,ResetDevice))(pdo.dhpdev(), NULL) == DRD_SUCCESS)
  2337. {
  2338. Result = EHN_RESTORED;
  2339. }
  2340. else
  2341. {
  2342. RIP("Unable to recover device.\n");
  2343. }
  2344. }
  2345. return Result;
  2346. }
  2347. /******************************Public*Routine******************************\
  2348. * ldevGetDriverModes
  2349. *
  2350. * Loads the device driver long enough to pass the DrvGetModes call to it.
  2351. *
  2352. \**************************************************************************/
  2353. ULONG
  2354. ldevGetDriverModes(
  2355. LPWSTR pwszDriver,
  2356. HANDLE hDriver,
  2357. PDEVMODEW *pdm
  2358. )
  2359. {
  2360. PLDEV pldev;
  2361. ULONG ulRet = 0;
  2362. TRACE_INIT(("ldevGetDriverModes: Entering\n"));
  2363. *pdm = NULL;
  2364. //
  2365. // Temporarily locate and load the driver.
  2366. //
  2367. pldev = ldevLoadDriver(pwszDriver, LDEV_DEVICE_DISPLAY);
  2368. if (pldev)
  2369. {
  2370. //
  2371. // Locate the function and call it.
  2372. //
  2373. PFN_DrvGetModes pfn = (PFN_DrvGetModes) pldev->apfn[INDEX_DrvGetModes];
  2374. if (pfn != NULL)
  2375. {
  2376. ULONG cjSize;
  2377. if (cjSize = (*pfn)(hDriver, 0, NULL)) { // get modelist size
  2378. //
  2379. // In NT4 we passed in a buffer of 64K. In NT5 we try to
  2380. // pass in a buffer size based on the number of modes the
  2381. // driver will actually use. However, some drivers are
  2382. // buggy and don't properly return the amount of buffer
  2383. // space they need. So we'll always pass in a buffer
  2384. // at least 64K in length.
  2385. //
  2386. if (pldev->ulDriverVersion < DDI_DRIVER_VERSION_NT5) {
  2387. cjSize = max(cjSize, 0x10000);
  2388. }
  2389. if (*pdm = (PDEVMODEW) PALLOCNOZ(cjSize, GDITAG_DRVSUP)) {
  2390. ulRet = (*pfn)(hDriver,cjSize,*pdm);
  2391. } else {
  2392. WARNING("ldevGetDriverModes failed to alloc mem for mode list\n");
  2393. }
  2394. }
  2395. }
  2396. ldevUnloadImage(pldev);
  2397. }
  2398. #define MAPDEVMODE_FLAGS (DM_BITSPERPEL | DM_PELSWIDTH | \
  2399. DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS)
  2400. if (ulRet)
  2401. {
  2402. if (((*pdm)->dmFields & MAPDEVMODE_FLAGS) != MAPDEVMODE_FLAGS)
  2403. {
  2404. ASSERTGDI(FALSE,"DrvGetModes did not set the dmFields value!\n");
  2405. ulRet = 0;
  2406. }
  2407. }
  2408. TRACE_INIT(("ldevGetDriverModes: Leaving\n"));
  2409. //
  2410. // Return the driver's result.
  2411. //
  2412. return(ulRet);
  2413. }
  2414. #define REGSTR_CCS L"\\Registry\\Machine\\System\\CurrentControlSet"
  2415. #define REGSTR_HP_CCS L"\\Hardware Profiles\\Current\\System\\CurrentControlSet"
  2416. /**************************************************************************\
  2417. * DrvGetRegistryHandleFromDeviceMap
  2418. *
  2419. * Gets the handle to the registry node for that driver.
  2420. *
  2421. * returns a HANDLE
  2422. *
  2423. *
  2424. * lpMatchString is passed in when the caller wants to make sure the device
  2425. * name (\Device\video0) matches a certain physical device in the registry
  2426. * (\Services\Weitekp9\Device0). We call this routine in a loop with a
  2427. * specific lpMatchString to find that device in the list in DeviceMap.
  2428. *
  2429. * 30-Nov-1992 andreva created
  2430. \**************************************************************************/
  2431. HANDLE
  2432. DrvGetRegistryHandleFromDeviceMap(
  2433. PGRAPHICS_DEVICE PhysDisp,
  2434. DISP_DRIVER_REGISTRY_TYPE ParamType,
  2435. PULONG pSubId,
  2436. LPWSTR pDriverName,
  2437. PNTSTATUS pStatus,
  2438. USHORT ProtocolType)
  2439. {
  2440. HANDLE hkRegistry = NULL;
  2441. UNICODE_STRING UnicodeString;
  2442. OBJECT_ATTRIBUTES ObjectAttributes;
  2443. NTSTATUS Status;
  2444. HANDLE handle;
  2445. ULONG cbStringSize;
  2446. WCHAR *pdriverRegistryPath = NULL;
  2447. WCHAR *pfullRegistryPath = NULL;
  2448. #ifdef _HYDRA_
  2449. WCHAR *pTerminalServerVideoRegistryPath;
  2450. #endif
  2451. TRACE_INIT(("Drv_Trace: GetHandleFromMap: Enter\n"));
  2452. //
  2453. // Initialize the handle
  2454. //
  2455. //
  2456. // Start by opening the registry devicemap for video.
  2457. //
  2458. #ifdef _HYDRA_
  2459. if ((pTerminalServerVideoRegistryPath = (WCHAR*)PALLOCMEM(256*sizeof(WCHAR), 'pmtG')) == NULL)
  2460. {
  2461. if (pStatus)
  2462. *pStatus = ERROR_NOT_ENOUGH_MEMORY;
  2463. goto Exit;
  2464. }
  2465. /*
  2466. * Look in TerminalServer VIDEO section for the video driver type as given by client.
  2467. *
  2468. */
  2469. if (ProtocolType != PROTOCOL_CONSOLE &&
  2470. ProtocolType != PROTOCOL_DISCONNECT) {
  2471. UnicodeString.Buffer = pTerminalServerVideoRegistryPath;
  2472. UnicodeString.Length = 0;
  2473. UnicodeString.MaximumLength = 255*sizeof(WCHAR);
  2474. RtlAppendUnicodeToString(&UnicodeString,
  2475. NTAPI_VIDEO_REG_NAME L"\\" );
  2476. RtlAppendUnicodeToString(&UnicodeString,
  2477. G_DisplayDriverNames);
  2478. }
  2479. else
  2480. #endif
  2481. RtlInitUnicodeString(&UnicodeString,
  2482. L"\\Registry\\Machine\\Hardware\\DeviceMap\\Video");
  2483. TRACE_INIT(("Video Registry path is %ws\n", UnicodeString.Buffer));
  2484. InitializeObjectAttributes(&ObjectAttributes,
  2485. &UnicodeString,
  2486. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  2487. NULL,
  2488. NULL);
  2489. Status = ZwOpenKey(&handle, KEY_READ, &ObjectAttributes);
  2490. if (NT_SUCCESS(Status))
  2491. {
  2492. pdriverRegistryPath = (WCHAR*)PALLOCMEM(2*256*sizeof(WCHAR), 'pmtG');
  2493. if (pdriverRegistryPath == NULL)
  2494. {
  2495. if (pStatus)
  2496. *pStatus = ERROR_NOT_ENOUGH_MEMORY;
  2497. goto Exit;
  2498. }
  2499. pfullRegistryPath = pdriverRegistryPath + 256;
  2500. if (ProtocolType != PROTOCOL_CONSOLE &&
  2501. ProtocolType != PROTOCOL_DISCONNECT) {
  2502. //
  2503. //We may have several remote display drivers
  2504. //in the same list, but only one per protocol.
  2505. //They are all registered in the registry as
  2506. //"\Device\Video0"
  2507. //
  2508. RtlInitUnicodeString(&UnicodeString,
  2509. L"\\Device\\Video0");
  2510. } else {
  2511. RtlInitUnicodeString(&UnicodeString,
  2512. PhysDisp->szNtDeviceName);
  2513. }
  2514. //
  2515. // Get the name of the driver based on the device name.
  2516. //
  2517. Status = ZwQueryValueKey(handle,
  2518. &UnicodeString,
  2519. KeyValueFullInformation,
  2520. pdriverRegistryPath,
  2521. 512,
  2522. &cbStringSize);
  2523. if (NT_SUCCESS(Status))
  2524. {
  2525. //
  2526. // Look up in the registry for the kernel driver node (it
  2527. // is a full path to the driver node) so we can get the
  2528. // display driver info.
  2529. //
  2530. LPWSTR lpstrStart;
  2531. LPWSTR lpstrDriverRegistryPath;
  2532. LPWSTR lpstrEndPath;
  2533. UNICODE_STRING FullRegistryPath;
  2534. //
  2535. // We can use wcsstr since we are guaranteed to find "Control" or
  2536. // "Services" in the string, and we won't run off the end of the
  2537. // string. Capitalize it so we don't have problems with different
  2538. // types of paths.
  2539. //
  2540. lpstrStart = (LPWSTR)((PUCHAR)pdriverRegistryPath +
  2541. ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset);
  2542. // We only want RegKey here
  2543. if (ParamType == DispDriverRegKey)
  2544. {
  2545. wcsncpy(pDriverName, lpstrStart, 127);
  2546. ZwCloseKey(handle);
  2547. if (pStatus)
  2548. *pStatus = Status;
  2549. goto Exit;
  2550. }
  2551. while (*lpstrStart)
  2552. {
  2553. *lpstrStart = (USHORT)(toupper(*lpstrStart));
  2554. lpstrStart++;
  2555. }
  2556. lpstrDriverRegistryPath = wcsstr((LPWSTR)((PUCHAR)pdriverRegistryPath +
  2557. ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset),
  2558. L"\\CONTROL\\");
  2559. if (lpstrDriverRegistryPath == NULL) {
  2560. lpstrDriverRegistryPath = wcsstr((LPWSTR)((PUCHAR)pdriverRegistryPath +
  2561. ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset),
  2562. L"\\SERVICES");
  2563. }
  2564. //
  2565. // Save the service name as the description in case it's needed
  2566. // later
  2567. //
  2568. if (pDriverName)
  2569. {
  2570. LPWSTR pName = pDriverName;
  2571. ULONG i = 31;
  2572. HANDLE CommonSubkeyHandle;
  2573. LPWSTR CommonSubkeyBuffer = NULL;
  2574. LPWSTR pSubkeyBuffer = NULL;
  2575. LONG BufferLen = 0, RegistryPathLen = 0;
  2576. //
  2577. // Get the registry path and find the last '\'
  2578. //
  2579. RegistryPathLen = wcslen((LPWSTR)((PUCHAR)pdriverRegistryPath +
  2580. ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset));
  2581. BufferLen = (max(RegistryPathLen + 6, 32) * sizeof(WCHAR));
  2582. CommonSubkeyBuffer = (LPWSTR) PALLOCMEM(BufferLen, GDITAG_DRVSUP);
  2583. if (CommonSubkeyBuffer)
  2584. {
  2585. RtlZeroMemory(CommonSubkeyBuffer, BufferLen);
  2586. wcscpy(CommonSubkeyBuffer, (LPWSTR)((PUCHAR)pdriverRegistryPath +
  2587. ((PKEY_VALUE_FULL_INFORMATION)pdriverRegistryPath)->DataOffset));
  2588. pSubkeyBuffer = CommonSubkeyBuffer + RegistryPathLen - 1;
  2589. while ((pSubkeyBuffer > CommonSubkeyBuffer) &&
  2590. (*pSubkeyBuffer != L'\\'))
  2591. {
  2592. pSubkeyBuffer--;
  2593. }
  2594. if (*pSubkeyBuffer == L'\\')
  2595. {
  2596. pSubkeyBuffer++;
  2597. //
  2598. // Open the Video subkey
  2599. //
  2600. wcscpy(pSubkeyBuffer, L"Video");
  2601. RtlInitUnicodeString(&UnicodeString, CommonSubkeyBuffer);
  2602. InitializeObjectAttributes(&ObjectAttributes,
  2603. &UnicodeString,
  2604. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2605. NULL,
  2606. NULL);
  2607. Status = ZwOpenKey(&CommonSubkeyHandle,
  2608. KEY_READ,
  2609. &ObjectAttributes);
  2610. if (NT_SUCCESS(Status))
  2611. {
  2612. ULONG cbLegacyRegistryPathSize;
  2613. //
  2614. // Get the service name
  2615. //
  2616. RtlInitUnicodeString(&UnicodeString, L"Service");
  2617. RtlZeroMemory(CommonSubkeyBuffer, BufferLen);
  2618. Status = ZwQueryValueKey(CommonSubkeyHandle,
  2619. &UnicodeString,
  2620. KeyValueFullInformation,
  2621. CommonSubkeyBuffer,
  2622. BufferLen,
  2623. &cbLegacyRegistryPathSize);
  2624. if (NT_SUCCESS(Status))
  2625. {
  2626. //
  2627. // Convert to upper chars ...
  2628. //
  2629. pSubkeyBuffer = CommonSubkeyBuffer;
  2630. while (*pSubkeyBuffer)
  2631. {
  2632. *pSubkeyBuffer = (USHORT)(toupper(*pSubkeyBuffer));
  2633. pSubkeyBuffer++;
  2634. }
  2635. //
  2636. // Copy the service name
  2637. //
  2638. pSubkeyBuffer = CommonSubkeyBuffer;
  2639. while ((i--) && (*pSubkeyBuffer != NULL))
  2640. {
  2641. *pName++ = *pSubkeyBuffer++;
  2642. if ((i == 28) && (_wcsnicmp(pDriverName, L"VGA", 3) == 0))
  2643. {
  2644. break;
  2645. }
  2646. }
  2647. }
  2648. ZwCloseKey(CommonSubkeyHandle);
  2649. }
  2650. }
  2651. else
  2652. {
  2653. //
  2654. // This should not happen ...
  2655. //
  2656. ASSERTGDI(FALSE, "invalid registry key\n");
  2657. }
  2658. VFREEMEM(CommonSubkeyBuffer);
  2659. }
  2660. *pName = UNICODE_NULL;
  2661. //
  2662. // Make sure we do not set a remote device or the disconnect device as the VGA device.
  2663. //
  2664. if (!(PhysDisp->stateFlags &(DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT) ) ) {
  2665. gPhysDispVGA = PhysDisp;
  2666. }
  2667. }
  2668. //
  2669. // This sectione is for per Monitor settings. Each monitor has UID.
  2670. // So we save under Servive\XXXX\DeviceX\UID
  2671. //
  2672. if (pSubId)
  2673. {
  2674. swprintf(lpstrDriverRegistryPath+wcslen(lpstrDriverRegistryPath),
  2675. L"\\Mon%08X",
  2676. *pSubId);
  2677. }
  2678. //
  2679. // Start composing the fully qualified path name.
  2680. //
  2681. FullRegistryPath.Buffer = pfullRegistryPath;
  2682. FullRegistryPath.Length = 0;
  2683. FullRegistryPath.MaximumLength = 255*sizeof(WCHAR);
  2684. RtlAppendUnicodeToString(&FullRegistryPath, REGSTR_CCS);
  2685. //
  2686. // If we want the hardware profile, insert the hardware profile
  2687. // in there
  2688. //
  2689. if ((ParamType == DispDriverRegHardwareProfile) ||
  2690. (ParamType == DispDriverRegHardwareProfileCreate))
  2691. {
  2692. TRACE_INIT(("Drv_Trace: GetHandleFromMap: using a hardware profile\n"));
  2693. RtlAppendUnicodeToString(&FullRegistryPath, REGSTR_HP_CCS);
  2694. }
  2695. //
  2696. // If we have the create Options, we have to create the subkeys
  2697. // otherwise, just open the key
  2698. //
  2699. InitializeObjectAttributes(&ObjectAttributes,
  2700. &FullRegistryPath,
  2701. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  2702. NULL,
  2703. NULL);
  2704. //
  2705. // Check if the subkeys need to be created.
  2706. //
  2707. if (ParamType == DispDriverRegHardwareProfileCreate)
  2708. {
  2709. TRACE_INIT(("Drv_Trace: GetHandleFromMap: creating a hardware profile\n"));
  2710. //
  2711. // We are guaranteed to go through the loop at least once,
  2712. // which will ensure the status is set properly.
  2713. //
  2714. // Basically, find the '\' replace it by NULL and add that
  2715. // partial string to the full path (so we can create that
  2716. // subkey), put back the '\' and keep on going for the next
  2717. // string. We must also add the end of the string.
  2718. //
  2719. do
  2720. {
  2721. lpstrEndPath = wcschr(lpstrDriverRegistryPath + 1, L'\\');
  2722. if (lpstrEndPath != NULL)
  2723. {
  2724. *lpstrEndPath = UNICODE_NULL;
  2725. }
  2726. RtlAppendUnicodeToString(&FullRegistryPath,
  2727. lpstrDriverRegistryPath);
  2728. //
  2729. // Close the previous key if necessary.
  2730. //
  2731. if (hkRegistry)
  2732. {
  2733. ZwCloseKey(hkRegistry);
  2734. }
  2735. //
  2736. // Create the Key.
  2737. //
  2738. Status = ZwCreateKey(&hkRegistry,
  2739. (ACCESS_MASK) NULL,
  2740. &ObjectAttributes,
  2741. 0,
  2742. NULL,
  2743. 0,
  2744. NULL);
  2745. if (!NT_SUCCESS(Status))
  2746. {
  2747. hkRegistry = NULL;
  2748. break;
  2749. }
  2750. //
  2751. // Check to see if we need to loop again.
  2752. //
  2753. if (lpstrEndPath == NULL)
  2754. {
  2755. break;
  2756. }
  2757. else
  2758. {
  2759. *lpstrEndPath = L'\\';
  2760. lpstrDriverRegistryPath = lpstrEndPath;
  2761. }
  2762. } while(1);
  2763. if (!NT_SUCCESS(Status))
  2764. {
  2765. TRACE_INIT(("Drv_Trace: GetHandleFromMap: failed to create key\n"));
  2766. }
  2767. }
  2768. else
  2769. {
  2770. RtlAppendUnicodeToString(&FullRegistryPath,
  2771. lpstrDriverRegistryPath);
  2772. Status = ZwOpenKey(&hkRegistry, KEY_READ, &ObjectAttributes);
  2773. if (!NT_SUCCESS(Status))
  2774. {
  2775. TRACE_INIT(("Drv_Trace: GetHandleFromMap: failed to open key\n"));
  2776. //
  2777. // We set this special status so the looping code in the
  2778. // video port can handle unconfigured devices properly
  2779. // (in the case where the second video card entry may not
  2780. // be present).
  2781. //
  2782. Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  2783. }
  2784. }
  2785. TRACE_INIT(("Drv_Trace: GetHandleFromMap: reg-key path =\n\t%ws\n",
  2786. pfullRegistryPath));
  2787. }
  2788. ZwCloseKey(handle);
  2789. }
  2790. if (!NT_SUCCESS(Status))
  2791. {
  2792. TRACE_INIT(("Drv_Trace: GetHandleFromMap: Error opening registry - status = %08lx\n",
  2793. Status));
  2794. }
  2795. if (pStatus)
  2796. {
  2797. *pStatus = Status;
  2798. }
  2799. TRACE_INIT(("Drv_Trace: GetHandleFromMap: Exit\n\n"));
  2800. Exit:
  2801. #ifdef _HYDRA_
  2802. if (pTerminalServerVideoRegistryPath)
  2803. VFREEMEM(pTerminalServerVideoRegistryPath);
  2804. #endif
  2805. if (pdriverRegistryPath)
  2806. VFREEMEM(pdriverRegistryPath);
  2807. return hkRegistry;
  2808. }
  2809. /**************************************************************************\
  2810. * DrvPrepareForEARecovery
  2811. *
  2812. * Remove all devices other than the VGA device from the graphics
  2813. * device list.
  2814. *
  2815. * In multi-mon we could just disable the now "dead" display. In single
  2816. * mon we need to disable the "high-res" display and switch to VGA.
  2817. *
  2818. * 27-Mar-2002 ericks created
  2819. \**************************************************************************/
  2820. VOID
  2821. DrvPrepareForEARecovery(
  2822. VOID
  2823. )
  2824. {
  2825. ULONG ulBytes;
  2826. if (gPhysDispVGA) {
  2827. GreDeviceIoControl(gPhysDispVGA->pDeviceHandle,
  2828. IOCTL_VIDEO_PREPARE_FOR_EARECOVERY,
  2829. NULL,
  2830. 0,
  2831. NULL,
  2832. 0,
  2833. &ulBytes);
  2834. }
  2835. return;
  2836. }
  2837. /**************************************************************************\
  2838. * DrvGetDisplayDriverNames
  2839. *
  2840. * Get the display driver name out of the registry.
  2841. *
  2842. * 12-Jan-1994 andreva created
  2843. \**************************************************************************/
  2844. typedef struct _DRV_NAMES {
  2845. ULONG cNames;
  2846. struct {
  2847. HANDLE hDriver;
  2848. LPWSTR lpDisplayName;
  2849. } D[1];
  2850. } DRV_NAMES, *PDRV_NAMES;
  2851. PDRV_NAMES
  2852. DrvGetDisplayDriverNames(
  2853. PGRAPHICS_DEVICE PhysDisp
  2854. )
  2855. {
  2856. DWORD status;
  2857. LPWSTR lptmpdisplay;
  2858. DWORD cCountNames;
  2859. DWORD cCountNamesDevice;
  2860. PDRV_NAMES lpNames = NULL;
  2861. ULONG cb = 0;
  2862. ULONG cbVga = 0;
  2863. //
  2864. // At this point, create the array, and put in the VGA driver
  2865. // if necessary. (We morphed this from the ModeX hack.)
  2866. //
  2867. if (PhysDisp->DisplayDriverNames)
  2868. {
  2869. //
  2870. // Count the names in the list (first for PhysDisp)
  2871. //
  2872. cCountNames = 0;
  2873. lptmpdisplay = PhysDisp->DisplayDriverNames;
  2874. while (*lptmpdisplay != UNICODE_NULL)
  2875. {
  2876. cCountNames++;
  2877. while (*lptmpdisplay != UNICODE_NULL)
  2878. {
  2879. lptmpdisplay++;
  2880. cb += 2;
  2881. }
  2882. lptmpdisplay++;
  2883. cb += 2;
  2884. }
  2885. //
  2886. // Track the number of display driver names for the root device
  2887. //
  2888. cCountNamesDevice = cCountNames;
  2889. //
  2890. // Now if this PhysDisp is associated with the VGA, then add
  2891. // the VGA display drivers as well.
  2892. //
  2893. if (PhysDisp->pVgaDevice &&
  2894. gFullscreenGraphicsDevice.pDeviceHandle &&
  2895. PhysDisp->pVgaDevice->DisplayDriverNames) {
  2896. lptmpdisplay = PhysDisp->pVgaDevice->DisplayDriverNames;
  2897. while (*lptmpdisplay != UNICODE_NULL)
  2898. {
  2899. cCountNames++;
  2900. while (*lptmpdisplay != UNICODE_NULL)
  2901. {
  2902. lptmpdisplay++;
  2903. cbVga += 2;
  2904. }
  2905. lptmpdisplay++;
  2906. cbVga += 2;
  2907. }
  2908. cbVga += 2;
  2909. }
  2910. //
  2911. // Alocate the names structure.
  2912. //
  2913. if (lpNames = (PDRV_NAMES) PALLOCNOZ(cb + cbVga + 2 + sizeof(DRV_NAMES) *
  2914. (cCountNames + 1),
  2915. GDITAG_DRVSUP))
  2916. {
  2917. lptmpdisplay = (LPWSTR) (((PUCHAR)lpNames) +
  2918. sizeof(DRV_NAMES) * (cCountNames + 1));
  2919. RtlCopyMemory(lptmpdisplay,
  2920. PhysDisp->DisplayDriverNames,
  2921. cb + 2);
  2922. if (cbVga) {
  2923. RtlCopyMemory((LPWSTR)((ULONG_PTR)lptmpdisplay + cb),
  2924. PhysDisp->pVgaDevice->DisplayDriverNames,
  2925. cbVga + 2);
  2926. }
  2927. //
  2928. // Set all the names pointers in the names structure
  2929. //
  2930. lpNames->cNames = 0;
  2931. while (*lptmpdisplay != UNICODE_NULL)
  2932. {
  2933. lpNames->D[lpNames->cNames].lpDisplayName = lptmpdisplay;
  2934. if (lpNames->cNames < cCountNamesDevice) {
  2935. lpNames->D[lpNames->cNames].hDriver = PhysDisp->pDeviceHandle;
  2936. } else {
  2937. lpNames->D[lpNames->cNames].hDriver = PhysDisp->pVgaDevice->pDeviceHandle;
  2938. //
  2939. // For now, only return the first in the list of vga
  2940. // display driver names (vga.dll)
  2941. //
  2942. lpNames->cNames++;
  2943. break;
  2944. }
  2945. lpNames->cNames++;
  2946. while (*lptmpdisplay != UNICODE_NULL)
  2947. {
  2948. lptmpdisplay++;
  2949. }
  2950. lptmpdisplay++;
  2951. }
  2952. }
  2953. }
  2954. return lpNames;
  2955. }
  2956. //
  2957. // We need to update monitor PDOs whenever reenumaration of devices has been occured
  2958. // This function has to be called every time before PhysDisp->MonitorDevices is to be used
  2959. //
  2960. VOID UpdateMonitorDevices(VOID)
  2961. {
  2962. PGRAPHICS_DEVICE PhysDisp;
  2963. ULONG numMonitorDevice, i;
  2964. for (PhysDisp = gpGraphicsDeviceList;
  2965. PhysDisp != NULL;
  2966. PhysDisp = PhysDisp->pNextGraphicsDevice)
  2967. {
  2968. PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL;
  2969. BOOL bNoMonitor = TRUE;
  2970. if ((PhysDisp->pDeviceHandle != NULL ) &&
  2971. NT_SUCCESS(GreDeviceIoControl(PhysDisp->pDeviceHandle,
  2972. IOCTL_VIDEO_ENUM_MONITOR_PDO,
  2973. NULL,
  2974. 0,
  2975. &pMonitorDevices,
  2976. sizeof(PVOID),
  2977. &numMonitorDevice))
  2978. )
  2979. {
  2980. if (pMonitorDevices != NULL)
  2981. {
  2982. numMonitorDevice = 0;
  2983. while (pMonitorDevices[numMonitorDevice].pdo != NULL)
  2984. {
  2985. ObDereferenceObject(pMonitorDevices[numMonitorDevice].pdo);
  2986. numMonitorDevice++;
  2987. }
  2988. //
  2989. // The buffer always grows
  2990. //
  2991. if (PhysDisp->numMonitorDevice < numMonitorDevice)
  2992. {
  2993. if (PhysDisp->MonitorDevices)
  2994. {
  2995. VFREEMEM(PhysDisp->MonitorDevices);
  2996. }
  2997. PhysDisp->MonitorDevices = (PVIDEO_MONITOR_DEVICE)PALLOCMEM(sizeof(VIDEO_MONITOR_DEVICE) * numMonitorDevice,
  2998. GDITAG_GDEVICE);
  2999. //
  3000. // If fail, do cleanup here
  3001. //
  3002. if (PhysDisp->MonitorDevices == NULL)
  3003. {
  3004. PhysDisp->numMonitorDevice = 0;
  3005. ExFreePool(pMonitorDevices);
  3006. return;
  3007. }
  3008. }
  3009. PhysDisp->numMonitorDevice = numMonitorDevice;
  3010. for (i = 0; i < numMonitorDevice; i++)
  3011. {
  3012. PhysDisp->MonitorDevices[i].flag = 0;
  3013. if (pMonitorDevices[i].flag & VIDEO_CHILD_ACTIVE) {
  3014. PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_ACTIVE;
  3015. }
  3016. if ((pMonitorDevices[i].flag & VIDEO_CHILD_DETACHED) == 0) {
  3017. PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_ATTACHED;
  3018. }
  3019. if ((pMonitorDevices[i].flag & VIDEO_CHILD_NOPRUNE_FREQ) == 0) {
  3020. PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_PRUNE_FREQ;
  3021. }
  3022. if ((pMonitorDevices[i].flag & VIDEO_CHILD_NOPRUNE_RESOLUTION) == 0) {
  3023. PhysDisp->MonitorDevices[i].flag |= DISPLAY_DEVICE_PRUNE_RESOLUTION;
  3024. }
  3025. PhysDisp->MonitorDevices[i].pdo = pMonitorDevices[i].pdo;
  3026. PhysDisp->MonitorDevices[i].HwID = pMonitorDevices[i].HwID;
  3027. bNoMonitor = FALSE;
  3028. }
  3029. ExFreePool(pMonitorDevices);
  3030. }
  3031. }
  3032. if (bNoMonitor)
  3033. {
  3034. if (PhysDisp->MonitorDevices)
  3035. {
  3036. VFREEMEM(PhysDisp->MonitorDevices);
  3037. }
  3038. PhysDisp->numMonitorDevice = 0;
  3039. PhysDisp->MonitorDevices = NULL;
  3040. }
  3041. }
  3042. }
  3043. VOID
  3044. dbgDumpDevmode(
  3045. PDEVMODEW pdm
  3046. )
  3047. {
  3048. TRACE_INIT((" Size = %d\n", pdm->dmSize));
  3049. TRACE_INIT((" Fields = %08lx\n", pdm->dmFields));
  3050. TRACE_INIT((" XPosition = %d\n", pdm->dmPosition.x));
  3051. TRACE_INIT((" YPosition = %d\n", pdm->dmPosition.y));
  3052. TRACE_INIT((" Orientation = %d\n", pdm->dmDisplayOrientation));
  3053. TRACE_INIT((" FixedOutput = %d\n", pdm->dmDisplayFixedOutput));
  3054. TRACE_INIT((" XResolution = %d\n", pdm->dmPelsWidth));
  3055. TRACE_INIT((" YResolution = %d\n", pdm->dmPelsHeight));
  3056. TRACE_INIT((" Bpp = %d\n", pdm->dmBitsPerPel));
  3057. TRACE_INIT((" Frequency = %d\n", pdm->dmDisplayFrequency));
  3058. TRACE_INIT((" Flags = %d\n", pdm->dmDisplayFlags));
  3059. TRACE_INIT((" XPanning = %d\n", pdm->dmPanningWidth));
  3060. TRACE_INIT((" YPanning = %d\n", pdm->dmPanningHeight));
  3061. TRACE_INIT((" DPI = %d\n", pdm->dmLogPixels));
  3062. TRACE_INIT((" DriverExtra = %d", pdm->dmDriverExtra));
  3063. if (pdm->dmDriverExtra)
  3064. {
  3065. TRACE_INIT((" - %08lx %08lx\n",
  3066. *(PULONG)(((PUCHAR)pdm)+pdm->dmSize),
  3067. *(PULONG)(((PUCHAR)pdm)+pdm->dmSize + 4)));
  3068. }
  3069. else
  3070. {
  3071. TRACE_INIT(("\n"));
  3072. }
  3073. }
  3074. #define NUM_DISPLAY_PARAMETERS 13
  3075. #define NUM_DISPLAY_DRIVER_EXTRA (NUM_DISPLAY_PARAMETERS - 1)
  3076. static
  3077. LPWSTR DefaultSettings[NUM_DISPLAY_PARAMETERS] = {
  3078. L"DefaultSettings.BitsPerPel",
  3079. L"DefaultSettings.XResolution",
  3080. L"DefaultSettings.YResolution",
  3081. L"DefaultSettings.VRefresh",
  3082. L"DefaultSettings.Flags",
  3083. L"DefaultSettings.XPanning",
  3084. L"DefaultSettings.YPanning",
  3085. L"DefaultSettings.Orientation",
  3086. L"DefaultSettings.FixedOutput",
  3087. L"Attach.RelativeX",
  3088. L"Attach.RelativeY",
  3089. L"Attach.ToDesktop",
  3090. L"DefaultSettings.DriverExtra" // MUST be at the end
  3091. };
  3092. static
  3093. LPWSTR AttachedSettings[] = {
  3094. L"Attach.PrimaryDevice",
  3095. L"Attach.ToDesktop",
  3096. };
  3097. static
  3098. LPWSTR SoftwareSettings[] = {
  3099. L"DriverDesc",
  3100. L"InstalledDisplayDrivers",
  3101. L"MultiDisplayDriver",
  3102. L"MirrorDriver",
  3103. L"VgaCompatible",
  3104. L"Device Description",
  3105. L"HardwareInformation.AdapterString",
  3106. L"HardwareInformation.ChipType",
  3107. };
  3108. NTSTATUS
  3109. DrvDriverExtraCallback(
  3110. PWSTR ValueName,
  3111. ULONG ValueType,
  3112. PVOID ValueData,
  3113. ULONG ValueLength,
  3114. PVOID Context,
  3115. PVOID EntryContext)
  3116. {
  3117. PDEVMODEW pdevmode = (PDEVMODEW) EntryContext;
  3118. //
  3119. // Put the driver extra data in the right place, if necessary.
  3120. //
  3121. pdevmode->dmDriverExtra = min(pdevmode->dmDriverExtra, (USHORT)ValueLength);
  3122. RtlMoveMemory(pdevmode+1,
  3123. ValueData,
  3124. pdevmode->dmDriverExtra);
  3125. return STATUS_SUCCESS;
  3126. UNREFERENCED_PARAMETER(Context);
  3127. UNREFERENCED_PARAMETER(ValueType);
  3128. UNREFERENCED_PARAMETER(ValueName);
  3129. }
  3130. /**************************************************************************\
  3131. * DrvGetDisplayDriverParameters
  3132. *
  3133. * Reads the resolution parameters from the registry.
  3134. *
  3135. * NOTE:
  3136. * We assume the caller has initialized the DEVMODE to zero,
  3137. * and that the DEVMODE is the current size for the system.
  3138. * We only look at the dmDriverExtra field to determine any extra size.
  3139. * We do check the dmSize for debugging purposes.
  3140. *
  3141. * CRIT not needed
  3142. *
  3143. * 25-Jan-1995 andreva created
  3144. \**************************************************************************/
  3145. NTSTATUS
  3146. DrvGetDisplayDriverParameters(
  3147. PGRAPHICS_DEVICE PhysDisp,
  3148. PDEVMODEW pdevmode,
  3149. BOOL bEmptyDevmode,
  3150. BOOL bFromMonitor
  3151. )
  3152. {
  3153. ULONG i, k;
  3154. NTSTATUS retStatus;
  3155. HANDLE hkRegistry;
  3156. ULONG attached = 0;
  3157. DISP_DRIVER_REGISTRY_TYPE registryParam = DispDriverRegHardwareProfile;
  3158. DWORD nullValue = 0;
  3159. //
  3160. // Our current algorithm is to save or get things from the hardware profile
  3161. // first, and then try the global profile as a backup.
  3162. //
  3163. // NOTE ??? For saving, should we always back propagate the changes to the
  3164. // global settings also ? We do this at this point.
  3165. //
  3166. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  3167. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmBitsPerPel,
  3168. REG_NONE, NULL, 0},
  3169. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPelsWidth,
  3170. REG_NONE, NULL, 0},
  3171. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPelsHeight,
  3172. REG_NONE, NULL, 0},
  3173. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFrequency,
  3174. REG_NONE, NULL, 0},
  3175. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFlags,
  3176. REG_NONE, NULL, 0},
  3177. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPanningWidth,
  3178. REG_NONE, NULL, 0},
  3179. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPanningHeight,
  3180. REG_NONE, NULL, 0},
  3181. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayOrientation,
  3182. REG_NONE, NULL, 0},
  3183. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmDisplayFixedOutput,
  3184. REG_NONE, NULL, 0},
  3185. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPosition.x,
  3186. REG_NONE, NULL, 0},
  3187. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &pdevmode->dmPosition.y,
  3188. REG_NONE, NULL, 0},
  3189. {NULL, RTL_QUERY_REGISTRY_DIRECT, NULL, &attached,
  3190. REG_NONE, NULL, 0},
  3191. // if the value is not there, we want the call to succeed anyway.
  3192. // so specify a vlue that is NULL modulo 64K !
  3193. {DrvDriverExtraCallback, 0, NULL, pdevmode,
  3194. REG_DWORD, &nullValue, 0x10000},
  3195. {NULL, 0, NULL}
  3196. };
  3197. TRACE_INIT(("Drv_Trace: GetDriverParams\n"));
  3198. //
  3199. // Special debug code to ensure that anyone who calls this API
  3200. // knows what they are doing, and we don't end up in here with a
  3201. // "random" devmode that does not ensure sizes.
  3202. //
  3203. ASSERTGDI(pdevmode->dmSize == 0xDDDD, "DEVMODE not set to DDDD\n");
  3204. //
  3205. // If there is no place for the Driver Extra data, don't ask for it.
  3206. // This will just cause the code not to read that value
  3207. //
  3208. if (pdevmode->dmDriverExtra == 0)
  3209. {
  3210. QueryTable[NUM_DISPLAY_PARAMETERS - 1].Flags = 0;
  3211. pdevmode->dmDriverExtra = 0;
  3212. }
  3213. //
  3214. // We assume that the DEVMODE was previously zeroed out by the caller
  3215. //
  3216. retStatus = STATUS_SUCCESS;
  3217. if (bEmptyDevmode)
  3218. {
  3219. //
  3220. // We want an empty DEVMODE (except for the LogPixels).
  3221. //
  3222. TRACE_INIT(("Drv_Trace: GetDriverParams: Default (empty) DEVMODE\n"));
  3223. RtlZeroMemory(pdevmode, sizeof(DEVMODEW));
  3224. }
  3225. else
  3226. {
  3227. #if LATER
  3228. //
  3229. // Let's try to get the per-user settings first.
  3230. //
  3231. TRACE_INIT(("Drv_Trace: GetDriverParams: USER Settings\n"));
  3232. for (i=0; i < NUM_DISPLAY_PARAMETERS; i++)
  3233. {
  3234. QueryTable[i].Name = DefaultSettings[i];
  3235. }
  3236. retStatus = RtlQueryRegistryValues(RTL_REGISTRY_USER,
  3237. NULL,
  3238. &QueryTable[0],
  3239. NULL,
  3240. NULL);
  3241. if (!NT_SUCCESS(retStatus))
  3242. #endif
  3243. TRACE_INIT(("Drv_Trace: GetDriverParams: Hardware Profile Settings\n"));
  3244. for (i = 0; i < NUM_DISPLAY_PARAMETERS; i++)
  3245. QueryTable[i].Name = (PWSTR)DefaultSettings[i];
  3246. if (bFromMonitor)
  3247. {
  3248. //
  3249. // We retrieve from per-monitor settings first, only if failed then we go to old registry
  3250. // And if we have multiple active monitors, we pick the smaller mode
  3251. //
  3252. UpdateMonitorDevices();
  3253. DEVMODEW tmpDevMode, pickedDevMode;
  3254. // Save original pdevmode away. We are using pdevmode to retrieve registry
  3255. RtlCopyMemory(&tmpDevMode, pdevmode, sizeof(DEVMODEW));
  3256. pdevmode->dmBitsPerPel = 0;
  3257. pdevmode->dmPelsWidth = 0;
  3258. pdevmode->dmPelsHeight = 0;
  3259. pdevmode->dmDisplayFrequency = 0;
  3260. pdevmode->dmDisplayFlags = 0;
  3261. pdevmode->dmPanningWidth = 0;
  3262. pdevmode->dmPanningHeight = 0;
  3263. pdevmode->dmPosition.x = 0;
  3264. pdevmode->dmPosition.y = 0;
  3265. pdevmode->dmDisplayOrientation = 0;
  3266. pdevmode->dmDisplayFixedOutput = 0;
  3267. RtlZeroMemory(&pickedDevMode, sizeof(DEVMODEW));
  3268. k = PhysDisp->numMonitorDevice;
  3269. for (i = 0; i < PhysDisp->numMonitorDevice; i++)
  3270. {
  3271. if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag))
  3272. {
  3273. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  3274. registryParam,
  3275. &PhysDisp->MonitorDevices[i].HwID,
  3276. NULL,
  3277. NULL,
  3278. gProtocolType);
  3279. if (hkRegistry)
  3280. {
  3281. retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  3282. (PWSTR)hkRegistry,
  3283. &QueryTable[0],
  3284. NULL,
  3285. NULL);
  3286. ZwCloseKey(hkRegistry);
  3287. }
  3288. else
  3289. continue;
  3290. if (!NT_SUCCESS(retStatus))
  3291. continue;
  3292. if ((pdevmode->dmBitsPerPel == 0) ||
  3293. (pdevmode->dmPelsWidth == 0) ||
  3294. (pdevmode->dmPelsHeight == 0)
  3295. )
  3296. continue;
  3297. //
  3298. // Pick the smallest mode
  3299. //
  3300. if (pickedDevMode.dmPelsWidth == 0 ||
  3301. pdevmode->dmPelsWidth < pickedDevMode.dmPelsWidth ||
  3302. (pdevmode->dmPelsWidth == pickedDevMode.dmPelsWidth &&
  3303. pdevmode->dmPelsHeight < pickedDevMode.dmPelsHeight)
  3304. )
  3305. {
  3306. k = i;
  3307. pickedDevMode.dmPelsWidth = pdevmode->dmPelsWidth;
  3308. pickedDevMode.dmPelsHeight = pdevmode->dmPelsHeight;
  3309. }
  3310. }
  3311. }
  3312. // Restore original pdevmode
  3313. pdevmode->dmDriverExtra = tmpDevMode.dmDriverExtra;
  3314. pdevmode->dmBitsPerPel = tmpDevMode.dmBitsPerPel;
  3315. pdevmode->dmPelsWidth = tmpDevMode.dmPelsWidth;
  3316. pdevmode->dmPelsHeight = tmpDevMode.dmPelsHeight;
  3317. pdevmode->dmDisplayFrequency = tmpDevMode.dmDisplayFrequency;
  3318. pdevmode->dmDisplayFlags = tmpDevMode.dmDisplayFlags;
  3319. pdevmode->dmPanningWidth = tmpDevMode.dmPanningWidth;
  3320. pdevmode->dmPanningHeight = tmpDevMode.dmPanningHeight;
  3321. pdevmode->dmPosition.x = tmpDevMode.dmPosition.x;
  3322. pdevmode->dmPosition.y = tmpDevMode.dmPosition.y;
  3323. pdevmode->dmDisplayOrientation = tmpDevMode.dmDisplayOrientation;
  3324. pdevmode->dmDisplayFixedOutput = tmpDevMode.dmDisplayFixedOutput;
  3325. }
  3326. if (k < PhysDisp->numMonitorDevice && bFromMonitor)
  3327. {
  3328. //
  3329. // Come here if we succeed to get per monitor settings
  3330. //
  3331. retStatus = STATUS_UNSUCCESSFUL;
  3332. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  3333. registryParam,
  3334. &PhysDisp->MonitorDevices[k].HwID,
  3335. NULL,
  3336. NULL,
  3337. gProtocolType );
  3338. if (hkRegistry)
  3339. {
  3340. retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  3341. (PWSTR)hkRegistry,
  3342. &QueryTable[0],
  3343. NULL,
  3344. NULL);
  3345. ZwCloseKey(hkRegistry);
  3346. }
  3347. if (!NT_SUCCESS(retStatus))
  3348. {
  3349. ASSERTGDI(FALSE, "Failed to get Monitor Settings\n");
  3350. return retStatus;
  3351. }
  3352. }
  3353. else
  3354. {
  3355. //
  3356. // If we failed to get per monitor settings,
  3357. // try the hardware profile first and see if we can get parameters
  3358. // from that. If that fails, fall back to getting the system
  3359. // parameters.
  3360. //
  3361. for (k=1; k<=2; k++)
  3362. {
  3363. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  3364. registryParam,
  3365. NULL,
  3366. NULL,
  3367. NULL,
  3368. gProtocolType);
  3369. if (hkRegistry == NULL)
  3370. {
  3371. TRACE_INIT(("Drv_Trace: GetDriverParams: failed - registry could not be opened\n"));
  3372. retStatus = STATUS_UNSUCCESSFUL;
  3373. }
  3374. else
  3375. {
  3376. retStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  3377. (PWSTR)hkRegistry,
  3378. &QueryTable[0],
  3379. NULL,
  3380. NULL);
  3381. ZwCloseKey(hkRegistry);
  3382. }
  3383. //
  3384. // If something failed for the hardware profile, try
  3385. // to get the global settings
  3386. // If everything is OK, just exit the loop
  3387. //
  3388. if (NT_SUCCESS(retStatus))
  3389. {
  3390. break;
  3391. }
  3392. else
  3393. {
  3394. TRACE_INIT(("Drv_Trace: GetDriverParams: get hardware profile failed - try global settings\n"));
  3395. registryParam = DispDriverRegGlobal;
  3396. }
  3397. }
  3398. }
  3399. //
  3400. // AndreVa - do we still need this information passed back to the
  3401. // applet ?
  3402. //
  3403. //
  3404. // Other common fields to the DEVMODEs
  3405. //
  3406. if (NT_SUCCESS(retStatus))
  3407. {
  3408. //
  3409. // Lets check if the DEVMODE we got is all NULLs (like when
  3410. // the driver just got installed).
  3411. // If it is, the driver should be reconfigured
  3412. //
  3413. // We will only do this if we are NOT in BaseVideo, since the VGA
  3414. // BaseVideo driver need not be configured.
  3415. //
  3416. if ((attached) &&
  3417. (pdevmode->dmBitsPerPel == 0) &&
  3418. (pdevmode->dmPelsWidth == 0) &&
  3419. (pdevmode->dmPelsHeight == 0) &&
  3420. (pdevmode->dmDisplayFrequency == 0) &&
  3421. (pdevmode->dmDisplayFlags == 0) &&
  3422. (gbBaseVideo == FALSE))
  3423. {
  3424. DrvLogDisplayDriverEvent(MsgInvalidUsingDefaultMode);
  3425. }
  3426. }
  3427. }
  3428. //
  3429. // Let's fill out all the other fields of the DEVMODE that ALWAYS
  3430. // need to be initialized.
  3431. //
  3432. if (NT_SUCCESS(retStatus))
  3433. {
  3434. //
  3435. // Set versions and size.
  3436. //
  3437. pdevmode->dmSpecVersion = DM_SPECVERSION;
  3438. pdevmode->dmDriverVersion = DM_SPECVERSION;
  3439. pdevmode->dmSize = sizeof(DEVMODEW);
  3440. //
  3441. // Currently, the logpixel value should not be changed on the fly.
  3442. // So once it has been read out of the registry at boot time, keep
  3443. // that same value and ignore the registry.
  3444. //
  3445. if (gdmLogPixels)
  3446. {
  3447. pdevmode->dmLogPixels = gdmLogPixels;
  3448. }
  3449. else
  3450. {
  3451. //
  3452. // Get the devices pelDPI out of the registry
  3453. //
  3454. UNICODE_STRING us;
  3455. OBJECT_ATTRIBUTES ObjectAttributes;
  3456. NTSTATUS Status;
  3457. HANDLE hKey;
  3458. DWORD cbSize;
  3459. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  3460. pdevmode->dmLogPixels = 96;
  3461. //
  3462. // Look in the Hardware Profile for the current font size.
  3463. // If that fails, look in the global software location.
  3464. //
  3465. RtlInitUnicodeString(&us, L"\\Registry\\Machine\\System"
  3466. L"\\CurrentControlSet\\Hardware Profiles"
  3467. L"\\Current\\Software\\Fonts");
  3468. InitializeObjectAttributes(&ObjectAttributes,
  3469. &us,
  3470. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  3471. NULL,
  3472. NULL);
  3473. Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  3474. if (!NT_SUCCESS(Status))
  3475. {
  3476. RtlInitUnicodeString(&us, L"\\Registry\\Machine\\Software"
  3477. L"\\Microsoft\\Windows NT"
  3478. L"\\CurrentVersion\\FontDPI");
  3479. InitializeObjectAttributes(&ObjectAttributes,
  3480. &us,
  3481. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  3482. NULL,
  3483. NULL);
  3484. Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  3485. }
  3486. if (NT_SUCCESS(Status))
  3487. {
  3488. RtlInitUnicodeString(&us, L"LogPixels");
  3489. Status = ZwQueryValueKey(hKey,
  3490. &us,
  3491. KeyValuePartialInformation,
  3492. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  3493. sizeof(Buf),
  3494. &cbSize);
  3495. if (NT_SUCCESS(Status))
  3496. {
  3497. pdevmode->dmLogPixels =
  3498. *((PUSHORT)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  3499. }
  3500. ZwCloseKey(hKey);
  3501. }
  3502. //
  3503. // For non high-res mode, let's force small font size so
  3504. // that various dialogs are not clipped out.
  3505. //
  3506. if (pdevmode->dmPelsHeight < 600)
  3507. {
  3508. pdevmode->dmLogPixels = 96;
  3509. }
  3510. gdmLogPixels = pdevmode->dmLogPixels;
  3511. }
  3512. //
  3513. // Set all the appropriate DEVMODE flags.
  3514. //
  3515. pdevmode->dmFields = DM_INTERNAL_VALID_FLAGS;
  3516. if (attached)
  3517. {
  3518. pdevmode->dmFields |= DM_POSITION;
  3519. }
  3520. if (pdevmode->dmDisplayFixedOutput != DMDFO_DEFAULT)
  3521. {
  3522. pdevmode->dmFields |= DM_DISPLAYFIXEDOUTPUT;
  3523. }
  3524. TRACE_INIT(("Drv_Trace: GetDriverParams: DEVMODE\n"));
  3525. dbgDumpDevmode(pdevmode);
  3526. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) != 0 )
  3527. {
  3528. DEVMODEW disconnectDevmode;
  3529. disconnectDevmode.dmFields = 0;
  3530. UserGetDisconnectDeviceResolutionHint(&disconnectDevmode);
  3531. if (disconnectDevmode.dmFields & DM_PELSWIDTH && disconnectDevmode.dmFields & DM_PELSHEIGHT)
  3532. {
  3533. pdevmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
  3534. pdevmode->dmPelsWidth = disconnectDevmode.dmPelsWidth;
  3535. pdevmode->dmPelsHeight = disconnectDevmode.dmPelsHeight;
  3536. }
  3537. }
  3538. }
  3539. else
  3540. {
  3541. TRACE_INIT(("Drv_Trace: GetSetParms: Get failed\n\n"));
  3542. }
  3543. TRACE_INIT(("Drv_Trace: GetDriverParams: Exit\n\n"));
  3544. return (retStatus);
  3545. }
  3546. /**************************************************************************\
  3547. * DrvWriteDisplayDriverParameters
  3548. *
  3549. * Wites the resolution parameters to the registry.
  3550. *
  3551. * 13-Mar-1996 andreva created
  3552. \**************************************************************************/
  3553. NTSTATUS
  3554. DrvWriteDisplayDriverParameters(
  3555. ULONG RelativeTo,
  3556. PWSTR Path,
  3557. PDEVMODEW pdevmode,
  3558. BOOL bDetach)
  3559. {
  3560. ULONG i;
  3561. NTSTATUS retStatus = STATUS_SUCCESS;
  3562. DWORD data[NUM_DISPLAY_DRIVER_EXTRA];
  3563. DWORD numData = NUM_DISPLAY_DRIVER_EXTRA - 1;
  3564. DWORD dataval;
  3565. //
  3566. // If we are deteaching, shortcircuit and just write that value out.
  3567. //
  3568. if (bDetach)
  3569. {
  3570. dataval = 0;
  3571. ASSERTGDI(pdevmode == NULL, "Detach should have NULL DEVMODE\n");
  3572. return RtlWriteRegistryValue(RelativeTo,
  3573. Path,
  3574. (PWSTR)AttachedSettings[1],
  3575. REG_DWORD,
  3576. &dataval,
  3577. sizeof(DWORD));
  3578. }
  3579. //
  3580. // DM_POSITION determine whether or not we write the attach values
  3581. //
  3582. if (pdevmode->dmFields & DM_POSITION)
  3583. {
  3584. //
  3585. // Determine what we want to set the attached value to.
  3586. //
  3587. dataval = 1;
  3588. retStatus = RtlWriteRegistryValue(RelativeTo,
  3589. Path,
  3590. (PWSTR)AttachedSettings[1],
  3591. REG_DWORD,
  3592. &dataval,
  3593. sizeof(DWORD));
  3594. }
  3595. else
  3596. {
  3597. //
  3598. // Don't write the Position values if we are not attaching
  3599. //
  3600. numData -= 2;
  3601. }
  3602. //
  3603. // Write all the reset of the data
  3604. //
  3605. data[0] = pdevmode->dmBitsPerPel;
  3606. data[1] = pdevmode->dmPelsWidth;
  3607. data[2] = pdevmode->dmPelsHeight;
  3608. data[3] = pdevmode->dmDisplayFrequency;
  3609. data[4] = pdevmode->dmDisplayFlags;
  3610. data[5] = pdevmode->dmPanningWidth;
  3611. data[6] = pdevmode->dmPanningHeight;
  3612. data[7] = pdevmode->dmDisplayOrientation;
  3613. data[8] = pdevmode->dmDisplayFixedOutput;
  3614. data[9] = pdevmode->dmPosition.x;
  3615. data[10]= pdevmode->dmPosition.y;
  3616. for (i=0; NT_SUCCESS(retStatus) && (i < numData); i++)
  3617. {
  3618. retStatus = RtlWriteRegistryValue(RelativeTo,
  3619. Path,
  3620. (PWSTR)DefaultSettings[i],
  3621. REG_DWORD,
  3622. &data[i],
  3623. sizeof(DWORD));
  3624. }
  3625. if (NT_SUCCESS(retStatus) && pdevmode->dmDriverExtra)
  3626. {
  3627. retStatus = RtlWriteRegistryValue(RelativeTo,
  3628. Path,
  3629. (PWSTR)DefaultSettings[NUM_DISPLAY_DRIVER_EXTRA],
  3630. REG_BINARY,
  3631. ((PUCHAR)pdevmode) + pdevmode->dmSize,
  3632. pdevmode->dmDriverExtra);
  3633. }
  3634. return retStatus;
  3635. }
  3636. NTSTATUS
  3637. DrvUpdateDisplayDriverParameters(
  3638. PGRAPHICS_DEVICE PhysDisp,
  3639. LPDEVMODEW pdevmodeInformation,
  3640. BOOL bDetach,
  3641. BOOL bUpdateMonitors)
  3642. {
  3643. HANDLE hkRegistry;
  3644. ULONG i;
  3645. NTSTATUS retStatus = STATUS_UNSUCCESSFUL;
  3646. DISP_DRIVER_REGISTRY_TYPE registryParam = DispDriverRegHardwareProfileCreate;
  3647. //
  3648. // Change the settings for the whole machine or for the user.
  3649. //
  3650. // CDS_GLOBAL is the default right now.
  3651. // When we store the settings on a per-user basis, then this flag
  3652. // will override that behaviour.
  3653. //
  3654. // if (ChangeGlobalSettings)
  3655. {
  3656. TRACE_INIT(("Drv_Trace: SetParms: Default Settings\n"));
  3657. //
  3658. // try the hardware profile first and see if we can get parameters
  3659. // from that. If that fails, fall back to getting the system
  3660. // parameters.
  3661. //
  3662. while (1)
  3663. {
  3664. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  3665. registryParam,
  3666. NULL,
  3667. NULL,
  3668. NULL,
  3669. gProtocolType);
  3670. if (hkRegistry)
  3671. {
  3672. retStatus = DrvWriteDisplayDriverParameters(RTL_REGISTRY_HANDLE,
  3673. (LPWSTR) hkRegistry,
  3674. pdevmodeInformation,
  3675. bDetach);
  3676. ZwCloseKey(hkRegistry);
  3677. }
  3678. if ( (NT_SUCCESS(retStatus)) ||
  3679. (registryParam != DispDriverRegHardwareProfileCreate) )
  3680. break;
  3681. registryParam = DispDriverRegGlobal;
  3682. }
  3683. }
  3684. //
  3685. // Update per-monitor setting
  3686. //
  3687. if (NT_SUCCESS(retStatus) && bUpdateMonitors)
  3688. {
  3689. UpdateMonitorDevices();
  3690. for (i = 0; i < PhysDisp->numMonitorDevice; i++)
  3691. {
  3692. if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag))
  3693. {
  3694. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  3695. registryParam,
  3696. &PhysDisp->MonitorDevices[i].HwID,
  3697. NULL,
  3698. NULL,
  3699. gProtocolType);
  3700. if (hkRegistry)
  3701. {
  3702. // We don't need to check the status here. Per adapter settings plays
  3703. // as a backup
  3704. DrvWriteDisplayDriverParameters(RTL_REGISTRY_HANDLE,
  3705. (LPWSTR) hkRegistry,
  3706. pdevmodeInformation,
  3707. bDetach);
  3708. ZwCloseKey(hkRegistry);
  3709. }
  3710. }
  3711. }
  3712. }
  3713. TRACE_INIT(("Drv_Trace: SetParms: Exit\n\n"));
  3714. return retStatus;
  3715. }
  3716. /**************************************************************************\
  3717. * DrvGetHdevName
  3718. *
  3719. * Returns the name of the device associated with an HDEV so GetMonitorInfo
  3720. * can return this information
  3721. *
  3722. * 07-Jul-1998 andreva created
  3723. \**************************************************************************/
  3724. BOOL
  3725. DrvGetHdevName(
  3726. HDEV hdev,
  3727. PWCHAR DeviceName
  3728. )
  3729. {
  3730. PDEVOBJ pdo(hdev);
  3731. RtlCopyMemory(DeviceName,
  3732. pdo.ppdev->pGraphicsDevice->szWinDeviceName,
  3733. sizeof(pdo.ppdev->pGraphicsDevice->szWinDeviceName));
  3734. return TRUE;
  3735. }
  3736. /**************************************************************************\
  3737. * DrvGetDeviceFromName
  3738. *
  3739. * Given the name of a device, returns a pointer to a structure describing
  3740. * the device.
  3741. *
  3742. * Specifying NULL tells the system to return the information for the default
  3743. * device on which the application is running.
  3744. *
  3745. * returns a PGRAPHICS_DEVICE
  3746. *
  3747. * *** NOTE
  3748. * If the caller requests Exclusive access, the caller must call back and
  3749. * release the access once the device is no longer used.
  3750. *
  3751. * 31-May-1994 andreva created
  3752. \**************************************************************************/
  3753. PGRAPHICS_DEVICE
  3754. DrvGetDeviceFromName(
  3755. PUNICODE_STRING pstrDeviceName,
  3756. MODE PreviousMode)
  3757. {
  3758. ULONG i = 0;
  3759. NTSTATUS status;
  3760. PGRAPHICS_DEVICE PhysDisp;
  3761. PDEVICE_OBJECT pDeviceObject = NULL;
  3762. UNICODE_STRING uCapturedString;
  3763. UNICODE_STRING uString;
  3764. BOOL fDisableSuccess;
  3765. TRACE_INIT(("Drv_Trace: GetDev: Enter"));
  3766. __try
  3767. {
  3768. if (PreviousMode == UserMode)
  3769. {
  3770. uCapturedString.Length = 0;
  3771. if (pstrDeviceName)
  3772. {
  3773. ProbeForRead(pstrDeviceName, sizeof(UNICODE_STRING), sizeof(CHAR));
  3774. uCapturedString = *pstrDeviceName;
  3775. }
  3776. if (uCapturedString.Length)
  3777. {
  3778. ProbeForRead(uCapturedString.Buffer,
  3779. uCapturedString.Length,
  3780. sizeof(BYTE));
  3781. }
  3782. else
  3783. {
  3784. #if DONT_CHECKIN
  3785. PDESKTOP pdesk = PtiCurrent()->rpdesk;
  3786. PDISPLAYINFO pDispInfo;
  3787. if (pdesk)
  3788. {
  3789. //
  3790. // Special case for boot-up time.
  3791. //
  3792. pDispInfo = pdesk->pDispInfo;
  3793. }
  3794. else
  3795. {
  3796. pDispInfo = G_TERM(pDispInfo);
  3797. }
  3798. RtlInitUnicodeString(&uCapturedString,
  3799. pDispInfo->pDevInfo->szWinDeviceName);
  3800. #endif
  3801. }
  3802. }
  3803. else
  3804. {
  3805. ASSERTGDI(pstrDeviceName >= (PUNICODE_STRING const)MM_USER_PROBE_ADDRESS,
  3806. "Bad kernel mode address\n");
  3807. uCapturedString = *pstrDeviceName;
  3808. }
  3809. //
  3810. // Look for an existing handle in our handle table.
  3811. // Start by looking for the VGACOMPATIBLE string, which is
  3812. // our VgaCompatible device
  3813. //
  3814. RtlInitUnicodeString(&uString, L"VGACOMPATIBLE");
  3815. if (RtlEqualUnicodeString(&uCapturedString,
  3816. &uString,
  3817. TRUE))
  3818. {
  3819. PhysDisp = &gFullscreenGraphicsDevice;
  3820. }
  3821. else
  3822. {
  3823. for (PhysDisp = gpGraphicsDeviceList;
  3824. PhysDisp;
  3825. PhysDisp = PhysDisp->pNextGraphicsDevice)
  3826. {
  3827. RtlInitUnicodeString(&uString,
  3828. &(PhysDisp->szWinDeviceName[0]));
  3829. if (RtlEqualUnicodeString(&uCapturedString,
  3830. &uString,
  3831. TRUE))
  3832. {
  3833. break;
  3834. }
  3835. }
  3836. }
  3837. }
  3838. __except (EXCEPTION_EXECUTE_HANDLER)
  3839. {
  3840. PhysDisp = NULL;
  3841. }
  3842. if (PhysDisp == NULL)
  3843. {
  3844. WARNING("DrvGetDeviceFromName: Calling for a non-exsting device!");
  3845. return NULL;
  3846. }
  3847. TRACE_INIT((" - Exit\n"));
  3848. return PhysDisp;
  3849. }
  3850. /**************************************************************************\
  3851. * PruneModesByMonitors
  3852. *
  3853. * Read the EDID from regstry first. Retrieve the Monitor capabilities.
  3854. * And prune mode list based on Monitor capability.
  3855. \**************************************************************************/
  3856. int compModeCap(LPMODECAP pModeCap1, LPMODECAP pModeCap2)
  3857. {
  3858. if (pModeCap1->dmWidth != pModeCap2->dmWidth)
  3859. {
  3860. return (pModeCap1->dmWidth - pModeCap2->dmWidth);
  3861. }
  3862. return (pModeCap1->dmHeight - pModeCap2->dmHeight);
  3863. }
  3864. ULONG InsertModecapList(LPMODECAP pmc, LPMODECAP ModeCaps, ULONG numModeCaps)
  3865. {
  3866. ULONG i;
  3867. int comp = -1;
  3868. for (i = 0; i < numModeCaps; i++)
  3869. {
  3870. comp = compModeCap(pmc, &ModeCaps[i]);
  3871. if (comp > 0)
  3872. {
  3873. continue;
  3874. }
  3875. if (comp == 0)
  3876. {
  3877. //
  3878. // For duplicated entries, pick the bigger one
  3879. //
  3880. if (ModeCaps[i].freq < pmc->freq)
  3881. {
  3882. ModeCaps[i].freq = pmc->freq;
  3883. ModeCaps[i].MinVFreq = pmc->MinVFreq;
  3884. }
  3885. if (ModeCaps[i].MaxHFreq < pmc->MaxHFreq)
  3886. {
  3887. ModeCaps[i].MaxHFreq = pmc->MaxHFreq;
  3888. ModeCaps[i].MinHFreq = pmc->MinHFreq;
  3889. }
  3890. return numModeCaps;
  3891. }
  3892. //
  3893. // If buffer size reaches the limit, do nothing and return
  3894. //
  3895. if (numModeCaps >= MAX_MODE_CAPABILITY)
  3896. {
  3897. return numModeCaps;
  3898. }
  3899. RtlMoveMemory(&ModeCaps[i+1], &ModeCaps[i], (numModeCaps-i)*sizeof(MODECAP));
  3900. ModeCaps[i] = *pmc;
  3901. return (numModeCaps+1);
  3902. }
  3903. ModeCaps[numModeCaps] = *pmc;
  3904. return (numModeCaps+1);
  3905. }
  3906. ULONG xwtol(LPWSTR wptr)
  3907. {
  3908. for (ULONG v = 0;
  3909. (*wptr >= L'0' && *wptr <= L'9') || *wptr == L' ';
  3910. *wptr++)
  3911. {
  3912. if (*wptr != L' ')
  3913. v = v*10 + (*wptr - L'0');
  3914. }
  3915. return v;
  3916. }
  3917. BOOL ParseModeCap(LPWSTR wstr, LPMODECAP pmc, BOOL bFreq)
  3918. {
  3919. LPWSTR wptr1, wptr2, wptr3;
  3920. ULONG v[4] = {0, 0xFFFFFFFF, 0, 0xFFFFFFFF}, i;
  3921. for (wptr1 = wptr2 = wstr, i = 0;
  3922. wptr2 != NULL && i < 4;
  3923. wptr1 = wptr2+1, i++)
  3924. {
  3925. wptr2 = wcschr(wptr1, L',');
  3926. if (wptr2 != NULL)
  3927. {
  3928. *wptr2 = 0;
  3929. }
  3930. if (bFreq)
  3931. {
  3932. wptr3 = wcschr(wptr1, L'-');
  3933. if (wptr3 != NULL)
  3934. {
  3935. *wptr3 = 0;
  3936. v[i] = xwtol(wptr1);
  3937. wptr1 = wptr3+1;
  3938. }
  3939. else
  3940. {
  3941. v[i] = 0;
  3942. }
  3943. i++;
  3944. }
  3945. v[i] = xwtol(wptr1);
  3946. }
  3947. if (bFreq)
  3948. {
  3949. pmc->MinVFreq = max(pmc->MinVFreq, v[2]);
  3950. pmc->freq = min(pmc->freq, v[3]);
  3951. pmc->MinHFreq = max(pmc->MinHFreq, v[0] * 1000);
  3952. pmc->MaxHFreq = min(pmc->MaxHFreq, v[1] * 1000);
  3953. }
  3954. else
  3955. {
  3956. if (v[0] == 0 || v[1] == 0xFFFFFFFF)
  3957. {
  3958. return FALSE;
  3959. }
  3960. pmc->dmWidth = v[0];
  3961. pmc->dmHeight = v[1];
  3962. pmc->freq = v[2];
  3963. }
  3964. return TRUE;
  3965. }
  3966. ULONG GetMonitorCapabilityFromInf(PDEVICE_OBJECT pdo, LPMODECAP ModeCaps)
  3967. {
  3968. HANDLE hkRegistry, hkRegistry1, hkRegistry2;
  3969. if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hkRegistry)) )
  3970. {
  3971. return 0;
  3972. }
  3973. ULONG numModeCaps = 0;
  3974. OBJECT_ATTRIBUTES ObjectAttributes;
  3975. UNICODE_STRING UnicodeString;
  3976. RtlInitUnicodeString(&UnicodeString, L"MODES");
  3977. InitializeObjectAttributes(&ObjectAttributes,
  3978. &UnicodeString,
  3979. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  3980. hkRegistry,
  3981. NULL);
  3982. if ( NT_SUCCESS (ZwOpenKey(&hkRegistry1, KEY_READ, &ObjectAttributes)) )
  3983. {
  3984. WCHAR data[128], buf[128];
  3985. ULONG i = 0, size;
  3986. MODECAP mc;
  3987. while (NT_SUCCESS(ZwEnumerateKey(hkRegistry1,
  3988. i,
  3989. KeyBasicInformation,
  3990. data,
  3991. sizeof(data),
  3992. &size)))
  3993. {
  3994. i++;
  3995. UnicodeString.Buffer = ((PKEY_BASIC_INFORMATION) data)->Name;
  3996. UnicodeString.Length = (USHORT) ((PKEY_BASIC_INFORMATION) data)->NameLength;
  3997. UnicodeString.MaximumLength = (USHORT) ((PKEY_BASIC_INFORMATION) data)->NameLength;
  3998. //
  3999. // 1024, 768
  4000. //
  4001. wcsncpy(buf, UnicodeString.Buffer, min(UnicodeString.Length, sizeof(buf))/sizeof(WCHAR));
  4002. if (UnicodeString.Length < sizeof(buf) )
  4003. buf[UnicodeString.Length/sizeof(WCHAR)] = 0;
  4004. buf[sizeof(buf)/sizeof(WCHAR)-1] = 0;
  4005. if (!ParseModeCap(buf, &mc, FALSE))
  4006. continue;
  4007. InitializeObjectAttributes(&ObjectAttributes,
  4008. &UnicodeString,
  4009. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  4010. hkRegistry1,
  4011. NULL);
  4012. if (NT_SUCCESS (ZwOpenKey(&hkRegistry2,
  4013. MAXIMUM_ALLOWED,
  4014. &ObjectAttributes)))
  4015. {
  4016. WCHAR modeStr[] = L"Mode1";
  4017. BOOL bSucceed = FALSE;
  4018. for (ULONG j = 0; j < 9; j++)
  4019. {
  4020. RtlInitUnicodeString(&UnicodeString, modeStr);
  4021. if (NT_SUCCESS(ZwQueryValueKey(hkRegistry2,
  4022. &UnicodeString,
  4023. KeyValueFullInformation,
  4024. data,
  4025. sizeof(data),
  4026. &size)) )
  4027. {
  4028. wcsncpy(buf,
  4029. (LPWSTR)((PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset),
  4030. sizeof(buf)/sizeof(WCHAR)-1);
  4031. //
  4032. // MinHFreq MaxHFreq MinVFreq MaxVFreq
  4033. // 31.0 - 82.0, 55.0 - 100.0, +,+
  4034. //
  4035. mc.MinVFreq = MIN_REFRESH_RATE;
  4036. mc.freq = 0xFFFFFFFF;
  4037. mc.MinHFreq = 0;
  4038. mc.MaxHFreq = 0xFFFFFFFF;
  4039. if (ParseModeCap(buf, &mc, TRUE))
  4040. {
  4041. numModeCaps = InsertModecapList(&mc, ModeCaps, numModeCaps);
  4042. }
  4043. bSucceed = TRUE;
  4044. }
  4045. else if (bSucceed)
  4046. {
  4047. break;
  4048. }
  4049. modeStr[4]++;
  4050. }
  4051. ZwCloseKey(hkRegistry2);
  4052. }
  4053. }
  4054. ZwCloseKey(hkRegistry1);
  4055. }
  4056. ZwCloseKey(hkRegistry);
  4057. return numModeCaps;
  4058. }
  4059. BOOL GetRegEDID(PDEVICE_OBJECT pdo, PBYTE pBuffer, PBYTE *ppEdid)
  4060. {
  4061. HANDLE hkRegistry;
  4062. NTSTATUS status;
  4063. // Get EDID information from registry
  4064. if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &hkRegistry)) )
  4065. {
  4066. TRACE_INIT(("Drv_Trace: GetMonitorCapability: Failed to retrieve EDID\n"));
  4067. return FALSE;
  4068. }
  4069. UNICODE_STRING UnicodeString;
  4070. ULONG cbSize;
  4071. RtlInitUnicodeString(&UnicodeString, L"EDID");
  4072. status = ZwQueryValueKey(hkRegistry,
  4073. &UnicodeString,
  4074. KeyValueFullInformation,
  4075. pBuffer,
  4076. 400,
  4077. &cbSize);
  4078. if (NT_SUCCESS(status))
  4079. {
  4080. if ( (((PKEY_VALUE_FULL_INFORMATION)pBuffer)->DataLength) < 256)
  4081. status = STATUS_UNSUCCESSFUL;
  4082. else
  4083. *ppEdid = (PBYTE)(pBuffer + ((PKEY_VALUE_FULL_INFORMATION)pBuffer)->DataOffset);
  4084. }
  4085. (VOID)ZwCloseKey(hkRegistry);
  4086. if (!NT_SUCCESS(status))
  4087. return FALSE;
  4088. return TRUE;
  4089. }
  4090. BOOL GetValuesFromInf(PDEVICE_OBJECT pdo, ULONG op, LPMODECAP pmc)
  4091. {
  4092. if (op > 1)
  4093. return FALSE;
  4094. HANDLE hkRegistry;
  4095. static LPWSTR ValueName[] = {
  4096. L"PreferredMode",
  4097. L"ClearType"
  4098. };
  4099. if ( !NT_SUCCESS(IoOpenDeviceRegistryKey(pdo, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &hkRegistry)) )
  4100. return FALSE;
  4101. UNICODE_STRING UnicodeString;
  4102. WCHAR data[128], buf[128];
  4103. ULONG size;
  4104. // Assuming return failure
  4105. BOOL bRet = FALSE;
  4106. RtlInitUnicodeString(&UnicodeString, ValueName[op]);
  4107. if (NT_SUCCESS(ZwQueryValueKey(hkRegistry,
  4108. &UnicodeString,
  4109. KeyValueFullInformation,
  4110. data,
  4111. sizeof(data),
  4112. &size)) )
  4113. {
  4114. switch (op)
  4115. {
  4116. case 0: // GetPreferredMode
  4117. wcsncpy(buf,
  4118. (LPWSTR)((PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset),
  4119. sizeof(buf)/sizeof(WCHAR)-1);
  4120. // 1024,768,60
  4121. if (ParseModeCap(buf, pmc, FALSE))
  4122. {
  4123. if (pmc->dmWidth != 0 && pmc->dmHeight != 0 && pmc->freq != 0)
  4124. bRet = TRUE;
  4125. }
  4126. break;
  4127. case 1: // Get ClearType Capability
  4128. pmc->dmWidth = *(PULONG) ( (PBYTE)data + ((PKEY_VALUE_FULL_INFORMATION)data)->DataOffset );
  4129. bRet = TRUE;
  4130. break;
  4131. default:
  4132. break;
  4133. }
  4134. }
  4135. ZwCloseKey(hkRegistry);
  4136. return bRet;
  4137. }
  4138. /**************************************************************************\
  4139. * GetDefaultFrequencyRange
  4140. *
  4141. * Routine Description:
  4142. *
  4143. * Returns default frequency range for the monitor.
  4144. *
  4145. * Arguments:
  4146. *
  4147. * pFrequencyRange - Points to storage for monitor frequency limits.
  4148. *
  4149. * Returns:
  4150. *
  4151. * Default monitor frequency limits returned in pFrequencyRange.
  4152. *
  4153. * 08-Oct-1999 mmacie created
  4154. \**************************************************************************/
  4155. VOID
  4156. GetDefaultFrequencyRange(
  4157. OUT PFREQUENCY_RANGE pFrequencyRange
  4158. )
  4159. {
  4160. ASSERT(NULL != pFrequencyRange);
  4161. pFrequencyRange->ulMinVerticalRate = MIN_REFRESH_RATE;
  4162. pFrequencyRange->ulMaxVerticalRate = 0xffffffff;
  4163. pFrequencyRange->ulMinHorizontalRate = 0;
  4164. pFrequencyRange->ulMaxHorizontalRate = 0xffffffff;
  4165. pFrequencyRange->ulMinPixelClock = 0;
  4166. pFrequencyRange->ulMaxPixelClock = 0xffffffff;
  4167. }
  4168. /**************************************************************************\
  4169. * GetMonitorCapability2
  4170. *
  4171. * Routine Description:
  4172. *
  4173. * Parsing routine for EDID Version 2.
  4174. *
  4175. * Arguments:
  4176. *
  4177. * pEdid2 - Points to EDID Version 2 data.
  4178. * pModeCaps - Points to storage for monitor cap details.
  4179. * pFrequencyRange - Points to storage for monitor frequency limits.
  4180. *
  4181. * Returns:
  4182. *
  4183. * Number of mode capabilites.
  4184. * - Mode cap data returned in pModeCaps.
  4185. * - Monitor frequency limits returned in pFrequencyRange.
  4186. *
  4187. * 21-Sep-1999 mmacie created
  4188. \**************************************************************************/
  4189. ULONG
  4190. GetMonitorCapability2(
  4191. IN PEDID2 pEdid2,
  4192. OUT PMODECAP pModeCaps,
  4193. OUT PFREQUENCY_RANGE pFrequencyRange
  4194. )
  4195. {
  4196. ULONG ulNumberOfModeCaps;
  4197. ULONG ulNumberOfLuminanceTables;
  4198. ULONG ulNumberOfFrequencyRanges;
  4199. ULONG ulNumberOfDetailTimingRanges;
  4200. ULONG ulNumberOfTimingCodes;
  4201. ULONG ulNumberOfDetailTimings;
  4202. ULONG ulEdidOffset;
  4203. ULONG ulTemp;
  4204. ASSERT(NULL != pEdid2);
  4205. ASSERT(NULL != pModeCaps);
  4206. ASSERT(NULL != pFrequencyRange);
  4207. ASSERT(0x20 == pEdid2->ucEdidVersionRevision); // Make sure EDID Version 2
  4208. //
  4209. // Parse map of timings.
  4210. //
  4211. ulNumberOfLuminanceTables = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_LUMINANCE_TABLE_MASK) >>
  4212. EDID2_MOT0_LUMINANCE_TABLE_SHIFT;
  4213. ulNumberOfFrequencyRanges = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_FREQUENCY_RANGE_MASK) >>
  4214. EDID2_MOT0_FREQUENCY_RANGE_SHIFT;
  4215. ulNumberOfDetailTimingRanges = (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_DETAIL_TIMING_RANGE_MASK) >>
  4216. EDID2_MOT0_DETAIL_TIMING_RANGE_SHIFT;
  4217. ulNumberOfTimingCodes = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_TIMING_CODE_MASK) >>
  4218. EDID2_MOT1_TIMING_CODE_SHIFT;
  4219. ulNumberOfDetailTimings = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) >>
  4220. EDID2_MOT1_DETAIL_TIMING_SHIFT;
  4221. TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfLuminanceTables = %lu\n", ulNumberOfLuminanceTables));
  4222. TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfFrequencyRanges = %lu\n", ulNumberOfFrequencyRanges));
  4223. TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimingRanges = %lu\n", ulNumberOfDetailTimingRanges));
  4224. TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimingCodes = %lu\n", ulNumberOfTimingCodes));
  4225. TRACE_INIT(("win32k!GetMonitorCapability2: NumberOfDetailTimings = %lu\n", ulNumberOfDetailTimings));
  4226. //
  4227. // Check for bad EDIDs.
  4228. //
  4229. if ((ulNumberOfLuminanceTables > EDID2_MAX_LUMINANCE_TABLES) ||
  4230. (ulNumberOfFrequencyRanges > EDID2_MAX_FREQUENCY_RANGES) ||
  4231. (ulNumberOfDetailTimingRanges > EDID2_MAX_DETAIL_TIMING_RANGES) ||
  4232. (ulNumberOfTimingCodes > EDID2_MAX_TIMING_CODES) ||
  4233. (ulNumberOfDetailTimings > EDID2_MAX_DETAIL_TIMINGS))
  4234. {
  4235. WARNING("Bad EDID2\n");
  4236. GetDefaultFrequencyRange(pFrequencyRange);
  4237. return 0;
  4238. }
  4239. ulEdidOffset = EDID2_LUMINANCE_TABLE_OFFSET;
  4240. //
  4241. // Move over luminance tables.
  4242. //
  4243. if (ulNumberOfLuminanceTables)
  4244. {
  4245. PUCHAR pucLuminanceTable;
  4246. for (ulTemp = 0; ulTemp < ulNumberOfLuminanceTables; ulTemp++)
  4247. {
  4248. //
  4249. // Check for bad EDIDs.
  4250. //
  4251. if (ulEdidOffset >= (sizeof (EDID2) - 1))
  4252. {
  4253. WARNING("Bad EDID2\n");
  4254. GetDefaultFrequencyRange(pFrequencyRange);
  4255. return 0;
  4256. }
  4257. pucLuminanceTable = (PUCHAR)pEdid2 + ulEdidOffset;
  4258. ulEdidOffset += (((*pucLuminanceTable & EDID2_LT0_SUB_CHANNELS_FLAG) ? 3 : 1) *
  4259. ((*pucLuminanceTable & EDID2_LT0_ENTRIES_MASK) >> EDID2_LT0_ENTRIES_SHIFT) + 1);
  4260. }
  4261. }
  4262. //
  4263. // Parse frequency ranges.
  4264. //
  4265. if (ulNumberOfFrequencyRanges)
  4266. {
  4267. PEDID2_FREQUENCY_RANGE pEdidRange;
  4268. ULONG ulRate;
  4269. //
  4270. // Currently the mode prunning code cannot handle multiple
  4271. // frequency ranges but EDID Version 2 can supply them.
  4272. // We're hacking around here by merging all of them into a single
  4273. // "super frequency range".
  4274. //
  4275. //
  4276. // Make sure we pick up the first range.
  4277. //
  4278. pFrequencyRange->ulMinVerticalRate = 0xffffffff;
  4279. pFrequencyRange->ulMaxVerticalRate = 0;
  4280. pFrequencyRange->ulMinHorizontalRate = 0xffffffff;
  4281. pFrequencyRange->ulMaxHorizontalRate = 0;
  4282. pFrequencyRange->ulMinPixelClock = 0xffffffff;
  4283. pFrequencyRange->ulMaxPixelClock = 0;
  4284. for (ulTemp = 0; ulTemp < ulNumberOfFrequencyRanges; ulTemp++,
  4285. ulEdidOffset += sizeof (EDID2_FREQUENCY_RANGE))
  4286. {
  4287. //
  4288. // Check for bad EDIDs.
  4289. //
  4290. if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_FREQUENCY_RANGE)))
  4291. {
  4292. WARNING("Bad EDID2\n");
  4293. GetDefaultFrequencyRange(pFrequencyRange);
  4294. return 0;
  4295. }
  4296. pEdidRange = (PEDID2_FREQUENCY_RANGE)((PUCHAR)pEdid2 + ulEdidOffset);
  4297. ulRate = (ULONG)(pEdidRange->ucMinFrameFieldRateBits9_2) << 2;
  4298. ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0xc0) >> 6;
  4299. if (ulRate < pFrequencyRange->ulMinVerticalRate)
  4300. pFrequencyRange->ulMinVerticalRate = ulRate;
  4301. ulRate = (ULONG)(pEdidRange->ucMaxFrameFieldRateBits9_2) << 2;
  4302. ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x30) >> 4;
  4303. if (ulRate > pFrequencyRange->ulMaxVerticalRate)
  4304. pFrequencyRange->ulMaxVerticalRate = ulRate;
  4305. ulRate = (ULONG)(pEdidRange->ucMinLineRateBits9_2) << 2;
  4306. ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x0c) >> 2;
  4307. ulRate *= 1000;
  4308. if (ulRate < pFrequencyRange->ulMinHorizontalRate)
  4309. pFrequencyRange->ulMinHorizontalRate = ulRate;
  4310. ulRate = (ULONG)(pEdidRange->ucMaxLineRateBits9_2) << 2;
  4311. ulRate += (pEdidRange->ucFrameFieldLineRatesBits1_0 & 0x03);
  4312. ulRate *= 1000;
  4313. if (ulRate > pFrequencyRange->ulMaxHorizontalRate)
  4314. pFrequencyRange->ulMaxHorizontalRate = ulRate;
  4315. ulRate = (ULONG)((pEdidRange->ucPixelRatesBits11_8) & 0xf0) << 4;
  4316. ulRate += pEdidRange->ucMinPixelRateBits7_0;
  4317. ulRate *= 1000000;
  4318. if (ulRate < pFrequencyRange->ulMinPixelClock)
  4319. pFrequencyRange->ulMinPixelClock = ulRate;
  4320. ulRate = (ULONG)((pEdidRange->ucPixelRatesBits11_8) & 0x0f) << 8;
  4321. ulRate += pEdidRange->ucMaxPixelRateBits7_0;
  4322. ulRate *= 1000000;
  4323. if (ulRate > pFrequencyRange->ulMaxPixelClock)
  4324. pFrequencyRange->ulMaxPixelClock = ulRate;
  4325. //
  4326. // Check for bad EDIDs.
  4327. //
  4328. if ((pFrequencyRange->ulMinVerticalRate > pFrequencyRange->ulMaxVerticalRate) ||
  4329. (pFrequencyRange->ulMinHorizontalRate > pFrequencyRange->ulMaxHorizontalRate) ||
  4330. (pFrequencyRange->ulMinPixelClock > pFrequencyRange->ulMaxPixelClock) ||
  4331. (pFrequencyRange->ulMaxVerticalRate < 60) ||
  4332. (pFrequencyRange->ulMaxHorizontalRate < (60*480)) ||
  4333. (pFrequencyRange->ulMaxPixelClock < (60*480*640))
  4334. )
  4335. {
  4336. WARNING("Bad EDID2\n");
  4337. GetDefaultFrequencyRange(pFrequencyRange);
  4338. }
  4339. }
  4340. }
  4341. ulNumberOfModeCaps = 0;
  4342. //
  4343. // Parse detail timing ranges.
  4344. //
  4345. if (ulNumberOfDetailTimingRanges)
  4346. {
  4347. PEDID2_DETAIL_TIMING_RANGE pEdidRange;
  4348. MODECAP modeCap;
  4349. ULONG ulHorizontalTotal;
  4350. ULONG ulVerticalTotal;
  4351. ULONG ulPixelClock;
  4352. //
  4353. // Currently the mode prunning code cannot handle detailed
  4354. // timing ranges but EDID Version 2 can supply them.
  4355. // We're hacking around here by taking maximum values only.
  4356. //
  4357. modeCap.MinVFreq = MIN_REFRESH_RATE;
  4358. modeCap.MinHFreq = 0;
  4359. modeCap.MaxHFreq = 0xffffffff;
  4360. for (ulTemp = 0; ulTemp < ulNumberOfDetailTimingRanges; ulTemp++,
  4361. ulEdidOffset += sizeof (EDID2_DETAIL_TIMING_RANGE))
  4362. {
  4363. //
  4364. // Check for bad EDIDs.
  4365. //
  4366. if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_DETAIL_TIMING_RANGE)))
  4367. {
  4368. WARNING("Bad EDID2\n");
  4369. GetDefaultFrequencyRange(pFrequencyRange);
  4370. return 0;
  4371. }
  4372. pEdidRange = (PEDID2_DETAIL_TIMING_RANGE)((PUCHAR)pEdid2 + ulEdidOffset);
  4373. modeCap.dmWidth = (ULONG)(pEdidRange->ucActiveHighBits & 0xf0) << 4;
  4374. modeCap.dmWidth += pEdidRange->ucHorizontalActiveLowByte;
  4375. modeCap.dmHeight = (ULONG)(pEdidRange->ucActiveHighBits & 0x0f) << 8;
  4376. modeCap.dmHeight += pEdidRange->ucVerticalActiveLowByte;
  4377. ulHorizontalTotal = (ULONG)(pEdidRange->ucMaxBlankHighBits & 0xf0) << 4;
  4378. ulHorizontalTotal += pEdidRange->ucMaxHorizontalBlankLowByte + modeCap.dmWidth;
  4379. ulVerticalTotal = (ULONG)(pEdidRange->ucMaxBlankHighBits & 0x0f) << 8;
  4380. ulVerticalTotal += pEdidRange->ucMaxVerticalBlankLowByte + modeCap.dmHeight;
  4381. //
  4382. // Make sure we won't divide by zero in case of bad EDID.
  4383. //
  4384. if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal))
  4385. {
  4386. WARNING("Bad EDID2\n");
  4387. GetDefaultFrequencyRange(pFrequencyRange);
  4388. return 0;
  4389. }
  4390. ulPixelClock = (ULONG)(pEdidRange->usMaxPixelClock) * 10000;
  4391. //
  4392. // Calculate refresh rate rounding to the nearest integer.
  4393. //
  4394. modeCap.freq = (((10 * ulPixelClock) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
  4395. if (pEdidRange->ucFlags & EDID2_DT_INTERLACED)
  4396. modeCap.freq /= 2;
  4397. TRACE_INIT(("win32k!GetMonitorCapability2: Detailed range %lux%lu at %luHz\n",
  4398. modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
  4399. ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps);
  4400. }
  4401. }
  4402. //
  4403. // Parse timing codes.
  4404. //
  4405. if (ulNumberOfTimingCodes)
  4406. {
  4407. PEDID2_TIMING_CODE pTimingCode;
  4408. MODECAP modeCap;
  4409. modeCap.MinVFreq = MIN_REFRESH_RATE;
  4410. modeCap.MinHFreq = 0;
  4411. modeCap.MaxHFreq = 0xffffffff;
  4412. for (ulTemp = 0; ulTemp < ulNumberOfTimingCodes; ulTemp++,
  4413. ulEdidOffset += sizeof (EDID2_TIMING_CODE))
  4414. {
  4415. //
  4416. // Check for bad EDIDs.
  4417. //
  4418. if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_TIMING_CODE)))
  4419. {
  4420. WARNING("Bad EDID2\n");
  4421. GetDefaultFrequencyRange(pFrequencyRange);
  4422. return 0;
  4423. }
  4424. pTimingCode = (PEDID2_TIMING_CODE)((PUCHAR)pEdid2 + ulEdidOffset);
  4425. modeCap.dmWidth = 16 * pTimingCode->ucHorizontalActive + 256;
  4426. modeCap.dmHeight = (100 * modeCap.dmWidth) / pTimingCode->ucAspectRatio;
  4427. modeCap.freq = pTimingCode->ucRefreshRate;
  4428. if (pTimingCode->ucFlags & EDID2_TC_INTERLACED)
  4429. modeCap.freq /= 2;
  4430. TRACE_INIT(("win32k!GetMonitorCapability2: Timing code %lux%lu at %luHz\n",
  4431. modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
  4432. ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps);
  4433. }
  4434. }
  4435. //
  4436. // Parse detail timings.
  4437. //
  4438. if (ulNumberOfDetailTimings)
  4439. {
  4440. PEDID2_DETAIL_TIMING pDetailTiming;
  4441. MODECAP modeCap;
  4442. ULONG ulHorizontalTotal;
  4443. ULONG ulVerticalTotal;
  4444. ULONG ulPixelClock;
  4445. modeCap.MinVFreq = MIN_REFRESH_RATE;
  4446. modeCap.MinHFreq = 0;
  4447. modeCap.MaxHFreq = 0xffffffff;
  4448. for (ulTemp = 0; ulTemp < ulNumberOfDetailTimings; ulTemp++,
  4449. ulEdidOffset += sizeof (EDID2_DETAIL_TIMING))
  4450. {
  4451. //
  4452. // Check for bad EDIDs.
  4453. //
  4454. if (ulEdidOffset >= (sizeof (EDID2) - sizeof (EDID2_DETAIL_TIMING)))
  4455. {
  4456. WARNING("Bad EDID2\n");
  4457. GetDefaultFrequencyRange(pFrequencyRange);
  4458. return 0;
  4459. }
  4460. pDetailTiming = (PEDID2_DETAIL_TIMING)((PUCHAR)pEdid2 + ulEdidOffset);
  4461. modeCap.dmWidth = (ULONG)(pDetailTiming->ucHorizontalHighBits & 0xf0) << 4;
  4462. modeCap.dmWidth += pDetailTiming->ucHorizontalActiveLowByte;
  4463. modeCap.dmHeight = (ULONG)(pDetailTiming->ucVerticalHighBits & 0xf0) << 4;
  4464. modeCap.dmHeight += pDetailTiming->ucVerticalActiveLowByte;
  4465. ulHorizontalTotal = (ULONG)(pDetailTiming->ucHorizontalHighBits & 0x0f) << 8;
  4466. ulHorizontalTotal += pDetailTiming->ucHorizontalBlankLowByte + modeCap.dmWidth;
  4467. ulVerticalTotal = (ULONG)(pDetailTiming->ucVerticalHighBits & 0x0f) << 8;
  4468. ulVerticalTotal += pDetailTiming->ucVerticalBlankLowByte + modeCap.dmHeight;
  4469. //
  4470. // Make sure we won't divide by zero in case of bad EDID.
  4471. //
  4472. if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal))
  4473. {
  4474. WARNING("Bad EDID2\n");
  4475. GetDefaultFrequencyRange(pFrequencyRange);
  4476. return 0;
  4477. }
  4478. ulPixelClock = (ULONG)(pDetailTiming->usPixelClock) * 10000;
  4479. //
  4480. // Calculate refresh rate rounding to the nearest integer.
  4481. //
  4482. modeCap.freq = (((10 * ulPixelClock) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
  4483. if (pDetailTiming->ucFlags & EDID2_DT_INTERLACED)
  4484. modeCap.freq /= 2;
  4485. TRACE_INIT(("win32k!GetMonitorCapability2: Detailed timing %lux%lu at %luHz\n",
  4486. modeCap.dmWidth, modeCap.dmHeight, modeCap.freq));
  4487. ulNumberOfModeCaps = InsertModecapList(&modeCap, pModeCaps, ulNumberOfModeCaps);
  4488. }
  4489. }
  4490. //
  4491. // Define monitor frequency limits in case EDID didn't have it.
  4492. //
  4493. if (0 == ulNumberOfFrequencyRanges)
  4494. {
  4495. GetDefaultFrequencyRange(pFrequencyRange);
  4496. }
  4497. TRACE_INIT(("win32k!GetMonitorCapability2: MinVerticalRate = %lu\n", pFrequencyRange->ulMinVerticalRate));
  4498. TRACE_INIT(("win32k!GetMonitorCapability2: MaxVerticalRate = %lu\n", pFrequencyRange->ulMaxVerticalRate));
  4499. TRACE_INIT(("win32k!GetMonitorCapability2: MinHorizontalRate = %lu\n", pFrequencyRange->ulMinHorizontalRate));
  4500. TRACE_INIT(("win32k!GetMonitorCapability2: MaxHorizontalRate = %lu\n", pFrequencyRange->ulMaxHorizontalRate));
  4501. TRACE_INIT(("win32k!GetMonitorCapability2: MinPixelClock = %lu\n", pFrequencyRange->ulMinPixelClock));
  4502. TRACE_INIT(("win32k!GetMonitorCapability2: MaxPixelClock = %lu\n", pFrequencyRange->ulMaxPixelClock));
  4503. //
  4504. // Cascade refresh rates.
  4505. //
  4506. for (ulTemp = ulNumberOfModeCaps; ulTemp > 1; ulTemp--)
  4507. {
  4508. if (pModeCaps[ulTemp - 2].freq < pModeCaps[ulTemp - 1].freq)
  4509. pModeCaps[ulTemp - 2].freq = pModeCaps[ulTemp - 1].freq;
  4510. }
  4511. return ulNumberOfModeCaps;
  4512. }
  4513. /**************************************************************************\
  4514. * GetMonitorCapability1
  4515. *
  4516. * Routine Description:
  4517. *
  4518. * Parsing routine for EDID Version 1.x
  4519. *
  4520. * Arguments:
  4521. *
  4522. * pEdid - Points to EDID Version 1 data.
  4523. * pModeCaps - Points to storage for monitor cap details.
  4524. * pFrequencyRange - Points to storage for monitor frequency limits.
  4525. *
  4526. * Returns:
  4527. *
  4528. * Number of mode capabilites.
  4529. * - Mode cap data returned in pModeCaps.
  4530. * - Monitor frequency limits returned in pFrequencyRange.
  4531. *
  4532. * 21-Sep-1999 dennyd created
  4533. \**************************************************************************/
  4534. ULONG
  4535. GetMonitorCapability1(
  4536. IN PBYTE pEdid,
  4537. OUT PMODECAP pModeCaps,
  4538. OUT PFREQUENCY_RANGE pFrequencyRange
  4539. )
  4540. {
  4541. ULONG numModeCaps = 0;
  4542. MODECAP mc;
  4543. PBYTE ptr;
  4544. BYTE c;
  4545. int i;
  4546. int r1[] = {1, 4, 5, 16}, r2[] = {1, 3, 4, 9};
  4547. UCHAR ucaEdid1Header[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
  4548. GetDefaultFrequencyRange(pFrequencyRange);
  4549. //
  4550. // Check if EDID Version 1.
  4551. //
  4552. for (i = 0; i < (sizeof (ucaEdid1Header) / sizeof (UCHAR)); i++)
  4553. {
  4554. if (pEdid[i] != ucaEdid1Header[i])
  4555. return 0;
  4556. }
  4557. // Handle established timings
  4558. MODECAP mcArray[] = {{1280, 1024, 75},
  4559. {1024, 768, 75}, {1024, 768, 70}, {1024, 768, 60}, {1024, 768, 87},
  4560. {800, 600, 75}, {800, 600, 72}, {800, 600, 60}, {800, 600, 56},
  4561. {640, 480, 75}, {640, 480, 72}, {640, 480, 67}, {640, 480, 60} };
  4562. pEdid[0x24] = ((((pEdid[0x24] & 0xc0) >> 1) & 0x60) | (pEdid[0x24] & 0x1f)) & 0x7f;
  4563. for (i = 0; i < 13; i++)
  4564. {
  4565. mcArray[i].MinVFreq = MIN_REFRESH_RATE;
  4566. mcArray[i].MinHFreq = 0;
  4567. mcArray[i].MaxHFreq = 0xFFFFFFFF;
  4568. if ((pEdid[0x24-i/7] >> (i%7)) & 0x01)
  4569. numModeCaps = InsertModecapList(&mcArray[i], pModeCaps, numModeCaps);
  4570. }
  4571. mc.MinVFreq = MIN_REFRESH_RATE;
  4572. mc.MinHFreq = 0;
  4573. mc.MaxHFreq = 0xFFFFFFFF;
  4574. // Standard Timing
  4575. for (i = 0, ptr = &pEdid[0x26]; i < 8; i++, ptr += 2)
  4576. {
  4577. if (*ptr == 0 || *ptr == 1)
  4578. continue;
  4579. mc.dmWidth = ((ULONG)ptr[0] + 31) << 3;
  4580. c = (ptr[1] >> 6 ) & 0x03;
  4581. mc.dmHeight = mc.dmWidth * r2[c] / r1[c];
  4582. mc.freq = (ULONG)(ptr[1] & 0x3F) + 60;
  4583. numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps);
  4584. }
  4585. // Detailed timing/Monitor Descriptor
  4586. for (int k = 0; k < 4; k++)
  4587. {
  4588. ptr = &pEdid[0x36+ 18*k];
  4589. if ((ptr[0] != 0 || ptr[1] != 0) && ptr[4] != 0)
  4590. {
  4591. // Detailed timing Descriptor
  4592. mc.dmWidth = (ULONG)ptr[2] + ((ULONG)(ptr[4]&0xF0)) * 0x10;
  4593. mc.dmHeight = (ULONG)ptr[5] + ((ULONG)(ptr[7]&0xF0)) * 0x10;
  4594. if (mc.dmWidth == 0 || mc.dmHeight == 0)
  4595. continue;
  4596. mc.freq = ((ULONG)ptr[0] + ((ULONG)ptr[1]) * 0x100) * 10000;
  4597. mc.freq /= (mc.dmWidth + (ULONG)ptr[3] + ((ULONG)(ptr[4]&0x0F)) * 0x100) *
  4598. (mc.dmHeight+ (ULONG)ptr[6] + ((ULONG)(ptr[7]&0x0F)) * 0x100);
  4599. // If it's interlaced mode
  4600. if (ptr[17] & 0x80)
  4601. mc.freq >>= 1;
  4602. numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps);
  4603. }
  4604. else if (ptr[3] == 0xFA)
  4605. {
  4606. // Monitor Descriptor--Standard Timing
  4607. for (i = 0, ptr += 5; i < 6; i++, ptr += 2)
  4608. {
  4609. if (*ptr == 0 || *ptr == 1)
  4610. continue;
  4611. mc.dmWidth = ((ULONG)ptr[0] + 31) << 3;
  4612. c = (ptr[1] >> 6 ) & 0x03;
  4613. mc.dmHeight = mc.dmWidth * r2[c] / r1[c];
  4614. mc.freq = (ULONG)(ptr[1] & 0x3F) + 60;
  4615. numModeCaps = InsertModecapList(&mc, pModeCaps, numModeCaps);
  4616. }
  4617. }
  4618. else if (ptr[3] == 0xFD)
  4619. {
  4620. pFrequencyRange->ulMinVerticalRate = (ULONG)ptr[5];
  4621. pFrequencyRange->ulMaxVerticalRate = (ULONG)ptr[6];
  4622. pFrequencyRange->ulMinHorizontalRate = ((ULONG)ptr[7]) * 1000;
  4623. pFrequencyRange->ulMaxHorizontalRate = ((ULONG)ptr[8]) * 1000;
  4624. pFrequencyRange->ulMinPixelClock = 0;
  4625. pFrequencyRange->ulMaxPixelClock = ((ULONG)ptr[9]) * 10000000;
  4626. }
  4627. }
  4628. for (i = (int)numModeCaps-2; i >= 0; i--)
  4629. {
  4630. if (pModeCaps[i].freq < pModeCaps[i+1].freq)
  4631. pModeCaps[i].freq = pModeCaps[i+1].freq;
  4632. }
  4633. return numModeCaps;
  4634. }
  4635. ULONG GetMonitorCapability(PDEVICE_OBJECT pdo, LPMODECAP ModeCaps, PFREQUENCY_RANGE pFrequencyRange)
  4636. {
  4637. BYTE pBuffer[512], *pEdid;
  4638. ULONG numModeCaps = 0;
  4639. //
  4640. // Predefine monitor frequency limits in case we won't get it.
  4641. //
  4642. GetDefaultFrequencyRange(pFrequencyRange);
  4643. numModeCaps = GetMonitorCapabilityFromInf(pdo, ModeCaps);
  4644. if (numModeCaps)
  4645. {
  4646. pFrequencyRange->ulMinVerticalRate = ModeCaps[0].MinVFreq;
  4647. pFrequencyRange->ulMaxVerticalRate = ModeCaps[0].freq;
  4648. return numModeCaps;
  4649. }
  4650. else
  4651. {
  4652. TRACE_INIT(("Drv_Trace: GetMonitorCapabilityFromInf: Failed to retrieve Monitor inf\n"));
  4653. }
  4654. if (GetRegEDID(pdo, pBuffer, &pEdid) == 0)
  4655. {
  4656. TRACE_INIT(("Drv_Trace: GetMonitorCapability: Failed to get EDID capability\n"));
  4657. return 0;
  4658. }
  4659. //
  4660. // Check if EDID Version 2.
  4661. //
  4662. if (0x20 == pEdid[0])
  4663. {
  4664. return GetMonitorCapability2((PEDID2)pEdid, ModeCaps, pFrequencyRange);
  4665. }
  4666. //
  4667. // Otherwise always assume it's EDID 1.x
  4668. //
  4669. return GetMonitorCapability1(pEdid, ModeCaps, pFrequencyRange);
  4670. }
  4671. BOOL PruneMode(PDEVMODEW pdm, LPMODECAP pModeCaps, int numModeCaps, PFREQUENCY_RANGE pMaxFreqs, ULONG flag)
  4672. {
  4673. ULONG f, f1, freq = pdm->dmDisplayFrequency;
  4674. BOOL bSwapWH = FALSE;
  4675. if (pdm->dmFields & DM_DISPLAYORIENTATION)
  4676. {
  4677. if (pdm->dmDisplayOrientation == DMDO_90 ||
  4678. pdm->dmDisplayOrientation == DMDO_270)
  4679. {
  4680. bSwapWH = TRUE;
  4681. }
  4682. }
  4683. //
  4684. // For Inf, MaxFreq = {56, 0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF}
  4685. // The following block only effective to EDID
  4686. //
  4687. if (freq > 1 && (flag & DISPLAY_DEVICE_PRUNE_FREQ)) // Non Driver-default frequency
  4688. {
  4689. if (freq < pMaxFreqs->ulMinVerticalRate)
  4690. {
  4691. return TRUE;
  4692. }
  4693. if (freq > pMaxFreqs->ulMaxVerticalRate && freq > 61)
  4694. {
  4695. return TRUE;
  4696. }
  4697. f = (LONG)(freq * pdm->dmPelsHeight);
  4698. if (f < pMaxFreqs->ulMinHorizontalRate && freq < 60)
  4699. {
  4700. return TRUE;
  4701. }
  4702. if (f > pMaxFreqs->ulMaxHorizontalRate && freq > 61)
  4703. {
  4704. return TRUE;
  4705. }
  4706. //
  4707. // ISSUE: We should check against MinPixelClock too. Fix in NT 5.1.
  4708. //
  4709. if ((pdm->dmPelsWidth*f) > pMaxFreqs->ulMaxPixelClock)
  4710. {
  4711. return TRUE;
  4712. }
  4713. // 1.05 is a fudge factor that corrects for vetical retrace time.
  4714. // From Win98
  4715. f1 = f * ((pdm->dmPelsHeight > 600) ? 107 : 105) / 100;
  4716. }
  4717. MODECAP mc = { bSwapWH ? pdm->dmPelsHeight : pdm->dmPelsWidth,
  4718. bSwapWH ? pdm->dmPelsWidth : pdm->dmPelsHeight, freq};
  4719. LPMODECAP pModeCap;
  4720. // Found weird case of 1200x1600
  4721. if (numModeCaps && (flag & DISPLAY_DEVICE_PRUNE_RESOLUTION))
  4722. {
  4723. if (mc.dmHeight > pModeCaps[numModeCaps-1].dmHeight)
  4724. return TRUE;
  4725. }
  4726. for (int i = 0; i < numModeCaps; i++)
  4727. {
  4728. int comp = compModeCap(&mc, &pModeCaps[i]);
  4729. if (comp > 0)
  4730. {
  4731. if (i >= (numModeCaps-1))
  4732. {
  4733. if (flag & DISPLAY_DEVICE_PRUNE_RESOLUTION) {
  4734. return TRUE;
  4735. }
  4736. }
  4737. else
  4738. continue;
  4739. }
  4740. if (freq > 1 && (flag & DISPLAY_DEVICE_PRUNE_FREQ)) // Non Driver-default frequency
  4741. {
  4742. pModeCap = (comp == 0 || i == 0) ? &pModeCaps[i] : &pModeCaps[i-1];
  4743. if (freq > pModeCap->freq && freq > 61 && (comp == 0 || i > 0))
  4744. {
  4745. return TRUE;
  4746. }
  4747. //
  4748. // For EDID, pModeCap = {width, height, freq, 56, 0, 0xFFFFFFFF}.
  4749. // So the following block of code is only effective for INF
  4750. //
  4751. if (freq < pModeCap->MinVFreq)
  4752. {
  4753. return TRUE;
  4754. }
  4755. if (f1 < pModeCap->MinHFreq && freq < 60)
  4756. {
  4757. return TRUE;
  4758. }
  4759. // Sometimes the fulge value downgrades maximum freq below 60, which will lead
  4760. // all modes not supported. Freq 60 has to be supported
  4761. if (f1 > pModeCap->MaxHFreq && freq > 61)
  4762. {
  4763. return TRUE;
  4764. }
  4765. }
  4766. return FALSE;
  4767. }
  4768. return TRUE;
  4769. }
  4770. //
  4771. // Return Value
  4772. // Number of effective modes
  4773. //
  4774. ULONG PruneModesByMonitors(PGRAPHICS_DEVICE PhysDisp, ULONG numRawModes, PDEVMODEMARK pdevmodeMarks)
  4775. {
  4776. PULONG pNumModeCaps;
  4777. ULONG i, numEffectiveModes;
  4778. PMODECAP pModeCaps = NULL;
  4779. FREQUENCY_RANGE MaxFreqs =
  4780. {
  4781. MIN_REFRESH_RATE, // This is to prune out interlaced modes
  4782. 0xffffffff,
  4783. 0,
  4784. 0xffffffff,
  4785. 0,
  4786. 0xffffffff
  4787. };
  4788. PhysDisp->stateFlags &= ~DISPLAY_DEVICE_MODESPRUNED;
  4789. if (PhysDisp->numMonitorDevice == 0)
  4790. return numRawModes;
  4791. pNumModeCaps = (PULONG) PALLOCMEM((MAX_MODE_CAPABILITY * sizeof(MODECAP) + sizeof(ULONG)) * PhysDisp->numMonitorDevice,
  4792. GDITAG_DEVMODE);
  4793. if (pNumModeCaps == NULL)
  4794. return numRawModes;
  4795. pModeCaps = (PMODECAP)((PBYTE)pNumModeCaps + sizeof(ULONG) * PhysDisp->numMonitorDevice);
  4796. TRACE_INIT(("Drv_Trace: PruneModesByMonitors: Enter-- Number of raw modes=%d\n", numRawModes));
  4797. UpdateMonitorDevices();
  4798. numEffectiveModes = 0;
  4799. for (i = 0; i < PhysDisp->numMonitorDevice; i++)
  4800. {
  4801. pNumModeCaps[i] = 0;
  4802. if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag))
  4803. {
  4804. FREQUENCY_RANGE freqs;
  4805. pNumModeCaps[i] = GetMonitorCapability((PDEVICE_OBJECT)PhysDisp->MonitorDevices[i].pdo, pModeCaps, &freqs);
  4806. if (pNumModeCaps[i] == 0)
  4807. {
  4808. TRACE_INIT(("Drv_Trace: GetMonitorCapability Failed for device %08lx\n", PhysDisp->MonitorDevices[i].pdo));
  4809. }
  4810. //
  4811. // Intersect frequency ranges for all display devices.
  4812. //
  4813. MaxFreqs.ulMinVerticalRate = max(MaxFreqs.ulMinVerticalRate, freqs.ulMinVerticalRate);
  4814. MaxFreqs.ulMaxVerticalRate = min(MaxFreqs.ulMaxVerticalRate, freqs.ulMaxVerticalRate);
  4815. MaxFreqs.ulMinHorizontalRate = max(MaxFreqs.ulMinHorizontalRate, freqs.ulMinHorizontalRate);
  4816. MaxFreqs.ulMaxHorizontalRate = min(MaxFreqs.ulMaxHorizontalRate, freqs.ulMaxHorizontalRate);
  4817. MaxFreqs.ulMinPixelClock = max(MaxFreqs.ulMinPixelClock, freqs.ulMinPixelClock);
  4818. MaxFreqs.ulMaxPixelClock = min(MaxFreqs.ulMaxPixelClock, freqs.ulMaxPixelClock);
  4819. }
  4820. pModeCaps += pNumModeCaps[i];
  4821. numEffectiveModes += pNumModeCaps[i];
  4822. }
  4823. // If get nothing to prune
  4824. if (numEffectiveModes == 0)
  4825. {
  4826. VFREEMEM(pNumModeCaps);
  4827. return numRawModes;
  4828. }
  4829. numEffectiveModes = 0;
  4830. for ( ; numRawModes > 0; numRawModes--)
  4831. {
  4832. PDEVMODEW pdevMode = pdevmodeMarks[numRawModes-1].pDevMode;
  4833. TRACE_INIT(("Drv_Trace: PruneMode Width=%d, Height=%d, Freq=%d\n",
  4834. pdevMode->dmPelsWidth, pdevMode->dmPelsHeight, pdevMode->dmDisplayFrequency));
  4835. pModeCaps = (PMODECAP)((PBYTE)pNumModeCaps + sizeof(ULONG) * PhysDisp->numMonitorDevice);
  4836. for (i = 0; i < PhysDisp->numMonitorDevice; i++)
  4837. {
  4838. if (pNumModeCaps[i] == 0)
  4839. continue;
  4840. if (PruneMode(pdevMode, pModeCaps, pNumModeCaps[i], &MaxFreqs, PhysDisp->MonitorDevices[i].flag))
  4841. {
  4842. TRACE_INIT(("---Pruned\n"));
  4843. pdevmodeMarks[numRawModes-1].bPruned = TRUE;
  4844. PhysDisp->stateFlags |= DISPLAY_DEVICE_MODESPRUNED;
  4845. break;
  4846. }
  4847. pModeCaps += pNumModeCaps[i];
  4848. }
  4849. if (i == PhysDisp->numMonitorDevice)
  4850. numEffectiveModes++;
  4851. }
  4852. TRACE_INIT(("Drv_Trace: PruneModesByMonitors: Effective Mode Number=%d\n", numEffectiveModes));
  4853. VFREEMEM(pNumModeCaps);
  4854. return numEffectiveModes;
  4855. }
  4856. BOOL CalculateDefaultPreferredModeFromEdid(PDEVICE_OBJECT pdo, LPMODECAP pmc)
  4857. {
  4858. //
  4859. // Try to set our default preferred mode to 800x600x60
  4860. // We try 60Hz only to prevent some crappy EDID from screwing the screen
  4861. // right after Setup, for example, some external LCDs.
  4862. //
  4863. FREQUENCY_RANGE MaxFreqs;
  4864. PMODECAP pModeCaps = (PMODECAP) PALLOCMEM(MAX_MODE_CAPABILITY * sizeof(MODECAP), GDITAG_DEVMODE);
  4865. BOOL bGotMode = FALSE;
  4866. if (pModeCaps == NULL)
  4867. {
  4868. return FALSE;
  4869. }
  4870. ULONG NumModeCaps = GetMonitorCapability(pdo, pModeCaps, &MaxFreqs);
  4871. if (NumModeCaps)
  4872. {
  4873. DEVMODEW dm;
  4874. ULONG Freqs[] = {85, 82, 75, 72, 70, 60};
  4875. pmc->dmWidth = dm.dmPelsWidth = 800 ;
  4876. pmc->dmHeight = dm.dmPelsHeight = 600 ;
  4877. for (ULONG i = 0; i < sizeof(Freqs)/sizeof(ULONG); i++)
  4878. {
  4879. pmc->freq = dm.dmDisplayFrequency = Freqs[i];
  4880. if (!PruneMode(&dm, pModeCaps, NumModeCaps, &MaxFreqs, DISPLAY_DEVICE_PRUNE_FREQ | DISPLAY_DEVICE_PRUNE_RESOLUTION))
  4881. {
  4882. bGotMode = TRUE;
  4883. break;
  4884. }
  4885. }
  4886. }
  4887. VFREEMEM(pModeCaps);
  4888. if (!bGotMode) {
  4889. return FALSE;
  4890. }
  4891. TRACE_INIT(("win32k!GetPreferredModeFromEdid1: Detailed timing %lux%lu at %luHz\n",
  4892. pmc->dmWidth, pmc->dmHeight, pmc->freq));
  4893. return TRUE;
  4894. }
  4895. BOOL CalculatePreferredModeFromEdid1 (PBYTE pEdid, PDEVICE_OBJECT pdo, LPMODECAP pmc)
  4896. {
  4897. PBYTE ptr = &pEdid[0x36];
  4898. ULONG count, area;
  4899. //
  4900. // If EDID has preferrred mode bit
  4901. // This function calculates a preferred mode based on the data in
  4902. // the first detailed timing block. If that data indicates that we can do
  4903. // 800x600x85hz, return that as the preferred mode. Otherwise, just
  4904. // return FALSE indicating that we should fall back to normal default
  4905. // behavior.
  4906. //
  4907. // Otherwise
  4908. // This function returns the preferred mode from the first detailed timing
  4909. // block in the EDID.
  4910. //
  4911. for (count = 0; count < 4; count++) {
  4912. ptr += count * 18;
  4913. if ((ptr[0] != 0 || ptr[1] != 0) && ptr[4] != 0) {
  4914. pmc->dmWidth = (ULONG) ptr[2] + ((ULONG)(ptr[4] & 0xF0)) * 0x10;
  4915. pmc->dmHeight = (ULONG) ptr[5] + ((ULONG)(ptr[7] & 0xF0)) * 0x10 ;
  4916. pmc->freq = ((ULONG)ptr[0] + ((ULONG)ptr[1]) * 0x100) * 10000;
  4917. area = (pmc->dmWidth + (ULONG)ptr[3] + ((ULONG)(ptr[4]&0x0F)) * 0x100) *
  4918. (pmc->dmHeight+ (ULONG)ptr[6] + ((ULONG)(ptr[7]&0x0F)) * 0x100);
  4919. if (area == 0) {
  4920. ASSERT (FALSE);
  4921. return FALSE;
  4922. }
  4923. pmc->freq /= area;
  4924. if ((pEdid[0x18] & 0x02)) {
  4925. TRACE_INIT(("win32k!GetPreferredModeFromEdid1: Detailed timing %lux%lu at %luHz\n",
  4926. pmc->dmWidth, pmc->dmHeight, pmc->freq));
  4927. return TRUE;
  4928. }
  4929. else
  4930. {
  4931. break;
  4932. }
  4933. }
  4934. }
  4935. return CalculateDefaultPreferredModeFromEdid(pdo, pmc);
  4936. }
  4937. BOOL CalculatePreferredModeFromEdid2 (PEDID2 pEdid2, PDEVICE_OBJECT pdo, LPMODECAP pmc)
  4938. {
  4939. ULONG ulEdidOffset = EDID2_LUMINANCE_TABLE_OFFSET,
  4940. count;
  4941. //
  4942. // No detailed timing block
  4943. //
  4944. if ((pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) == 0) {
  4945. return FALSE;
  4946. }
  4947. PUCHAR pucLuminanceTable = (PUCHAR)pEdid2 + ulEdidOffset;
  4948. //
  4949. // Luminance Table
  4950. //
  4951. ulEdidOffset += (((*pucLuminanceTable & EDID2_LT0_SUB_CHANNELS_FLAG) ? 3 : 1) *
  4952. (*pucLuminanceTable & EDID2_LT0_ENTRIES_MASK) + 1);
  4953. //
  4954. // Frequency Ranges
  4955. //
  4956. ulEdidOffset += ((pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_FREQUENCY_RANGE_MASK) >>
  4957. EDID2_MOT0_FREQUENCY_RANGE_SHIFT) *
  4958. sizeof (EDID2_FREQUENCY_RANGE);
  4959. //
  4960. // Detailed Range Limits
  4961. //
  4962. ulEdidOffset += ((pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_DETAIL_TIMING_RANGE_MASK) >>
  4963. EDID2_MOT0_DETAIL_TIMING_RANGE_SHIFT) *
  4964. sizeof(EDID2_DETAIL_TIMING_RANGE);
  4965. //
  4966. // Timing Codes
  4967. //
  4968. ulEdidOffset += ((pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_TIMING_CODE_MASK) >>
  4969. EDID2_MOT1_TIMING_CODE_SHIFT) *
  4970. sizeof(EDID2_TIMING_CODE);
  4971. ULONG ulNumberOfDetailTimings = (pEdid2->ucaMapOfTiming[1] & EDID2_MOT1_DETAIL_TIMING_MASK) >>
  4972. EDID2_MOT1_DETAIL_TIMING_SHIFT;
  4973. for (count = 0; count < ulNumberOfDetailTimings; count++)
  4974. {
  4975. ulEdidOffset += count*sizeof(EDID2_DETAIL_TIMING);
  4976. if ((ulEdidOffset + sizeof(EDID2_DETAIL_TIMING)) >= sizeof (EDID2))
  4977. {
  4978. ASSERT(FALSE);
  4979. return FALSE;
  4980. }
  4981. PEDID2_DETAIL_TIMING pDetailTiming = (PEDID2_DETAIL_TIMING)((PUCHAR)pEdid2 + ulEdidOffset);
  4982. pmc->dmWidth = ((ULONG)(pDetailTiming->ucHorizontalHighBits & 0xf0) << 4) +
  4983. pDetailTiming->ucHorizontalActiveLowByte;
  4984. pmc->dmHeight = ((ULONG)(pDetailTiming->ucVerticalHighBits & 0xf0) << 4) +
  4985. pDetailTiming->ucVerticalActiveLowByte;
  4986. ULONG ulHorizontalTotal = ((ULONG)(pDetailTiming->ucHorizontalHighBits & 0x0f) << 8) +
  4987. pDetailTiming->ucHorizontalBlankLowByte + pmc->dmWidth;
  4988. ULONG ulVerticalTotal = ((ULONG)(pDetailTiming->ucVerticalHighBits & 0x0f) << 8) +
  4989. pDetailTiming->ucVerticalBlankLowByte + pmc->dmHeight;
  4990. //
  4991. // Make sure we won't divide by zero in case of bad EDID.
  4992. //
  4993. if ((0 == ulHorizontalTotal) || (0 == ulVerticalTotal))
  4994. {
  4995. ASSERT(FALSE);
  4996. return FALSE;
  4997. }
  4998. //
  4999. // Calculate refresh rate rounding to the nearest integer.
  5000. //
  5001. pmc->freq = ((((ULONG)(pDetailTiming->usPixelClock) * 100000) / (ulHorizontalTotal * ulVerticalTotal)) + 5) / 10;
  5002. if (pDetailTiming->ucFlags & EDID2_DT_INTERLACED) {
  5003. pmc->freq /= 2;
  5004. }
  5005. if (pEdid2->ucaMapOfTiming[0] & EDID2_MOT0_PREFFERED_MODE_FLAG)
  5006. {
  5007. TRACE_INIT(("win32k!GetPreferredModeFromEdid2: Detailed timing %lux%lu at %luHz\n",
  5008. pmc->dmWidth, pmc->dmHeight, pmc->freq));
  5009. return TRUE;
  5010. }
  5011. else
  5012. {
  5013. break;
  5014. }
  5015. }
  5016. return CalculateDefaultPreferredModeFromEdid(pdo, pmc);
  5017. }
  5018. BOOL GetPreferredModeFromEdid(PDEVICE_OBJECT pdo, LPMODECAP pmc)
  5019. {
  5020. BYTE pBuffer[512], *pEdid;
  5021. if (!GetRegEDID(pdo, pBuffer, &pEdid))
  5022. return FALSE;
  5023. //
  5024. // It's EDID2
  5025. //
  5026. if (0x20 == pEdid[0]) {
  5027. return CalculatePreferredModeFromEdid2((PEDID2)pEdid, pdo, pmc);
  5028. }
  5029. if (pEdid[0] != 0 || pEdid[7] != 0) {
  5030. return FALSE;
  5031. }
  5032. for (int i = 1; i < 7; i++)
  5033. {
  5034. if (pEdid[i] != 0xFF)
  5035. return FALSE;
  5036. }
  5037. return (CalculatePreferredModeFromEdid1 (pEdid, pdo, pmc));
  5038. }
  5039. /***************************************************************************\
  5040. * DrvGetPreferredMode
  5041. *
  5042. * Routine that returns the prefered mode.
  5043. *
  5044. \***************************************************************************/
  5045. NTSTATUS
  5046. DrvGetPreferredMode(
  5047. LPDEVMODEW lpDevMode,
  5048. PGRAPHICS_DEVICE PhysDisp
  5049. )
  5050. {
  5051. NTSTATUS retval = STATUS_INVALID_PARAMETER_1;
  5052. DWORD iModeNum;
  5053. ASSERTGDI((lpDevMode != NULL), "Invalid lpDevMode\n");
  5054. ASSERTGDI((PhysDisp != NULL), "Invalid PhysDisp\n");
  5055. UpdateMonitorDevices();
  5056. __try
  5057. {
  5058. lpDevMode->dmPelsWidth = lpDevMode->dmPelsHeight = lpDevMode->dmDisplayFrequency = 0x7FFF;
  5059. for (iModeNum = 0; iModeNum < PhysDisp->numMonitorDevice; iModeNum++)
  5060. {
  5061. if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[iModeNum].flag))
  5062. {
  5063. MODECAP mc;
  5064. if (!GetValuesFromInf((PDEVICE_OBJECT)PhysDisp->MonitorDevices[iModeNum].pdo, 0, &mc))
  5065. {
  5066. if (!GetPreferredModeFromEdid((PDEVICE_OBJECT)PhysDisp->MonitorDevices[iModeNum].pdo, &mc))
  5067. {
  5068. lpDevMode->dmDisplayFrequency = 60;
  5069. continue;
  5070. }
  5071. }
  5072. //
  5073. // To be safe, always pick the smaller refresh rate
  5074. //
  5075. if (mc.freq < lpDevMode->dmDisplayFrequency)
  5076. lpDevMode->dmDisplayFrequency = mc.freq;
  5077. if (mc.dmWidth > lpDevMode->dmPelsWidth)
  5078. continue;
  5079. if (mc.dmWidth == lpDevMode->dmPelsWidth &&
  5080. mc.dmHeight > lpDevMode->dmPelsHeight)
  5081. continue;
  5082. lpDevMode->dmPelsWidth = mc.dmWidth;
  5083. lpDevMode->dmPelsHeight = mc.dmHeight;
  5084. lpDevMode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
  5085. }
  5086. }
  5087. if (lpDevMode->dmPelsWidth == 0x7FFF)
  5088. retval = STATUS_INVALID_PARAMETER_3;
  5089. else
  5090. retval = STATUS_SUCCESS;
  5091. }
  5092. __except (EXCEPTION_EXECUTE_HANDLER)
  5093. {
  5094. }
  5095. return retval;
  5096. }
  5097. /***************************************************************************\
  5098. * DrvBuildDevmodeList
  5099. *
  5100. * Builds the list of DEVMODEs for a particular GRAPHICS_DEVICE structure
  5101. *
  5102. * CRIT must be held before this call is made.
  5103. *
  5104. * History:
  5105. * 10-Mar-1996 andreva Created.
  5106. \***************************************************************************/
  5107. VOID
  5108. DrvBuildDevmodeList(
  5109. PGRAPHICS_DEVICE PhysDisp,
  5110. BOOL bUpdateCache)
  5111. {
  5112. GDIFunctionID(DrvBuildDevmodeList);
  5113. ULONG i, j;
  5114. PDRV_NAMES lpNames = NULL;
  5115. DWORD cbOutputSize;
  5116. LPDEVMODEW tmpBuffer;
  5117. PUCHAR reallocBuffer;
  5118. //
  5119. // check if the information is cached already
  5120. // if not, then get the information from the drivers.
  5121. //
  5122. // NOTE : we may want to synchronize access to this list
  5123. // of modes so that we can dynamically update the list
  5124. // when plug - and - play arrives.
  5125. //
  5126. // NOTE : the list of text modes is built at boot time, and we depend
  5127. // on that list being valid if the PhysDisp is returned.
  5128. // see DrvInitConsole().
  5129. //
  5130. TRACE_INIT(("Drv_Trace: BuildDevmode: Enter"));
  5131. // If HYDRA Remote session we don't want to cache the mode as
  5132. // we can be in a reconnect with a different resolution.
  5133. // It these case the driver's only mode has changed so
  5134. // we want to query him to get latest valid mode
  5135. //
  5136. // bUpdateCache = TRUE only when display switching occured. At this time,
  5137. // we need to update mode list
  5138. //
  5139. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) || bUpdateCache)
  5140. {
  5141. if ( (PhysDisp != &gFullscreenGraphicsDevice) &&
  5142. ( (PhysDisp->cbdevmodeInfo != 0) && (PhysDisp->devmodeInfo != NULL)) )
  5143. {
  5144. if (PhysDisp->devmodeInfo)
  5145. {
  5146. VFREEMEM(PhysDisp->devmodeInfo);
  5147. PhysDisp->devmodeInfo = NULL;
  5148. }
  5149. PhysDisp->cbdevmodeInfo = 0;
  5150. if (PhysDisp->devmodeMarks)
  5151. {
  5152. VFREEMEM(PhysDisp->devmodeMarks);
  5153. PhysDisp->devmodeMarks = NULL;
  5154. }
  5155. }
  5156. }
  5157. if ( (PhysDisp != &gFullscreenGraphicsDevice) &&
  5158. (PhysDisp->cbdevmodeInfo == 0) &&
  5159. (PhysDisp->devmodeInfo == NULL) )
  5160. {
  5161. TRACE_INIT(("\nDrv_Trace: BuildDevmode: Rebuild List\n"));
  5162. PhysDisp->numRawModes = 0;
  5163. lpNames = DrvGetDisplayDriverNames(PhysDisp);
  5164. if (lpNames)
  5165. {
  5166. for (i = 0; i < lpNames->cNames; i++)
  5167. {
  5168. cbOutputSize = ldevGetDriverModes(lpNames->D[i].lpDisplayName,
  5169. lpNames->D[i].hDriver,
  5170. &tmpBuffer);
  5171. if (cbOutputSize)
  5172. {
  5173. //
  5174. // create a new buffer copy the old data into it
  5175. // and append the new data at the end - we want
  5176. // a continuous buffer for all the data.
  5177. //
  5178. reallocBuffer = (PUCHAR) PALLOCNOZ(PhysDisp->cbdevmodeInfo + cbOutputSize,
  5179. GDITAG_DRVSUP);
  5180. if (reallocBuffer)
  5181. {
  5182. if (PhysDisp->cbdevmodeInfo)
  5183. {
  5184. //
  5185. // Copy the contents of the old buffer
  5186. // and free it
  5187. //
  5188. RtlCopyMemory(reallocBuffer,
  5189. PhysDisp->devmodeInfo,
  5190. PhysDisp->cbdevmodeInfo);
  5191. VFREEMEM(PhysDisp->devmodeInfo);
  5192. }
  5193. RtlCopyMemory(reallocBuffer +
  5194. PhysDisp->cbdevmodeInfo,
  5195. tmpBuffer,
  5196. cbOutputSize);
  5197. PhysDisp->cbdevmodeInfo += cbOutputSize;
  5198. PhysDisp->devmodeInfo = (PDEVMODEW) reallocBuffer;
  5199. }
  5200. else
  5201. {
  5202. WARNING("failed realloc\n");
  5203. }
  5204. }
  5205. else
  5206. {
  5207. WARNING("display driver not present\n");
  5208. }
  5209. if (tmpBuffer) {
  5210. VFREEMEM(tmpBuffer);
  5211. }
  5212. }
  5213. VFREEMEM(lpNames);
  5214. }
  5215. if ( (PhysDisp->cbdevmodeInfo == 0) &&
  5216. (PhysDisp->devmodeInfo == NULL) )
  5217. {
  5218. DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver);
  5219. }
  5220. else
  5221. {
  5222. PDEVMODEW lpdm, lpdm1;
  5223. for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++)
  5224. {
  5225. lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize);
  5226. cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra;
  5227. }
  5228. PhysDisp->devmodeMarks = (PDEVMODEMARK)PALLOCMEM(i * sizeof(DEVMODEMARK),
  5229. GDITAG_DRVSUP);
  5230. if (PhysDisp->devmodeMarks == NULL)
  5231. {
  5232. PhysDisp->cbdevmodeInfo = 0;
  5233. VFREEMEM(PhysDisp->devmodeInfo);
  5234. PhysDisp->devmodeInfo = NULL;
  5235. WARNING("failed allocate lookside list\n");
  5236. DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver);
  5237. }
  5238. else
  5239. {
  5240. PhysDisp->numRawModes = i;
  5241. for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++)
  5242. {
  5243. lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize);
  5244. // jasonha 07/13/2001 Display Orientation Support
  5245. if (!(lpdm->dmFields & DM_DISPLAYORIENTATION))
  5246. {
  5247. lpdm->dmFields |= DM_DISPLAYORIENTATION;
  5248. if (lpdm->dmDisplayOrientation != 0)
  5249. {
  5250. WARNING("driver reported non-zero dmDisplayOrientation, but not DM_DISPLAYORIENTATION flag.\n");
  5251. }
  5252. lpdm->dmDisplayOrientation = DMDO_DEFAULT;
  5253. }
  5254. else if (lpdm->dmDisplayOrientation > DMDO_LAST)
  5255. {
  5256. WARNING("driver reported invalid dmDisplayOrientation.\n");
  5257. lpdm->dmDisplayOrientation = DMDO_DEFAULT;
  5258. }
  5259. // jasonha 09/17/2001 Display Fixed Output Support
  5260. if (!(lpdm->dmFields & DM_DISPLAYFIXEDOUTPUT))
  5261. {
  5262. if (lpdm->dmDisplayFixedOutput != 0)
  5263. {
  5264. WARNING("driver reported non-zero dmDisplayFixedOutput, but not DM_DISPLAYFIXEDOUTPUT flag.\n");
  5265. }
  5266. lpdm->dmDisplayFixedOutput = DMDFO_DEFAULT;
  5267. }
  5268. else if (lpdm->dmDisplayFixedOutput == DMDFO_DEFAULT ||
  5269. lpdm->dmDisplayFixedOutput > DMDFO_LAST)
  5270. {
  5271. WARNING("driver reported invalid dmDisplayFixedOutput.\n");
  5272. lpdm->dmFields &= ~DM_DISPLAYFIXEDOUTPUT;
  5273. lpdm->dmDisplayFixedOutput = DMDFO_DEFAULT;
  5274. }
  5275. PhysDisp->devmodeMarks[i].bPruned = FALSE;
  5276. PhysDisp->devmodeMarks[i].pDevMode = lpdm;
  5277. cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra;
  5278. }
  5279. // 11/26/98 Ignore miniport default refresh rate
  5280. // But if the default rate is the only mode in the list, we still keep it
  5281. // For example, VGA and mnmdd
  5282. for (i = 1; i <= PhysDisp->numRawModes; i++)
  5283. {
  5284. lpdm = PhysDisp->devmodeMarks[i-1].pDevMode;
  5285. if (lpdm->dmDisplayFrequency == 1)
  5286. {
  5287. for (j = 1; j <= PhysDisp->numRawModes; j++)
  5288. {
  5289. if (j == i)
  5290. continue;
  5291. lpdm1 = PhysDisp->devmodeMarks[j-1].pDevMode;
  5292. if (lpdm->dmBitsPerPel != lpdm1->dmBitsPerPel)
  5293. continue;
  5294. if (lpdm->dmPelsWidth != lpdm1->dmPelsWidth)
  5295. continue;
  5296. if (lpdm->dmPelsHeight != lpdm1->dmPelsHeight)
  5297. continue;
  5298. if ((lpdm->dmDisplayFlags & DMDISPLAYFLAGS_TEXTMODE) !=
  5299. (lpdm1->dmDisplayFlags & DMDISPLAYFLAGS_TEXTMODE))
  5300. continue;
  5301. if (lpdm->dmDisplayOrientation != lpdm1->dmDisplayOrientation)
  5302. continue;
  5303. if (lpdm->dmDisplayFixedOutput != lpdm1->dmDisplayFixedOutput)
  5304. continue;
  5305. // We find a duplicated mode, so cut off this mode
  5306. if (PhysDisp->numRawModes > i)
  5307. RtlMoveMemory(&PhysDisp->devmodeMarks[i-1],
  5308. &PhysDisp->devmodeMarks[i],
  5309. sizeof(DEVMODEMARK) * (PhysDisp->numRawModes-i));
  5310. PhysDisp->numRawModes--;
  5311. i--;
  5312. break;
  5313. }
  5314. }
  5315. }
  5316. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) == 0 &&
  5317. (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) == 0 &&
  5318. (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0)
  5319. cbOutputSize = PruneModesByMonitors(PhysDisp, PhysDisp->numRawModes, PhysDisp->devmodeMarks);
  5320. if (cbOutputSize == 0)
  5321. DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver);
  5322. //
  5323. // Expand all 32bpp modes to double the effective dots-per-inch.
  5324. // Panning.cxx handles the actual downsizing.
  5325. //
  5326. if (G_fDoubleDpi)
  5327. {
  5328. for (i = 0, cbOutputSize = 0; cbOutputSize < PhysDisp->cbdevmodeInfo; i++)
  5329. {
  5330. lpdm = (LPDEVMODEW)(((LPBYTE)PhysDisp->devmodeInfo) + cbOutputSize);
  5331. if (lpdm->dmBitsPerPel == 32)
  5332. {
  5333. lpdm->dmPelsWidth *= 2;
  5334. lpdm->dmPelsHeight *= 2;
  5335. }
  5336. cbOutputSize += lpdm->dmSize + lpdm->dmDriverExtra;
  5337. }
  5338. }
  5339. }
  5340. }
  5341. }
  5342. else
  5343. {
  5344. TRACE_INIT((" - Use cache"));
  5345. }
  5346. TRACE_INIT((" - Exit\n"));
  5347. return;
  5348. }
  5349. #define DIFF(x, y) ( ((x) >= (y)) ? ((x)-(y)) : ((y)-(x)) )
  5350. // Orientation Difference Table
  5351. // Table lookup returns matching level for two dmDisplayOrientation values.
  5352. // Lower number mean a better match.
  5353. // Exact match => 0
  5354. // 180 rotation => 1
  5355. // 90/270 rotation => 2
  5356. DWORD dwOrientationDiffTable[4][4] = {
  5357. { 0, 2, 1, 2},
  5358. { 2, 0, 2, 1},
  5359. { 1, 2, 0, 2},
  5360. { 2, 1, 2, 0}
  5361. };
  5362. #define ORIENTATION_DIFF(x, y) dwOrientationDiffTable[y][x]
  5363. LPDEVMODEW GetClosestMode(PGRAPHICS_DEVICE PhysDisp, LPDEVMODEW pOrgDevMode, BOOL bPrune)
  5364. {
  5365. DEVMODEW diffMode;
  5366. LPDEVMODEW lpdm, lpModePicked = NULL, lpModeWanted = NULL;
  5367. ULONG diff;
  5368. diffMode.dmBitsPerPel = 0xFFFFFFFF;
  5369. diffMode.dmPelsWidth = 0xFFFFFFFF;
  5370. diffMode.dmPelsHeight = 0xFFFFFFFF;
  5371. diffMode.dmDisplayFrequency = 0xFFFFFFFF;
  5372. diffMode.dmDisplayOrientation = 0xFFFFFFFF;
  5373. diffMode.dmDisplayFixedOutput = 0xFFFFFFFF;
  5374. if (pOrgDevMode->dmDisplayFrequency == 0)
  5375. pOrgDevMode->dmDisplayFrequency = 60;
  5376. if (pOrgDevMode->dmBitsPerPel == 0)
  5377. pOrgDevMode->dmBitsPerPel = 32;
  5378. if ( !(pOrgDevMode->dmFields & DM_DISPLAYORIENTATION) )
  5379. pOrgDevMode->dmDisplayOrientation = DMDO_DEFAULT;
  5380. if ( !(pOrgDevMode->dmFields & DM_DISPLAYFIXEDOUTPUT) )
  5381. pOrgDevMode->dmDisplayFixedOutput = DMDFO_DEFAULT;
  5382. //
  5383. // Do 2 rounds of search.
  5384. // First round, only find smaller or exact mode. Done if exact match.
  5385. // Second round is used done if:
  5386. // Orientation doesn't match or
  5387. // Mode is smalller than 640x480x60 (480x640x60 for rotated modes)
  5388. //
  5389. for (ULONG k = 0; k < 2; k++)
  5390. {
  5391. if (lpModeWanted &&
  5392. diffMode.dmDisplayOrientation == 0 &&
  5393. ((lpModeWanted->dmPelsWidth >= lpModeWanted->dmPelsHeight) ?
  5394. (lpModeWanted->dmPelsWidth >= 640 &&
  5395. lpModeWanted->dmPelsHeight>= 480) :
  5396. (lpModeWanted->dmPelsWidth >= 480 &&
  5397. lpModeWanted->dmPelsHeight>= 640)) &&
  5398. lpModeWanted->dmDisplayFrequency >= 60)
  5399. {
  5400. break;
  5401. }
  5402. for (ULONG i = 0; i < PhysDisp->numRawModes; i++)
  5403. {
  5404. if (bPrune && PhysDisp->devmodeMarks[i].bPruned)
  5405. continue;
  5406. lpdm = PhysDisp->devmodeMarks[i].pDevMode;
  5407. if (pOrgDevMode->dmFields & DM_DISPLAYORIENTATION)
  5408. {
  5409. diff = ORIENTATION_DIFF(pOrgDevMode->dmDisplayOrientation, lpdm->dmDisplayOrientation);
  5410. if (diffMode.dmDisplayOrientation < diff) continue;
  5411. if (diffMode.dmDisplayOrientation > diff)
  5412. {
  5413. lpModePicked = lpdm;
  5414. }
  5415. }
  5416. if (pOrgDevMode->dmPelsWidth && lpModePicked != lpdm)
  5417. {
  5418. diff = DIFF(pOrgDevMode->dmPelsWidth, lpdm->dmPelsWidth);
  5419. if (diffMode.dmPelsWidth < diff)
  5420. continue;
  5421. else if (diffMode.dmPelsWidth > diff)
  5422. {
  5423. lpModePicked = lpdm;
  5424. }
  5425. }
  5426. if (pOrgDevMode->dmPelsHeight && lpModePicked != lpdm)
  5427. {
  5428. diff = DIFF(pOrgDevMode->dmPelsHeight, lpdm->dmPelsHeight);
  5429. if (diffMode.dmPelsHeight < diff)
  5430. continue;
  5431. else if (diffMode.dmPelsHeight > diff)
  5432. {
  5433. lpModePicked = lpdm;
  5434. }
  5435. }
  5436. if (lpModePicked != lpdm)
  5437. {
  5438. diff = DIFF(pOrgDevMode->dmBitsPerPel, lpdm->dmBitsPerPel);
  5439. if (diffMode.dmBitsPerPel < diff)
  5440. continue;
  5441. else if (diffMode.dmBitsPerPel > diff)
  5442. {
  5443. lpModePicked = lpdm;
  5444. }
  5445. }
  5446. if (lpModePicked != lpdm)
  5447. {
  5448. diff = (pOrgDevMode->dmDisplayFixedOutput != lpdm->dmDisplayFixedOutput) ? 1 : 0;
  5449. if (diffMode.dmDisplayFixedOutput < diff)
  5450. continue;
  5451. else if (diffMode.dmDisplayFixedOutput > diff)
  5452. {
  5453. lpModePicked = lpdm;
  5454. }
  5455. }
  5456. if (lpModePicked != lpdm)
  5457. {
  5458. diff = DIFF(pOrgDevMode->dmDisplayFrequency, lpdm->dmDisplayFrequency);
  5459. if (diffMode.dmDisplayFrequency < diff)
  5460. continue;
  5461. else if (diffMode.dmDisplayFrequency > diff)
  5462. {
  5463. lpModePicked = lpdm;
  5464. }
  5465. }
  5466. // continue if we haven't found a better match
  5467. if (lpModePicked != lpdm)
  5468. continue;
  5469. if (k == 0)
  5470. {
  5471. // skip larger or higher frequency modes (first round only)
  5472. if (lpModePicked->dmPelsWidth > pOrgDevMode->dmPelsWidth &&
  5473. pOrgDevMode->dmPelsWidth)
  5474. continue;
  5475. if (lpModePicked->dmPelsHeight > pOrgDevMode->dmPelsHeight &&
  5476. pOrgDevMode->dmPelsHeight != 0)
  5477. continue;
  5478. if (lpModePicked->dmDisplayFrequency > pOrgDevMode->dmDisplayFrequency)
  5479. continue;
  5480. }
  5481. lpModeWanted = lpModePicked;
  5482. diffMode.dmDisplayOrientation = ORIENTATION_DIFF(pOrgDevMode->dmDisplayOrientation, lpdm->dmDisplayOrientation);
  5483. diffMode.dmPelsWidth = DIFF(pOrgDevMode->dmPelsWidth, lpdm->dmPelsWidth);
  5484. diffMode.dmPelsHeight = DIFF(pOrgDevMode->dmPelsHeight, lpdm->dmPelsHeight);
  5485. diffMode.dmBitsPerPel = DIFF(pOrgDevMode->dmBitsPerPel, lpdm->dmBitsPerPel);
  5486. diffMode.dmDisplayFixedOutput = (pOrgDevMode->dmDisplayFixedOutput != lpdm->dmDisplayFixedOutput) ? 1 : 0;
  5487. diffMode.dmDisplayFrequency = DIFF(pOrgDevMode->dmDisplayFrequency, lpdm->dmDisplayFrequency);
  5488. if (diffMode.dmDisplayOrientation == 0 &&
  5489. diffMode.dmBitsPerPel == 0 &&
  5490. diffMode.dmPelsWidth == 0 &&
  5491. diffMode.dmPelsHeight == 0 &&
  5492. diffMode.dmDisplayFixedOutput == 0 &&
  5493. diffMode.dmDisplayFrequency == 0)
  5494. break;
  5495. }
  5496. }
  5497. #if DBG
  5498. if (lpModeWanted == NULL)
  5499. {
  5500. WARNING("Drv_Trace: GetClosestMode: The PhysDisp driver has Zero mode\n");
  5501. }
  5502. #endif
  5503. return lpModeWanted;
  5504. }
  5505. /***************************************************************************\
  5506. * ProbeAndCaptureDevmode
  5507. *
  5508. * Maps a partial DEVMODE (for example, may only contain width and height)
  5509. * to a complete DEVMODE that the kernel routines will like.
  5510. *
  5511. * CRIT need not be held when calling.
  5512. *
  5513. * History:
  5514. * 10-Mar-1996 andreva Created.
  5515. \***************************************************************************/
  5516. NTSTATUS
  5517. DrvProbeAndCaptureDevmode(
  5518. PGRAPHICS_DEVICE PhysDisp,
  5519. PDEVMODEW *DestinationDevmode,
  5520. BOOL *bDetach,
  5521. PDEVMODEW SourceDevmode,
  5522. BOOL bDefaultMode,
  5523. MODE PreviousMode,
  5524. BOOL bPrune,
  5525. BOOL bClosest,
  5526. BOOL bFromMonitor
  5527. )
  5528. {
  5529. NTSTATUS ntRet = STATUS_UNSUCCESSFUL;
  5530. BOOL bRet = FALSE;
  5531. BOOL btmpError;
  5532. ULONG sourceSize;
  5533. ULONG sourceSizeExtra;
  5534. ULONG sizeExtra;
  5535. PDEVMODEW matchedDevmode = NULL;
  5536. PDEVMODEW partialDevmode;
  5537. DWORD tmpDisplayFlags = 0;
  5538. DWORD tmpPanningWidth = 0;
  5539. DWORD tmpPanningHeight = 0;
  5540. DWORD tmpPositionX = 0;
  5541. DWORD tmpPositionY = 0;
  5542. BOOL tmpPosition;
  5543. BOOL bOrientationSpecified = FALSE;
  5544. BOOL bFixedOutputSpecified = FALSE;
  5545. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Entering\n"));
  5546. *DestinationDevmode = NULL;
  5547. *bDetach = FALSE;
  5548. if (SourceDevmode == NULL)
  5549. {
  5550. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit DEVMODE NULL\n\n"));
  5551. return STATUS_SUCCESS;
  5552. }
  5553. TRACE_INIT(("\n"));
  5554. TRACE_INIT((" pDevMode %08lx\n", SourceDevmode));
  5555. partialDevmode = (PDEVMODEW) PALLOCNOZ(sizeof(DEVMODEW) + MAXUSHORT,
  5556. GDITAG_DEVMODE);
  5557. if (partialDevmode == NULL)
  5558. {
  5559. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Could not allocate partial DEVMODE\n\n"));
  5560. return STATUS_UNSUCCESSFUL;
  5561. }
  5562. //
  5563. // Put everything in a try except so we can always reference the original
  5564. // passed in structure.
  5565. //
  5566. __try
  5567. {
  5568. if (PreviousMode == UserMode)
  5569. {
  5570. ProbeForRead(SourceDevmode,
  5571. FIELD_OFFSET(DEVMODEW, dmFields),
  5572. sizeof(DWORD));
  5573. }
  5574. else
  5575. {
  5576. ASSERTGDI(SourceDevmode >= (PDEVMODEW const)MM_USER_PROBE_ADDRESS,
  5577. "Bad kernel mode address\n");
  5578. }
  5579. //
  5580. // Capture these so that they don't change right after the probe.
  5581. //
  5582. sourceSize = SourceDevmode->dmSize;
  5583. sourceSizeExtra = SourceDevmode->dmDriverExtra;
  5584. if (PreviousMode == UserMode)
  5585. {
  5586. ProbeForRead(SourceDevmode,
  5587. sourceSize + sourceSizeExtra,
  5588. sizeof(DWORD));
  5589. }
  5590. dbgDumpDevmode(SourceDevmode);
  5591. if (SourceDevmode->dmFields == 0)
  5592. bClosest = TRUE;
  5593. //
  5594. // At the introduction time of this API, the DEVMODE already contained
  5595. // up to the dmDisplayFrequency field. We will fail is the DEVMODE is
  5596. // smaller than that.
  5597. //
  5598. if (sourceSize >= FIELD_OFFSET(DEVMODEW, dmICMMethod))
  5599. {
  5600. //
  5601. // Determine if the position reflects a detach operation
  5602. //
  5603. // If the size of the rectangle is NULL, that means the device
  5604. // needs to be detached from the desktop.
  5605. //
  5606. if ((SourceDevmode->dmFields & DM_POSITION) &&
  5607. (SourceDevmode->dmFields & DM_PELSWIDTH) &&
  5608. (SourceDevmode->dmPelsWidth == 0) &&
  5609. (SourceDevmode->dmFields & DM_PELSHEIGHT) &&
  5610. (SourceDevmode->dmPelsHeight == 0))
  5611. {
  5612. *bDetach = TRUE;
  5613. VFREEMEM(partialDevmode);
  5614. return STATUS_SUCCESS;
  5615. }
  5616. //
  5617. // Lets build a temporary DEVMODE that will contain the
  5618. // "wished for" DEVMODE, based on matching from the registry.
  5619. // Only match the basic devmode. Other fields (optional ones
  5620. // will be added later)
  5621. //
  5622. // NOTE special case VGA mode so that we don't try to match to the
  5623. // current screen mode.
  5624. //
  5625. RtlZeroMemory(partialDevmode, sizeof(DEVMODEW));
  5626. partialDevmode->dmSize = 0xDDDD;
  5627. partialDevmode->dmDriverExtra = MAXUSHORT;
  5628. if (PhysDisp == &gFullscreenGraphicsDevice)
  5629. {
  5630. //
  5631. // We should never get called to probe the fullscreen modes
  5632. // since they are only called by the console
  5633. //
  5634. ASSERTGDI(FALSE, "ProbeAndCaptureDEVMODE called with VGA device\n");
  5635. VFREEMEM(partialDevmode);
  5636. return STATUS_UNSUCCESSFUL;
  5637. }
  5638. else if (bDefaultMode)
  5639. {
  5640. //
  5641. // We just want to pick the default mode from the driver.
  5642. //
  5643. // Leave the partial DEVMODE with all NULLs
  5644. //
  5645. DrvGetDisplayDriverParameters(PhysDisp,
  5646. partialDevmode,
  5647. TRUE,
  5648. bFromMonitor);
  5649. }
  5650. else
  5651. {
  5652. if (!NT_SUCCESS(DrvGetDisplayDriverParameters(PhysDisp,
  5653. partialDevmode,
  5654. gbBaseVideo,
  5655. bFromMonitor)))
  5656. {
  5657. partialDevmode->dmDriverExtra = 0;
  5658. /*
  5659. * If the above should fail (it seemed to under low memory conditions),
  5660. * then we'd better have a valid size or the following memory copies
  5661. * will be wrong.
  5662. */
  5663. partialDevmode->dmSize = sizeof(DEVMODEW);
  5664. // if (G_TERM(pDispInfo)->hdcScreen)
  5665. // {
  5666. // //
  5667. // // Use the caps as a guess for this.
  5668. // //
  5669. //
  5670. // WARNING("Drv_Trace: CaptMatchDevmode: Could not get current devmode\n");
  5671. //
  5672. // partialDevmode->dmBitsPerPel =
  5673. // GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, BITSPIXEL) *
  5674. // GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, PLANES);
  5675. // partialDevmode->dmPelsWidth =
  5676. // GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, HORZRES);
  5677. // partialDevmode->dmPelsHeight =
  5678. // GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, VERTRES);
  5679. // partialDevmode->dmDisplayFrequency =
  5680. // GreGetDeviceCaps(G_TERM(pDispInfo)->hdcScreen, VREFRESH);
  5681. // }
  5682. }
  5683. if ((SourceDevmode->dmFields & DM_BITSPERPEL) &&
  5684. (SourceDevmode->dmBitsPerPel != 0))
  5685. {
  5686. partialDevmode->dmBitsPerPel = SourceDevmode->dmBitsPerPel;
  5687. }
  5688. if ((SourceDevmode->dmFields & DM_PELSWIDTH) &&
  5689. (SourceDevmode->dmPelsWidth != 0))
  5690. {
  5691. partialDevmode->dmPelsWidth = SourceDevmode->dmPelsWidth;
  5692. }
  5693. if ((SourceDevmode->dmFields & DM_PELSHEIGHT) &&
  5694. (SourceDevmode->dmPelsHeight != 0))
  5695. {
  5696. partialDevmode->dmPelsHeight = SourceDevmode->dmPelsHeight;
  5697. }
  5698. if ((SourceDevmode->dmFields & DM_DISPLAYFREQUENCY) &&
  5699. (SourceDevmode->dmDisplayFrequency != 0))
  5700. {
  5701. partialDevmode->dmDisplayFrequency = SourceDevmode->dmDisplayFrequency;
  5702. }
  5703. else
  5704. {
  5705. //
  5706. // Only use the registry refresh rate if we are going
  5707. // down in resolution. If we are going up in resolution,
  5708. // we will want to pick the lowest refresh rate that
  5709. // makes sense.
  5710. //
  5711. // The exception to this is if we have resetting the mode
  5712. // to the regsitry mode (passing in all 0's), in which case
  5713. // we want exactly what is in the registry.
  5714. //
  5715. if ( ((SourceDevmode->dmPelsWidth != 0) ||
  5716. (SourceDevmode->dmPelsHeight != 0)) )
  5717. {
  5718. partialDevmode->dmDisplayFrequency = 0;
  5719. }
  5720. }
  5721. }
  5722. btmpError = FALSE;
  5723. //
  5724. // These fields are somewhat optional.
  5725. // We capture them if they are valid. Otherwise, they will
  5726. // be initialized back to zero.
  5727. //
  5728. //
  5729. // Pick whichever set of flags we can. Source is first choice,
  5730. // registry is second.
  5731. //
  5732. if (SourceDevmode->dmFields & DM_DISPLAYFLAGS)
  5733. {
  5734. if (SourceDevmode->dmDisplayFlags & (~DMDISPLAYFLAGS_VALID))
  5735. {
  5736. btmpError = TRUE;
  5737. }
  5738. tmpDisplayFlags = SourceDevmode->dmDisplayFlags;
  5739. }
  5740. else if ((partialDevmode->dmFields & DM_DISPLAYFLAGS) &&
  5741. (partialDevmode->dmDisplayFlags &
  5742. (~DMDISPLAYFLAGS_VALID)))
  5743. {
  5744. tmpDisplayFlags = partialDevmode->dmDisplayFlags;
  5745. }
  5746. //
  5747. // If the caller specified panning keep the value, unless it was
  5748. // bigger than the resolution, which is an error.
  5749. //
  5750. // Otherwise, use the value from the registry if it makes sense
  5751. // (i.e. panning is still smaller than the resolution).
  5752. //
  5753. if ((SourceDevmode->dmFields & DM_PANNINGWIDTH) &&
  5754. (SourceDevmode->dmFields & DM_PANNINGHEIGHT))
  5755. {
  5756. if ((SourceDevmode->dmPanningWidth > partialDevmode->dmPelsWidth) ||
  5757. (SourceDevmode->dmPanningHeight > partialDevmode->dmPelsHeight))
  5758. {
  5759. btmpError = TRUE;
  5760. }
  5761. tmpPanningWidth = SourceDevmode->dmPanningWidth;
  5762. tmpPanningHeight = SourceDevmode->dmPanningHeight;
  5763. }
  5764. else if ((partialDevmode->dmFields & DM_PANNINGWIDTH) &&
  5765. (partialDevmode->dmFields & DM_PANNINGHEIGHT) &&
  5766. (partialDevmode->dmPanningHeight < partialDevmode->dmPelsHeight) &&
  5767. (partialDevmode->dmPanningWidth < partialDevmode->dmPelsWidth))
  5768. {
  5769. tmpPanningWidth = partialDevmode->dmPanningWidth;
  5770. tmpPanningHeight = partialDevmode->dmPanningHeight;
  5771. }
  5772. //
  5773. // Check the orientation.
  5774. //
  5775. if (SourceDevmode->dmFields & DM_DISPLAYORIENTATION)
  5776. {
  5777. bOrientationSpecified = TRUE;
  5778. partialDevmode->dmDisplayOrientation = SourceDevmode->dmDisplayOrientation;
  5779. if (SourceDevmode->dmDisplayOrientation > DMDO_LAST)
  5780. {
  5781. btmpError = TRUE;
  5782. }
  5783. }
  5784. //
  5785. // Check fixed output mode.
  5786. //
  5787. if (SourceDevmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
  5788. {
  5789. partialDevmode->dmDisplayFixedOutput = SourceDevmode->dmDisplayFixedOutput;
  5790. // DMDFO_DEFAULT means the first driver reported devmode
  5791. // matching the other parameters is to be picked; so, in
  5792. // that case bFixedOutputSpecified remains FALSE.
  5793. if (SourceDevmode->dmDisplayFixedOutput != DMDFO_DEFAULT)
  5794. {
  5795. bFixedOutputSpecified = TRUE;
  5796. if (SourceDevmode->dmDisplayFixedOutput > DMDFO_LAST)
  5797. {
  5798. btmpError = TRUE;
  5799. }
  5800. }
  5801. }
  5802. //
  5803. // Capture the position.
  5804. //
  5805. // If the size of the rectangle is NULL, that means the device
  5806. // needs to be detached from the desktop.
  5807. //
  5808. if (SourceDevmode->dmFields & DM_POSITION)
  5809. {
  5810. tmpPosition = TRUE;
  5811. tmpPositionX = SourceDevmode->dmPosition.x;
  5812. tmpPositionY = SourceDevmode->dmPosition.y;
  5813. }
  5814. else
  5815. {
  5816. tmpPosition = partialDevmode->dmFields & DM_POSITION;
  5817. tmpPositionX = partialDevmode->dmPosition.x;
  5818. tmpPositionY = partialDevmode->dmPosition.y;
  5819. }
  5820. //
  5821. // If the PhysDisp attaches to a device which removable, never put
  5822. // the primary desktop on it. And never put origin (0,0) on it
  5823. //
  5824. if (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOVABLE)
  5825. {
  5826. if (tmpPosition &&
  5827. tmpPositionX == 0 &&
  5828. tmpPositionY == 0 )
  5829. {
  5830. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: User tried to put the primary desktop on a removable device.\n"));
  5831. VFREEMEM(partialDevmode);
  5832. return STATUS_UNSUCCESSFUL;
  5833. }
  5834. }
  5835. if (btmpError == TRUE)
  5836. {
  5837. //
  5838. // The panning values or the flags are invalid
  5839. //
  5840. RIP("Drv_Trace: CaptMatchDevmode: Invalid Optional DEVMODE fields\n");
  5841. }
  5842. else
  5843. {
  5844. //
  5845. // Allocate enough memory so we can store the whole devmode.
  5846. //
  5847. sizeExtra = sourceSizeExtra;
  5848. if (sizeExtra == 0)
  5849. {
  5850. sizeExtra = partialDevmode->dmDriverExtra;
  5851. }
  5852. matchedDevmode = (PDEVMODEW) PALLOCMEM(sizeof(DEVMODEW) + sizeExtra,
  5853. GDITAG_DEVMODE);
  5854. if (matchedDevmode)
  5855. {
  5856. //
  5857. // Let's copy any DriverExtra information that the
  5858. // application may have passed down while we are still in
  5859. // the try\except. If we fail the call later, the memory
  5860. // will get deallocated anyways.
  5861. //
  5862. // If the application did not specify any such data, then
  5863. // copy it from the registry.
  5864. //
  5865. if (sourceSizeExtra)
  5866. {
  5867. RtlCopyMemory(matchedDevmode + 1,
  5868. (PUCHAR)SourceDevmode + sourceSize,
  5869. sizeExtra);
  5870. }
  5871. else if (partialDevmode->dmDriverExtra)
  5872. {
  5873. RtlCopyMemory(matchedDevmode + 1,
  5874. (PUCHAR)partialDevmode + partialDevmode->dmSize,
  5875. sizeExtra);
  5876. }
  5877. }
  5878. }
  5879. }
  5880. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Capture Complete\n"));
  5881. }
  5882. __except (EXCEPTION_EXECUTE_HANDLER)
  5883. {
  5884. WARNINGX(101);
  5885. //
  5886. // If we hit an exception, free the buffer we have allocated.
  5887. //
  5888. if (matchedDevmode)
  5889. {
  5890. VFREEMEM(matchedDevmode);
  5891. }
  5892. matchedDevmode = NULL;
  5893. }
  5894. //
  5895. // This is our matching algorithm, based on requirements from Win95.
  5896. //
  5897. // As a rule, a value in the DEVMODE is only valid when BOTH the value is
  5898. // non-zero, and the dmFields flag is set. Otherwise, the value from the
  5899. // registry must be used
  5900. //
  5901. // For X, Y and color depth, we will follow this rule.
  5902. //
  5903. // For the refresh rate, we are just trying to find something that works
  5904. // for the screen. We are far from guaranteed that the refresh rate in
  5905. // the registry will be found for the X and Y we have since refresh rates
  5906. // vary a lot from mode to mode.
  5907. //
  5908. // So if the value is not specifically set and we do not find the exact
  5909. // value from the reigstry in the new resolution, Then we will try 60 Hz.
  5910. // We just want to get something that works MOST of the time so that the
  5911. // user does not get a mode that does not work.
  5912. //
  5913. // For the other fields (dmDisplayFlags, and panning), we just pass on what
  5914. // the application specified, and it's up to the driver to parse those,
  5915. // fields appropriatly.
  5916. //
  5917. //
  5918. // Now lets enumerate all the DEVMODEs and see if we have one
  5919. // that matches what we need.
  5920. //
  5921. if (matchedDevmode)
  5922. {
  5923. typedef enum {
  5924. NO_MATCH,
  5925. DEFAULT_MATCH,
  5926. EXACT_MATCH
  5927. } MatchLevel;
  5928. PDEVMODEW pdevmodeMatch = NULL;
  5929. MatchLevel eOrientationMatch = NO_MATCH;
  5930. MatchLevel eFixedOutputMatch = NO_MATCH;
  5931. MatchLevel eFrequencyMatch = NO_MATCH;
  5932. BOOL bExactMatch = FALSE;
  5933. PDEVMODEW pdevmodeInfo;
  5934. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Start matching\n"));
  5935. DrvBuildDevmodeList(PhysDisp, FALSE);
  5936. pdevmodeInfo = PhysDisp->devmodeInfo;
  5937. //
  5938. // If we can not find a mode because the caller was asking for the
  5939. // default mode, then just pick any 640x480 mode.
  5940. // We are not worried about picking a nice default because the applet
  5941. // generally takes care of that during configuration.
  5942. //
  5943. // In the case of hydra, the first mode in the driver is picked - why ?
  5944. //
  5945. // For mirroring, the mode for the primary device should be used.
  5946. // A special error code will be used for that
  5947. //
  5948. if ((partialDevmode->dmBitsPerPel == 0) &&
  5949. (partialDevmode->dmPelsWidth == 0) &&
  5950. (partialDevmode->dmPelsHeight == 0) &&
  5951. (partialDevmode->dmDisplayOrientation == DMDO_DEFAULT))
  5952. {
  5953. WARNING("Drv_Trace: CaptMatchDevmode: DEFAULT DEVMODE picked\n");
  5954. if (PhysDisp->stateFlags & (DISPLAY_DEVICE_DISCONNECT | DISPLAY_DEVICE_REMOTE))
  5955. {
  5956. //
  5957. // Hydra only supports one mode.
  5958. //
  5959. if (PhysDisp->devmodeInfo)
  5960. {
  5961. partialDevmode->dmBitsPerPel = PhysDisp->devmodeInfo->dmBitsPerPel;
  5962. partialDevmode->dmPelsWidth = PhysDisp->devmodeInfo->dmPelsWidth;
  5963. partialDevmode->dmPelsHeight = PhysDisp->devmodeInfo->dmPelsHeight;
  5964. partialDevmode->dmDisplayFrequency = PhysDisp->devmodeInfo->dmDisplayFrequency;
  5965. partialDevmode->dmDisplayOrientation = PhysDisp->devmodeInfo->dmDisplayOrientation;
  5966. partialDevmode->dmDisplayFixedOutput = PhysDisp->devmodeInfo->dmDisplayFixedOutput;
  5967. }
  5968. }
  5969. else if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  5970. {
  5971. //
  5972. // For the mirror driver:
  5973. // If we have no modes in the driver, fail.
  5974. // Otherwise, return the default mode the driver provides.
  5975. //
  5976. if (PhysDisp->cbdevmodeInfo == 0)
  5977. {
  5978. ntRet = STATUS_INVALID_PARAMETER_MIX;
  5979. }
  5980. }
  5981. else
  5982. {
  5983. partialDevmode->dmBitsPerPel = 0;
  5984. partialDevmode->dmPelsWidth = 640;
  5985. partialDevmode->dmPelsHeight = 480;
  5986. if (bClosest)
  5987. {
  5988. LPDEVMODEW pdm = GetClosestMode(PhysDisp, partialDevmode, bPrune);
  5989. if (pdm != NULL)
  5990. {
  5991. partialDevmode->dmBitsPerPel = pdm->dmBitsPerPel;
  5992. partialDevmode->dmPelsWidth = pdm->dmPelsWidth;
  5993. partialDevmode->dmPelsHeight = pdm->dmPelsHeight;
  5994. partialDevmode->dmDisplayFrequency = pdm->dmDisplayFrequency;
  5995. partialDevmode->dmDisplayOrientation = pdm->dmDisplayOrientation;
  5996. partialDevmode->dmDisplayFixedOutput = pdm->dmDisplayFixedOutput;
  5997. }
  5998. }
  5999. }
  6000. }
  6001. //
  6002. // For mirror drivers:
  6003. // If the driver return no modes but something was specified in the
  6004. // registry, return that to the driver.
  6005. //
  6006. else if ((PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
  6007. (PhysDisp->cbdevmodeInfo == 0))
  6008. {
  6009. pdevmodeMatch = partialDevmode;
  6010. ASSERTGDI(PhysDisp->cbdevmodeInfo == 0, "MIRROR driver must have no modes\n");
  6011. }
  6012. else if (bClosest)
  6013. {
  6014. LPDEVMODEW pdm = GetClosestMode(PhysDisp, partialDevmode, bPrune);
  6015. if (pdm != NULL)
  6016. {
  6017. partialDevmode->dmBitsPerPel = pdm->dmBitsPerPel;
  6018. partialDevmode->dmPelsWidth = pdm->dmPelsWidth;
  6019. partialDevmode->dmPelsHeight = pdm->dmPelsHeight;
  6020. partialDevmode->dmDisplayFrequency = pdm->dmDisplayFrequency;
  6021. partialDevmode->dmDisplayOrientation = pdm->dmDisplayOrientation;
  6022. partialDevmode->dmDisplayFixedOutput = pdm->dmDisplayFixedOutput;
  6023. }
  6024. }
  6025. for (ULONG i = 0; i < PhysDisp->numRawModes; i++)
  6026. {
  6027. if (bPrune && PhysDisp->devmodeMarks[i].bPruned)
  6028. continue;
  6029. pdevmodeInfo = PhysDisp->devmodeMarks[i].pDevMode;
  6030. if (((partialDevmode->dmBitsPerPel == 0) ||
  6031. (partialDevmode->dmBitsPerPel == pdevmodeInfo->dmBitsPerPel)) &&
  6032. (partialDevmode->dmPelsWidth == pdevmodeInfo->dmPelsWidth) &&
  6033. (partialDevmode->dmPelsHeight == pdevmodeInfo->dmPelsHeight) &&
  6034. ((partialDevmode->dmDisplayOrientation == pdevmodeInfo->dmDisplayOrientation) ||
  6035. (
  6036. (eOrientationMatch != EXACT_MATCH) &&
  6037. !bOrientationSpecified &&
  6038. (
  6039. (eOrientationMatch != DEFAULT_MATCH) ||
  6040. (pdevmodeInfo->dmDisplayOrientation == DMDO_DEFAULT))
  6041. )) &&
  6042. (!bFixedOutputSpecified ||
  6043. (partialDevmode->dmDisplayFixedOutput == pdevmodeInfo->dmDisplayFixedOutput))
  6044. )
  6045. {
  6046. //
  6047. // Pick at least the first mode that matches the resolution
  6048. // so that we at least have a chance at working.
  6049. //
  6050. // Then pick 60 Hz if we find it.
  6051. //
  6052. // Even better, pick the refresh that matches the current
  6053. // refresh (we assume that what's in the registry has the
  6054. // best chance of working.
  6055. //
  6056. if (pdevmodeMatch == NULL)
  6057. {
  6058. pdevmodeMatch = pdevmodeInfo;
  6059. }
  6060. if ((eOrientationMatch == NO_MATCH) &&
  6061. (pdevmodeInfo->dmDisplayOrientation == DMDO_DEFAULT))
  6062. {
  6063. pdevmodeMatch = pdevmodeInfo;
  6064. eOrientationMatch = DEFAULT_MATCH;
  6065. eFixedOutputMatch = NO_MATCH;
  6066. eFrequencyMatch = NO_MATCH;
  6067. }
  6068. if ((eOrientationMatch != EXACT_MATCH) &&
  6069. (partialDevmode->dmDisplayOrientation ==
  6070. pdevmodeInfo->dmDisplayOrientation))
  6071. {
  6072. pdevmodeMatch = pdevmodeInfo;
  6073. eOrientationMatch = EXACT_MATCH;
  6074. eFixedOutputMatch = NO_MATCH;
  6075. eFrequencyMatch = NO_MATCH;
  6076. }
  6077. // Fixed Output setting only matches exactly when specified,
  6078. // but matches first when not specified (when field flag isn't
  6079. // set or dmDisplayFixedOutput == DMDFO_DEFAULT.)
  6080. if ((eFixedOutputMatch != EXACT_MATCH) &&
  6081. (!bFixedOutputSpecified ||
  6082. (partialDevmode->dmDisplayFixedOutput ==
  6083. pdevmodeInfo->dmDisplayFixedOutput)
  6084. ))
  6085. {
  6086. pdevmodeMatch = pdevmodeInfo;
  6087. eFixedOutputMatch = EXACT_MATCH;
  6088. eFrequencyMatch = NO_MATCH;
  6089. }
  6090. if ((eFrequencyMatch == NO_MATCH) &&
  6091. (pdevmodeInfo->dmDisplayFrequency == 60))
  6092. {
  6093. pdevmodeMatch = pdevmodeInfo;
  6094. eFrequencyMatch = DEFAULT_MATCH;
  6095. }
  6096. if ((eFrequencyMatch != EXACT_MATCH) &&
  6097. (partialDevmode->dmDisplayFrequency ==
  6098. pdevmodeInfo->dmDisplayFrequency))
  6099. {
  6100. //
  6101. // We found even better than 60 - an exact frequency match !
  6102. //
  6103. eFrequencyMatch = EXACT_MATCH;
  6104. pdevmodeMatch = pdevmodeInfo;
  6105. if (eOrientationMatch == EXACT_MATCH &&
  6106. eFixedOutputMatch == EXACT_MATCH)
  6107. {
  6108. bExactMatch = TRUE;
  6109. break;
  6110. }
  6111. //
  6112. // For now, we ignore these other fields since they
  6113. // considered optional.
  6114. //
  6115. // pdevmodeInfo->dmDisplayFlags;
  6116. // pdevmodeInfo->dmPanningWidth;
  6117. // pdevmodeInfo->dmPanningHeight;
  6118. }
  6119. }
  6120. }
  6121. //
  6122. // Always set these flags since we initialize the values.
  6123. // We need consistent flags all the time to avoid extra modesets
  6124. //
  6125. // Also, force font size to be static for now.
  6126. //
  6127. if (pdevmodeMatch != NULL)
  6128. {
  6129. RtlCopyMemory(matchedDevmode,
  6130. pdevmodeMatch,
  6131. pdevmodeMatch->dmSize);
  6132. matchedDevmode->dmDriverExtra = (WORD) sizeExtra;
  6133. matchedDevmode->dmLogPixels = (partialDevmode->dmLogPixels == 0) ?
  6134. 96 :
  6135. partialDevmode->dmLogPixels;
  6136. matchedDevmode->dmFields |= (DM_PANNINGHEIGHT |
  6137. DM_PANNINGWIDTH |
  6138. DM_DISPLAYFLAGS |
  6139. DM_LOGPIXELS);
  6140. //
  6141. // Check that the display driver specified all the other
  6142. // flags (res, color, frequency) properly.
  6143. //
  6144. if ((matchedDevmode->dmFields & DM_INTERNAL_VALID_FLAGS) !=
  6145. DM_INTERNAL_VALID_FLAGS)
  6146. {
  6147. RIP("Drv_Trace: CaptMatchDevmode: BAD DM FLAGS\n");
  6148. }
  6149. //
  6150. // Extra flag that determines if we should set the attach or
  6151. // detach flag
  6152. //
  6153. matchedDevmode->dmFields |= ((tmpPosition) ? DM_POSITION : 0);
  6154. //
  6155. // In the case of a good match, also use these extra values.
  6156. //
  6157. matchedDevmode->dmPosition.x = tmpPositionX;
  6158. matchedDevmode->dmPosition.y = tmpPositionY;
  6159. matchedDevmode->dmDisplayFlags = tmpDisplayFlags;
  6160. matchedDevmode->dmPanningWidth = tmpPanningWidth;
  6161. matchedDevmode->dmPanningHeight = tmpPanningHeight;
  6162. }
  6163. //
  6164. // MAJOR optimization : Do not free the list at this point.
  6165. // Many apps call EnumDisplaySettings, and for each mode call
  6166. // ChangeDisplaySettings with it to see if it can be changed
  6167. // dynamically. When we free the list here, it causes us to recreate
  6168. // the list for each mode we have in the list, which can take on
  6169. // the order of 30 seconds if there are multiple display drivers
  6170. // involved.
  6171. // Even if we keep the list here, it should properly get freed
  6172. // at the end of EnumDisplaySettings.
  6173. //
  6174. //
  6175. // Exit path
  6176. //
  6177. if (pdevmodeMatch != NULL)
  6178. {
  6179. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Matched DEVMODE\n"));
  6180. dbgDumpDevmode(matchedDevmode);
  6181. *DestinationDevmode = matchedDevmode;
  6182. ntRet = (bExactMatch) ? STATUS_SUCCESS :
  6183. (((eFrequencyMatch != EXACT_MATCH) &&
  6184. partialDevmode->dmDisplayFrequency) ?
  6185. STATUS_INVALID_PARAMETER :
  6186. ((eFrequencyMatch == EXACT_MATCH) ?
  6187. STATUS_SUCCESS :
  6188. STATUS_RECEIVE_PARTIAL));
  6189. }
  6190. else
  6191. {
  6192. VFREEMEM(matchedDevmode);
  6193. }
  6194. }
  6195. VFREEMEM(partialDevmode);
  6196. if (NT_SUCCESS(ntRet))
  6197. {
  6198. if (ntRet == STATUS_RECEIVE_PARTIAL)
  6199. {
  6200. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit partial success\n\n"));
  6201. }
  6202. else
  6203. {
  6204. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit exact success\n\n"));
  6205. }
  6206. }
  6207. else
  6208. {
  6209. TRACE_INIT(("Drv_Trace: CaptMatchDevmode: Exit error\n\n"));
  6210. }
  6211. return (ntRet);
  6212. }
  6213. /***************************************************************************\
  6214. * DrvGetVideoPowerState
  6215. *
  6216. * History:
  6217. * 02-Dec-1996 AndreVa Created.
  6218. \***************************************************************************/
  6219. NTSTATUS
  6220. DrvGetMonitorPowerState(
  6221. PMDEV pmdev,
  6222. DEVICE_POWER_STATE PowerState)
  6223. {
  6224. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  6225. VIDEO_POWER_STATE VideoPowerState = (VIDEO_POWER_STATE) PowerState;
  6226. ULONG BytesReturned;
  6227. ULONG i;
  6228. #ifdef _HYDRA_
  6229. if (gProtocolType != PROTOCOL_CONSOLE ) {
  6230. //
  6231. // Don't Call this for remote video drivers
  6232. //
  6233. return STATUS_UNSUCCESSFUL;
  6234. }
  6235. #endif
  6236. for (i = 0; i < pmdev->chdev; i++)
  6237. {
  6238. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  6239. if ((pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DISCONNECT) != 0 ) {
  6240. //
  6241. // Don't Call this for disconnect drivers
  6242. //
  6243. ASSERT(pdo.ppdev->pGraphicsDevice->pDeviceHandle == NULL );
  6244. continue;
  6245. }
  6246. Status = GreDeviceIoControl(pdo.ppdev->pGraphicsDevice->pDeviceHandle,
  6247. IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE,
  6248. &VideoPowerState,
  6249. sizeof(VideoPowerState),
  6250. NULL,
  6251. 0,
  6252. &BytesReturned);
  6253. if (!NT_SUCCESS(Status))
  6254. {
  6255. break;
  6256. }
  6257. }
  6258. return Status;
  6259. }
  6260. /***************************************************************************\
  6261. * DrvSetVideoPowerState
  6262. *
  6263. * History:
  6264. * 02-Dec-1996 AndreVa Created.
  6265. \***************************************************************************/
  6266. NTSTATUS
  6267. DrvSetMonitorPowerState(
  6268. PMDEV pmdev,
  6269. DEVICE_POWER_STATE PowerState)
  6270. {
  6271. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  6272. VIDEO_POWER_STATE VideoPowerState = (VIDEO_POWER_STATE) PowerState;
  6273. ULONG BytesReturned;
  6274. ULONG i;
  6275. #ifdef _HYDRA_
  6276. if (gProtocolType != PROTOCOL_CONSOLE ) {
  6277. //
  6278. // Don't Call this for remote video drivers
  6279. //
  6280. return STATUS_UNSUCCESSFUL;
  6281. }
  6282. #endif
  6283. for (i = 0; i < pmdev->chdev; i++)
  6284. {
  6285. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  6286. #ifdef _HYDRA_
  6287. if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DISCONNECT) {
  6288. //
  6289. // Don't Call this for disconnect drivers
  6290. //
  6291. if (pdo.ppdev->pGraphicsDevice->pDeviceHandle) {
  6292. TRACE_INIT(("DrvSetMonitorPowerState: Disconnect DD has a Device Handle = %p!\n",
  6293. pdo.ppdev->pGraphicsDevice->pDeviceHandle));
  6294. #if DBG
  6295. DbgBreakPoint();
  6296. #endif
  6297. }
  6298. continue;
  6299. }
  6300. #endif
  6301. Status = GreDeviceIoControl(pdo.ppdev->pGraphicsDevice->pDeviceHandle,
  6302. IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE,
  6303. &VideoPowerState,
  6304. sizeof(VideoPowerState),
  6305. NULL,
  6306. 0,
  6307. &BytesReturned);
  6308. // !!! partial state problem ...
  6309. if (!NT_SUCCESS(Status))
  6310. {
  6311. break;
  6312. }
  6313. }
  6314. return Status;
  6315. }
  6316. /***************************************************************************\
  6317. * DrvQueryMDEVPowerState(
  6318. *
  6319. * History:
  6320. * 26-Jul-1998 AndreVa Created.
  6321. \***************************************************************************/
  6322. BOOL
  6323. DrvQueryMDEVPowerState(
  6324. PMDEV pmdev
  6325. )
  6326. {
  6327. ULONG i;
  6328. HDEV hdev;
  6329. for (i=0; i < pmdev->chdev; i++)
  6330. {
  6331. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  6332. if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_POWERED_OFF)
  6333. {
  6334. TRACE_INIT(("Drv_Trace: DrvQueryMDEVPowerState is OFF\n"));
  6335. return FALSE;
  6336. }
  6337. }
  6338. TRACE_INIT(("Drv_Trace: DrvQueryMDEVPowerState is ON\n"));
  6339. return TRUE;
  6340. }
  6341. VOID
  6342. DrvSetMDEVPowerState(
  6343. PMDEV pmdev,
  6344. BOOL On
  6345. )
  6346. {
  6347. TRACE_INIT(("Drv_Trace: DrvSetMDEVPowerState MDEV %p %s\n",
  6348. pmdev, On ? "ON" : "OFF"));
  6349. ULONG i;
  6350. HDEV hdev;
  6351. for (i=0; i < pmdev->chdev; i++)
  6352. {
  6353. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  6354. if (On) {
  6355. pdo.ppdev->pGraphicsDevice->stateFlags &= ~DISPLAY_DEVICE_POWERED_OFF;
  6356. } else {
  6357. pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_POWERED_OFF;
  6358. }
  6359. }
  6360. }
  6361. /***************************************************************************\
  6362. * DrvDisplaySwitchHandler()
  6363. *
  6364. * Return Value:
  6365. * TRUE: System needs to update to a new mode
  6366. * FALSE: The current mode works fine
  6367. *
  6368. * History:
  6369. * Dennyd Created
  6370. \***************************************************************************/
  6371. #define PRUNEMODE_REGKEY L"PruningMode" // PruneMode Flag
  6372. #define PRUNEMODE_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(PRUNEMODE_REGKEY) + sizeof(DWORD))
  6373. BOOL
  6374. DrvGetPruneFlag(PGRAPHICS_DEVICE PhysDisp)
  6375. {
  6376. HANDLE hkRegistry;
  6377. DWORD PrunningMode = 1;
  6378. BYTE buffer[PRUNEMODE_BUFSIZE];
  6379. PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION)buffer;
  6380. ULONG Length = PRUNEMODE_BUFSIZE;
  6381. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  6382. PhysDisp,
  6383. DispDriverRegGlobal,
  6384. NULL,
  6385. NULL,
  6386. NULL,
  6387. gProtocolType);
  6388. if (hkRegistry)
  6389. {
  6390. UNICODE_STRING UnicodeString;
  6391. RtlInitUnicodeString(&UnicodeString, PRUNEMODE_REGKEY);
  6392. if (NT_SUCCESS(ZwQueryValueKey(hkRegistry,
  6393. &UnicodeString,
  6394. KeyValueFullInformation,
  6395. Information,
  6396. Length,
  6397. &Length)))
  6398. {
  6399. PrunningMode = *(LPDWORD) ((((PUCHAR)Information) +
  6400. Information->DataOffset));
  6401. }
  6402. ZwCloseKey(hkRegistry);
  6403. }
  6404. return (PrunningMode != 0);
  6405. }
  6406. BOOL
  6407. DrvDisplaySwitchHandler(
  6408. PVOID physDisp, // IN
  6409. PUNICODE_STRING pstrDeviceName, // OUT
  6410. LPDEVMODEW pNewMode, // OUT
  6411. PULONG pPrune // OUT
  6412. )
  6413. {
  6414. DEVMODEW srcMode;
  6415. LPDEVMODEW lpModeWanted;
  6416. PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE)physDisp;
  6417. ULONG i;
  6418. BOOL uu, bPrune;
  6419. TRACE_INIT(("DrvDisplaySwitchHandler: Enter\n"));
  6420. gbUpdateMonitor = TRUE;
  6421. UpdateMonitorDevices();
  6422. //
  6423. // On display switching, update mode list according to new active displays
  6424. //
  6425. DrvBuildDevmodeList(PhysDisp, TRUE);
  6426. bPrune = DrvGetPruneFlag(PhysDisp);
  6427. *pPrune = bPrune;
  6428. //
  6429. // Check if the mode in registry complies with the new mode list
  6430. // This is neccessary because when the system was first setup, there is no reg value
  6431. // under per monitor registry.
  6432. //
  6433. RtlZeroMemory(&srcMode, sizeof(DEVMODEW));
  6434. srcMode.dmSize = sizeof(DEVMODEW);
  6435. if (NT_SUCCESS (DrvProbeAndCaptureDevmode(PhysDisp,
  6436. &lpModeWanted,
  6437. &uu,
  6438. &srcMode,
  6439. FALSE,
  6440. KernelMode,
  6441. bPrune,
  6442. TRUE,
  6443. TRUE) )
  6444. )
  6445. {
  6446. TRACE_INIT(("DrvDisplaySwitchHandler: Pick reg mode B=%d W=%d H=%d F=%d R=%lu\n",
  6447. lpModeWanted->dmBitsPerPel, lpModeWanted->dmPelsWidth, lpModeWanted->dmPelsHeight, lpModeWanted->dmDisplayFrequency, lpModeWanted->dmDisplayOrientation*90));
  6448. RtlCopyMemory(pNewMode, lpModeWanted, sizeof(DEVMODEW));
  6449. RtlInitUnicodeString(pstrDeviceName, &(PhysDisp->szWinDeviceName[0]));
  6450. {
  6451. //
  6452. // If there is only one output device, update per monitor settings as well
  6453. //
  6454. ULONG activePdos = 0;
  6455. for (i = 0; i < PhysDisp->numMonitorDevice; i++)
  6456. {
  6457. if (IS_ATTACHED_ACTIVE(PhysDisp->MonitorDevices[i].flag))
  6458. {
  6459. activePdos++;
  6460. }
  6461. }
  6462. DrvUpdateDisplayDriverParameters(PhysDisp, lpModeWanted, FALSE, (activePdos == 1));
  6463. }
  6464. VFREEMEM(lpModeWanted);
  6465. return TRUE;
  6466. }
  6467. return FALSE;
  6468. }
  6469. PVOID
  6470. DrvWakeupHandler(
  6471. HANDLE *ppdo // OUT
  6472. )
  6473. {
  6474. PGRAPHICS_DEVICE PhysDisp;
  6475. for (PhysDisp = gpGraphicsDeviceList;
  6476. PhysDisp != NULL;
  6477. PhysDisp = PhysDisp->pNextGraphicsDevice)
  6478. {
  6479. if (PhysDisp->stateFlags & DISPLAY_DEVICE_ACPI)
  6480. {
  6481. break;
  6482. }
  6483. }
  6484. if (PhysDisp)
  6485. {
  6486. *ppdo = PhysDisp->pPhysDeviceHandle;
  6487. }
  6488. return (PVOID)PhysDisp;
  6489. }
  6490. /***************************************************************************\
  6491. *
  6492. * DrvSendPnPIrp
  6493. *
  6494. * History:
  6495. \***************************************************************************/
  6496. NTSTATUS
  6497. DrvSendPnPIrp(
  6498. PDEVICE_OBJECT pDeviceObject,
  6499. DEVICE_RELATION_TYPE relationType,
  6500. PDEVICE_RELATIONS *pDeviceRelations)
  6501. {
  6502. NTSTATUS status;
  6503. PIRP Irp;
  6504. PIO_STACK_LOCATION IrpSp;
  6505. KEVENT event;
  6506. IO_STATUS_BLOCK IoStatusBlock;
  6507. //
  6508. // Anything else is illegal.
  6509. //
  6510. ASSERT(relationType == TargetDeviceRelation);
  6511. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  6512. Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  6513. pDeviceObject,
  6514. NULL,
  6515. 0,
  6516. NULL,
  6517. &event,
  6518. &IoStatusBlock);
  6519. if (Irp == NULL) {
  6520. return STATUS_INSUFFICIENT_RESOURCES;
  6521. }
  6522. //
  6523. // Set the default error code.
  6524. //
  6525. Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
  6526. IrpSp = IoGetNextIrpStackLocation(Irp);
  6527. IrpSp->MajorFunction = IRP_MJ_PNP;
  6528. IrpSp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
  6529. IrpSp->Parameters.QueryDeviceRelations.Type = relationType;
  6530. //
  6531. // Call the filter driver.
  6532. //
  6533. status = IoCallDriver(pDeviceObject, Irp);
  6534. if (status == STATUS_PENDING) {
  6535. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6536. status = IoStatusBlock.Status;
  6537. }
  6538. if (NT_SUCCESS(status))
  6539. {
  6540. *pDeviceRelations = (PDEVICE_RELATIONS) IoStatusBlock.Information;
  6541. }
  6542. return status;
  6543. }
  6544. /**************************************************************************\
  6545. * __EnumDisplayQueryRoutine
  6546. *
  6547. * Callback to get the display driver name.
  6548. *
  6549. * CRIT not needed
  6550. *
  6551. * 12-Jan-1994 andreva created
  6552. \**************************************************************************/
  6553. NTSTATUS
  6554. __DisplayDriverQueryRoutine(
  6555. IN PWSTR ValueName,
  6556. IN ULONG ValueType,
  6557. IN PVOID ValueData,
  6558. IN ULONG ValueLength,
  6559. IN PVOID Context,
  6560. IN PVOID EntryContext)
  6561. {
  6562. //
  6563. // If the context value is NULL and the entry type is correct, then store
  6564. // the length of the value. Otherwise, copy the value to the specified
  6565. // memory.
  6566. //
  6567. PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE) Context;
  6568. //
  6569. // Include workaround for vendors that don't understand MULTI_SZ !
  6570. //
  6571. if (ValueType != REG_MULTI_SZ)
  6572. {
  6573. ASSERT(FALSE);
  6574. }
  6575. TRACE_INIT(("Drv_Trace: __DisplayDriverQueryRoutine MULTISZ %ws = %ws\n", ValueName, ValueData));
  6576. if (!(PhysDisp->DisplayDriverNames = (LPWSTR) PALLOCNOZ(ValueLength + 2, GDITAG_DRVSUP)))
  6577. {
  6578. return STATUS_INSUFFICIENT_RESOURCES;
  6579. }
  6580. RtlCopyMemory(PhysDisp->DisplayDriverNames, ValueData, ValueLength);
  6581. *((LPWSTR) (((PUCHAR)PhysDisp->DisplayDriverNames) + ValueLength)) = UNICODE_NULL;
  6582. return STATUS_SUCCESS;
  6583. UNREFERENCED_PARAMETER(ValueName);
  6584. UNREFERENCED_PARAMETER(EntryContext);
  6585. }
  6586. NTSTATUS
  6587. __EnumDisplayQueryRoutine(
  6588. IN PWSTR ValueName,
  6589. IN ULONG ValueType,
  6590. IN PVOID ValueData,
  6591. IN ULONG ValueLength,
  6592. IN PVOID Context,
  6593. IN PVOID EntryContext)
  6594. {
  6595. //
  6596. // If the context value is NULL and the entry type is correct, then store
  6597. // the length of the value. Otherwise, copy the value to the specified
  6598. // memory.
  6599. //
  6600. PGRAPHICS_DEVICE PhysDisp = (PGRAPHICS_DEVICE) Context;
  6601. NTSTATUS status = STATUS_SUCCESS;
  6602. //
  6603. // If the value is a string with only a NULL value, then keep going
  6604. // to the next possible string.
  6605. // So only try to save the string for > 2 characters.
  6606. //
  6607. if (ValueLength > 2)
  6608. {
  6609. if (ValueType == REG_SZ)
  6610. {
  6611. if (PhysDisp->DeviceDescription == NULL)
  6612. {
  6613. TRACE_INIT(("Drv_Trace: __EnumDisplayQueryRoutine SZ %ws = %ws\n", ValueName, ValueData));
  6614. if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(ValueLength, GDITAG_DRVSUP))
  6615. {
  6616. RtlCopyMemory(PhysDisp->DeviceDescription, ValueData, ValueLength);
  6617. }
  6618. else
  6619. {
  6620. status = STATUS_INSUFFICIENT_RESOURCES;
  6621. }
  6622. }
  6623. }
  6624. else if (ValueType == REG_BINARY)
  6625. {
  6626. if (PhysDisp->DeviceDescription == NULL)
  6627. {
  6628. TRACE_INIT(("Drv_Trace: __EnumDisplayQueryRoutine BINARY %ws = %ws\n", ValueName, ValueData));
  6629. if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(ValueLength + sizeof(WCHAR), GDITAG_DRVSUP))
  6630. {
  6631. RtlCopyMemory(PhysDisp->DeviceDescription, ValueData, ValueLength);
  6632. *((LPWSTR)((LPBYTE)PhysDisp->DeviceDescription + ValueLength)) = UNICODE_NULL;
  6633. }
  6634. else
  6635. {
  6636. status = STATUS_INSUFFICIENT_RESOURCES;
  6637. }
  6638. }
  6639. }
  6640. else
  6641. {
  6642. ASSERTGDI(FALSE, "Drv_Trace: __EnumDisplayQueryRoutine: Invalid callout type\n");
  6643. status = STATUS_SUCCESS;
  6644. }
  6645. }
  6646. return status;
  6647. UNREFERENCED_PARAMETER(ValueName);
  6648. UNREFERENCED_PARAMETER(EntryContext);
  6649. }
  6650. /***************************************************************************\
  6651. * IsVgaDevice
  6652. *
  6653. * Determine if the given PhysDisp is for the VGA.
  6654. *
  6655. * 13-Oct-1999 ericks Created
  6656. \***************************************************************************/
  6657. BOOLEAN
  6658. IsVgaDevice(
  6659. PGRAPHICS_DEVICE PhysDisp
  6660. )
  6661. {
  6662. BOOLEAN Result = FALSE;
  6663. ULONG bytesReturned;
  6664. NTSTATUS status;
  6665. status = GreDeviceIoControl(PhysDisp->pDeviceHandle,
  6666. IOCTL_VIDEO_IS_VGA_DEVICE,
  6667. NULL,
  6668. 0,
  6669. &Result,
  6670. sizeof(Result),
  6671. &bytesReturned);
  6672. if (NT_SUCCESS(status)) {
  6673. return Result;
  6674. }
  6675. return FALSE;
  6676. }
  6677. /**************************************************************************\
  6678. * DrvGetDeviceConfigurationInformation
  6679. *
  6680. * Get the registry parameters for the driver
  6681. *
  6682. * 30-Apr-1998 andreva created
  6683. \**************************************************************************/
  6684. VOID
  6685. DrvGetDeviceConfigurationInformation(
  6686. PGRAPHICS_DEVICE PhysDisp,
  6687. HANDLE hkRegistry,
  6688. BOOL bIsPdo
  6689. )
  6690. {
  6691. NTSTATUS status;
  6692. ULONG defaultValue = 0;
  6693. ULONG multiDriver = 0;
  6694. ULONG mirroring = 0;
  6695. ULONG vgaCompat = 0;
  6696. RTL_QUERY_REGISTRY_TABLE multiQueryTable[] = {
  6697. {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND,
  6698. SoftwareSettings[0], NULL, REG_NONE, NULL, 0},
  6699. {NULL, RTL_QUERY_REGISTRY_SUBKEY,
  6700. L"Settings", NULL, REG_NONE, NULL, 0},
  6701. {__DisplayDriverQueryRoutine, RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND,
  6702. SoftwareSettings[1], NULL, REG_NONE, NULL, 0},
  6703. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  6704. SoftwareSettings[2], &multiDriver, REG_DWORD, &defaultValue, 4},
  6705. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  6706. SoftwareSettings[3], &mirroring, REG_DWORD, &defaultValue, 4},
  6707. {NULL, RTL_QUERY_REGISTRY_DIRECT,
  6708. SoftwareSettings[4], &vgaCompat, REG_DWORD, &defaultValue, 4},
  6709. // Device Description is optional, for 4.0 legacy only
  6710. {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND,
  6711. SoftwareSettings[5], NULL, REG_NONE, NULL, 0},
  6712. {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND,
  6713. SoftwareSettings[6], NULL, REG_NONE, NULL, 0},
  6714. {__EnumDisplayQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND,
  6715. SoftwareSettings[7], NULL, REG_NONE, NULL, 0},
  6716. {NULL, 0, NULL}
  6717. };
  6718. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  6719. (PWSTR)hkRegistry,
  6720. bIsPdo ?
  6721. &multiQueryTable[0] :
  6722. &multiQueryTable[2],
  6723. PhysDisp,
  6724. NULL);
  6725. if (NT_SUCCESS(status))
  6726. {
  6727. if (multiDriver)
  6728. PhysDisp->stateFlags |= DISPLAY_DEVICE_MULTI_DRIVER;
  6729. if (mirroring)
  6730. PhysDisp->stateFlags |= DISPLAY_DEVICE_MIRRORING_DRIVER;
  6731. //
  6732. // We must determine which graphics device actually has the VGA resources
  6733. //
  6734. if (vgaCompat && IsVgaDevice(PhysDisp))
  6735. PhysDisp->stateFlags |= DISPLAY_DEVICE_VGA_COMPATIBLE;
  6736. TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %sa multi display driver\n",
  6737. multiDriver ? "" : "NOT "));
  6738. TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %smirroring the desktop\n",
  6739. mirroring ? "" : "NOT "));
  6740. TRACE_INIT(("DrvGetDeviceConfigurationInformation: Display driver is %sVga Compatible\n",
  6741. vgaCompat ? "" : "NOT "));
  6742. }
  6743. else
  6744. {
  6745. //
  6746. //
  6747. // An error occured - this device is miss-configured.
  6748. //
  6749. TRACE_INIT(("DrvGetDeviceConfigurationInformation: Device is misconfigured\n"));
  6750. DrvLogDisplayDriverEvent(MsgInvalidConfiguration);
  6751. if (PhysDisp->DisplayDriverNames)
  6752. {
  6753. VFREEMEM(PhysDisp->DisplayDriverNames);
  6754. PhysDisp->DisplayDriverNames = NULL;
  6755. }
  6756. if (PhysDisp->DeviceDescription)
  6757. {
  6758. VFREEMEM(PhysDisp->DeviceDescription);
  6759. PhysDisp->DeviceDescription = NULL;
  6760. }
  6761. }
  6762. return;
  6763. }
  6764. /**************************************************************************\
  6765. * DrvSetSingleDisplay
  6766. *
  6767. * Remove all physical displays except for specified primary.
  6768. * If PhysDispPrimary == NULL, the list physical displays is
  6769. * searched for the marked display and secondly any one.
  6770. *
  6771. * 25-May-2000 jasonha created
  6772. \**************************************************************************/
  6773. BOOL bPrunedDisplayDevice = FALSE; // Was a secondary display devcice rejected?
  6774. PGRAPHICS_DEVICE
  6775. DrvSetSingleDisplay(
  6776. PGRAPHICS_DEVICE PhysDispPrimary
  6777. )
  6778. {
  6779. GDIFunctionID(DrvSetSingleDisplay);
  6780. PGRAPHICS_DEVICE PhysDispTemp;
  6781. PGRAPHICS_DEVICE PhysDispPrev = NULL;
  6782. PGRAPHICS_DEVICE PhysDispNext = NULL;
  6783. // Confirm the given primary is in the list
  6784. // or identify the marked primary.
  6785. for (PhysDispTemp = gpGraphicsDeviceList;
  6786. PhysDispTemp != NULL;
  6787. PhysDispTemp = PhysDispTemp->pNextGraphicsDevice)
  6788. {
  6789. if (! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT)))
  6790. {
  6791. if (PhysDispPrimary == NULL)
  6792. {
  6793. if (PhysDispTemp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  6794. {
  6795. PhysDispPrimary = PhysDispTemp;
  6796. break;
  6797. }
  6798. }
  6799. else
  6800. {
  6801. if (PhysDispTemp == PhysDispPrimary)
  6802. {
  6803. break;
  6804. }
  6805. }
  6806. }
  6807. }
  6808. // If we haven't identified a primary,
  6809. // select any physical display.
  6810. if (PhysDispPrimary == NULL)
  6811. {
  6812. for (PhysDispTemp = gpGraphicsDeviceList;
  6813. PhysDispTemp != NULL;
  6814. PhysDispTemp = PhysDispTemp->pNextGraphicsDevice)
  6815. {
  6816. if (! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT)))
  6817. {
  6818. PhysDispPrimary = PhysDispTemp;
  6819. break;
  6820. }
  6821. }
  6822. }
  6823. // If we didn't find the specified primary or a
  6824. // suitable one, then there is nothing to do.
  6825. if (PhysDispTemp == NULL)
  6826. {
  6827. return NULL;
  6828. }
  6829. // Remove all physical secondary displays
  6830. PhysDispPrev = NULL;
  6831. for (PhysDispTemp = gpGraphicsDeviceList;
  6832. PhysDispTemp != NULL;
  6833. PhysDispTemp = PhysDispNext)
  6834. {
  6835. PhysDispNext = PhysDispTemp->pNextGraphicsDevice;
  6836. if (PhysDispTemp != PhysDispPrimary &&
  6837. ! (PhysDispTemp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_REMOTE | DISPLAY_DEVICE_DISCONNECT)))
  6838. {
  6839. ASSERTGDI(PhysDispTemp != gPhysDispVGA, "Removing VGA as a secondary.\n");
  6840. bPrunedDisplayDevice = TRUE;
  6841. // Remove from list
  6842. if (PhysDispPrev == NULL)
  6843. {
  6844. gpGraphicsDeviceList = PhysDispTemp->pNextGraphicsDevice;
  6845. }
  6846. else
  6847. {
  6848. PhysDispPrev->pNextGraphicsDevice = PhysDispTemp->pNextGraphicsDevice;
  6849. }
  6850. if (PhysDispTemp == gpGraphicsDeviceListLast)
  6851. {
  6852. gpGraphicsDeviceListLast = PhysDispPrev;
  6853. }
  6854. // Cleanup any allocations
  6855. if (PhysDispTemp->DisplayDriverNames)
  6856. VFREEMEM(PhysDispTemp->DisplayDriverNames);
  6857. if (PhysDispTemp->DeviceDescription)
  6858. VFREEMEM(PhysDispTemp->DeviceDescription);
  6859. if (PhysDispTemp->MonitorDevices)
  6860. VFREEMEM(PhysDispTemp->MonitorDevices);
  6861. if (PhysDispTemp->devmodeInfo)
  6862. VFREEMEM(PhysDispTemp->devmodeInfo);
  6863. if (PhysDispTemp->devmodeMarks)
  6864. VFREEMEM(PhysDispTemp->devmodeMarks);
  6865. VFREEMEM(PhysDispTemp);
  6866. // Reuse output numbers so next added display is in order.
  6867. gcNextGlobalPhysicalOutputNumber--;
  6868. }
  6869. else
  6870. {
  6871. PhysDispPrev = PhysDispTemp;
  6872. }
  6873. }
  6874. // Set Primary markings
  6875. if (PhysDispPrimary)
  6876. {
  6877. PhysDispPrimary->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
  6878. // Make sure this is display 1 for app compat.
  6879. wcscpy(&(PhysDispPrimary->szWinDeviceName[0]),
  6880. L"\\\\.\\DISPLAY1");
  6881. // If we loaded VGA and it is not the primary display, then
  6882. // rename it to display 2. It can't actually be referenced
  6883. // from APIs, but we can keep the numbers in order.
  6884. if (gPhysDispVGA && gPhysDispVGA != PhysDispPrimary)
  6885. {
  6886. // Rename VGA's WinDeviceName
  6887. wcscpy(&(gPhysDispVGA->szWinDeviceName[0]),
  6888. L"\\\\.\\DISPLAY2");
  6889. ASSERTGDI(gcNextGlobalPhysicalOutputNumber == 3,
  6890. "gcNextGlobalPhysicalOutputNumber != 3\n");
  6891. }
  6892. else
  6893. {
  6894. ASSERTGDI(gcNextGlobalPhysicalOutputNumber == 2,
  6895. "gcNextGlobalPhysicalOutputNumber != 2\n");
  6896. }
  6897. }
  6898. return PhysDispPrimary;
  6899. }
  6900. /**************************************************************************\
  6901. * DrvUpdateVgaDevice
  6902. *
  6903. * Update the VGA graphics device in the machine.
  6904. *
  6905. * 01-Apr-1998 andreva created
  6906. \**************************************************************************/
  6907. PGRAPHICS_DEVICE
  6908. DrvUpdateVgaDevice()
  6909. {
  6910. PGRAPHICS_DEVICE PhysDispIsVga;
  6911. PGRAPHICS_DEVICE PhysDispMarkVga;
  6912. PGRAPHICS_DEVICE PhysDispTmp;
  6913. NTSTATUS Status;
  6914. VIDEO_NUM_MODES NumModes;
  6915. ULONG NumModesLength = sizeof(NumModes);
  6916. ULONG cbBuffer;
  6917. ULONG BytesReturned;
  6918. PVIDEO_MODE_INFORMATION lpModes;
  6919. PVIDEO_MODE_INFORMATION pVideoModeSave;
  6920. ULONG cTextModes = 0;
  6921. ULONG cGraphicsModes = 0;
  6922. LPDEVMODEW pUsDevmode;
  6923. LPDEVMODEW ptmpDevmode;
  6924. LPDEVMODEMARK pUsDevmodeMark;
  6925. BOOLEAN PrimaryExists = FALSE;
  6926. BOOL VGAInUse = FALSE;
  6927. TRACE_INIT(("Drv_Trace: DrvUpdateVgaDevice: Finding VGA device\n"));
  6928. //
  6929. // Find the VGA compatible driver for the console.
  6930. //
  6931. // NOTE - These fullscreen modes are only supported on X86
  6932. //
  6933. //
  6934. // Clear out the VGA, and the VGA flag of the parent if necessary
  6935. //
  6936. for (PhysDispTmp = gpGraphicsDeviceList;
  6937. PhysDispTmp != NULL;
  6938. PhysDispTmp = PhysDispTmp->pNextGraphicsDevice)
  6939. {
  6940. PhysDispTmp->pVgaDevice = NULL;
  6941. if ((PhysDispTmp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) &&
  6942. (PhysDispTmp != gPhysDispVGA)) {
  6943. //
  6944. // Determine if this device is currently a primary, and it
  6945. // is not the VGA. (The VGA may later be removed).
  6946. //
  6947. PrimaryExists = TRUE;
  6948. }
  6949. }
  6950. //
  6951. // If there is no primary device yet, lets choose the vga.
  6952. //
  6953. if (PrimaryExists == FALSE) {
  6954. for (PhysDispTmp = gpGraphicsDeviceList;
  6955. PhysDispTmp != NULL;
  6956. PhysDispTmp = PhysDispTmp->pNextGraphicsDevice) {
  6957. if (IsVgaDevice(PhysDispTmp)) {
  6958. PhysDispTmp->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
  6959. PrimaryExists = TRUE;
  6960. break;
  6961. }
  6962. }
  6963. }
  6964. //
  6965. // Find the VGA compatible device
  6966. //
  6967. for (PhysDispIsVga = gpGraphicsDeviceList;
  6968. PhysDispIsVga != NULL;
  6969. PhysDispIsVga = PhysDispIsVga->pNextGraphicsDevice)
  6970. {
  6971. //
  6972. // The vga driver is here for compatibility.
  6973. // Look for all other possibilities, and revert to VGA as a last
  6974. // possibility
  6975. //
  6976. if (PhysDispIsVga == gPhysDispVGA)
  6977. {
  6978. continue;
  6979. }
  6980. if (PhysDispIsVga->stateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)
  6981. {
  6982. break;
  6983. }
  6984. }
  6985. //
  6986. // If no vga device was found, use the vga driver
  6987. //
  6988. if (PhysDispIsVga == NULL)
  6989. {
  6990. PhysDispIsVga = gPhysDispVGA;
  6991. }
  6992. //
  6993. // On some machines, with TGA for example, it's possible to have no
  6994. // VGA compatible device.
  6995. //
  6996. if (PhysDispIsVga == NULL)
  6997. {
  6998. return NULL;
  6999. }
  7000. //
  7001. // Now determine if there is a duplicate device (like VGA)
  7002. //
  7003. // HACK - we only support the VGA as a duplicate device right now.
  7004. // We need more info for cirrus + #9
  7005. //
  7006. // VGA is a duplicate if there is ANOTHER driver in the machine, excluding
  7007. // for MIRROR DEVICES, Disconnected device and remote devices. Personal
  7008. // Windows also requires the driver to be the VGA device driver.
  7009. //
  7010. PhysDispMarkVga = PhysDispIsVga;
  7011. if (gPhysDispVGA)
  7012. {
  7013. PPDEV ppdev;
  7014. // Determine if VGA device is being used.
  7015. // We have to hold ghsemDriverMgmt to be sure its
  7016. // status doesn't change.
  7017. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  7018. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  7019. {
  7020. if (ppdev->pGraphicsDevice == gPhysDispVGA)
  7021. {
  7022. VGAInUse = TRUE;
  7023. break;
  7024. }
  7025. }
  7026. // If the VGA device's driver is non-VGA compatible
  7027. // (DISPLAY_DEVICE_VGA_COMPATIBLE was not marked on
  7028. // any device so
  7029. // PhysDispMarkVga = PhysDispIsVga = gPhysDispVGA),
  7030. // then search for it so it may be marked as the VGA
  7031. if (PhysDispMarkVga == gPhysDispVGA)
  7032. {
  7033. // Look for the real VGA device
  7034. for (PhysDispMarkVga = gpGraphicsDeviceList;
  7035. PhysDispMarkVga != NULL;
  7036. PhysDispMarkVga = PhysDispMarkVga->pNextGraphicsDevice
  7037. )
  7038. {
  7039. if ((PhysDispMarkVga != gPhysDispVGA) &&
  7040. ((PhysDispMarkVga->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER |
  7041. DISPLAY_DEVICE_DISCONNECT |
  7042. DISPLAY_DEVICE_REMOTE) ) == 0) &&
  7043. IsVgaDevice(PhysDispMarkVga)
  7044. )
  7045. break;
  7046. }
  7047. // If no real VGA device was found and
  7048. // the VGA device isn't in use and
  7049. // this is not Personal Windows, choose
  7050. // any display to be marked as the VGA
  7051. if (PhysDispMarkVga == NULL &&
  7052. !VGAInUse &&
  7053. !((USER_SHARED_DATA->NtProductType == NtProductWinNt) &&
  7054. (USER_SHARED_DATA->SuiteMask & (1 << Personal))))
  7055. {
  7056. for (PhysDispMarkVga = gpGraphicsDeviceList;
  7057. PhysDispMarkVga != NULL;
  7058. PhysDispMarkVga = PhysDispMarkVga->pNextGraphicsDevice
  7059. )
  7060. {
  7061. if ((PhysDispMarkVga != gPhysDispVGA) &&
  7062. ((PhysDispMarkVga->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER |
  7063. DISPLAY_DEVICE_DISCONNECT |
  7064. DISPLAY_DEVICE_REMOTE) ) == 0)
  7065. )
  7066. break;
  7067. }
  7068. }
  7069. // No real VGA device was found,
  7070. // so we'll use VGA.sys device.
  7071. if (PhysDispMarkVga == NULL)
  7072. {
  7073. PhysDispMarkVga = gPhysDispVGA;
  7074. }
  7075. }
  7076. //
  7077. // Remove the VGA.sys device from the list of devices if it is a duplicate.
  7078. //
  7079. if (gPhysDispVGA != PhysDispMarkVga)
  7080. {
  7081. //
  7082. // Take this device out of the list.
  7083. //
  7084. // Handle the case where the device is already removed
  7085. //
  7086. if (gpGraphicsDeviceList == gPhysDispVGA)
  7087. {
  7088. gpGraphicsDeviceList = gPhysDispVGA->pNextGraphicsDevice;
  7089. }
  7090. else
  7091. {
  7092. PhysDispTmp = gpGraphicsDeviceList;
  7093. while (PhysDispTmp)
  7094. {
  7095. if (PhysDispTmp->pNextGraphicsDevice != gPhysDispVGA)
  7096. {
  7097. PhysDispTmp = PhysDispTmp->pNextGraphicsDevice;
  7098. continue;
  7099. }
  7100. PhysDispTmp->pNextGraphicsDevice = gPhysDispVGA->pNextGraphicsDevice;
  7101. if (PhysDispTmp->pNextGraphicsDevice == NULL)
  7102. {
  7103. gpGraphicsDeviceListLast = PhysDispTmp;
  7104. }
  7105. break;
  7106. }
  7107. }
  7108. //
  7109. // Mark the VGA as a VGA so we can do easy test later to match
  7110. // graphics devices.
  7111. //
  7112. gPhysDispVGA->pVgaDevice = gPhysDispVGA;
  7113. //
  7114. // If VGA device is in use, replace all ppdev
  7115. // references to it with the new device and
  7116. // update state on new device.
  7117. //
  7118. if (VGAInUse)
  7119. {
  7120. DWORD VGATransferFlags = (DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
  7121. DISPLAY_DEVICE_PRIMARY_DEVICE);
  7122. PhysDispMarkVga->stateFlags |= gPhysDispVGA->stateFlags & VGATransferFlags;
  7123. gPhysDispVGA->stateFlags &= ~VGATransferFlags;
  7124. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  7125. {
  7126. if (ppdev->pGraphicsDevice == gPhysDispVGA)
  7127. {
  7128. ppdev->pGraphicsDevice = PhysDispMarkVga;
  7129. }
  7130. }
  7131. }
  7132. }
  7133. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  7134. }
  7135. //
  7136. // Save the VGA device
  7137. //
  7138. PhysDispMarkVga->pVgaDevice = PhysDispIsVga;
  7139. //
  7140. // Build the list of text modes for this device
  7141. //
  7142. TRACE_INIT(("Drv_Trace: LoadDriver: get text modes\n"));
  7143. Status = GreDeviceIoControl(PhysDispIsVga->pDeviceHandle,
  7144. IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
  7145. NULL,
  7146. 0,
  7147. &NumModes,
  7148. NumModesLength,
  7149. &BytesReturned);
  7150. cbBuffer = NumModes.NumModes * NumModes.ModeInformationLength;
  7151. if ( (NT_SUCCESS(Status)) &&
  7152. (lpModes = (PVIDEO_MODE_INFORMATION)
  7153. PALLOCMEM(cbBuffer, GDITAG_DRVSUP)) )
  7154. {
  7155. Status = GreDeviceIoControl(PhysDispIsVga->pDeviceHandle,
  7156. IOCTL_VIDEO_QUERY_AVAIL_MODES,
  7157. NULL,
  7158. 0,
  7159. lpModes,
  7160. cbBuffer,
  7161. &BytesReturned);
  7162. pVideoModeSave = lpModes;
  7163. //
  7164. // We will not support more than three text modes.
  7165. // So just allocate enough for that.
  7166. //
  7167. if ((NT_SUCCESS(Status)) &&
  7168. (pUsDevmode = (LPDEVMODEW)PALLOCMEM(3 * sizeof(DEVMODEW), GDITAG_DRVSUP)) &&
  7169. (pUsDevmodeMark = (LPDEVMODEMARK)PALLOCMEM(3 * sizeof(DEVMODEMARK), GDITAG_DRVSUP)) )
  7170. {
  7171. TRACE_INIT(("Drv_Trace: LoadDriver: parsing fullscreen modes\n"));
  7172. while (cbBuffer != 0)
  7173. {
  7174. if (lpModes->AttributeFlags & VIDEO_MODE_COLOR)
  7175. {
  7176. if (lpModes->AttributeFlags & VIDEO_MODE_GRAPHICS)
  7177. {
  7178. if (cGraphicsModes)
  7179. {
  7180. goto ConsoleNextMode;
  7181. }
  7182. ptmpDevmode = pUsDevmode + 2;
  7183. //
  7184. // Make sure we have only one graphics mode
  7185. //
  7186. if (IsNEC_98)
  7187. {
  7188. if ((lpModes->VisScreenWidth != 640) ||
  7189. (lpModes->VisScreenHeight != 480) ||
  7190. ((lpModes->NumberOfPlanes *
  7191. lpModes->BitsPerPlane) != 8))
  7192. {
  7193. goto ConsoleNextMode;
  7194. }
  7195. }
  7196. else if ((lpModes->VisScreenWidth != 640) ||
  7197. (lpModes->VisScreenHeight != 480) ||
  7198. ((lpModes->NumberOfPlanes *
  7199. lpModes->BitsPerPlane) != 4))
  7200. {
  7201. goto ConsoleNextMode;
  7202. }
  7203. TRACE_INIT(("Drv_Trace: DrvInitConsole: VGA graphics mode\n"));
  7204. cGraphicsModes++;
  7205. }
  7206. else
  7207. {
  7208. ptmpDevmode = pUsDevmode + cTextModes;
  7209. //
  7210. // Make sure we have only 2 text modes
  7211. //
  7212. if (cTextModes == 2)
  7213. {
  7214. RIP("Drv_Trace: VGA compatible device has too many text modes\n");
  7215. goto ConsoleNextMode;
  7216. }
  7217. TRACE_INIT(("Drv_Trace: DrvInitConsole: VGA text mode\n"));
  7218. cTextModes++;
  7219. }
  7220. RtlZeroMemory(ptmpDevmode, sizeof(DEVMODEW));
  7221. if (!(lpModes->AttributeFlags & VIDEO_MODE_GRAPHICS))
  7222. {
  7223. ptmpDevmode->dmDisplayFlags = DMDISPLAYFLAGS_TEXTMODE;
  7224. }
  7225. memcpy(ptmpDevmode->dmDeviceName,
  7226. L"FULLSCREEN CONSOLE",
  7227. sizeof(L"FULLSCREEN CONSOLE"));
  7228. ptmpDevmode->dmSize = sizeof(DEVMODEW);
  7229. ptmpDevmode->dmSpecVersion = DM_SPECVERSION;
  7230. ptmpDevmode->dmDriverVersion = DM_SPECVERSION;
  7231. ptmpDevmode->dmPelsWidth =
  7232. lpModes->VisScreenWidth;
  7233. ptmpDevmode->dmPelsHeight =
  7234. lpModes->VisScreenHeight;
  7235. ptmpDevmode->dmBitsPerPel =
  7236. lpModes->NumberOfPlanes *
  7237. lpModes->BitsPerPlane;
  7238. ptmpDevmode->dmDisplayOrientation = DMDO_DEFAULT;
  7239. ptmpDevmode->dmDisplayFixedOutput = DMDFO_DEFAULT;
  7240. ptmpDevmode->dmFields = DM_BITSPERPEL |
  7241. DM_PELSWIDTH |
  7242. DM_PELSHEIGHT |
  7243. DM_DISPLAYFREQUENCY |
  7244. DM_DISPLAYFLAGS |
  7245. DM_DISPLAYORIENTATION;
  7246. //
  7247. // NOTE !!!
  7248. // As a hack, lets store the mode number in
  7249. // a field we don't use
  7250. //
  7251. ptmpDevmode->dmOrientation =
  7252. (USHORT) lpModes->ModeIndex;
  7253. }
  7254. ConsoleNextMode:
  7255. cbBuffer -= NumModes.ModeInformationLength;
  7256. lpModes = (PVIDEO_MODE_INFORMATION)
  7257. (((PUCHAR)lpModes) + NumModes.ModeInformationLength);
  7258. }
  7259. }
  7260. VFREEMEM(pVideoModeSave);
  7261. }
  7262. //
  7263. // if everything went OK with that, then we can save this
  7264. // device as vga compatible !
  7265. //
  7266. // If no modes are available, do not setup this device.
  7267. // Otherwise, EnumDisplaySettings will end up trying to get
  7268. // the list of modes for this device, which it can not do.
  7269. //
  7270. if ((cGraphicsModes == 1) &&
  7271. (cTextModes == 2))
  7272. {
  7273. UNICODE_STRING DeviceName;
  7274. HANDLE pDeviceHandle;
  7275. PVOID pFileObject;
  7276. TRACE_INIT(("Drv_Trace: LoadDriver: saving VGA compatible device\n"));
  7277. //
  7278. // Copy the string and the handle ...
  7279. //
  7280. RtlCopyMemory(&gFullscreenGraphicsDevice,
  7281. PhysDispIsVga,
  7282. sizeof(GRAPHICS_DEVICE));
  7283. //
  7284. // 2 text modes + 1 graphics mode.
  7285. //
  7286. gFullscreenGraphicsDevice.cbdevmodeInfo = 3 * sizeof(DEVMODEW);
  7287. gFullscreenGraphicsDevice.devmodeInfo = pUsDevmode;
  7288. gFullscreenGraphicsDevice.numRawModes = 3;
  7289. gFullscreenGraphicsDevice.devmodeMarks = pUsDevmodeMark;
  7290. for (ULONG i = 0; i < 3; i++)
  7291. {
  7292. pUsDevmodeMark[i].bPruned = 0;
  7293. pUsDevmodeMark[i].pDevMode = &pUsDevmode[i];
  7294. }
  7295. //
  7296. // Write the name of the fullscreen device in the registry.
  7297. //
  7298. RtlInitUnicodeString(&DeviceName,
  7299. gFullscreenGraphicsDevice.szNtDeviceName);
  7300. RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  7301. L"Video",
  7302. L"VgaCompatible",
  7303. REG_SZ,
  7304. DeviceName.Buffer,
  7305. DeviceName.Length + sizeof(UNICODE_NULL));
  7306. //
  7307. // Now create the FE fullscreen device.
  7308. //
  7309. RtlInitUnicodeString(&DeviceName, DD_FULLSCREEN_VIDEO_DEVICE_NAME);
  7310. Status = IoGetDeviceObjectPointer(&DeviceName,
  7311. (ACCESS_MASK) (0),
  7312. (PFILE_OBJECT *) &pFileObject,
  7313. (PDEVICE_OBJECT *) &pDeviceHandle);
  7314. if (NT_SUCCESS(Status))
  7315. {
  7316. gFeFullscreenGraphicsDevice.hkClassDriverConfig = 0;
  7317. gFeFullscreenGraphicsDevice.pDeviceHandle = pDeviceHandle;
  7318. RtlCopyMemory(&gFeFullscreenGraphicsDevice,
  7319. DD_FULLSCREEN_VIDEO_DEVICE_NAME,
  7320. sizeof(DD_FULLSCREEN_VIDEO_DEVICE_NAME));
  7321. }
  7322. }
  7323. //
  7324. // Make VGA the head of list, so that VGA always get processed first upon mode change
  7325. // And make it "\\.\Display1" for compatibility purpose
  7326. //
  7327. if (PhysDispMarkVga != gpGraphicsDeviceList)
  7328. {
  7329. for (PhysDispTmp = gpGraphicsDeviceList;
  7330. PhysDispTmp != NULL;
  7331. PhysDispTmp = PhysDispTmp->pNextGraphicsDevice)
  7332. {
  7333. if (PhysDispTmp->pNextGraphicsDevice == PhysDispMarkVga)
  7334. {
  7335. break;
  7336. }
  7337. }
  7338. ASSERTGDI (PhysDispTmp != NULL, "VGA device should alway be in gpGraphicsDeviceList chain\n");
  7339. PhysDispTmp->pNextGraphicsDevice = PhysDispMarkVga->pNextGraphicsDevice;
  7340. PhysDispMarkVga->pNextGraphicsDevice = gpGraphicsDeviceList;
  7341. gpGraphicsDeviceList = PhysDispMarkVga;
  7342. if (gpGraphicsDeviceListLast == PhysDispMarkVga)
  7343. gpGraphicsDeviceListLast = PhysDispTmp;
  7344. }
  7345. if (wcscmp(gpGraphicsDeviceList->szWinDeviceName, L"\\\\.\\DISPLAY1") != 0)
  7346. {
  7347. for (PhysDispTmp = gpGraphicsDeviceList;
  7348. PhysDispTmp != NULL;
  7349. PhysDispTmp = PhysDispTmp->pNextGraphicsDevice)
  7350. {
  7351. if (wcscmp(PhysDispTmp->szWinDeviceName, L"\\\\.\\DISPLAY1") == 0)
  7352. {
  7353. wcscpy(PhysDispTmp->szWinDeviceName, gpGraphicsDeviceList->szWinDeviceName);
  7354. }
  7355. }
  7356. wcscpy(gpGraphicsDeviceList->szWinDeviceName, L"\\\\.\\DISPLAY1");
  7357. }
  7358. return PhysDispMarkVga;
  7359. }
  7360. #ifdef IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  7361. BOOL
  7362. bSetDeviceSessionUsage(
  7363. PGRAPHICS_DEVICE PhysDisp,
  7364. BOOL bEnable
  7365. )
  7366. {
  7367. GDIFunctionID(bSetDeviceSessionUsage);
  7368. ASSERTGDI(PhysDisp != NULL, "NULL Graphics Device\n");
  7369. BOOL bRet;
  7370. // Virtual devices (meta, mirror, remote, and disconnect) have the
  7371. // capability of being used in multiple sessions since there is no
  7372. // physical device.
  7373. // NOTE: What are the implications for mirroring drivers?
  7374. if (PhysDisp != (PGRAPHICS_DEVICE) DDML_DRIVER &&
  7375. !(PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER |
  7376. DISPLAY_DEVICE_REMOTE |
  7377. DISPLAY_DEVICE_DISCONNECT)))
  7378. {
  7379. NTSTATUS Status;
  7380. DWORD dwBytesReturned;
  7381. VIDEO_DEVICE_SESSION_STATUS vdSessionStatus = { bEnable, FALSE };
  7382. ASSERTGDI(PhysDisp->pDeviceHandle != NULL, "Physical device has NULL handle.");
  7383. Status = GreDeviceIoControl(PhysDisp->pDeviceHandle,
  7384. IOCTL_VIDEO_USE_DEVICE_IN_SESSION,
  7385. &vdSessionStatus,
  7386. sizeof(vdSessionStatus),
  7387. &vdSessionStatus,
  7388. sizeof(vdSessionStatus),
  7389. &dwBytesReturned);
  7390. if (NT_SUCCESS(Status))
  7391. {
  7392. if (!vdSessionStatus.bSuccess)
  7393. {
  7394. if (bEnable)
  7395. {
  7396. DbgPrint("Trying to enable physical device already in use.\n");
  7397. }
  7398. else
  7399. {
  7400. DbgPrint("Trying to disable physical device not enabled in this session.\n");
  7401. }
  7402. }
  7403. bRet = vdSessionStatus.bSuccess;
  7404. }
  7405. else
  7406. {
  7407. WARNING("IOCTL_VIDEO_USE_DEVICE_IN_SESSION requested failed.");
  7408. bRet = TRUE;
  7409. }
  7410. }
  7411. else
  7412. {
  7413. bRet = TRUE;
  7414. }
  7415. return bRet;
  7416. }
  7417. #endif IOCTL_VIDEO_USE_DEVICE_IN_SESSION
  7418. extern "C"
  7419. VOID
  7420. CloseLocalGraphicsDevices()
  7421. {
  7422. PGRAPHICS_DEVICE PhysDisp = NULL;
  7423. TRACE_INIT(("CloseLocalGraphicsDevices\n"));
  7424. if (gpLocalGraphicsDeviceList == NULL) {
  7425. TRACE_INIT(("CloseLocalGraphicsDevices - gpLocalGraphicsDeviceList is not st yet\n"));
  7426. return;
  7427. }
  7428. for (PhysDisp = gpLocalGraphicsDeviceList;
  7429. PhysDisp != NULL;
  7430. PhysDisp = PhysDisp->pNextGraphicsDevice)
  7431. {
  7432. if (PhysDisp->pFileObject != NULL) {
  7433. TRACE_INIT(("CloseLocalGraphicsDevices, Closing : %ws\n", PhysDisp->szNtDeviceName));
  7434. ObDereferenceObject(PhysDisp->pFileObject);
  7435. PhysDisp->pDeviceHandle = NULL;
  7436. PhysDisp->pFileObject = NULL;
  7437. }
  7438. }
  7439. // If there is a separate VGA device close it too
  7440. if ( (gPhysDispVGA != NULL) && (gPhysDispVGA->pFileObject != NULL) ) {
  7441. ObDereferenceObject(gPhysDispVGA->pFileObject);
  7442. gPhysDispVGA->pDeviceHandle = NULL;
  7443. gPhysDispVGA->pFileObject = NULL;
  7444. }
  7445. }
  7446. extern "C"
  7447. VOID
  7448. OpenLocalGraphicsDevices()
  7449. {
  7450. UNICODE_STRING DeviceName;
  7451. PGRAPHICS_DEVICE PhysDisp = NULL;
  7452. NTSTATUS status;
  7453. BOOL bVgaDeviceInList = FALSE;
  7454. TRACE_INIT(("OpenLocalGraphicsDevices\n"));
  7455. if (gpLocalGraphicsDeviceList == NULL) {
  7456. TRACE_INIT(("OpenLocalGraphicsDevices - gpLocalGraphicsDeviceList is not st yet\n"));
  7457. return;
  7458. }
  7459. for (PhysDisp = gpLocalGraphicsDeviceList;
  7460. PhysDisp != NULL;
  7461. PhysDisp = PhysDisp->pNextGraphicsDevice)
  7462. {
  7463. if (PhysDisp->pFileObject == NULL) {
  7464. TRACE_INIT(("OpenLocalGraphicsDevices opening : %ws\n", PhysDisp->szNtDeviceName));
  7465. RtlInitUnicodeString(&DeviceName, PhysDisp->szNtDeviceName);
  7466. status = IoGetDeviceObjectPointer(&DeviceName,
  7467. (ACCESS_MASK) (0),
  7468. (PFILE_OBJECT *) &PhysDisp->pFileObject,
  7469. (PDEVICE_OBJECT *)&PhysDisp->pDeviceHandle);
  7470. if (PhysDisp == gPhysDispVGA ) {
  7471. bVgaDeviceInList = TRUE;
  7472. }
  7473. if (!NT_SUCCESS(status)) {
  7474. TRACE_INIT(("OpenLocalGraphicsDevices failed with status %0x\n", status));
  7475. } else{
  7476. TRACE_INIT(("OpenLocalGraphicsDevices OK\n"));
  7477. }
  7478. }
  7479. }
  7480. // If there is a separate VGA device, Open it too
  7481. if (!bVgaDeviceInList && (gPhysDispVGA != NULL)) {
  7482. RtlInitUnicodeString(&DeviceName, gPhysDispVGA->szNtDeviceName);
  7483. status = IoGetDeviceObjectPointer(&DeviceName,
  7484. (ACCESS_MASK) (0),
  7485. (PFILE_OBJECT *) &gPhysDispVGA->pFileObject,
  7486. (PDEVICE_OBJECT *)&gPhysDispVGA->pDeviceHandle);
  7487. if (!NT_SUCCESS(status)) {
  7488. TRACE_INIT(("OpenLocalGraphicsDevices failed to ope VGA device with status %0x\n", status));
  7489. } else{
  7490. TRACE_INIT(("OpenLocalGraphicsDevices, open VGA device OK\n"));
  7491. }
  7492. }
  7493. }
  7494. extern "C"
  7495. BOOL
  7496. DrvSetGraphicsDevices(PWSTR pDisplayDriverName)
  7497. {
  7498. BOOL bLocal;
  7499. if (gProtocolType == PROTOCOL_CONSOLE) {
  7500. bLocal = TRUE;
  7501. } else {
  7502. bLocal = FALSE;
  7503. }
  7504. wcscpy(G_DisplayDriverNames, pDisplayDriverName);
  7505. return (DrvUpdateGraphicsDeviceList(TRUE,FALSE,bLocal));
  7506. }
  7507. /**************************************************************************\
  7508. * DrvUpdateGraphicsDeviceList
  7509. *
  7510. * Update the list of devices in the PhysDisp linked list.
  7511. *
  7512. * This function return TRUE for SUCCESS
  7513. * If the functions returns FALSE, the it means the active HDEV should be
  7514. * disabled, and we should get called back With the parameter being set to TRUE.
  7515. *
  7516. * 09-Oct-1996 andreva created
  7517. * Updates the local graphics device list or the remote graphics device list.
  7518. * This function is called on InitVideo but also by xxxRemoteReconnect since
  7519. * At reconnect the list may change ( case of reconnecting a session with a
  7520. * client from a different protocol or case of reconnecting the console session
  7521. * to a remote client or reconnecting an inialy remote session to the local
  7522. * console video.
  7523. \**************************************************************************/
  7524. BOOL
  7525. DrvUpdateGraphicsDeviceList(
  7526. BOOL bDefaultDisplayDisabled,
  7527. BOOL bReenumerationNeeded,
  7528. BOOL bLocal)
  7529. {
  7530. ULONG deviceNumber = 0;
  7531. BOOL newDevice = FALSE;
  7532. WCHAR devName[32];
  7533. UNICODE_STRING DeviceName;
  7534. PDEVICE_OBJECT pDeviceHandle = NULL;
  7535. PVOID pFileObject;
  7536. PWSTR *SymbolicLinkList;
  7537. BOOL bGotMonitorPdos;
  7538. PDEVICE_RELATIONS pDeviceRelations;
  7539. NTSTATUS status;
  7540. PGRAPHICS_DEVICE PhysDisp = NULL;
  7541. HANDLE hkRegistry = NULL;
  7542. VIDEO_WIN32K_CALLBACKS videoCallback;
  7543. ULONG bytesReturned;
  7544. BOOL bReturn = TRUE;
  7545. TRACE_INIT(("Drv_Trace: DrvUpdateGraphicsDeviceList: Enter\n"));
  7546. //
  7547. // ISSUE - we don't handle deletions !!!
  7548. //
  7549. //
  7550. // If the maximum value has increased for video device objects, then
  7551. // go open the new ones.
  7552. //
  7553. if ( bLocal ) {
  7554. gcNextGlobalDeviceNumber = gcLocalNextGlobalDeviceNumber;
  7555. gpGraphicsDeviceList = gpLocalGraphicsDeviceList;
  7556. gpGraphicsDeviceListLast =gpLocalGraphicsDeviceListLast;
  7557. gcNextGlobalPhysicalOutputNumber = gcLocalNextGlobalPhysicalOutputNumber;
  7558. gcNextGlobalVirtualOutputNumber = gcLocalNextGlobalVirtualOutputNumber;
  7559. ULONG defaultValue = 0;
  7560. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  7561. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"MaxObjectNumber",
  7562. &deviceNumber, REG_DWORD, &defaultValue, 4},
  7563. {NULL, 0, NULL}
  7564. };
  7565. RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
  7566. L"VIDEO",
  7567. &QueryTable[0],
  7568. NULL,
  7569. NULL);
  7570. } else{
  7571. gcNextGlobalDeviceNumber = gcRemoteNextGlobalDeviceNumber;
  7572. gpGraphicsDeviceList = gpRemoteGraphicsDeviceList;
  7573. gpGraphicsDeviceListLast =gpRemoteGraphicsDeviceListLast;
  7574. gcNextGlobalPhysicalOutputNumber = gcRemoteNextGlobalPhysicalOutputNumber;
  7575. gcNextGlobalVirtualOutputNumber = gcRemoteNextGlobalVirtualOutputNumber;
  7576. //
  7577. // If we don't yet have this protocol in our remote device list,
  7578. // Set deviceNumber in a way that we'll iterate once to create
  7579. // a GRAPHICS_DEVICE for it, otherwise set to zero so that we don't
  7580. // create a new GRAPHICS_DEVICE.
  7581. //
  7582. if (gProtocolType != PROTOCOL_DISCONNECT && !DrvIsProtocolAlreadyKnown()) {
  7583. deviceNumber = gcRemoteNextGlobalDeviceNumber;
  7584. }
  7585. }
  7586. // IoGetDeviceInterfaces(GUID_DISPLAY_INTERFACE_STANDARD,
  7587. // NULL,
  7588. // 0,
  7589. // &SymbolicLinkList);
  7590. while (gProtocolType != PROTOCOL_DISCONNECT && gcNextGlobalDeviceNumber <= deviceNumber)
  7591. {
  7592. TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Device %d\n", gcNextGlobalDeviceNumber));
  7593. if (bDefaultDisplayDisabled == FALSE) {
  7594. TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Exit RETRY\n\n"));
  7595. return FALSE;
  7596. }
  7597. newDevice = TRUE;
  7598. swprintf(devName,
  7599. L"\\Device\\Video%d",
  7600. gcNextGlobalDeviceNumber);
  7601. RtlInitUnicodeString(&DeviceName, devName);
  7602. TRACE_INIT(("Drv_Trace: \tNewDevice: Try creating device %ws\n",
  7603. devName));
  7604. if ( !bLocal )
  7605. {
  7606. //
  7607. // FOR HYDRA
  7608. //
  7609. pFileObject = (PFILE_OBJECT)G_RemoteVideoFileObject;
  7610. pDeviceHandle = IoGetRelatedDeviceObject ((PFILE_OBJECT)pFileObject);
  7611. if (pDeviceHandle) {
  7612. status = STATUS_SUCCESS;
  7613. } else {
  7614. status = STATUS_OBJECT_NAME_NOT_FOUND;
  7615. }
  7616. //deviceNumber = 0; //Only one display driver for remote sessions
  7617. }
  7618. else
  7619. {
  7620. //
  7621. // Opening a new device will cause the Initialize
  7622. // routine of a miniport driver to be called.
  7623. // This may cause the driver to change some state, which could
  7624. // affect the state of another driver on the same device
  7625. // (opening the weitek driver if the vga is running.
  7626. //
  7627. // For that reason, the other device should be temporarily
  7628. // closed down when we do the create, and then reinitialized
  7629. // afterwards.
  7630. //
  7631. // Handle special case when we are opening initial device and
  7632. // gpDispInfo->hDev does not exist yet.
  7633. //
  7634. status = IoGetDeviceObjectPointer(&DeviceName,
  7635. (ACCESS_MASK) (0),
  7636. (PFILE_OBJECT *) &pFileObject,
  7637. &pDeviceHandle);
  7638. }
  7639. //
  7640. // if we got a configuration error from the device (HwInitialize
  7641. // routine failed, then just go on to the next device.
  7642. //
  7643. if (!NT_SUCCESS(status))
  7644. {
  7645. TRACE_INIT(("Drv_Trace: \tNewDevice: No such device - Status is %0x\n",status));
  7646. //
  7647. // For remote devices, we don't want to increment the Next device number
  7648. // if we are not creating the device. The reason is that remote devices
  7649. // do not have a fixed number and we want to use a device number only
  7650. // if we are really creating a remote device for it.
  7651. if (bLocal) {
  7652. gcNextGlobalDeviceNumber++;
  7653. continue;
  7654. }
  7655. break;
  7656. }
  7657. //
  7658. // Allocate a buffer if necessary:
  7659. //
  7660. if (PhysDisp == NULL)
  7661. {
  7662. PhysDisp = (PGRAPHICS_DEVICE) PALLOCMEM(sizeof(GRAPHICS_DEVICE),
  7663. GDITAG_GDEVICE);
  7664. }
  7665. if (PhysDisp)
  7666. {
  7667. PhysDisp->numMonitorDevice = 0;
  7668. PhysDisp->MonitorDevices = NULL;
  7669. PhysDisp->pDeviceHandle = (HANDLE) pDeviceHandle;
  7670. PhysDisp->ProtocolType = gProtocolType;
  7671. if (!bLocal) {
  7672. PhysDisp->stateFlags |= DISPLAY_DEVICE_REMOTE;
  7673. }
  7674. if (bLocal) {
  7675. PhysDisp->pFileObject = pFileObject;
  7676. } else {
  7677. PhysDisp->pFileObject = NULL;
  7678. }
  7679. bGotMonitorPdos = FALSE;
  7680. if (bLocal)
  7681. {
  7682. //
  7683. // Tell the video port driver about us so we can
  7684. // do power management notifucations
  7685. //
  7686. RtlZeroMemory(&videoCallback, sizeof(VIDEO_WIN32K_CALLBACKS));
  7687. videoCallback.PhysDisp = PhysDisp;
  7688. videoCallback.Callout = VideoPortCallout;
  7689. status = GreDeviceIoControl(PhysDisp->pDeviceHandle,
  7690. IOCTL_VIDEO_INIT_WIN32K_CALLBACKS,
  7691. &videoCallback,
  7692. sizeof(VIDEO_WIN32K_CALLBACKS),
  7693. &videoCallback,
  7694. sizeof(VIDEO_WIN32K_CALLBACKS),
  7695. &bytesReturned);
  7696. if (videoCallback.bACPI)
  7697. {
  7698. PhysDisp->stateFlags |= DISPLAY_DEVICE_ACPI;
  7699. }
  7700. if (videoCallback.DualviewFlags & VIDEO_DUALVIEW_REMOVABLE)
  7701. {
  7702. PhysDisp->stateFlags |= DISPLAY_DEVICE_REMOVABLE;
  7703. }
  7704. if (videoCallback.DualviewFlags & (VIDEO_DUALVIEW_PRIMARY | VIDEO_DUALVIEW_SECONDARY))
  7705. {
  7706. PhysDisp->stateFlags |= DISPLAY_DEVICE_DUALVIEW;
  7707. }
  7708. PhysDisp->pPhysDeviceHandle = videoCallback.pPhysDeviceObject;
  7709. ASSERT(NT_SUCCESS(status));
  7710. }
  7711. //
  7712. // For a PnP Driver, get the PDO so we can enumerate the monitors
  7713. //
  7714. status = DrvSendPnPIrp(pDeviceHandle,
  7715. TargetDeviceRelation,
  7716. &pDeviceRelations);
  7717. if (NT_SUCCESS(status))
  7718. {
  7719. PDEVICE_OBJECT pdoVideoChip = pDeviceRelations->Objects[0];
  7720. PDEVICE_OBJECT pdoChild;
  7721. PDEVICE_OBJECT *pActivePdos, *pPdos;
  7722. ULONG_PTR cCount = 0;
  7723. ULONG i;
  7724. WCHAR className[8];
  7725. NTSTATUS status2;
  7726. ASSERTGDI(pDeviceRelations->Count == 1,
  7727. "TargetDeviceRelation should only get one PDO\n");
  7728. //
  7729. // Note: free with ExFreePool rather than GdiFreePool
  7730. // because pDeviceRelations is allocated by IoAllocateIrp
  7731. // (ntos\io\iosubs.c) in DrvSendPnPIrp.
  7732. //
  7733. ExFreePool(pDeviceRelations);
  7734. //
  7735. // In 5.0, the driver configuration data is stored under
  7736. // Class\GUID\xxx
  7737. //
  7738. TRACE_INIT(("Drv_Trace: \tNewDevice: Get device Configuration from Class Key\n"));
  7739. status = IoOpenDeviceRegistryKey(pdoVideoChip,
  7740. PLUGPLAY_REGKEY_DRIVER,
  7741. MAXIMUM_ALLOWED,
  7742. &hkRegistry);
  7743. if (NT_SUCCESS(status))
  7744. {
  7745. PVIDEO_MONITOR_DEVICE pMonitorDevices = NULL;
  7746. ULONG numMonitorDevice = 0;
  7747. //
  7748. // Force all the monitors on this device to be enumerated.
  7749. //
  7750. if (bReenumerationNeeded) {
  7751. IoSynchronousInvalidateDeviceRelations(pdoVideoChip, BusRelations);
  7752. }
  7753. if (NT_SUCCESS(GreDeviceIoControl(pDeviceHandle,
  7754. IOCTL_VIDEO_ENUM_MONITOR_PDO,
  7755. NULL,
  7756. 0,
  7757. &pMonitorDevices,
  7758. sizeof(PVOID),
  7759. &bytesReturned))
  7760. && pMonitorDevices != NULL)
  7761. {
  7762. bGotMonitorPdos = TRUE;
  7763. //
  7764. // Get the number of PDOs
  7765. //
  7766. numMonitorDevice = 0;
  7767. while (pMonitorDevices[numMonitorDevice].pdo != NULL)
  7768. {
  7769. ObDereferenceObject(pMonitorDevices[numMonitorDevice].pdo);
  7770. numMonitorDevice++;
  7771. }
  7772. }
  7773. //
  7774. // Create the standard graphics device
  7775. //
  7776. TRACE_INIT(("Drv_Trace: \tNewDevice: Get display Configuration from Class Key\n"));
  7777. DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, TRUE);
  7778. //
  7779. // Per Monitor Settings
  7780. //
  7781. if (bGotMonitorPdos && numMonitorDevice)
  7782. {
  7783. PhysDisp->numMonitorDevice = numMonitorDevice;
  7784. PhysDisp->MonitorDevices = (PVIDEO_MONITOR_DEVICE)
  7785. PALLOCMEM(sizeof(VIDEO_MONITOR_DEVICE) * numMonitorDevice,
  7786. GDITAG_GDEVICE);
  7787. for (cCount = 0; cCount < numMonitorDevice; cCount++)
  7788. {
  7789. PhysDisp->MonitorDevices[cCount].flag = 0;
  7790. if (pMonitorDevices[cCount].flag & VIDEO_CHILD_ACTIVE) {
  7791. PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_ACTIVE;
  7792. }
  7793. if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_DETACHED) == 0) {
  7794. PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_ATTACHED;
  7795. }
  7796. if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_NOPRUNE_FREQ) == 0) {
  7797. PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_PRUNE_FREQ;
  7798. }
  7799. if ((pMonitorDevices[cCount].flag & VIDEO_CHILD_NOPRUNE_RESOLUTION) == 0) {
  7800. PhysDisp->MonitorDevices[cCount].flag |= DISPLAY_DEVICE_PRUNE_RESOLUTION;
  7801. }
  7802. PhysDisp->MonitorDevices[cCount].pdo = pMonitorDevices[cCount].pdo;
  7803. PhysDisp->MonitorDevices[cCount].HwID = pMonitorDevices[cCount].HwID;
  7804. }
  7805. }
  7806. if (bGotMonitorPdos)
  7807. {
  7808. ExFreePool(pMonitorDevices);
  7809. }
  7810. ZwCloseKey(hkRegistry);
  7811. }
  7812. ObDereferenceObject(pdoVideoChip);
  7813. }
  7814. else if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  7815. PhysDisp->pPhysDeviceHandle )
  7816. {
  7817. //
  7818. // For Dualview secondary, there is no real PDO
  7819. //
  7820. status = IoOpenDeviceRegistryKey((PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle,
  7821. PLUGPLAY_REGKEY_DRIVER,
  7822. MAXIMUM_ALLOWED,
  7823. &hkRegistry);
  7824. if (NT_SUCCESS(status))
  7825. {
  7826. DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, TRUE);
  7827. ZwCloseKey(hkRegistry);
  7828. }
  7829. }
  7830. //
  7831. // Do this here as this field must be initialized for the next
  7832. // function call.
  7833. //
  7834. swprintf(&(PhysDisp->szNtDeviceName[0]),
  7835. L"\\Device\\Video%d",
  7836. gcNextGlobalDeviceNumber++);
  7837. //
  7838. // If the software key information could not be obtained,
  7839. // try the legacy location
  7840. // In 4.0, the driver configuration data was located in
  7841. // <services>\DeviceX
  7842. //
  7843. if (!NT_SUCCESS(status))
  7844. {
  7845. TRACE_INIT(("Drv_Trace: \tNewDevice: Failed to get PDO device Configuration info\n"));
  7846. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  7847. PhysDisp,
  7848. DispDriverRegGlobal,
  7849. NULL,
  7850. NULL,
  7851. &status,
  7852. gProtocolType);
  7853. //
  7854. // Start at entry 2 in the list because we want to skip the
  7855. // subdirectory
  7856. //
  7857. if (NT_SUCCESS(status))
  7858. {
  7859. DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, FALSE);
  7860. ZwCloseKey(hkRegistry);
  7861. }
  7862. }
  7863. //
  7864. // VGA driver and other old, MS detected drivers may have no
  7865. // description string. Add *something*.
  7866. //
  7867. if ((NT_SUCCESS(status)) &&
  7868. (PhysDisp->DeviceDescription == NULL))
  7869. {
  7870. if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(32, GDITAG_DRVSUP))
  7871. {
  7872. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  7873. PhysDisp,
  7874. DispDriverRegGlobal,
  7875. NULL,
  7876. PhysDisp->DeviceDescription,
  7877. &status,
  7878. gProtocolType);
  7879. if (hkRegistry)
  7880. {
  7881. ZwCloseKey(hkRegistry);
  7882. }
  7883. }
  7884. else
  7885. {
  7886. status = STATUS_INSUFFICIENT_RESOURCES;
  7887. }
  7888. }
  7889. if (PhysDisp->DeviceDescription == NULL) {
  7890. WARNING("\nDisplay Device Description is NULL!\n");
  7891. }
  7892. //
  7893. // If the device exists, keep it open and try the next one.
  7894. // Here we give Mirroring driver different names. Many applications assumes
  7895. // "\\.\Display1" as their primary display. But sometimes, mirroring driver
  7896. // gets loaded first, thus makes the assumption go complete bogus.
  7897. //
  7898. if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  7899. {
  7900. swprintf(&(PhysDisp->szWinDeviceName[0]),
  7901. L"\\\\.\\DISPLAYV%d",
  7902. gcNextGlobalVirtualOutputNumber++);
  7903. }
  7904. else
  7905. {
  7906. swprintf(&(PhysDisp->szWinDeviceName[0]),
  7907. L"\\\\.\\DISPLAY%d",
  7908. gcNextGlobalPhysicalOutputNumber++);
  7909. }
  7910. //
  7911. // Link the new device at the end so we can enumerate
  7912. // in the right order. For remote devices, link the
  7913. // device to the list only if everything worked fine.
  7914. //
  7915. if (bLocal || NT_SUCCESS(status)) {
  7916. if (gpGraphicsDeviceList == NULL)
  7917. {
  7918. gpGraphicsDeviceList = PhysDisp;
  7919. gpGraphicsDeviceListLast = PhysDisp;
  7920. }
  7921. else
  7922. {
  7923. gpGraphicsDeviceListLast->pNextGraphicsDevice = PhysDisp;
  7924. gpGraphicsDeviceListLast = PhysDisp;
  7925. }
  7926. //
  7927. // We have successfully installed a GRAPHICS_DEVICE for a new
  7928. // remote protocol : increment known protocols count.
  7929. //
  7930. if (!bLocal) {
  7931. gcRemoteNextGlobalDeviceNumber++;
  7932. }
  7933. } else {
  7934. DrvCleanupOneGraphicsDevice(PhysDisp);
  7935. gcNextGlobalPhysicalOutputNumber--;
  7936. PhysDisp = NULL;
  7937. bReturn = FALSE;
  7938. }
  7939. PhysDisp = NULL;
  7940. }
  7941. }
  7942. //
  7943. // Update the VGA device on the console.
  7944. //
  7945. if (bLocal && newDevice)
  7946. {
  7947. PGRAPHICS_DEVICE PhysDispVGA = DrvUpdateVgaDevice();
  7948. if (gbBaseVideo)
  7949. {
  7950. DrvSetSingleDisplay(PhysDispVGA);
  7951. }
  7952. }
  7953. // Create the entry for the Disconnect graphics device
  7954. if (DrvSetDisconnectedGraphicsDevice(bLocal)) {
  7955. TRACE_INIT(("DrvSetDisconnectedGraphicsDevice succeeded!\n"));
  7956. } else{
  7957. TRACE_INIT(("DrvSetDisconnectedGraphicsDevice Failed!\n"));
  7958. }
  7959. // write any change back to device lists
  7960. if ( bLocal ) {
  7961. gcLocalNextGlobalDeviceNumber = gcNextGlobalDeviceNumber;
  7962. gpLocalGraphicsDeviceList = gpGraphicsDeviceList;
  7963. gpLocalGraphicsDeviceListLast = gpGraphicsDeviceListLast;
  7964. gcLocalNextGlobalPhysicalOutputNumber = gcNextGlobalPhysicalOutputNumber;
  7965. gcLocalNextGlobalVirtualOutputNumber = gcNextGlobalVirtualOutputNumber;
  7966. } else{
  7967. //gcRemoteNextGlobalDeviceNumber = gcNextGlobalDeviceNumber;
  7968. gpRemoteGraphicsDeviceList = gpGraphicsDeviceList;
  7969. gpRemoteGraphicsDeviceListLast = gpGraphicsDeviceListLast;
  7970. gcRemoteNextGlobalPhysicalOutputNumber = gcNextGlobalPhysicalOutputNumber;
  7971. gcRemoteNextGlobalVirtualOutputNumber = gcNextGlobalVirtualOutputNumber;
  7972. }
  7973. TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpGraphicsDeviceList : %x\n",gpGraphicsDeviceList));
  7974. TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpLocalGraphicsDeviceList : %x\n",gpLocalGraphicsDeviceList));
  7975. TRACE_INIT(("DrvUpdateGraphicsDeviceList - gpRemoteGraphicsDeviceList : %x\n",gpRemoteGraphicsDeviceList));
  7976. TRACE_INIT(("Drv_Trace:DrvUpdateGraphicsDeviceList: Exit\n\n"));
  7977. return bReturn;
  7978. }
  7979. /***************************************************************************\
  7980. * DrvSetDisconnectedGraphicsDevice
  7981. * Creates an Entry for the disconnect grapgics device (either for the local
  7982. * or for the remote list.
  7983. \***************************************************************************/
  7984. BOOL
  7985. DrvSetDisconnectedGraphicsDevice(
  7986. BOOL bLocal)
  7987. {
  7988. const WCHAR DisconnectDeviceName[] = L"\\Device\\Disc";
  7989. NTSTATUS status;
  7990. PGRAPHICS_DEVICE PhysDisp = NULL;
  7991. HANDLE hkRegistry = NULL;
  7992. BOOL bReturn = FALSE;
  7993. TRACE_INIT(("Drv_Trace:DrvSetDisconnectedGraphicsDevice: \n"));
  7994. if ((bLocal && gpLocalDiscGraphicsDevice != NULL ) ||
  7995. (!bLocal && gpRemoteDiscGraphicsDevice != NULL))
  7996. {
  7997. TRACE_INIT(("DrvSetDisconnectedGraphicsDevice - Device already set"));
  7998. return TRUE;
  7999. }
  8000. //
  8001. // Allocate a buffer .
  8002. //
  8003. PhysDisp = (PGRAPHICS_DEVICE) PALLOCMEM(sizeof(GRAPHICS_DEVICE),
  8004. GDITAG_GDEVICE);
  8005. if (PhysDisp)
  8006. {
  8007. UNICODE_STRING DeviceName;
  8008. //
  8009. // Assign NtDeviceName as "\\Device\\Disc".
  8010. // This has to be have an entry in DEVICEMAP\Video
  8011. //
  8012. RtlInitUnicodeString(&DeviceName,
  8013. L"\\REGISTRY\\Machine\\System\\CurrentControlSet\\Services\\TSDDD\\Device0");
  8014. RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  8015. L"VIDEO",
  8016. DisconnectDeviceName,
  8017. REG_SZ,
  8018. DeviceName.Buffer,
  8019. DeviceName.Length + sizeof(UNICODE_NULL));
  8020. RtlCopyMemory(&(PhysDisp->szNtDeviceName[0]), DisconnectDeviceName, sizeof(DisconnectDeviceName));
  8021. PhysDisp->numMonitorDevice = 0;
  8022. PhysDisp->MonitorDevices = NULL;
  8023. PhysDisp->stateFlags |= DISPLAY_DEVICE_DISCONNECT;
  8024. PhysDisp->ProtocolType = PROTOCOL_DISCONNECT;
  8025. // Read device Configuration from registry
  8026. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  8027. PhysDisp,
  8028. DispDriverRegGlobal,
  8029. NULL,
  8030. NULL,
  8031. &status,
  8032. PROTOCOL_DISCONNECT);
  8033. if (NT_SUCCESS(status))
  8034. {
  8035. DrvGetDeviceConfigurationInformation(PhysDisp, hkRegistry, FALSE);
  8036. ZwCloseKey(hkRegistry);
  8037. bReturn = TRUE;
  8038. }
  8039. //
  8040. // If we haven't specified a device description set it to something.
  8041. //
  8042. if ((NT_SUCCESS(status)) &&
  8043. (PhysDisp->DeviceDescription == NULL))
  8044. {
  8045. if (PhysDisp->DeviceDescription = (LPWSTR) PALLOCNOZ(32, GDITAG_DRVSUP))
  8046. {
  8047. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  8048. DispDriverRegGlobal,
  8049. NULL,
  8050. PhysDisp->DeviceDescription,
  8051. &status,
  8052. PROTOCOL_DISCONNECT);
  8053. if (hkRegistry)
  8054. {
  8055. ZwCloseKey(hkRegistry);
  8056. }
  8057. }
  8058. else
  8059. {
  8060. status = STATUS_INSUFFICIENT_RESOURCES;
  8061. }
  8062. }
  8063. if (!NT_SUCCESS(status))
  8064. {
  8065. if (PhysDisp->DisplayDriverNames != NULL) {
  8066. VFREEMEM(PhysDisp->DisplayDriverNames);
  8067. }
  8068. VFREEMEM(PhysDisp);
  8069. return FALSE;
  8070. }
  8071. //
  8072. // Set WinDeviceName (name for extenal reference; usually \\.\DISPLAY#)
  8073. //
  8074. swprintf(&(PhysDisp->szWinDeviceName[0]),L"WinDisc");
  8075. PhysDisp->pDeviceHandle = (HANDLE) NULL;
  8076. //
  8077. // Link the new device at the end so we can enumerate
  8078. // in the right order.
  8079. //
  8080. if (gpGraphicsDeviceList == NULL)
  8081. {
  8082. gpGraphicsDeviceList = PhysDisp;
  8083. gpGraphicsDeviceListLast = PhysDisp;
  8084. }
  8085. else
  8086. {
  8087. gpGraphicsDeviceListLast->pNextGraphicsDevice = PhysDisp;
  8088. gpGraphicsDeviceListLast = PhysDisp;
  8089. }
  8090. if (bLocal)
  8091. {
  8092. gpLocalDiscGraphicsDevice = PhysDisp;
  8093. }
  8094. else
  8095. {
  8096. gpRemoteDiscGraphicsDevice = PhysDisp;
  8097. }
  8098. }
  8099. return bReturn;
  8100. }
  8101. /***************************************************************************\
  8102. * DrvEnumDisplaySettings
  8103. *
  8104. * Routines that enumerate the list of modes available in the driver.
  8105. *
  8106. * andreva Created
  8107. \***************************************************************************/
  8108. NTSTATUS
  8109. DrvEnumDisplaySettings(
  8110. PUNICODE_STRING pstrDeviceName,
  8111. HDEV hdevPrimary,
  8112. DWORD iModeNum,
  8113. LPDEVMODEW lpDevMode,
  8114. DWORD dwFlags)
  8115. {
  8116. GDIFunctionID(DrvEnumDisplaySettings);
  8117. NTSTATUS retval = STATUS_INVALID_PARAMETER_1;
  8118. PGRAPHICS_DEVICE PhysDisp = NULL;
  8119. USHORT DriverExtraSize;
  8120. TRACE_INIT(("Drv_Trace: DrvEnumDisplaySettings\n"));
  8121. //
  8122. // Probe the DeviceName and the DEVMODE.
  8123. //
  8124. __try
  8125. {
  8126. ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(USHORT));
  8127. DriverExtraSize = lpDevMode->dmDriverExtra;
  8128. ProbeForWrite(lpDevMode,
  8129. sizeof(DEVMODEW) + DriverExtraSize,
  8130. sizeof(USHORT));
  8131. if (lpDevMode->dmSize != sizeof(DEVMODEW))
  8132. {
  8133. return STATUS_BUFFER_TOO_SMALL;
  8134. }
  8135. }
  8136. __except (EXCEPTION_EXECUTE_HANDLER)
  8137. {
  8138. return GetExceptionCode();
  8139. }
  8140. if (pstrDeviceName)
  8141. {
  8142. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, UserMode);
  8143. }
  8144. else
  8145. {
  8146. PDEVOBJ pdo(hdevPrimary);
  8147. if (pdo.bValid())
  8148. {
  8149. PhysDisp = pdo.ppdev->pGraphicsDevice;
  8150. }
  8151. }
  8152. if (PhysDisp)
  8153. {
  8154. //
  8155. // -3 means we want the Monitor prefered DEVMODE
  8156. //
  8157. if (iModeNum == (DWORD) -3) // ENUM_MONITOR_PREFERED
  8158. {
  8159. retval = DrvGetPreferredMode(lpDevMode, PhysDisp);
  8160. }
  8161. //
  8162. // -2 means we want the registry DEVMODE to do matching on the
  8163. // client side.
  8164. //
  8165. else if (iModeNum == (DWORD) -2) // ENUM_REGISTRY_SETTINGS
  8166. {
  8167. PDEVMODEW pdevmode;
  8168. TRACE_INIT(("DrvEnumDisp: -2 mode\n"));
  8169. pdevmode = (PDEVMODEW) PALLOCMEM(sizeof(DEVMODEW) + MAXUSHORT,
  8170. GDITAG_DEVMODE);
  8171. if (pdevmode)
  8172. {
  8173. pdevmode->dmSize = 0xDDDD;
  8174. pdevmode->dmDriverExtra = MAXUSHORT;
  8175. retval = DrvGetDisplayDriverParameters(PhysDisp,
  8176. pdevmode,
  8177. FALSE,
  8178. FALSE);
  8179. if (NT_SUCCESS(retval))
  8180. {
  8181. __try
  8182. {
  8183. DriverExtraSize = min(DriverExtraSize,
  8184. pdevmode->dmDriverExtra);
  8185. RtlCopyMemory(lpDevMode + 1,
  8186. pdevmode + 1,
  8187. DriverExtraSize);
  8188. RtlCopyMemory(lpDevMode,
  8189. pdevmode,
  8190. sizeof(DEVMODEW));
  8191. }
  8192. __except(EXCEPTION_EXECUTE_HANDLER)
  8193. {
  8194. retval = STATUS_INVALID_PARAMETER_3;
  8195. }
  8196. }
  8197. VFREEMEM(pdevmode);
  8198. }
  8199. }
  8200. //
  8201. // -1 means returns the current device mode.
  8202. // We store the full DEVMODE in the
  8203. //
  8204. else if (iModeNum == (DWORD) -1) // ENUM_CURRENT_SETTINGS
  8205. {
  8206. PPDEV ppdev;
  8207. TRACE_INIT(("DrvEnumDisp: -1 mode\n"));
  8208. //
  8209. // Since we are accessing variable fields off of this device,
  8210. // acquire the lock for them.
  8211. //
  8212. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  8213. //
  8214. // Find the currently adtive PDEV on this device.
  8215. //
  8216. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  8217. {
  8218. PDEVOBJ po((HDEV) ppdev);
  8219. //
  8220. // Also need to check VGA(alias) device
  8221. //
  8222. if (((po.ppdev->pGraphicsDevice == PhysDisp) ||
  8223. ((po.ppdev->pGraphicsDevice == PhysDisp->pVgaDevice) &&
  8224. (po.ppdev->pGraphicsDevice != NULL)))
  8225. && (!po.bDeleted()))
  8226. {
  8227. __try
  8228. {
  8229. DriverExtraSize = min(DriverExtraSize,
  8230. po.ppdev->ppdevDevmode->dmDriverExtra);
  8231. //
  8232. // We know the DEVMODE we called the driver with is of
  8233. // size sizeof(DEVMODEW)
  8234. //
  8235. RtlCopyMemory(lpDevMode + 1,
  8236. po.ppdev->ppdevDevmode + 1,
  8237. DriverExtraSize);
  8238. RtlCopyMemory(lpDevMode,
  8239. po.ppdev->ppdevDevmode,
  8240. sizeof(DEVMODEW));
  8241. retval = STATUS_SUCCESS;
  8242. }
  8243. __except(EXCEPTION_EXECUTE_HANDLER)
  8244. {
  8245. retval = STATUS_INVALID_PARAMETER_3;
  8246. }
  8247. break;
  8248. }
  8249. }
  8250. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  8251. }
  8252. else
  8253. {
  8254. //
  8255. // We don't need synchronize access to the list of modes.
  8256. // Who cares.
  8257. //
  8258. DrvBuildDevmodeList(PhysDisp, FALSE);
  8259. //
  8260. // now return the information
  8261. //
  8262. if ( (PhysDisp->cbdevmodeInfo == 0) ||
  8263. (PhysDisp->devmodeInfo == NULL) )
  8264. {
  8265. WARNING("EnumDisplaySettings PhysDisp is inconsistent\n");
  8266. retval = STATUS_UNSUCCESSFUL;
  8267. }
  8268. else
  8269. {
  8270. LPDEVMODEW lpdm = NULL;
  8271. DWORD i, count;
  8272. retval = STATUS_INVALID_PARAMETER_2;
  8273. if (iModeNum < PhysDisp->numRawModes)
  8274. {
  8275. if (dwFlags & EDS_RAWMODE)
  8276. lpdm = PhysDisp->devmodeMarks[iModeNum].pDevMode;
  8277. else
  8278. {
  8279. for (i = 0, count = 0; i < PhysDisp->numRawModes; i++)
  8280. {
  8281. if (PhysDisp->devmodeMarks[i].bPruned)
  8282. continue;
  8283. if (count == iModeNum)
  8284. {
  8285. lpdm = PhysDisp->devmodeMarks[i].pDevMode;
  8286. break;
  8287. }
  8288. count++;
  8289. }
  8290. }
  8291. }
  8292. if (lpdm)
  8293. {
  8294. __try
  8295. {
  8296. DriverExtraSize = min(DriverExtraSize,
  8297. lpdm->dmDriverExtra);
  8298. RtlZeroMemory(lpDevMode, sizeof(*lpDevMode));
  8299. //
  8300. // Check the size since the devmode returned
  8301. // by the driver can be smaller than the current
  8302. // size.
  8303. //
  8304. RtlCopyMemory(lpDevMode + 1,
  8305. ((PUCHAR)lpdm) + lpdm->dmSize,
  8306. DriverExtraSize);
  8307. RtlCopyMemory(lpDevMode,
  8308. lpdm,
  8309. min(sizeof(DEVMODEW), lpdm->dmSize));
  8310. retval = STATUS_SUCCESS;
  8311. }
  8312. __except(EXCEPTION_EXECUTE_HANDLER)
  8313. {
  8314. retval = STATUS_INVALID_PARAMETER_3;
  8315. }
  8316. }
  8317. }
  8318. //
  8319. // As an acceleration, we will only free the list if the call
  8320. // failed because "i" was too large, so that listing all the modes
  8321. // does not require building the list each time.
  8322. //
  8323. if (retval == STATUS_INVALID_PARAMETER_2)
  8324. {
  8325. //
  8326. // Free up the resources - as long as it's not the VGA.
  8327. // Assume the VGA is always first
  8328. //
  8329. if (PhysDisp != &gFullscreenGraphicsDevice)
  8330. {
  8331. PhysDisp->cbdevmodeInfo = 0;
  8332. if (PhysDisp->devmodeInfo)
  8333. {
  8334. VFREEMEM(PhysDisp->devmodeInfo);
  8335. PhysDisp->devmodeInfo = NULL;
  8336. }
  8337. if (PhysDisp->devmodeMarks)
  8338. {
  8339. VFREEMEM(PhysDisp->devmodeMarks);
  8340. PhysDisp->devmodeMarks = NULL;
  8341. }
  8342. PhysDisp->numRawModes = 0;
  8343. }
  8344. }
  8345. }
  8346. }
  8347. //
  8348. // Update the driver extra size
  8349. //
  8350. if (retval == STATUS_SUCCESS)
  8351. {
  8352. __try
  8353. {
  8354. lpDevMode->dmDriverExtra = DriverExtraSize;
  8355. }
  8356. __except (EXCEPTION_EXECUTE_HANDLER)
  8357. {
  8358. retval = GetExceptionCode();
  8359. }
  8360. }
  8361. return (retval);
  8362. }
  8363. /***************************************************************************\
  8364. *
  8365. * DrvEnumDisplayDevices
  8366. *
  8367. * History:
  8368. \***************************************************************************/
  8369. NTSTATUS
  8370. DrvEnumDisplayDevices(
  8371. PUNICODE_STRING pstrDeviceName,
  8372. HDEV hdevPrimary,
  8373. DWORD iDevNum,
  8374. LPDISPLAY_DEVICEW lpDisplayDevice,
  8375. DWORD dwFlags,
  8376. MODE PreviousMode)
  8377. {
  8378. PGRAPHICS_DEVICE PhysDisp;
  8379. ULONG cbSize;
  8380. ULONG cCount = 0;
  8381. PDEVICE_OBJECT pdo = NULL;
  8382. NTSTATUS retStatus = STATUS_SUCCESS;
  8383. UNREFERENCED_PARAMETER(dwFlags);
  8384. UNREFERENCED_PARAMETER(hdevPrimary);
  8385. if (pstrDeviceName == NULL)
  8386. {
  8387. //
  8388. // Start enumerating at 0 ...
  8389. //
  8390. for (PhysDisp = gpGraphicsDeviceList;
  8391. PhysDisp != NULL;
  8392. PhysDisp = PhysDisp->pNextGraphicsDevice, cCount++)
  8393. {
  8394. //
  8395. // Do not enumerate the disconnected DD for user mode callers.
  8396. // Also if we are not on the physical console, do not enumerate
  8397. // drivers other than current protocol driver.
  8398. //
  8399. if (PreviousMode != KernelMode)
  8400. {
  8401. if((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) ||
  8402. (gProtocolType != PROTOCOL_CONSOLE && PhysDisp->ProtocolType != gProtocolType))
  8403. {
  8404. cCount--;
  8405. continue;
  8406. }
  8407. }
  8408. if (cCount == iDevNum)
  8409. break;
  8410. }
  8411. if (PhysDisp == NULL)
  8412. {
  8413. return STATUS_UNSUCCESSFUL;
  8414. }
  8415. PDEVICE_RELATIONS pDeviceRelations;
  8416. //pDeviceHandle migth be NULL in the case of the disconnected DD which
  8417. //has no associated miniport.
  8418. if (PhysDisp->pPhysDeviceHandle) {
  8419. pdo = (PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle;
  8420. }
  8421. else if ((PDEVICE_OBJECT)PhysDisp->pDeviceHandle != NULL) {
  8422. if (NT_SUCCESS(DrvSendPnPIrp((PDEVICE_OBJECT)PhysDisp->pDeviceHandle,
  8423. TargetDeviceRelation,
  8424. &pDeviceRelations) )
  8425. )
  8426. {
  8427. pdo = pDeviceRelations->Objects[0];
  8428. ASSERTGDI(pDeviceRelations->Count == 1,
  8429. "TargetDeviceRelation should only get one PDO\n");
  8430. ExFreePool(pDeviceRelations);
  8431. }
  8432. }else{
  8433. TRACE_INIT(("DrvEnumDisplayDevices - processing the disconnected GRAPHICS_DEVICE\n"));
  8434. }
  8435. }
  8436. else
  8437. {
  8438. UpdateMonitorDevices();
  8439. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
  8440. if (PhysDisp == NULL)
  8441. return STATUS_UNSUCCESSFUL;
  8442. if (iDevNum >= PhysDisp->numMonitorDevice)
  8443. return STATUS_UNSUCCESSFUL;
  8444. pdo = (PDEVICE_OBJECT)PhysDisp->MonitorDevices[iDevNum].pdo;
  8445. }
  8446. //
  8447. // We found the device, so the call will be successful unless
  8448. // we except later on.
  8449. //
  8450. __try
  8451. {
  8452. PVOID pBuffer;
  8453. NTSTATUS status;
  8454. //
  8455. // Capture the input buffer length
  8456. //
  8457. TRACE_INIT(("Drv_Trace: DrvEnumDisplayDevices %d\n", iDevNum));
  8458. if (PreviousMode == UserMode)
  8459. {
  8460. cbSize = ProbeAndReadUlong(&(lpDisplayDevice->cb));
  8461. ProbeForWrite(lpDisplayDevice, cbSize, sizeof(DWORD));
  8462. }
  8463. else
  8464. {
  8465. ASSERTGDI(lpDisplayDevice >= (LPDISPLAY_DEVICEW const)MM_USER_PROBE_ADDRESS,
  8466. "Bad kernel mode address\n");
  8467. cbSize = lpDisplayDevice->cb;
  8468. }
  8469. RtlZeroMemory(lpDisplayDevice, cbSize);
  8470. if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceName))
  8471. {
  8472. lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceName);
  8473. }
  8474. if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceString))
  8475. {
  8476. lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceString);
  8477. if (pstrDeviceName == NULL)
  8478. RtlCopyMemory(lpDisplayDevice->DeviceName,
  8479. PhysDisp->szWinDeviceName,
  8480. sizeof(PhysDisp->szWinDeviceName));
  8481. else
  8482. swprintf(lpDisplayDevice->DeviceName,
  8483. L"%ws\\Monitor%d",
  8484. PhysDisp->szWinDeviceName, iDevNum);
  8485. lpDisplayDevice->DeviceName[31] = 0;
  8486. }
  8487. if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, StateFlags))
  8488. {
  8489. lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, StateFlags);
  8490. lpDisplayDevice->DeviceString[0] = 0;
  8491. if (pstrDeviceName == NULL)
  8492. {
  8493. if (PhysDisp->DeviceDescription)
  8494. wcsncpy(lpDisplayDevice->DeviceString, PhysDisp->DeviceDescription, 127);
  8495. }
  8496. else if (pdo)
  8497. {
  8498. //
  8499. // Get the name for this device.
  8500. // Documentation says to try in a loop.
  8501. //
  8502. cCount = 256;
  8503. while (1)
  8504. {
  8505. pBuffer = PALLOCNOZ(cCount, 'ddeG');
  8506. if (pBuffer == NULL)
  8507. {
  8508. retStatus = STATUS_INSUFFICIENT_RESOURCES;
  8509. break;
  8510. }
  8511. status = IoGetDeviceProperty(pdo,
  8512. DevicePropertyDeviceDescription,
  8513. cCount,
  8514. pBuffer,
  8515. &cCount);
  8516. if (status == STATUS_BUFFER_TOO_SMALL)
  8517. {
  8518. VFREEMEM(pBuffer);
  8519. continue;
  8520. }
  8521. else if (status == STATUS_SUCCESS)
  8522. {
  8523. wcsncpy(lpDisplayDevice->DeviceString, (LPWSTR)pBuffer, 127);
  8524. VFREEMEM(pBuffer);
  8525. break;
  8526. }
  8527. VFREEMEM(pBuffer);
  8528. break;
  8529. }
  8530. }
  8531. lpDisplayDevice->DeviceString[127] = 0;
  8532. }
  8533. if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceID))
  8534. {
  8535. lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceID);
  8536. if (pstrDeviceName == NULL)
  8537. lpDisplayDevice->StateFlags = PhysDisp->stateFlags & 0x0FFFFFFF;
  8538. else
  8539. lpDisplayDevice->StateFlags = PhysDisp->MonitorDevices[iDevNum].flag & 0x0FFFFFFF;
  8540. }
  8541. if (cbSize >= FIELD_OFFSET(DISPLAY_DEVICEW, DeviceKey))
  8542. {
  8543. lpDisplayDevice->cb = FIELD_OFFSET(DISPLAY_DEVICEW, DeviceKey);
  8544. lpDisplayDevice->DeviceID[0] = 0;
  8545. if (pdo)
  8546. {
  8547. cCount = 256;
  8548. while (1)
  8549. {
  8550. pBuffer = PALLOCNOZ(cCount, 'ddeG');
  8551. if (pBuffer == NULL)
  8552. {
  8553. retStatus = STATUS_INSUFFICIENT_RESOURCES;
  8554. break;
  8555. }
  8556. status = IoGetDeviceProperty(pdo,
  8557. DevicePropertyHardwareID,
  8558. cCount,
  8559. pBuffer,
  8560. &cCount);
  8561. if (status == STATUS_BUFFER_TOO_SMALL)
  8562. {
  8563. VFREEMEM(pBuffer);
  8564. continue;
  8565. }
  8566. else if (status == STATUS_SUCCESS)
  8567. {
  8568. wcsncpy(lpDisplayDevice->DeviceID, (LPWSTR)pBuffer, 127);
  8569. VFREEMEM(pBuffer);
  8570. break;
  8571. }
  8572. VFREEMEM(pBuffer);
  8573. break;
  8574. }
  8575. // For Monitor devices, we will make the ID unique.
  8576. // Applet and GDIs are expecting this behavior.
  8577. if (pstrDeviceName != NULL)
  8578. {
  8579. lpDisplayDevice->DeviceID[127] = 0;
  8580. cCount = wcslen(lpDisplayDevice->DeviceID)+1;
  8581. if (cCount < 126)
  8582. {
  8583. lpDisplayDevice->DeviceID[cCount-1] = L'\\';
  8584. status = IoGetDeviceProperty(pdo,
  8585. DevicePropertyDriverKeyName,
  8586. (127-cCount)*sizeof(WCHAR),
  8587. (PBYTE)(lpDisplayDevice->DeviceID+cCount),
  8588. &cCount);
  8589. }
  8590. }
  8591. }
  8592. lpDisplayDevice->DeviceID[127] = 0;
  8593. }
  8594. if (cbSize >= sizeof(DISPLAY_DEVICEW))
  8595. {
  8596. lpDisplayDevice->cb = sizeof(DISPLAY_DEVICEW);
  8597. lpDisplayDevice->DeviceKey[0] = 0;
  8598. if (pstrDeviceName == NULL)
  8599. {
  8600. DrvGetRegistryHandleFromDeviceMap(PhysDisp, DispDriverRegKey, NULL, lpDisplayDevice->DeviceKey, NULL, gProtocolType);
  8601. }
  8602. else
  8603. {
  8604. NTSTATUS Status;
  8605. WCHAR driverRegistryPath[127];
  8606. Status = IoGetDeviceProperty(pdo,
  8607. DevicePropertyDriverKeyName,
  8608. 127*sizeof(WCHAR),
  8609. (PBYTE)driverRegistryPath,
  8610. &cCount);
  8611. if (NT_SUCCESS(Status))
  8612. {
  8613. wcscpy(lpDisplayDevice->DeviceKey, REGSTR_CCS);
  8614. cCount = wcslen(lpDisplayDevice->DeviceKey);
  8615. wcsncpy(lpDisplayDevice->DeviceKey+cCount, L"\\Control\\Class\\", 127-cCount);
  8616. cCount = wcslen(lpDisplayDevice->DeviceKey);
  8617. wcsncpy(lpDisplayDevice->DeviceKey+cCount, driverRegistryPath, 127-cCount);
  8618. }
  8619. }
  8620. lpDisplayDevice->DeviceKey[127] = 0;
  8621. }
  8622. }
  8623. __except (EXCEPTION_EXECUTE_HANDLER)
  8624. {
  8625. WARNINGX(100);
  8626. retStatus = STATUS_UNSUCCESSFUL;
  8627. }
  8628. if (pstrDeviceName == NULL && pdo && (PhysDisp->pPhysDeviceHandle == NULL))
  8629. {
  8630. ObDereferenceObject(pdo);
  8631. }
  8632. return retStatus;
  8633. }
  8634. /******************************Public*Routine******************************\
  8635. * DrvGetDriverAccelerationsLevel()
  8636. *
  8637. * Reads the driver acceleration 'filter' level from the registry. This
  8638. * values determines how we let the display driver do in terms of
  8639. * accelerations, where a value of 0 means full acceleration.
  8640. *
  8641. * 20-Aug-1998 -by- Hideyuki Nagase [hideyukn]
  8642. * Lifted it from AndrewGo's code.
  8643. \**************************************************************************/
  8644. #define ACCEL_REGKEY L"Acceleration.Level"
  8645. #define CAPABLE_REGKEY L"CapabilityOverride" // Driver capable override
  8646. #define ACCEL_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(ACCEL_REGKEY) + sizeof(DWORD))
  8647. #define CAPABLE_BUFSIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(CAPABLE_REGKEY) + sizeof(DWORD))
  8648. DWORD
  8649. DrvGetDriverAccelerationsLevel(
  8650. PGRAPHICS_DEVICE pGraphicsDevice
  8651. )
  8652. {
  8653. HANDLE hkRegistry;
  8654. UNICODE_STRING UnicodeString;
  8655. DWORD dwReturn = DRIVER_ACCELERATIONS_INVALID;
  8656. BYTE buffer[ACCEL_BUFSIZE];
  8657. ULONG Length = ACCEL_BUFSIZE;
  8658. PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION) buffer;
  8659. WCHAR aszValuename[] = ACCEL_REGKEY;
  8660. if (pGraphicsDevice == (PGRAPHICS_DEVICE) DDML_DRIVER)
  8661. {
  8662. dwReturn = 0;
  8663. }
  8664. if (dwReturn == DRIVER_ACCELERATIONS_INVALID)
  8665. {
  8666. //
  8667. // See adaptor specific setting first.
  8668. //
  8669. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  8670. pGraphicsDevice,
  8671. DispDriverRegGlobal,
  8672. NULL,
  8673. NULL,
  8674. NULL,
  8675. gProtocolType);
  8676. if (hkRegistry)
  8677. {
  8678. RtlInitUnicodeString(&UnicodeString, aszValuename);
  8679. if (NT_SUCCESS(ZwQueryValueKey(hkRegistry,
  8680. &UnicodeString,
  8681. KeyValueFullInformation,
  8682. Information,
  8683. Length,
  8684. &Length)))
  8685. {
  8686. dwReturn = *(LPDWORD) ((((PUCHAR)Information) +
  8687. Information->DataOffset));
  8688. }
  8689. ZwCloseKey(hkRegistry);
  8690. }
  8691. }
  8692. if (dwReturn == DRIVER_ACCELERATIONS_INVALID)
  8693. {
  8694. //
  8695. // If there is nothing specified, assume full acceleration.
  8696. //
  8697. dwReturn = DRIVER_ACCELERATIONS_FULL;
  8698. }
  8699. else if (dwReturn > DRIVER_ACCELERATIONS_NONE)
  8700. {
  8701. //
  8702. // If there is something invalid value, assume no acceleration.
  8703. //
  8704. dwReturn = DRIVER_ACCELERATIONS_NONE;
  8705. }
  8706. if (G_fDoubleDpi)
  8707. {
  8708. //
  8709. // Always set accelerations to 'none' when operating in double-the-
  8710. // dpi mode, so that panning.cxx can create a virtual display
  8711. // larger than the actual physical display.
  8712. //
  8713. dwReturn = DRIVER_ACCELERATIONS_NONE;
  8714. }
  8715. #if DBG
  8716. if (pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER)
  8717. {
  8718. DbgPrint("GDI: DriverAccelerationLevel on %ws is %d\n",
  8719. pGraphicsDevice->szWinDeviceName, dwReturn);
  8720. }
  8721. #endif
  8722. return(dwReturn);
  8723. }
  8724. DWORD
  8725. DrvGetDriverCapableOverRide(
  8726. PGRAPHICS_DEVICE pGraphicsDevice
  8727. )
  8728. {
  8729. HANDLE hkRegistry;
  8730. UNICODE_STRING UnicodeString;
  8731. DWORD dwReturn = DRIVER_CAPABLE_ALL;
  8732. BYTE buffer[CAPABLE_BUFSIZE];
  8733. ULONG ulLength = CAPABLE_BUFSIZE;
  8734. ULONG ulActualLength;
  8735. PKEY_VALUE_FULL_INFORMATION Information = (PKEY_VALUE_FULL_INFORMATION)buffer;
  8736. WCHAR aszValuename[] = CAPABLE_REGKEY;
  8737. if ( pGraphicsDevice == (PGRAPHICS_DEVICE)DDML_DRIVER )
  8738. {
  8739. return DRIVER_CAPABLE_ALL;
  8740. }
  8741. //
  8742. // See adaptor specific setting first.
  8743. //
  8744. hkRegistry = DrvGetRegistryHandleFromDeviceMap(
  8745. pGraphicsDevice,
  8746. DispDriverRegGlobal,
  8747. NULL,
  8748. NULL,
  8749. NULL,
  8750. gProtocolType);
  8751. if ( hkRegistry )
  8752. {
  8753. RtlInitUnicodeString(&UnicodeString, aszValuename);
  8754. if ( NT_SUCCESS(ZwQueryValueKey(hkRegistry,
  8755. &UnicodeString,
  8756. KeyValueFullInformation,
  8757. Information,
  8758. ulLength,
  8759. &ulActualLength)) )
  8760. {
  8761. dwReturn = *(LPDWORD)((((PUCHAR)Information)
  8762. + Information->DataOffset));
  8763. }
  8764. ZwClose(hkRegistry);
  8765. }
  8766. #if DBG
  8767. if ( pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER )
  8768. {
  8769. DbgPrint("GDI: DriverCapableOverride on %ws is %d\n",
  8770. pGraphicsDevice->szWinDeviceName, dwReturn);
  8771. }
  8772. #endif
  8773. return(dwReturn);
  8774. }// DrvGetDriverCapableOverRide()
  8775. VOID
  8776. DrvUpdateAttachFlag(PGRAPHICS_DEVICE PhysDisp, DWORD attach)
  8777. {
  8778. HANDLE hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  8779. DispDriverRegHardwareProfileCreate,
  8780. NULL,
  8781. NULL,
  8782. NULL,
  8783. gProtocolType);
  8784. if (hkRegistry)
  8785. {
  8786. RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  8787. (PCWSTR)hkRegistry,
  8788. (PWSTR)AttachedSettings[1],
  8789. REG_DWORD,
  8790. &attach,
  8791. sizeof(DWORD));
  8792. ZwCloseKey(hkRegistry);
  8793. }
  8794. }
  8795. /***************************************************************************\
  8796. *
  8797. * DrvEnableMDEV
  8798. *
  8799. * Enables a display MDEV.
  8800. *
  8801. * Should only be called from USER under the global CRIT
  8802. *
  8803. \***************************************************************************/
  8804. ULONG gtmpAssertModeFailed;
  8805. BOOL
  8806. DrvEnableDisplay(
  8807. HDEV hdev
  8808. )
  8809. {
  8810. PDEVOBJ po(hdev);
  8811. TRACE_INIT(("\nDrv_Trace: DrvEnableDisplay: Enter\n"));
  8812. ASSERTGDI(po.bValid(), "HDEV failure\n");
  8813. ASSERTGDI(po.bDisplayPDEV(), "HDEV is not a display device\n");
  8814. ASSERTGDI(po.bDisabled(), "HDEV must be disabled to call enable\n");
  8815. ASSERTGDI(po.ppdev->pGraphicsDevice, "HDEV must be on a device\n");
  8816. //
  8817. // Acquire the display locks here because we may get called from within
  8818. // ChangeDisplaySettings to enable\disable a particular device when
  8819. // creating the new HDEVs.
  8820. //
  8821. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  8822. GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  8823. GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock());
  8824. GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
  8825. //
  8826. // Enable the screen
  8827. // Repeat the call until it works.
  8828. //
  8829. bSetDeviceSessionUsage(po.ppdev->pGraphicsDevice, TRUE);
  8830. gtmpAssertModeFailed = 0;
  8831. while (!((*PPFNDRV(po,AssertMode))(po.dhpdev(), TRUE)))
  8832. {
  8833. gtmpAssertModeFailed = 1;
  8834. }
  8835. //
  8836. // Clear the PDEV for use
  8837. //
  8838. po.bDisabled(FALSE);
  8839. GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
  8840. GreReleaseSemaphoreEx(po.hsemPointer());
  8841. GreReleaseSemaphoreEx(po.hsemDevLock());
  8842. GreReleaseSemaphoreEx(ghsemShareDevLock);
  8843. //
  8844. // Allow DirectDraw to be reenabled.
  8845. //
  8846. GreResumeDirectDraw(hdev, FALSE);
  8847. TRACE_INIT(("Drv_Trace: DrvEnableDisplay: Leave\n"));
  8848. return TRUE;
  8849. }
  8850. BOOL
  8851. DrvEnableMDEV(
  8852. PMDEV pmdev,
  8853. BOOL bHardware
  8854. )
  8855. {
  8856. GDIFunctionID(DrvEnableMDEV);
  8857. ULONG i;
  8858. ERESOURCE_THREAD lockOwner;
  8859. TRACE_INIT(("\nDrv_Trace: DrvEnableMDEV: Enter\n"));
  8860. PDEVOBJ poParent(pmdev->hdevParent);
  8861. #if MDEV_STACK_TRACE_LENGTH
  8862. LONG lMDEVTraceEntry, lMDEVTraceEntryNext;
  8863. ULONG StackEntries, UserStackEntry;
  8864. do
  8865. {
  8866. lMDEVTraceEntry = glMDEVTrace;
  8867. lMDEVTraceEntryNext = lMDEVTraceEntry + 1;
  8868. if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0;
  8869. } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
  8870. RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry],
  8871. sizeof(gMDEVTrace[lMDEVTraceEntry]));
  8872. gMDEVTrace[lMDEVTraceEntry].pMDEV = pmdev;
  8873. gMDEVTrace[lMDEVTraceEntry].API = ((bHardware) ? DrvEnableMDEV_HWOn : DrvEnableMDEV_FromGRE);
  8874. StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]);
  8875. UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace,
  8876. StackEntries,
  8877. 0);
  8878. StackEntries -= UserStackEntry;
  8879. RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry],
  8880. StackEntries,
  8881. 1);
  8882. #endif
  8883. for (i = 0; i < pmdev->chdev; i++)
  8884. {
  8885. PDEVOBJ po(pmdev->Dev[i].hdev);
  8886. if (bHardware ||
  8887. ((po.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  8888. gbInvalidateDualView &&
  8889. po.bDisabled())
  8890. )
  8891. {
  8892. DrvEnableDisplay(po.hdev());
  8893. }
  8894. }
  8895. //
  8896. // Wait for the display to become available and unlock it.
  8897. //
  8898. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  8899. GreAcquireSemaphoreEx(poParent.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  8900. GreAcquireSemaphoreEx(poParent.hsemPointer(), SEMORDER_POINTER, poParent.hsemDevLock());
  8901. GreEnterMonitoredSection(poParent.ppdev, WD_DEVLOCK);
  8902. if (bHardware)
  8903. {
  8904. poParent.bDisabled(FALSE);
  8905. }
  8906. //
  8907. // Get the palette
  8908. //
  8909. XEPALOBJ pal(poParent.ppalSurf());
  8910. ASSERTGDI(pal.bValid(), "EPALOBJ failure\n");
  8911. if (pal.bIsPalManaged())
  8912. {
  8913. ASSERTGDI(PPFNVALID(poParent,SetPalette), "ERROR palette is not managed");
  8914. (*PPFNDRV(poParent,SetPalette))(poParent.dhpdev(),
  8915. (PALOBJ *) &pal,
  8916. 0,
  8917. 0,
  8918. pal.cEntries());
  8919. }
  8920. else if (pmdev->chdev > 1)
  8921. {
  8922. //
  8923. // Only for multi-monitor case.
  8924. //
  8925. PDEVOBJ pdoChild;
  8926. for (i = 0; i < pmdev->chdev; i++)
  8927. {
  8928. pdoChild.vInit(pmdev->Dev[i].hdev);
  8929. if (pdoChild.bIsPalManaged())
  8930. {
  8931. XEPALOBJ palChild(pdoChild.ppalSurf());
  8932. // Don't use PPFNDRV(pdoChild,...) since need to send
  8933. // this through DDML.
  8934. pdoChild.pfnSetPalette()(pdoChild.dhpdevParent(),
  8935. (PALOBJ *) &palChild,
  8936. 0,
  8937. 0,
  8938. palChild.cEntries());
  8939. break;
  8940. }
  8941. pdoChild.vInit(NULL);
  8942. }
  8943. // Even if parent is not pal-managed, but any of children are palette
  8944. // managed, need to reset one of them (only 1 is enough, since
  8945. // colour table is shared across all device palette)
  8946. //
  8947. // Realize halftone palette to secondary device
  8948. if (pdoChild.bValid())
  8949. {
  8950. KdPrint(("GDI DDML: Primary is not 8bpp, but one of display is 8bpp\n"));
  8951. if (!DrvRealizeHalftonePalette(pdoChild.hdev(),TRUE))
  8952. {
  8953. KdPrint(("GDI DDML: Failed to realize HT palette on secondary\n"));
  8954. }
  8955. }
  8956. }
  8957. GreExitMonitoredSection(poParent.ppdev, WD_DEVLOCK);
  8958. GreReleaseSemaphoreEx(poParent.hsemPointer());
  8959. GreReleaseSemaphoreEx(poParent.hsemDevLock());
  8960. GreReleaseSemaphoreEx(ghsemShareDevLock);
  8961. if (bHardware)
  8962. {
  8963. //
  8964. // Allow DirectDraw to be reenabled.
  8965. //
  8966. GreResumeDirectDraw(pmdev->hdevParent, FALSE);
  8967. }
  8968. TRACE_INIT(("Drv_Trace: DrvEnableMDEV: Leave\n"));
  8969. return TRUE;
  8970. }
  8971. /***************************************************************************\
  8972. *
  8973. * DrvDisableDisplay
  8974. *
  8975. * Disables a display device.
  8976. *
  8977. \***************************************************************************/
  8978. BOOL
  8979. DrvDisableDisplay(
  8980. HDEV hdev,
  8981. BOOL bClear
  8982. )
  8983. {
  8984. GDIFunctionID(DrvDisableDisplay);
  8985. BOOL bRet;
  8986. PDEVOBJ po(hdev);
  8987. TRACE_INIT(("\nDrv_Trace: DrvDisableDisplay: Enter\n"));
  8988. ASSERTGDI(po.bValid(), "HDEV failure\n");
  8989. ASSERTGDI(po.bDisplayPDEV(), "HDEV is not a display device\n");
  8990. ASSERTGDI(!po.bDisabled(), "HDEV must be enabled to call disable\n");
  8991. //
  8992. // Disable DirectDraw.
  8993. //
  8994. GreSuspendDirectDraw(hdev, FALSE);
  8995. //
  8996. // Acquire the display locks here because we may get called from within
  8997. // ChangeDisplaySettings to enable\disable a particular device when
  8998. // creating the new HDEVs.
  8999. //
  9000. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  9001. GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  9002. GreAcquireSemaphoreEx(po.hsemPointer(), SEMORDER_POINTER, po.hsemDevLock());
  9003. GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
  9004. if (bClear && !po.bDisabled()) {
  9005. PDEV *pdev = (PDEV*)hdev;
  9006. ERECTL erclDst(0,0,pdev->pSurface->sizl().cx, pdev->pSurface->sizl().cy);
  9007. //
  9008. // The display is about to be disabled, but some
  9009. // display drivers don't blank the display.
  9010. // We explicitly blank the display here.
  9011. //
  9012. (*(pdev->pSurface->pfnBitBlt()))(pdev->pSurface->pSurfobj(),
  9013. (SURFOBJ *) NULL,
  9014. (SURFOBJ *) NULL,
  9015. NULL,
  9016. NULL,
  9017. &erclDst,
  9018. (POINTL *) NULL,
  9019. (POINTL *) NULL,
  9020. NULL,
  9021. NULL,
  9022. 0
  9023. );
  9024. }
  9025. //
  9026. // The device may have something going on, synchronize with it first
  9027. //
  9028. po.vSync(po.pSurface()->pSurfobj(), NULL, 0);
  9029. //
  9030. // Disable the screen
  9031. //
  9032. bRet = (*PPFNDRV(po,AssertMode))(po.dhpdev(), FALSE);
  9033. if (bRet)
  9034. {
  9035. //
  9036. // Mark the PDEV as disabled
  9037. //
  9038. bSetDeviceSessionUsage(po.ppdev->pGraphicsDevice, FALSE);
  9039. po.bDisabled(TRUE);
  9040. gtmpAssertModeFailed = 0;
  9041. }
  9042. else
  9043. {
  9044. gtmpAssertModeFailed = 1;
  9045. }
  9046. GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
  9047. GreReleaseSemaphoreEx(po.hsemPointer());
  9048. GreReleaseSemaphoreEx(po.hsemDevLock());
  9049. GreReleaseSemaphoreEx(ghsemShareDevLock);
  9050. if (!bRet)
  9051. {
  9052. //
  9053. // We have to undo our 'GreSuspendDirectDraw' call:
  9054. //
  9055. GreResumeDirectDraw(hdev, FALSE);
  9056. }
  9057. TRACE_INIT(("Drv_Trace: DrvDisableDisplay: Leave\n"));
  9058. return (bRet);
  9059. }
  9060. /***************************************************************************\
  9061. *
  9062. * DrvDisableMDEV
  9063. *
  9064. * Disables a display MDEV.
  9065. *
  9066. * Should only be called from USER under the global CRIT
  9067. *
  9068. \***************************************************************************/
  9069. BOOL
  9070. DrvDisableMDEV(
  9071. PMDEV pmdev,
  9072. BOOL bHardware
  9073. )
  9074. {
  9075. GDIFunctionID(DrvDisableMDEV);
  9076. BOOL bSuccess = TRUE;
  9077. #if MDEV_STACK_TRACE_LENGTH
  9078. LONG lMDEVTraceEntry, lMDEVTraceEntryNext;
  9079. ULONG StackEntries, UserStackEntry;
  9080. do
  9081. {
  9082. lMDEVTraceEntry = glMDEVTrace;
  9083. lMDEVTraceEntryNext = lMDEVTraceEntry + 1;
  9084. if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0;
  9085. } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
  9086. RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry],
  9087. sizeof(gMDEVTrace[lMDEVTraceEntry]));
  9088. gMDEVTrace[lMDEVTraceEntry].pMDEV = pmdev;
  9089. gMDEVTrace[lMDEVTraceEntry].API = ((bHardware) ? DrvDisableMDEV_HWOff : DrvDisableMDEV_FromGRE);
  9090. StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]);
  9091. UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace,
  9092. StackEntries,
  9093. 0);
  9094. StackEntries -= UserStackEntry;
  9095. RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry],
  9096. StackEntries,
  9097. 1);
  9098. #endif
  9099. #if TEXTURE_DEMO
  9100. if (ghdevTextureParent)
  9101. {
  9102. WARNING("DrvDisableDisplay: Refused by texture demo");
  9103. return(FALSE);
  9104. }
  9105. #endif
  9106. TRACE_INIT(("\nDrv_Trace: DrvDisableMDEV: Enter\n"));
  9107. PDEVOBJ poParent(pmdev->hdevParent);
  9108. if (bHardware)
  9109. {
  9110. //
  9111. // Disable DirectDraw.
  9112. //
  9113. GreSuspendDirectDraw(pmdev->hdevParent, FALSE);
  9114. }
  9115. //
  9116. // Wait for the display to become available and unlock it.
  9117. //
  9118. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  9119. GreAcquireSemaphoreEx(poParent.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  9120. GreAcquireSemaphoreEx(poParent.hsemPointer(), SEMORDER_POINTER, poParent.hsemDevLock());
  9121. GreEnterMonitoredSection(poParent.ppdev, WD_DEVLOCK);
  9122. ULONG i, j;
  9123. for (i = 0; i < pmdev->chdev; i++)
  9124. {
  9125. //
  9126. // If Dualview, disable the view anyway
  9127. //
  9128. if (bHardware ||
  9129. ((((PDEV *) pmdev->Dev[i].hdev)->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  9130. gbInvalidateDualView)
  9131. )
  9132. {
  9133. if ((bSuccess = DrvDisableDisplay(pmdev->Dev[i].hdev, !bHardware)) == FALSE)
  9134. {
  9135. break;
  9136. }
  9137. }
  9138. }
  9139. //
  9140. // If we have a failure while disabling the device, try to reenable the
  9141. // devices that were already disabled.
  9142. //
  9143. if (bSuccess == FALSE)
  9144. {
  9145. for (j = 0; j < i; j++)
  9146. {
  9147. if (bHardware ||
  9148. ((((PDEV *)pmdev->Dev[i].hdev)->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  9149. gbInvalidateDualView)
  9150. )
  9151. {
  9152. while (DrvEnableDisplay(pmdev->Dev[j].hdev) == FALSE)
  9153. {
  9154. ASSERTGDI(FALSE, "We are hosed in Disable MDEV - try again!\n");
  9155. }
  9156. }
  9157. }
  9158. }
  9159. if (bSuccess)
  9160. {
  9161. if (bHardware)
  9162. {
  9163. poParent.bDisabled(TRUE);
  9164. }
  9165. }
  9166. GreExitMonitoredSection(poParent.ppdev, WD_DEVLOCK);
  9167. GreReleaseSemaphoreEx(poParent.hsemPointer());
  9168. GreReleaseSemaphoreEx(poParent.hsemDevLock());
  9169. GreReleaseSemaphoreEx(ghsemShareDevLock);
  9170. if (!bSuccess)
  9171. {
  9172. //
  9173. // We have to undo our 'GreSuspendDirectDraw' call:
  9174. //
  9175. GreResumeDirectDraw(pmdev->hdevParent, FALSE);
  9176. }
  9177. TRACE_INIT(("Drv_Trace: DrvDisableMDEV: Leave\n"));
  9178. return(bSuccess);
  9179. }
  9180. /******************************************************************************
  9181. *
  9182. * DrvDestroyMDEV
  9183. *
  9184. * Deletes a display MDEV.
  9185. *
  9186. \***************************************************************************/
  9187. VOID
  9188. DrvDestroyMDEV(
  9189. PMDEV pmdev
  9190. )
  9191. {
  9192. GDIFunctionID(DrvDestroyMDEV);
  9193. ULONG i;
  9194. // WinBug #306290 2-8-2001 jasonha STRESS: GDI: Two PDEVs using same semaphore as their DevLock
  9195. // WinBug #24003 7-24-2000 jasonha MULTIDISPLAY: Deadlock in DrvDestroyMDEV
  9196. // ghsemDriverManagement used to be held throughout DrvDestroyMDEV
  9197. // even when calling vUnreferencePdev, which might acquire a device
  9198. // lock. This would have been ok if the device had a unique device
  9199. // lock, but when changing from multiple displays to one display, the
  9200. // shared device lock is retained by the PDEVs no being freed. If the
  9201. // new primary display grabs the device lock and then tries to grab
  9202. // ghsemDriverMgmt as in GreCreateDisplayDC we could deadlock.
  9203. // ghsemDriverMgmt only needs to be held during accesses to cPdevOpenRefs.
  9204. TRACE_INIT(("\n\nDrv_Trace: DrvDestroyMDEV: Enter\n\n"));
  9205. for (i = 0; i < pmdev->chdev; i++)
  9206. {
  9207. PDEVOBJ po(pmdev->Dev[i].hdev);
  9208. // !!! What about outstanding bitmaps?
  9209. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9210. ASSERTGDI(!po.bDeleted(), "Deleting an already-deleted PDEV");
  9211. // Decrease the OpenRefCount which will
  9212. // mark the PDEV as being deleted so that we can also stop DrvEscape
  9213. // calls from going down (ExtEscape ignores the 'bDisabled()' flag):
  9214. if (--po.ppdev->cPdevOpenRefs == 0)
  9215. {
  9216. // The PDEV should already be disabled.
  9217. // Otherwise, we have no way of detecting whether or not we are just
  9218. // reducing the refcount on the PDEV or not.
  9219. if (G_fConsole) {
  9220. ASSERTGDI(po.bDisabled(), "Deleting an enabled PDEV");
  9221. }
  9222. }
  9223. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9224. // Once all the DCs open specifically on the PDEV (if there are any)
  9225. // are destroyed, free the PDEV:
  9226. po.vUnreferencePdev();
  9227. }
  9228. // If this is multimon system, destroy parent. Otherwise
  9229. // just skip here, since parent is same as its children
  9230. // in signle monitor system.
  9231. if (pmdev->chdev > 1)
  9232. {
  9233. PDEVOBJ po(pmdev->hdevParent);
  9234. // !!! What about outstanding bitmaps?
  9235. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9236. ASSERTGDI(!po.bDeleted(), "Deleting an already-deleted Parent PDEV");
  9237. // Decrease the OpenRefCount which will
  9238. // mark the PDEV as being deleted so that we can also stop DrvEscape
  9239. // calls from going down (ExtEscape ignores the 'bDisabled()' flag):
  9240. if (--po.ppdev->cPdevOpenRefs == 0)
  9241. {
  9242. // The PDEV should already be disabled.
  9243. // Otherwise, we have no way of detecting whether or not we are just
  9244. // reducing the refcount on the PDEV or not.
  9245. if (G_fConsole) {
  9246. ASSERTGDI(po.bDisabled(), "Deleting an enabled Parent PDEV");
  9247. }
  9248. }
  9249. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9250. // Once all the DCs open specifically on the PDEV (if there are any)
  9251. // are destroyed, free the PDEV:
  9252. po.vUnreferencePdev();
  9253. }
  9254. TRACE_INIT(("\n\nDrv_Trace: DrvDestroyMDEV: Leave\n\n"));
  9255. }
  9256. /******************************************************************************
  9257. *
  9258. * DrvBackoutMDEV
  9259. *
  9260. * This routine basically undoes all changes made by a ChangeDisplaySettings
  9261. * call.
  9262. *
  9263. \***************************************************************************/
  9264. VOID
  9265. DrvBackoutMDEV(
  9266. PMDEV pmdev)
  9267. {
  9268. GDIFunctionID(DrvBackoutMDEV);
  9269. ULONG i;
  9270. HDEV hdev;
  9271. //
  9272. // First disable all the HDEVs we created.
  9273. //
  9274. for (i = 0; i < pmdev->chdev; i++)
  9275. {
  9276. hdev = pmdev->Dev[i].hdev;
  9277. PDEVOBJ po(hdev);
  9278. if (po.ppdev->cPdevOpenRefs == 1)
  9279. {
  9280. if (!DrvDisableDisplay(hdev, FALSE))
  9281. {
  9282. ASSERTGDI(FALSE, "Failed Undoing CreateMDEV - we are hosed !!!\n");
  9283. }
  9284. }
  9285. //
  9286. // Remove the references so this object can go away
  9287. //
  9288. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9289. po.ppdev->cPdevOpenRefs--;
  9290. po.vUnreferencePdev();
  9291. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9292. }
  9293. //
  9294. // Restore the old HDEVs
  9295. //
  9296. for (i = 0; i < pmdev->chdev; i++)
  9297. {
  9298. if ((hdev = pmdev->Dev[i].Reserved) != NULL)
  9299. {
  9300. PDEVOBJ po(hdev);
  9301. //
  9302. // Reenable the display
  9303. //
  9304. if (po.ppdev->cPdevOpenRefs == 1)
  9305. {
  9306. if (!DrvEnableDisplay(hdev))
  9307. {
  9308. ASSERTGDI(FALSE, "Failed Undoing CreateMDEV - we are hosed !!!\n");
  9309. }
  9310. }
  9311. }
  9312. }
  9313. }
  9314. //*****************************************************************************
  9315. //
  9316. // hCreateHDEV
  9317. //
  9318. // Creates a PDEV that the window manager will use to open display DCs.
  9319. // This call is made by the window manager to open a new display surface
  9320. // for use. Any number of display surfaces may be open at one time.
  9321. //
  9322. // pDesktopId - Unique identifier to determine the Desktop the PDEV
  9323. // will be associated with.
  9324. //
  9325. // flags
  9326. //
  9327. // GCH_DEFAULT_DISPLAY
  9328. // - Whether or not this is the inital display device (on
  9329. // which the default bitmap will be located).
  9330. //
  9331. // GCH_DDML
  9332. // - The name of the display is the DDML entrypoint
  9333. //
  9334. // GCH_PANNING
  9335. // - The name of the display is the PANNING entrypoint
  9336. //
  9337. //*****************************************************************************
  9338. // !!! should be partly incorporate in PDEVOBJ::PDEVOBJ since many fields
  9339. // !!! are destroyed by that destructor
  9340. HDEV
  9341. hCreateHDEV(
  9342. PGRAPHICS_DEVICE PhysDisp,
  9343. PDRV_NAMES lpDisplayNames,
  9344. PDEVMODEW pdriv,
  9345. PVOID pDesktopId,
  9346. DWORD dwOverride,
  9347. DWORD dwAccelLevel,
  9348. BOOL bNoDisable,
  9349. FLONG flags,
  9350. HDEV *phDevDisabled
  9351. )
  9352. {
  9353. GDIFunctionID(hCreateHDEV);
  9354. ULONG i;
  9355. PDEV *ppdev;
  9356. PDEV *ppdevMatch = NULL;
  9357. PLDEV pldev;
  9358. BOOL bError = FALSE;
  9359. //
  9360. // Search through the entire PDEV cache to see if we have PDEVs on the
  9361. // same device. If any such a PDEV is active, we need to disable it.
  9362. //
  9363. // All see if a PDEV matches the given mode and is for the same device.
  9364. // If so, simply return that.
  9365. //
  9366. // To be a Match, the PDEV has to match:
  9367. // - The device
  9368. // - The devmode (except for position)
  9369. // - The desktop on which it is located
  9370. //
  9371. ASSERTGDI(lpDisplayNames != NULL, "NULL name to hCreateHDEV\n");
  9372. #if !defined(_GDIPLUS_)
  9373. ASSERTGDI(PhysDisp != NULL, "NULL physdisp to hCreateHDEV\n");
  9374. #endif
  9375. *phDevDisabled = NULL;
  9376. if (PhysDisp != (PGRAPHICS_DEVICE) DDML_DRIVER)
  9377. {
  9378. if (pdriv == NULL)
  9379. return NULL;
  9380. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9381. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  9382. {
  9383. PDEVOBJ po((HDEV) ppdev);
  9384. PGRAPHICS_DEVICE pGraphicsDevice = po.ppdev->pGraphicsDevice;
  9385. //
  9386. // Check if we are on the same actual device.
  9387. // We have to check the VGA device also, in case we are loading
  9388. // the S3 driver dynamically, and the main PhysDisp became a
  9389. // child physdisp on the fly.
  9390. //
  9391. // The VGA check is complex due to the following scenario:
  9392. // - Machine boots in VGA, so the pdev is on the VGA device.
  9393. // - The C&T driver is loaded on the fly, so the pVgaDevice becomes
  9394. // the C&T driver.
  9395. // - We change the mode on the fly, so now we would like to diable
  9396. // the vga pdev. -->> check if our device and the pdev are both
  9397. // on a VGA device.
  9398. //
  9399. if ((pGraphicsDevice != NULL) &&
  9400. (pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER) &&
  9401. ((PhysDisp == pGraphicsDevice) ||
  9402. (PhysDisp->pVgaDevice && pGraphicsDevice->pVgaDevice)))
  9403. {
  9404. po.ppdev->cPdevRefs++;
  9405. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9406. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  9407. GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  9408. GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
  9409. //
  9410. // If this is the matching device, just remember it here because
  9411. // we have to check for all active PDEVs.
  9412. // This also allows us to not disable\reenable the same device
  9413. // if we were not switching.
  9414. //
  9415. // But for Dualview, always reset the mode
  9416. //
  9417. if ((((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0) ||
  9418. (!gbInvalidateDualView) ||
  9419. (bNoDisable == TRUE)) &&
  9420. (!(po.bCloneDriver())) && /* don't pick clone pdev from cache */
  9421. (po.ppdev->pDesktopId == pDesktopId) &&
  9422. (po.ppdev->dwDriverCapableOverride == dwOverride) &&
  9423. (po.ppdev->dwDriverAccelerationLevel == dwAccelLevel) &&
  9424. RtlEqualMemory(pdriv, po.ppdev->ppdevDevmode, sizeof(DEVMODEW))
  9425. )
  9426. {
  9427. ASSERTGDI(ppdevMatch == NULL,
  9428. "Multiple cached PDEV matching the current mode.\n");
  9429. po.vReferencePdev();
  9430. ppdevMatch = ppdev;
  9431. }
  9432. else
  9433. {
  9434. //
  9435. // Don't disable the PDEV for an independant desktop open
  9436. //
  9437. if (bNoDisable == TRUE)
  9438. {
  9439. bError = TRUE;
  9440. }
  9441. else
  9442. {
  9443. //
  9444. // If there is an enabled PDEV in this same PhysDisp, then
  9445. // we must disable it.
  9446. // Only one HDEV per device at any one time.
  9447. //
  9448. // There may be multiple active in the case where outstanding
  9449. // Opens have been made (multiple display case only).
  9450. //
  9451. if (po.bDisabled() == FALSE)
  9452. {
  9453. ASSERTGDI(*phDevDisabled == NULL,
  9454. "Multiple active PDEVs on same device\n");
  9455. TRACE_INIT(("hCreateHDEV: disabling ppdev %08lx\n", ppdev));
  9456. if (DrvDisableDisplay((HDEV) ppdev, FALSE))
  9457. {
  9458. *phDevDisabled = (HDEV) ppdev;
  9459. }
  9460. else
  9461. {
  9462. bError = TRUE;
  9463. }
  9464. }
  9465. }
  9466. }
  9467. GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
  9468. GreReleaseSemaphoreEx(po.hsemDevLock());
  9469. GreReleaseSemaphoreEx(ghsemShareDevLock);
  9470. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9471. po.vUnreferencePdev();
  9472. }
  9473. }
  9474. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9475. if (bError)
  9476. {
  9477. //
  9478. // There was an error trying to disable the device.
  9479. // return NULL;
  9480. //
  9481. if (ppdevMatch != NULL)
  9482. {
  9483. PDEVOBJ po((HDEV) ppdevMatch);
  9484. po.vUnreferencePdev();
  9485. }
  9486. return NULL;
  9487. }
  9488. //
  9489. // If we found a match, reenable and refcount the device, as necessary.
  9490. //
  9491. if (ppdevMatch)
  9492. {
  9493. TRACE_INIT(("hCreateHDEV: Found a ppdev cache match\n"));
  9494. PDEVOBJ po((HDEV) ppdevMatch);
  9495. //
  9496. // Increment the Open count of the device
  9497. //
  9498. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  9499. GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  9500. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  9501. po.ppdev->cPdevOpenRefs++;
  9502. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  9503. GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
  9504. //
  9505. // Check for Software panning modes.
  9506. //
  9507. //
  9508. // If the Device was disabled, just reenable it.
  9509. //
  9510. if (po.bDisabled())
  9511. {
  9512. ASSERTGDI(po.ppdev->cPdevOpenRefs == 1,
  9513. "Inconsistent Open count on disabled PDEV\n");
  9514. DrvEnableDisplay((HDEV) ppdevMatch);
  9515. }
  9516. //
  9517. // Reset the offset appropriately.
  9518. //
  9519. GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
  9520. GreReleaseSemaphoreEx(po.hsemDevLock());
  9521. GreReleaseSemaphoreEx(ghsemShareDevLock);
  9522. return((HDEV) ppdevMatch);
  9523. }
  9524. }
  9525. //
  9526. // No existing PDEV in our list. Let's create a new one.
  9527. //
  9528. if (lpDisplayNames == NULL)
  9529. {
  9530. WARNING(("Drv_Trace: LoadDisplayDriver: Display driver list was not present.\n"));
  9531. }
  9532. //
  9533. // Make a fake DC so we can pass in the needed info to vInitBrush.
  9534. // We use allocation instead of stack since sizeof(DC) is about 1.5k
  9535. // WINBUG 393269
  9536. //
  9537. DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
  9538. if (pdc == NULL)
  9539. {
  9540. WARNING("hCreateHDEV: DC memory allocation failed\n");
  9541. goto Exit;
  9542. }
  9543. for (i = 0; i < lpDisplayNames->cNames; i++)
  9544. {
  9545. //
  9546. // Load the display driver image.
  9547. //
  9548. switch (flags)
  9549. {
  9550. case GCH_DEFAULT_DISPLAY:
  9551. pldev = ldevLoadDriver(lpDisplayNames->D[i].lpDisplayName,
  9552. LDEV_DEVICE_DISPLAY);
  9553. break;
  9554. case GCH_DDML:
  9555. pldev = ldevLoadInternal((PFN)(lpDisplayNames->D[i].lpDisplayName),
  9556. LDEV_DEVICE_META);
  9557. break;
  9558. case GCH_GDIPLUS_DISPLAY:
  9559. pldev = ldevLoadInternal((PFN)(lpDisplayNames->D[i].lpDisplayName),
  9560. LDEV_DEVICE_META);
  9561. break;
  9562. case GCH_MIRRORING:
  9563. pldev = ldevLoadDriver(lpDisplayNames->D[i].lpDisplayName,
  9564. LDEV_DEVICE_MIRROR);
  9565. break;
  9566. case GCH_PANNING:
  9567. ASSERTGDI(FALSE, "Software Panning not implemented yet\n");
  9568. pldev = NULL;
  9569. break;
  9570. default:
  9571. ASSERTGDI(FALSE, "Unknown driver type\n");
  9572. pldev = NULL;
  9573. break;
  9574. }
  9575. if (pldev == NULL)
  9576. {
  9577. TRACE_INIT(("hCreateHDEV: failed ldevLoadDriver\n"));
  9578. }
  9579. else
  9580. {
  9581. bSetDeviceSessionUsage(PhysDisp, TRUE);
  9582. PDEVOBJ po(pldev,
  9583. pdriv,
  9584. NULL, // no logical address
  9585. NULL, // no data file
  9586. lpDisplayNames->D[i].lpDisplayName, // device name is the display driver name
  9587. // necessary for hook drivers.
  9588. lpDisplayNames->D[i].hDriver,
  9589. NULL, // no remote typeone info (this isn't font driver)
  9590. 0, // prmr.bValid() ? prmr.GdiInfo() : NULL,
  9591. 0, // prmr.bValid() ? prmr.pdevinfo() : NULL
  9592. FALSE, // not UMPD driver
  9593. dwOverride, // Capable Override
  9594. dwAccelLevel); // acceleration level.
  9595. if (!po.bValid())
  9596. {
  9597. TRACE_INIT(("hCreateHDEV: PDEVOBJ::po failed\n"));
  9598. bSetDeviceSessionUsage(PhysDisp, FALSE);
  9599. ldevUnloadImage(pldev);
  9600. }
  9601. else
  9602. {
  9603. #ifdef DDI_WATCHDOG
  9604. //
  9605. // Watchdog objects require DEVICE_OBJECT now and we are associating DEVICE_OBJECT
  9606. // with PDEV here (i.e. we don't know DEVICE_OBJECT in PDEVOBJ::PDEVOBJ).
  9607. // Beacuse of this we have to delay creation of watchdog objects till we get here.
  9608. // It would be nice to keep all this stuff in PDEVOBJ::PDEVOBJ constructor.
  9609. //
  9610. //
  9611. // Create watchdogs for display or mirror device.
  9612. //
  9613. if ((po.ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) ||
  9614. (po.ppdev->pldev->ldevType == LDEV_DEVICE_MIRROR))
  9615. {
  9616. if ((NULL == po.ppdev->pWatchdogData) && PhysDisp)
  9617. {
  9618. PDEVICE_OBJECT pDeviceObject;
  9619. pDeviceObject = (PDEVICE_OBJECT)(PhysDisp->pDeviceHandle);
  9620. if (pDeviceObject)
  9621. {
  9622. po.ppdev->pWatchdogData = GreCreateWatchdogs(pDeviceObject,
  9623. WD_NUMBER,
  9624. DDI_TIMEOUT,
  9625. WdDdiWatchdogDpcCallback,
  9626. lpDisplayNames->D[i].lpDisplayName,
  9627. lpDisplayNames->D[i].hDriver,
  9628. &gpldevDrivers);
  9629. }
  9630. }
  9631. }
  9632. #endif // DDI_WATCHDOG
  9633. TRACE_INIT(("hCreateHDEV: about to call pr:bMakeSurface\n"));
  9634. if (po.bMakeSurface())
  9635. {
  9636. #if DBG
  9637. //
  9638. // Check the surface created by driver is same as what we want.
  9639. //
  9640. if (po.pSurface() && pdriv && (flags == GCH_DEFAULT_DISPLAY))
  9641. {
  9642. if ((pdriv->dmPelsWidth != (ULONG) po.pSurface()->sizl().cx) ||
  9643. (pdriv->dmPelsHeight != (ULONG) po.pSurface()->sizl().cy))
  9644. {
  9645. DbgPrint("hCreateHDEV() - DEVMODE %d,%d, SURFACE %d,%d\n",
  9646. pdriv->dmPelsWidth, pdriv->dmPelsHeight,
  9647. po.pSurface()->sizl().cx, po.pSurface()->sizl().cy);
  9648. }
  9649. }
  9650. #endif // DBG
  9651. //
  9652. // Realize the Gray pattern brush used for drag rectangles.
  9653. //
  9654. po.pbo()->vInit();
  9655. PBRUSH pbrGrayPattern;
  9656. pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern,
  9657. BRUSH_TYPE);
  9658. pdc->pDCAttr = &pdc->dcattr;
  9659. pdc->crTextClr(0x00000000);
  9660. pdc->crBackClr(0x00FFFFFF);
  9661. pdc->lIcmMode(DC_ICM_OFF);
  9662. pdc->hcmXform(NULL);
  9663. po.pbo()->vInitBrush(pdc,
  9664. pbrGrayPattern,
  9665. (XEPALOBJ) ppalDefault,
  9666. (XEPALOBJ) po.ppdev->pSurface->ppal(),
  9667. po.ppdev->pSurface);
  9668. DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
  9669. //
  9670. // Now set the global default bitmaps pdev to equal
  9671. // that of our global display device.
  9672. //
  9673. PSURFACE pSurfDefault = SURFACE::pdibDefault;
  9674. if (pSurfDefault->hdev() == NULL)
  9675. {
  9676. pSurfDefault->hdev(po.hdev());
  9677. }
  9678. po.ppdev->pGraphicsDevice = PhysDisp;
  9679. po.ppdev->pDesktopId = pDesktopId;
  9680. //
  9681. // Keep the DEVMODE, if this is a real display device
  9682. //
  9683. if ((flags != GCH_DDML) && (flags != GCH_GDIPLUS_DISPLAY))
  9684. {
  9685. po.ppdev->ppdevDevmode = (PDEVMODEW)
  9686. PALLOCNOZ(pdriv->dmSize + pdriv->dmDriverExtra,
  9687. GDITAG_DEVMODE);
  9688. if (po.ppdev->ppdevDevmode)
  9689. {
  9690. RtlMoveMemory(po.ppdev->ppdevDevmode,
  9691. pdriv,
  9692. pdriv->dmSize + pdriv->dmDriverExtra);
  9693. //
  9694. // At this moment, this device must be attached. DM_POSITION indicates that
  9695. //
  9696. po.ppdev->ppdevDevmode->dmFields |= DM_POSITION;
  9697. DrvUpdateAttachFlag(PhysDisp, 1);
  9698. }
  9699. else
  9700. {
  9701. bError = TRUE;
  9702. }
  9703. }
  9704. //
  9705. // Mark the PDEV as now being ready for use. This has to
  9706. // be one of the last steps, because GCAPS2_SYNCFLUSH and
  9707. // GCAPS2_SYNCTIMER asynchronously loop through the PDEV
  9708. // list and call the driver if 'bDisabled' is not set.
  9709. //
  9710. po.bDisabled(FALSE);
  9711. //
  9712. // Profile driver
  9713. //
  9714. // We can not profile meta (= DDML) driver, and while we
  9715. // are creating meta driver, we don't ssync'ed devlock
  9716. // with its children, so we can not call anything which
  9717. // will dispatch to its children.
  9718. //
  9719. if (!po.bMetaDriver())
  9720. {
  9721. po.vProfileDriver();
  9722. }
  9723. if (bError)
  9724. {
  9725. // There was an error of memory allocation.
  9726. po.vUnreferencePdev();
  9727. break;
  9728. }
  9729. VFREEMEM(pdc);
  9730. return(po.hdev());
  9731. }
  9732. else
  9733. {
  9734. TRACE_INIT(("hCreateHDEV: bMakeSurface failed\n"));
  9735. bSetDeviceSessionUsage(PhysDisp, FALSE);
  9736. }
  9737. //
  9738. // Destroy everything if something fails.
  9739. // This will remove the Surface, PDEV and image.
  9740. //
  9741. po.vUnreferencePdev();
  9742. }
  9743. }
  9744. }
  9745. Exit:
  9746. if (pdc)
  9747. VFREEMEM(pdc);
  9748. //
  9749. // There was an error creating the new device.
  9750. // Reenable the old one if we disabled it.
  9751. //
  9752. if (*phDevDisabled)
  9753. {
  9754. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0 || !gbInvalidateDualView)
  9755. {
  9756. DrvEnableDisplay(*phDevDisabled);
  9757. }
  9758. }
  9759. return NULL;
  9760. }
  9761. #if TEXTURE_DEMO
  9762. DHPDEV TexEnablePDEV(
  9763. DEVMODEW *pdm, // Actually, the HDEV
  9764. LPWSTR pwszLogAddress,
  9765. ULONG cPat,
  9766. HSURF *phsurfPatterns,
  9767. ULONG cjCaps,
  9768. GDIINFO *pdevcaps,
  9769. ULONG cjDevInfo,
  9770. DEVINFO *pdi,
  9771. HDEV hdev,
  9772. LPWSTR pwszDeviceName,
  9773. HANDLE hDriver)
  9774. {
  9775. HDEV hdevParent = (HDEV) pdm;
  9776. PDEVOBJ poParent(hdevParent);
  9777. PDEVOBJ po(hdev);
  9778. pdevcaps->ulHorzRes = gcxTexture;
  9779. pdevcaps->ulVertRes = gcyTexture;
  9780. ghdevTextureParent = poParent.hdev();
  9781. return(poParent.dhpdev());
  9782. }
  9783. HSURF TexEnableSurface(DHPDEV dhpdev)
  9784. {
  9785. PDEVOBJ poPrimary(ghdevTextureParent);
  9786. DEVLOCKOBJ dlo(poPrimary);
  9787. HSURF hsurf = hsurfCreateCompatibleSurface(poPrimary.hdev(),
  9788. poPrimary.pSurface()->iFormat(),
  9789. poPrimary.bIsPalManaged()
  9790. ? NULL
  9791. : (HPALETTE) poPrimary.ppalSurf()->hGet(),
  9792. 512,
  9793. 512,
  9794. TRUE);
  9795. return(hsurf);
  9796. }
  9797. VOID TexDisablePDEV(DHPDEV dhpdev)
  9798. {
  9799. }
  9800. VOID TexCompletePDEV(
  9801. DHPDEV dhpdev,
  9802. HDEV hdev)
  9803. {
  9804. }
  9805. VOID TexDisableSurface(DHPDEV dhpdev)
  9806. {
  9807. }
  9808. typedef struct _DEMOTEXTURE
  9809. {
  9810. HDC hdc;
  9811. ULONG iTexture;
  9812. BOOL bCopy;
  9813. DEMOQUAD Quad;
  9814. } DEMOTEXTURE;
  9815. BOOL
  9816. TexTexture(
  9817. VOID* pvBuffer,
  9818. ULONG cjBuffer)
  9819. {
  9820. BOOL bRet = FALSE;
  9821. DEMOTEXTURE tex;
  9822. KFLOATING_SAVE fsFpState;
  9823. if (cjBuffer < sizeof(DEMOTEXTURE))
  9824. {
  9825. WARNING("TexTexture: Buffer too small");
  9826. return(FALSE);
  9827. }
  9828. tex = *((DEMOTEXTURE*) pvBuffer);
  9829. if (ghdevTextureParent == NULL)
  9830. {
  9831. WARNING1("TexTexture: Texturing not enabled");
  9832. return(FALSE);
  9833. }
  9834. if (tex.iTexture >= gcTextures)
  9835. {
  9836. WARNING("TexTexture: Bad texture identifier");
  9837. return(FALSE);
  9838. }
  9839. if (!NT_SUCCESS(KeSaveFloatingPointState(&fsFpState)))
  9840. {
  9841. WARNING("TexTexture: Couldn't save floating point state");
  9842. return(FALSE);
  9843. }
  9844. DCOBJ dco(tex.hdc);
  9845. if (dco.bValid())
  9846. {
  9847. DEVLOCKOBJ dlo(dco);
  9848. if (dlo.bValid())
  9849. {
  9850. PDEVOBJ poParent(ghdevTextureParent);
  9851. PDEVOBJ po(gahdevTexture[tex.iTexture]);
  9852. if (1) // dco.pSurface()->hdev() == po.pSurface()->hdev())
  9853. {
  9854. ECLIPOBJ eco;
  9855. ERECTL erclBig(-10000, -10000, 10000, 10000);
  9856. eco.vSetup(dco.prgnEffRao(), erclBig);
  9857. if (!eco.erclExclude().bEmpty())
  9858. {
  9859. if (tex.bCopy)
  9860. {
  9861. ERECTL erclDst(0, 0, dco.pdc->sizl().cx, dco.pdc->sizl().cy);
  9862. PPFNGET(po, CopyBits, dco.pSurface()->flags())
  9863. (dco.pSurface()->pSurfobj(),
  9864. po.pSurface()->pSurfobj(),
  9865. &eco,
  9866. NULL,
  9867. &erclDst,
  9868. (POINTL*) &erclDst);
  9869. bRet = TRUE;
  9870. }
  9871. else
  9872. {
  9873. if (PPFNVALID(poParent, DemoTexture))
  9874. {
  9875. PPFNDRV(po, DemoTexture)(dco.pSurface()->pSurfobj(),
  9876. po.pSurface()->pSurfobj(),
  9877. &eco,
  9878. &tex.Quad,
  9879. 1);
  9880. bRet = TRUE;
  9881. }
  9882. else
  9883. {
  9884. WARNING("TexTexture: DrvDemoTexture not hooked");
  9885. }
  9886. }
  9887. }
  9888. }
  9889. else
  9890. {
  9891. WARNING("TexTexture: Mismatched HDEVs");
  9892. }
  9893. }
  9894. else
  9895. {
  9896. WARNING("TexTexture: Bad devlock");
  9897. }
  9898. }
  9899. else
  9900. {
  9901. WARNING("TexTexture: Bad DC");
  9902. }
  9903. KeRestoreFloatingPointState(&fsFpState);
  9904. return(bRet);
  9905. }
  9906. HDC
  9907. hdcTexture(
  9908. ULONG iTexture
  9909. )
  9910. {
  9911. HDC hdc;
  9912. HDEV hdev;
  9913. hdc = 0;
  9914. hdev = 0;
  9915. if (iTexture == (ULONG) -1)
  9916. {
  9917. hdev = ghdevTextureParent;
  9918. }
  9919. else if (iTexture < gcTextures)
  9920. {
  9921. hdev = gahdevTexture[iTexture];
  9922. }
  9923. if (hdev != NULL)
  9924. {
  9925. hdc = GreCreateDisplayDC(hdev,
  9926. DCTYPE_DIRECT,
  9927. FALSE);
  9928. }
  9929. else
  9930. {
  9931. WARNING("hdcTexture: Bad parameter");
  9932. }
  9933. return(hdc);
  9934. }
  9935. HDEV
  9936. hCreateTextureHDEV(
  9937. HDEV hdevOwner
  9938. )
  9939. {
  9940. PLDEV pldev;
  9941. PDEVOBJ poOwner(hdevOwner);
  9942. pldev = (PLDEV) PALLOCMEM(sizeof(LDEV), GDITAG_LDEV);
  9943. if (!pldev)
  9944. {
  9945. WARNING("hCreateTextureHDEV: LDEV alloc failed.");
  9946. return(0);
  9947. }
  9948. RtlCopyMemory(pldev, poOwner.ppdev->pldev, sizeof(LDEV));
  9949. pldev->apfn[INDEX_DrvEnablePDEV] = (PFN) TexEnablePDEV;
  9950. pldev->apfn[INDEX_DrvEnableSurface] = (PFN) TexEnableSurface;
  9951. pldev->apfn[INDEX_DrvCompletePDEV] = (PFN) TexCompletePDEV;
  9952. pldev->apfn[INDEX_DrvDisablePDEV] = (PFN) TexDisablePDEV;
  9953. pldev->apfn[INDEX_DrvDisableSurface] = (PFN) TexDisableSurface;
  9954. pldev->apfn[INDEX_DrvAssertMode] = NULL;
  9955. pldev->apfn[INDEX_DrvCreateDeviceBitmap] = NULL;
  9956. pldev->apfn[INDEX_DrvDeleteDeviceBitmap] = NULL;
  9957. pldev->apfn[INDEX_DrvSetPalette] = NULL;
  9958. pldev->apfn[INDEX_DrvSetPointerShape] = NULL;
  9959. pldev->apfn[INDEX_DrvSaveScreenBits] = NULL;
  9960. pldev->apfn[INDEX_DrvIcmSetDeviceGammaRamp] = NULL;
  9961. pldev->apfn[INDEX_DrvGetDirectDrawInfo] = NULL;
  9962. PDEVOBJ po(pldev,
  9963. (PDEVMODEW) hdevOwner,
  9964. NULL, // no logical address
  9965. NULL, // no data file
  9966. NULL, // device name is the display driver name
  9967. // necessary for hook drivers.
  9968. NULL, // driver handle
  9969. NULL,
  9970. poOwner.GdiInfo(),
  9971. poOwner.pdevinfo());
  9972. if (!po.bValid())
  9973. {
  9974. WARNING("hCreateTextureHDEV failed");
  9975. return(0);
  9976. }
  9977. else
  9978. {
  9979. TRACE_INIT(("hCreateTextureHDEV: about to call pr:bMakeSurface\n"));
  9980. if (po.bMakeSurface())
  9981. {
  9982. //
  9983. // Make a fake DC so we can pass in the needed info to vInitBrush.
  9984. // Watch out that this is a bit big (about 1k of stack space).
  9985. //
  9986. DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
  9987. if (pdc == NULL)
  9988. {
  9989. po.vUnreferencePdev();
  9990. WARNING("hCreateTextureHDEV: DC memory allocation failed\n");
  9991. return(0);
  9992. }
  9993. //
  9994. // Realize the gray pattern brush used for drag rectangles.
  9995. //
  9996. po.pbo()->vInit();
  9997. PBRUSH pbrGrayPattern;
  9998. pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern,
  9999. BRUSH_TYPE);
  10000. pdc->pDCAttr = &pdc->dcattr;
  10001. pdc->crTextClr(0x00000000);
  10002. pdc->crBackClr(0x00FFFFFF);
  10003. pdc->lIcmMode(DC_ICM_OFF);
  10004. pdc->hcmXform(NULL);
  10005. po.pbo()->vInitBrush(pdc,
  10006. pbrGrayPattern,
  10007. (XEPALOBJ) ppalDefault,
  10008. (XEPALOBJ) po.ppdev->pSurface->ppal(),
  10009. po.ppdev->pSurface);
  10010. DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
  10011. //
  10012. // Now set the global default bitmaps pdev to equal
  10013. // that of our global display device.
  10014. //
  10015. PSURFACE pSurfDefault = SURFACE::pdibDefault;
  10016. if (pSurfDefault->hdev() == NULL)
  10017. {
  10018. pSurfDefault->hdev(po.hdev());
  10019. }
  10020. po.ppdev->pGraphicsDevice = poOwner.ppdev->pGraphicsDevice;
  10021. po.ppdev->pDesktopId = poOwner.ppdev->pDesktopId;
  10022. po.bDisabled(FALSE);
  10023. po.vProfileDriver();
  10024. VFREEMEM(pDC);
  10025. return(po.hdev());
  10026. }
  10027. else
  10028. {
  10029. TRACE_INIT(("hCreateHDEV: bMakeSurface failed\n"));
  10030. }
  10031. //
  10032. // Destroy everything if something fails.
  10033. // This will remove the Surface, PDEV and image.
  10034. //
  10035. po.vUnreferencePdev();
  10036. }
  10037. return NULL;
  10038. }
  10039. PMDEV
  10040. pmdevSetupTextureDemo(
  10041. PMDEV pmdev)
  10042. {
  10043. ULONG i;
  10044. if ((gbTexture) && (pmdev) && (pmdev->chdev == 1))
  10045. {
  10046. PMDEV pmdevTmp;
  10047. //
  10048. // We allocate and copy too much, but we don't care ...
  10049. //
  10050. pmdevTmp = (PMDEV) PALLOCNOZ(sizeof(MDEV) * (pmdev->chdev + 8),
  10051. GDITAG_DRVSUP);
  10052. if (pmdevTmp)
  10053. {
  10054. PDEVOBJ poPrimary(pmdev->Dev[0].hdev);
  10055. //
  10056. // Copy the MDEV list
  10057. //
  10058. RtlMoveMemory(pmdevTmp, pmdev, sizeof(MDEV) * pmdev->chdev);
  10059. //
  10060. // Position the surfaces consecutively to the right of the primary.
  10061. //
  10062. LONG xLeft = pmdev->Dev[0].rect.left;
  10063. LONG yTop = pmdev->Dev[0].rect.bottom;
  10064. //
  10065. // Hard code them to 512x512.
  10066. //
  10067. for (i = 0; i < 3; i++)
  10068. {
  10069. //
  10070. // Create a clone of the PDEV.
  10071. //
  10072. HDEV hdevTexture = hCreateTextureHDEV(poPrimary.hdev());
  10073. if (!hdevTexture)
  10074. {
  10075. //
  10076. // Delete all the hdevs we have created. and restore the old
  10077. // ones.
  10078. //
  10079. DrvBackoutMDEV(pmdev);
  10080. VFREEMEM(pmdev);
  10081. pmdev = NULL;
  10082. return(pmdev);
  10083. }
  10084. PDEVOBJ poTexture(hdevTexture);
  10085. //
  10086. // Point the surface's HDEV to its true owner, so that
  10087. // software cursors work. I hope.
  10088. //
  10089. poTexture.pSurface()->hdev(hdevTexture);
  10090. gahdevTexture[i] = hdevTexture;
  10091. poTexture.ppdev->ptlOrigin.x = xLeft;
  10092. poTexture.ppdev->ptlOrigin.y = yTop;
  10093. gcxTexture = 512;
  10094. gcyTexture = 512;
  10095. pmdevTmp->Dev[1 + i].hdev = hdevTexture;
  10096. pmdevTmp->Dev[1 + i].rect.left = xLeft;
  10097. pmdevTmp->Dev[1 + i].rect.top = yTop;
  10098. pmdevTmp->Dev[1 + i].rect.right = xLeft + gcxTexture;
  10099. pmdevTmp->Dev[1 + i].rect.bottom = yTop + gcyTexture;
  10100. pmdevTmp->Dev[1 + i].Reserved = NULL;
  10101. pmdevTmp->chdev++;
  10102. gcTextures++;
  10103. yTop += gcyTexture;
  10104. }
  10105. VFREEMEM(pmdev);
  10106. pmdev = pmdevTmp;
  10107. }
  10108. else
  10109. {
  10110. VFREEMEM(pmdevTmp);
  10111. }
  10112. }
  10113. return(pmdev);
  10114. }
  10115. #endif // TEXTURE_DEMO
  10116. /***************************************************************************\
  10117. * DrvGetHDEV
  10118. *
  10119. * routine to find out HDEV for specified device name
  10120. *
  10121. * 01-Oct-1997 hideyukn Created
  10122. \***************************************************************************/
  10123. HDEV DrvGetHDEV(
  10124. PUNICODE_STRING pstrDeviceName)
  10125. {
  10126. GDIFunctionID(DrvGetHDEV);
  10127. HDEV hdev = NULL;
  10128. if (pstrDeviceName)
  10129. {
  10130. PGRAPHICS_DEVICE PhysDisp;
  10131. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, KernelMode);
  10132. if (PhysDisp)
  10133. {
  10134. PDEV *ppdev;
  10135. PDEV *ppdevDisabled = NULL;
  10136. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  10137. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  10138. {
  10139. PDEVOBJ po((HDEV) ppdev);
  10140. if ((po.ppdev->pGraphicsDevice != 0) &&
  10141. (po.ppdev->pGraphicsDevice == PhysDisp))
  10142. {
  10143. if (!(po.bDisabled()))
  10144. {
  10145. po.ppdev->cPdevRefs++;
  10146. hdev = po.hdev();
  10147. break;
  10148. }
  10149. else if (ppdevDisabled == NULL)
  10150. {
  10151. //
  10152. // We found a matching PDEV but it is disabled. Save
  10153. // a pointer to it; in case we don't find an enabled
  10154. // PDEV we will use this:
  10155. //
  10156. ppdevDisabled = ppdev;
  10157. }
  10158. }
  10159. }
  10160. if ((ppdev == NULL) && (ppdevDisabled != NULL))
  10161. {
  10162. //
  10163. // We could not find a matching, enabled PDEV but did find a
  10164. // matching disabled PDEV, so just use it:
  10165. //
  10166. PDEVOBJ po((HDEV) ppdevDisabled);
  10167. po.ppdev->cPdevRefs++;
  10168. hdev = po.hdev();
  10169. }
  10170. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  10171. }
  10172. }
  10173. return hdev;
  10174. }
  10175. /***************************************************************************\
  10176. * DrvReleaseHDEV
  10177. *
  10178. * routine to release an HDEV for specified device name
  10179. *
  10180. * 02-Mar-1999 a-oking Created
  10181. \***************************************************************************/
  10182. void DrvReleaseHDEV(
  10183. PUNICODE_STRING pstrDeviceName)
  10184. {
  10185. if (pstrDeviceName)
  10186. {
  10187. PGRAPHICS_DEVICE PhysDisp;
  10188. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, KernelMode);
  10189. if (PhysDisp)
  10190. {
  10191. PDEV *ppdev;
  10192. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  10193. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  10194. {
  10195. PDEVOBJ po((HDEV) ppdev);
  10196. if ((po.ppdev->pGraphicsDevice != 0) &&
  10197. (po.ppdev->pGraphicsDevice == PhysDisp))
  10198. {
  10199. po.ppdev->cPdevRefs--;
  10200. break;
  10201. }
  10202. }
  10203. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  10204. }
  10205. }
  10206. return;
  10207. }
  10208. /***************************************************************************\
  10209. * DrvCreateCloneHDEV
  10210. *
  10211. * create clone of passed HDEV.
  10212. *
  10213. * 27-Feb-1998 hideyukn Created
  10214. \***************************************************************************/
  10215. #define DRV_CLONE_DEREFERENCE_ORG 0x0001
  10216. HDEV DrvCreateCloneHDEV(
  10217. HDEV hdevOrg,
  10218. ULONG ulFlags)
  10219. {
  10220. GDIFunctionID(DrvCreateCloneHDEV);
  10221. HDEV hdevClone = NULL;
  10222. PDEVOBJ pdoOrg(hdevOrg);
  10223. ASSERTGDI(!pdoOrg.bDisabled(), "DrvCreateCloneHDEV(): hdevOrg must be enabled");
  10224. // Grab the SPRITELOCK. This is important in case sprites are still
  10225. // hooked at this point because the surface type and flags have been
  10226. // altered by the sprite code, and unless we grab the SPRITELOCK here
  10227. // they will be recorded incorrectly in the SPRITESTATE of the new PDEV
  10228. // during the call to bSpEnableSprites. See bug #266112 for details.
  10229. SPRITELOCK slock(pdoOrg);
  10230. // Create clone PDEVOBJ.
  10231. PDEVOBJ pdoClone(hdevOrg,GCH_CLONE_DISPLAY);
  10232. if (pdoClone.bValid())
  10233. {
  10234. BOOL bRet;
  10235. //
  10236. // Allocate a temporary DC so we can pass in the needed info to
  10237. // vInitBrush. We allocate on the heap since this is a big
  10238. // structure.
  10239. //
  10240. DC *pdc = (DC*)PALLOCMEM(sizeof(DC), 'pmtG');
  10241. if (pdc == NULL)
  10242. {
  10243. WARNING("DrvCreateCloneHDEV: DC memory allocation failed\n");
  10244. }
  10245. //
  10246. // Enable Sprites on new PDEV.
  10247. //
  10248. if ((pdc != NULL) &&
  10249. bSpEnableSprites(pdoClone.hdev()))
  10250. {
  10251. vEnableSynchronize(pdoClone.hdev());
  10252. // Realize the Gray pattern brush used for drag rectangles.
  10253. pdc->pDCAttr = &pdc->dcattr;
  10254. pdc->crTextClr(0x00000000);
  10255. pdc->crBackClr(0x00FFFFFF);
  10256. pdc->lIcmMode(DC_ICM_OFF);
  10257. pdc->hcmXform(NULL);
  10258. PBRUSH pbrGrayPattern = (PBRUSH)HmgShareCheckLock(
  10259. (HOBJ)ghbrGrayPattern,
  10260. BRUSH_TYPE);
  10261. pdoClone.pbo()->vInit();
  10262. pdoClone.pbo()->vInitBrush(pdc,
  10263. pbrGrayPattern,
  10264. (XEPALOBJ)ppalDefault,
  10265. (XEPALOBJ)pdoClone.ppdev->pSurface->ppal(),
  10266. pdoClone.ppdev->pSurface);
  10267. DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
  10268. // Dereference original HDEV, if nessesary.
  10269. if (ulFlags & DRV_CLONE_DEREFERENCE_ORG)
  10270. {
  10271. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  10272. ASSERTGDI(pdoOrg.ppdev->cPdevOpenRefs > 1,
  10273. "DrvCreateCloneHDEV: cPdevOpenRefs <= 1\n");
  10274. ASSERTGDI(pdoOrg.ppdev->cPdevRefs > 1,
  10275. "DrvCreateCloneHDEV: cPdevRefs <= 1\n");
  10276. pdoOrg.ppdev->cPdevOpenRefs--;
  10277. pdoOrg.vUnreferencePdev();
  10278. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  10279. }
  10280. // Mirror the status.
  10281. pdoClone.bDisabled(pdoOrg.bDisabled());
  10282. // Obtain cloned HDEV handle.
  10283. hdevClone = pdoClone.hdev();
  10284. }
  10285. else
  10286. {
  10287. pdoClone.vUnreferencePdev();
  10288. }
  10289. if (NULL != pdc)
  10290. {
  10291. VFREEMEM(pdc);
  10292. }
  10293. }
  10294. return (hdevClone);
  10295. }
  10296. BOOL
  10297. GetPrimaryAttachFlags(
  10298. PGRAPHICS_DEVICE PhysDisp,
  10299. PULONG pPrimary,
  10300. PULONG pAttached
  10301. )
  10302. {
  10303. HANDLE hkRegistry = NULL;
  10304. ULONG defaultValue = 0;
  10305. USHORT usProtocolType;
  10306. *pPrimary = *pAttached = 0;
  10307. //
  10308. // Get the attached and primary data, which is per config (or
  10309. // also global if necessary.
  10310. //
  10311. RTL_QUERY_REGISTRY_TABLE AttachedQueryTable[] = {
  10312. {NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[0],
  10313. pPrimary, REG_DWORD, &defaultValue, 4},
  10314. {NULL, RTL_QUERY_REGISTRY_DIRECT, AttachedSettings[1],
  10315. pAttached, REG_DWORD, &defaultValue, 4},
  10316. {NULL, 0, NULL}
  10317. };
  10318. if (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT){
  10319. usProtocolType = PROTOCOL_DISCONNECT;
  10320. } else if (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) {
  10321. usProtocolType = gProtocolType;
  10322. } else {
  10323. usProtocolType = PROTOCOL_CONSOLE;
  10324. }
  10325. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  10326. DispDriverRegHardwareProfile,
  10327. NULL,
  10328. NULL,
  10329. NULL,
  10330. usProtocolType);
  10331. if (hkRegistry)
  10332. {
  10333. RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  10334. (PWSTR)hkRegistry,
  10335. &AttachedQueryTable[0],
  10336. NULL,
  10337. NULL);
  10338. ZwCloseKey(hkRegistry);
  10339. }
  10340. else
  10341. {
  10342. hkRegistry = DrvGetRegistryHandleFromDeviceMap(PhysDisp,
  10343. DispDriverRegGlobal,
  10344. NULL,
  10345. NULL,
  10346. NULL,
  10347. usProtocolType);
  10348. if (hkRegistry)
  10349. {
  10350. NTSTATUS ntStatus;
  10351. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  10352. (PWSTR)hkRegistry,
  10353. &AttachedQueryTable[0],
  10354. NULL,
  10355. NULL);
  10356. ZwCloseKey(hkRegistry);
  10357. if (!NT_SUCCESS(ntStatus))
  10358. {
  10359. return FALSE;
  10360. }
  10361. }
  10362. else
  10363. {
  10364. return FALSE;
  10365. }
  10366. }
  10367. switch (gProtocolType) {
  10368. case PROTOCOL_CONSOLE:
  10369. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT) ||
  10370. (PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE))
  10371. *pAttached = 0;
  10372. break;
  10373. case PROTOCOL_DISCONNECT:
  10374. if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT)){
  10375. *pAttached = 0;
  10376. } else{
  10377. *pAttached = 1;
  10378. }
  10379. break;
  10380. default:
  10381. if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_REMOTE) || (PhysDisp->ProtocolType != gProtocolType)){
  10382. *pAttached = 0;
  10383. } else{
  10384. *pAttached = 1;
  10385. }
  10386. }
  10387. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display driver is %sprimary on the desktop\n",
  10388. *pPrimary ? "" : "NOT "));
  10389. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display driver is %sattached to the desktop\n",
  10390. *pAttached ? "" : "NOT "));
  10391. return TRUE;
  10392. }
  10393. /***************************************************************************\
  10394. * DrvCreateMDEV
  10395. *
  10396. * Initialize an MDEV structure
  10397. *
  10398. *
  10399. * andreva Created
  10400. \***************************************************************************/
  10401. PMDEV
  10402. DrvCreateMDEV(
  10403. PUNICODE_STRING pstrDeviceName,
  10404. LPDEVMODEW lpdevmodeInformation,
  10405. PVOID pDesktopId,
  10406. ULONG ulFlags,
  10407. PMDEV pMdevOrg,
  10408. MODE PreviousMode,
  10409. DWORD PruneFlag,
  10410. BOOL bClosest
  10411. )
  10412. {
  10413. GDIFunctionID(DrvCreateMDEV);
  10414. NTSTATUS retStatus = STATUS_SUCCESS;
  10415. BOOL bAttachMirroring = FALSE;
  10416. BOOL displayInstalled = FALSE;
  10417. BOOL bLoad;
  10418. PMDEV pmdev;
  10419. BOOL bNoDisable = (ulFlags & GRE_DISP_CREATE_NODISABLE);
  10420. BOOL bModeChange = (pMdevOrg != NULL);
  10421. BOOL bPrune = (PruneFlag != GRE_RAWMODE);
  10422. PGRAPHICS_DEVICE PhysDisp;
  10423. TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Enter\n"));
  10424. GRAPHICS_STATE GraphicsState = GraphicsStateFull;
  10425. if (pstrDeviceName)
  10426. {
  10427. //
  10428. // Check if CreateDC on Dualview.
  10429. // Since opening a DualView must affect the other view,
  10430. // so if a Dualview is not opened in orginal MDEV, don't allow it to open
  10431. //
  10432. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
  10433. if (PhysDisp && (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW))
  10434. {
  10435. PPDEV ppdev;
  10436. for (ppdev = gppdevList; ppdev != NULL; ppdev = ppdev->ppdevNext)
  10437. {
  10438. PDEVOBJ po((HDEV) ppdev);
  10439. if (po.ppdev->pGraphicsDevice == PhysDisp)
  10440. {
  10441. break;
  10442. }
  10443. }
  10444. if (ppdev == NULL)
  10445. return NULL;
  10446. }
  10447. }
  10448. //
  10449. // First pass through the loop - find all the devices that should be
  10450. // are atached.
  10451. // If not attached devices, go through the loop again to find a default
  10452. // device.
  10453. // Thirdly - try to find any mirroring devices.
  10454. //
  10455. //
  10456. // Allocate new MDEV (with zero initialization)
  10457. //
  10458. pmdev = (PMDEV) PALLOCMEM(sizeof(MDEV), GDITAG_DRVSUP);
  10459. if (pmdev == NULL)
  10460. {
  10461. return NULL;
  10462. }
  10463. pmdev->chdev = 0;
  10464. pmdev->pDesktopId = pDesktopId;
  10465. while (1)
  10466. {
  10467. BOOL bMultiDevice = TRUE;
  10468. HDEV hDev;
  10469. HDEV hDevDisabled;
  10470. PGRAPHICS_DEVICE PhysDispOfDeviceName = NULL;
  10471. DWORD devNum = 0;
  10472. NTSTATUS tmpStatus;
  10473. HANDLE hkRegistry = NULL;
  10474. ULONG defaultValue = 0;
  10475. ULONG attached = 0;
  10476. ULONG primary = 0;
  10477. PDRV_NAMES lpDisplayNames;
  10478. while (bMultiDevice &&
  10479. (retStatus == STATUS_SUCCESS))
  10480. {
  10481. PhysDisp = NULL;
  10482. hDev = NULL;
  10483. hDevDisabled = NULL;
  10484. if (pstrDeviceName && (PhysDispOfDeviceName == NULL))
  10485. {
  10486. PhysDispOfDeviceName = PhysDisp = DrvGetDeviceFromName(pstrDeviceName,
  10487. PreviousMode);
  10488. //
  10489. // If we are under mode change, and device name specified. it
  10490. // means caller want to change the mode for specified device
  10491. // and leave other device as is. so we will still look for
  10492. // other device in > 2 loops.
  10493. //
  10494. if (!bModeChange)
  10495. {
  10496. bMultiDevice = FALSE;
  10497. }
  10498. }
  10499. else
  10500. {
  10501. if (PhysDispOfDeviceName && bModeChange)
  10502. {
  10503. //
  10504. // We are here when ...
  10505. //
  10506. // + DrvCreateMDEV get called with specific device name,
  10507. // AND
  10508. // + During mode change.
  10509. //
  10510. // so get device from original MDEV instead of enumerate,
  10511. //
  10512. if (devNum < pMdevOrg->chdev)
  10513. {
  10514. hDev = pMdevOrg->Dev[devNum++].hdev;
  10515. PDEVOBJ pdo(hDev);
  10516. PhysDisp = pdo.ppdev->pGraphicsDevice;
  10517. //
  10518. // If this device is already attached (in 1st loop),
  10519. // don't need to attach again.
  10520. //
  10521. if (PhysDisp == PhysDispOfDeviceName)
  10522. {
  10523. continue;
  10524. }
  10525. //
  10526. // If we are in context of "adding mirroring driver"
  10527. // and this is mirroring
  10528. // device continue to add it, otherwise forget this.
  10529. //
  10530. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ?
  10531. (!bAttachMirroring) : bAttachMirroring)
  10532. {
  10533. continue;
  10534. }
  10535. //
  10536. // Increment the Open count of the device
  10537. //
  10538. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  10539. GreAcquireSemaphoreEx(pdo.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
  10540. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  10541. pdo.ppdev->cPdevOpenRefs++;
  10542. pdo.ppdev->cPdevRefs++;
  10543. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  10544. GreEnterMonitoredSection(pdo.ppdev, WD_DEVLOCK);
  10545. //
  10546. // If the Device was disabled, just reenable it.
  10547. // But for dualview, we want to delay the enable until new MDEV is created
  10548. //
  10549. if (pdo.bDisabled() &&
  10550. (((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) == 0) ||
  10551. !gbInvalidateDualView)
  10552. )
  10553. {
  10554. ASSERTGDI(pdo.ppdev->cPdevOpenRefs == 1,
  10555. "Inconsistent Open count on disabled PDEV\n");
  10556. DrvEnableDisplay((HDEV) pdo.ppdev);
  10557. }
  10558. GreExitMonitoredSection(pdo.ppdev, WD_DEVLOCK);
  10559. GreReleaseSemaphoreEx(pdo.hsemDevLock());
  10560. GreReleaseSemaphoreEx(ghsemShareDevLock);
  10561. primary = (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? 1 : 0;
  10562. attached = 1; // since already attached.
  10563. }
  10564. else
  10565. {
  10566. break;
  10567. }
  10568. }
  10569. else
  10570. {
  10571. DWORD cCount = 0;
  10572. for (PhysDisp = gpGraphicsDeviceList;
  10573. PhysDisp != NULL;
  10574. PhysDisp = PhysDisp->pNextGraphicsDevice, cCount++)
  10575. {
  10576. if (cCount == devNum)
  10577. break;
  10578. }
  10579. devNum++;
  10580. //
  10581. // For BaseVideo, on a default boot (as opposed to a test
  10582. // in the applet), just look for the VGA driver.
  10583. //
  10584. if (gbBaseVideo && PhysDisp)
  10585. {
  10586. PhysDisp = PhysDisp->pVgaDevice;
  10587. if (PhysDisp == NULL)
  10588. {
  10589. continue;
  10590. }
  10591. }
  10592. }
  10593. }
  10594. if (PhysDisp == NULL) {
  10595. break;
  10596. }
  10597. if (PruneFlag == GRE_DEFAULT) {
  10598. bPrune = DrvGetPruneFlag(PhysDisp);
  10599. }
  10600. ASSERTGDI(PhysDisp, "Can not have NULL PhysDisp here\n");
  10601. if (!hDev)
  10602. {
  10603. /*****************************************************************
  10604. *****************************************************************
  10605. Get Device Information
  10606. *****************************************************************
  10607. *****************************************************************/
  10608. TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Trying to open device %ws \n", &(PhysDisp->szNtDeviceName[0])));
  10609. if (!GetPrimaryAttachFlags(PhysDisp, &primary, &attached))
  10610. {
  10611. break;
  10612. }
  10613. /*****************************************************************
  10614. *****************************************************************
  10615. Load Display Drivers
  10616. *****************************************************************
  10617. *****************************************************************/
  10618. //
  10619. // Try to open the display driver associated to the kernel driver.
  10620. //
  10621. // We want to do this if we are looking for an attached device (taking
  10622. // into account mirror devices properly) or if we are just looking
  10623. // for any device.
  10624. //
  10625. if (GraphicsState == GraphicsStateFull)
  10626. {
  10627. bLoad = attached &&
  10628. ((PhysDisp->stateFlags &
  10629. DISPLAY_DEVICE_MIRRORING_DRIVER) ?
  10630. bAttachMirroring :
  10631. (!bAttachMirroring));
  10632. }
  10633. else if (GraphicsState == GraphicsStateNoAttach)
  10634. {
  10635. if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  10636. {
  10637. bLoad = (attached && bAttachMirroring);
  10638. }
  10639. else if (PhysDisp->stateFlags & DISPLAY_DEVICE_DISCONNECT)
  10640. {
  10641. bLoad = FALSE;
  10642. }
  10643. else
  10644. {
  10645. ASSERTGDI(displayInstalled || gProtocolType != PROTOCOL_DISCONNECT,
  10646. "Failed to load disconnected driver while in disconnect mode.\n");
  10647. bLoad = (!displayInstalled && (gProtocolType != PROTOCOL_DISCONNECT));
  10648. }
  10649. }
  10650. else if (GraphicsState == GraphicsStateAttachDisconnect)
  10651. {
  10652. if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  10653. {
  10654. bLoad = (attached && bAttachMirroring);
  10655. }
  10656. else
  10657. {
  10658. bLoad = (!displayInstalled);
  10659. }
  10660. }
  10661. else
  10662. {
  10663. bLoad = (PhysDisp->stateFlags &
  10664. DISPLAY_DEVICE_MIRRORING_DRIVER) ?
  10665. FALSE :
  10666. (!displayInstalled);
  10667. }
  10668. if (bLoad &&
  10669. (lpDisplayNames = DrvGetDisplayDriverNames(PhysDisp)))
  10670. {
  10671. PDEVMODEW pdevmodeInformation;
  10672. DEVMODEW sourceDevmodeInformation;
  10673. DWORD dwAccelLevel;
  10674. DWORD dwOverride;
  10675. BOOL uu;
  10676. FLONG flag = (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ?
  10677. GCH_MIRRORING : GCH_DEFAULT_DISPLAY;
  10678. if (flag == GCH_DEFAULT_DISPLAY)
  10679. {
  10680. dwOverride = DrvGetDriverCapableOverRide(PhysDisp);
  10681. dwAccelLevel = DrvGetDriverAccelerationsLevel(PhysDisp);
  10682. }
  10683. else
  10684. {
  10685. dwOverride = DRIVER_CAPABLE_ALL;
  10686. dwAccelLevel = 0;
  10687. }
  10688. //
  10689. // We will try to load the driver using the information in the
  10690. // registry. If it matches perfectly with a mode from the driver -
  10691. // great. If it's a loose match, the we just give a warning.
  10692. //
  10693. // If that does not work, we will want to try the first mode
  10694. // in the list - which we get by matching with 0,0,0
  10695. //
  10696. // If that also fails, we want to boot with the default DEVMODE
  10697. // that we pass to the driver.
  10698. //
  10699. if (lpdevmodeInformation)
  10700. {
  10701. tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp,
  10702. &pdevmodeInformation,
  10703. &uu,
  10704. lpdevmodeInformation,
  10705. FALSE,
  10706. PreviousMode,
  10707. bPrune,
  10708. bClosest,
  10709. FALSE);
  10710. }
  10711. else
  10712. {
  10713. RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
  10714. sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
  10715. tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp,
  10716. &pdevmodeInformation,
  10717. &uu,
  10718. &sourceDevmodeInformation,
  10719. FALSE,
  10720. KernelMode,
  10721. bPrune,
  10722. bClosest,
  10723. FALSE);
  10724. }
  10725. if (tmpStatus == STATUS_RECEIVE_PARTIAL)
  10726. {
  10727. DrvLogDisplayDriverEvent(MsgInvalidDisplayMode);
  10728. }
  10729. else if (tmpStatus == STATUS_INVALID_PARAMETER_MIX)
  10730. {
  10731. ASSERTGDI(PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER,
  10732. "Only mirror drivers can return this error code\n");
  10733. //
  10734. // In the case of mirroring, we want to use the same
  10735. // parameters as were provided for the main display.
  10736. // We do this by passing the HDEV of the device we are
  10737. // duplicating which will actually allow the driver to
  10738. // get all the details about the other device
  10739. //
  10740. PDEVOBJ pdo(pmdev->Dev[0].hdev);
  10741. PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
  10742. if (pdevmodeInformation &&
  10743. pdevmodeInformation != &sourceDevmodeInformation)
  10744. {
  10745. VFREEMEM(pdevmodeInformation);
  10746. pdevmodeInformation = NULL;
  10747. }
  10748. tmpStatus = DrvProbeAndCaptureDevmode(PhysDisp,
  10749. &pdevmodeInformation,
  10750. &uu,
  10751. pdm,
  10752. FALSE,
  10753. PreviousMode,
  10754. bPrune,
  10755. bClosest,
  10756. FALSE);
  10757. }
  10758. //
  10759. // hCreateHDEV will appropriately compare the current mode
  10760. // to the device, and disable the current PDEV if necessary
  10761. //
  10762. if (NT_SUCCESS(tmpStatus))
  10763. {
  10764. hDev = hCreateHDEV(PhysDisp,
  10765. lpDisplayNames,
  10766. pdevmodeInformation,
  10767. pDesktopId,
  10768. dwOverride,
  10769. dwAccelLevel,
  10770. bNoDisable,
  10771. flag,
  10772. &hDevDisabled);
  10773. }
  10774. //
  10775. // We failed to load a display driver with this devmode.
  10776. // Try to pick the first valid Devmode, unless the user
  10777. // requested a specific devmode.
  10778. //
  10779. // If it still fails, try 640x480x4 VGA mode. We must get
  10780. // something to set
  10781. //
  10782. if (!(PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) &&
  10783. (lpdevmodeInformation == NULL))
  10784. {
  10785. if (!hDev)
  10786. {
  10787. DrvLogDisplayDriverEvent(MsgInvalidDisplayMode);
  10788. //
  10789. // Free memory allocated by DrvProbeAndCaptureDevmode
  10790. //
  10791. if (pdevmodeInformation)
  10792. {
  10793. //
  10794. // Log an error saying the selected color or
  10795. // resolution is invalid.
  10796. //
  10797. if (pdevmodeInformation->dmBitsPerPel == 0x4)
  10798. {
  10799. DrvLogDisplayDriverEvent(MsgInvalidDisplay16Colors);
  10800. }
  10801. if (pdevmodeInformation != &sourceDevmodeInformation)
  10802. {
  10803. VFREEMEM(pdevmodeInformation);
  10804. pdevmodeInformation = NULL;
  10805. }
  10806. }
  10807. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Trying first DEVMODE\n"));
  10808. RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
  10809. sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
  10810. if (NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp,
  10811. &pdevmodeInformation,
  10812. &uu,
  10813. &sourceDevmodeInformation,
  10814. TRUE,
  10815. KernelMode,
  10816. bPrune,
  10817. bClosest,
  10818. FALSE)))
  10819. {
  10820. hDev = hCreateHDEV(PhysDisp,
  10821. lpDisplayNames,
  10822. pdevmodeInformation,
  10823. pDesktopId,
  10824. dwOverride,
  10825. dwAccelLevel,
  10826. bNoDisable,
  10827. GCH_DEFAULT_DISPLAY,
  10828. &hDevDisabled);
  10829. //
  10830. // At last try 640x480x4bpp. With Framebuf driver,
  10831. // 640x480x4 will never be picked by DrvProbeAndCapture().
  10832. // And it's very likely that the mode set can be failed.
  10833. //
  10834. if (hDev == NULL && pdevmodeInformation->dmBitsPerPel != 0x4)
  10835. {
  10836. if (pdevmodeInformation &&
  10837. pdevmodeInformation != &sourceDevmodeInformation)
  10838. {
  10839. VFREEMEM(pdevmodeInformation);
  10840. pdevmodeInformation = NULL;
  10841. }
  10842. RtlZeroMemory(&sourceDevmodeInformation, sizeof(DEVMODEW));
  10843. sourceDevmodeInformation.dmSize = sizeof(DEVMODEW);
  10844. sourceDevmodeInformation.dmBitsPerPel = 0x4;
  10845. sourceDevmodeInformation.dmPelsWidth = 640;
  10846. sourceDevmodeInformation.dmPelsHeight = 480;
  10847. sourceDevmodeInformation.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  10848. if (NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp,
  10849. &pdevmodeInformation,
  10850. &uu,
  10851. &sourceDevmodeInformation,
  10852. FALSE,
  10853. KernelMode,
  10854. bPrune,
  10855. bClosest,
  10856. FALSE)))
  10857. {
  10858. hDev = hCreateHDEV(PhysDisp,
  10859. lpDisplayNames,
  10860. pdevmodeInformation,
  10861. pDesktopId,
  10862. dwOverride,
  10863. dwAccelLevel,
  10864. bNoDisable,
  10865. GCH_DEFAULT_DISPLAY,
  10866. &hDevDisabled);
  10867. }
  10868. }
  10869. }
  10870. }
  10871. }
  10872. if (!hDev)
  10873. {
  10874. //
  10875. // If no display driver initialized with the requested
  10876. // settings, put a message in the error log.
  10877. // (unless this was a change display settings call).
  10878. //
  10879. if (lpdevmodeInformation == NULL)
  10880. {
  10881. DrvLogDisplayDriverEvent(MsgInvalidDisplayDriver);
  10882. }
  10883. }
  10884. //
  10885. // Free memory allocated by DrvProbeAndCaptureDevmode
  10886. //
  10887. if (pdevmodeInformation &&
  10888. (pdevmodeInformation != &sourceDevmodeInformation))
  10889. {
  10890. VFREEMEM(pdevmodeInformation);
  10891. }
  10892. VFREEMEM(lpDisplayNames);
  10893. }
  10894. }
  10895. if (hDev)
  10896. {
  10897. PMDEV pmdevTmp;
  10898. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Display Driver Loaded successfully\n"));
  10899. //
  10900. // We installed a display driver successfully, so we
  10901. // know to exit out of the loop successfully.
  10902. //
  10903. displayInstalled = TRUE;
  10904. //
  10905. // Mark this device as being part of the primary device
  10906. //
  10907. if (primary)
  10908. {
  10909. PhysDisp->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
  10910. }
  10911. else
  10912. {
  10913. //
  10914. // Otherwise, mask off it, since if this physical display
  10915. // was primary previously, it still keeps it, so need to
  10916. // mask of it.
  10917. //
  10918. PhysDisp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
  10919. }
  10920. //
  10921. // If we haven't found the previously enabled hdev for this device
  10922. // look for it in the original mdev's list.
  10923. //
  10924. if (hDevDisabled == NULL && pMdevOrg != NULL)
  10925. {
  10926. for (ULONG i = 0; i < pMdevOrg->chdev; i++)
  10927. {
  10928. PDEVOBJ po((HDEV) pMdevOrg->Dev[i].hdev);
  10929. PGRAPHICS_DEVICE pGraphicsDevice = po.ppdev->pGraphicsDevice;
  10930. if (PhysDisp == pGraphicsDevice)
  10931. {
  10932. hDevDisabled = pMdevOrg->Dev[i].hdev;
  10933. }
  10934. }
  10935. }
  10936. pmdev->Dev[pmdev->chdev].hdev = hDev;
  10937. pmdev->Dev[pmdev->chdev].Reserved = hDevDisabled;
  10938. pmdev->chdev += 1;
  10939. pmdevTmp = pmdev;
  10940. //
  10941. // We allocate and copy too much, but we don't care ...
  10942. //
  10943. pmdev = (PMDEV) PALLOCMEM(sizeof(MDEV) * (pmdevTmp->chdev + 1),
  10944. GDITAG_DRVSUP);
  10945. if (pmdev)
  10946. {
  10947. //
  10948. // Compiler bug workaround MoveMemory instead of Copy
  10949. //
  10950. RtlMoveMemory(pmdev,
  10951. pmdevTmp,
  10952. sizeof(MDEV) * pmdevTmp->chdev);
  10953. VFREEMEM(pmdevTmp);
  10954. }
  10955. else
  10956. {
  10957. //
  10958. // We will exit the loop since we had a memory
  10959. // allocation failure.
  10960. //
  10961. pmdev = pmdevTmp;
  10962. retStatus = STATUS_INSUFFICIENT_RESOURCES;
  10963. }
  10964. }
  10965. }
  10966. /*****************************************************************
  10967. *****************************************************************
  10968. Handle loop exit conditions
  10969. *****************************************************************
  10970. *****************************************************************/
  10971. //
  10972. // If an error occured, we want to bring back the devices to their
  10973. // normal state.
  10974. //
  10975. if (!NT_SUCCESS(retStatus))
  10976. {
  10977. break;
  10978. }
  10979. //
  10980. // If there is no attached display drivers, then go to compatibility
  10981. // mode and load any display device except Disconnect driver.
  10982. // If still fails(only applies to local session, check it's headless
  10983. // server and try to load Disconnect driver
  10984. //
  10985. if (!displayInstalled &&
  10986. (GraphicsState == GraphicsStateFull))
  10987. {
  10988. TRACE_INIT(("\n\nDrv_Trace: No attached device: Look for any device except dummy driver.\n\n"));
  10989. GraphicsState = GraphicsStateNoAttach;
  10990. continue;
  10991. }
  10992. if (!displayInstalled &&
  10993. (GraphicsState == GraphicsStateNoAttach) &&
  10994. (gProtocolType == PROTOCOL_CONSOLE ))
  10995. {
  10996. TRACE_INIT(("\n\nDrv_Trace: No attached device: Look for any device including dummy driver.\n\n"));
  10997. GraphicsState = GraphicsStateAttachDisconnect;
  10998. continue;
  10999. }
  11000. //
  11001. // If the display drivers have been installed, then look for the
  11002. // Mirroring devices - as long as we are not in basevideo !
  11003. //
  11004. if (displayInstalled &&
  11005. (bAttachMirroring == FALSE))
  11006. {
  11007. TRACE_INIT(("\n\nDrv_Trace: DrvCreateMDEV: Look for Mirroring drivers\n\n"));
  11008. bAttachMirroring = TRUE;
  11009. continue;
  11010. }
  11011. //
  11012. // We must be done. So if we did install the display driver, just
  11013. // break out of this.
  11014. //
  11015. if (displayInstalled)
  11016. {
  11017. retStatus = STATUS_SUCCESS;
  11018. break;
  11019. }
  11020. //
  11021. // There are no devices we can work with in the registry.
  11022. // We have a real failure and take appropriate action.
  11023. //
  11024. //
  11025. // If we failed on the first driver, then we can assume their is no
  11026. // driver installed.
  11027. //
  11028. if (devNum == 0)
  11029. {
  11030. WARNING("No kernel drivers initialized");
  11031. retStatus = STATUS_DEVICE_DOES_NOT_EXIST;
  11032. break;
  11033. }
  11034. //
  11035. // If the display driver is not installed, then this is another
  11036. // bad failure - report it.
  11037. //
  11038. if (!displayInstalled)
  11039. {
  11040. //This RIP is hit often in stress.
  11041. //RIP("Drv_Trace: DrvCreateMDEV: No display drivers loaded");
  11042. retStatus = STATUS_DRIVER_UNABLE_TO_LOAD;
  11043. break;
  11044. }
  11045. //
  11046. // Never get here !
  11047. //
  11048. retStatus = STATUS_UNSUCCESSFUL;
  11049. }
  11050. /*****************************************************************
  11051. *****************************************************************
  11052. Check Flags and calculate rectangles
  11053. *****************************************************************
  11054. *****************************************************************/
  11055. TRACE_INIT(("\nDrv_Trace: DrvCreateMDEV: Check flags and rectangles\n"));
  11056. if (retStatus == STATUS_SUCCESS)
  11057. {
  11058. if (ulFlags & GRE_DISP_NOT_APARTOF_DESKTOP)
  11059. {
  11060. //
  11061. // This MDEV is created for additional secondary use.
  11062. // Don't change any attribute in PDEV based on this MDEV,
  11063. // since these PDEV could be a part of other MDEV which
  11064. // ,for example, represents current desktop.
  11065. //
  11066. }
  11067. else
  11068. {
  11069. ULONG i;
  11070. LPRECT pSrcRect = NULL;
  11071. LPRECT pDstRect = NULL;
  11072. PGRAPHICS_DEVICE PhysDisp;
  11073. ULONG primary = 0;
  11074. PGRAPHICS_DEVICE primaryPhysDisp = NULL;
  11075. ULONG size;
  11076. //
  11077. // Make sure there is only one primary.
  11078. //
  11079. for (i = 0; i < pmdev->chdev; i++)
  11080. {
  11081. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  11082. PhysDisp = pdo.ppdev->pGraphicsDevice;
  11083. //
  11084. // The first non-removable PhysDisp would be a primary candicate
  11085. //
  11086. if (PhysDisp->stateFlags & (DISPLAY_DEVICE_REMOVABLE | DISPLAY_DEVICE_MIRRORING_DRIVER))
  11087. {
  11088. if (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  11089. {
  11090. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: The primary desktop is on a removable or Mirror device.\n"));
  11091. PhysDisp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
  11092. }
  11093. }
  11094. else
  11095. {
  11096. if (primaryPhysDisp == NULL) {
  11097. primary = i;
  11098. }
  11099. }
  11100. if (PhysDisp->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  11101. {
  11102. if (primaryPhysDisp == NULL)
  11103. {
  11104. primaryPhysDisp = PhysDisp;
  11105. primary = i;
  11106. }
  11107. else
  11108. {
  11109. ASSERTGDI(FALSE, "Two primary devices\n");
  11110. PhysDisp->stateFlags &=
  11111. ~DISPLAY_DEVICE_PRIMARY_DEVICE;
  11112. retStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  11113. }
  11114. }
  11115. }
  11116. //
  11117. // Create a list of rects which we can align.
  11118. //
  11119. size = pmdev->chdev * sizeof(RECT);
  11120. pSrcRect = (LPRECT) PALLOCNOZ(size, GDITAG_DRVSUP);
  11121. pDstRect = (LPRECT) PALLOCNOZ(size, GDITAG_DRVSUP);
  11122. if (pSrcRect && pDstRect)
  11123. {
  11124. ULONG ci = 0;
  11125. for (i = 0; i < pmdev->chdev; i++)
  11126. {
  11127. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  11128. PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
  11129. //
  11130. // Reset the position rect with the real values.
  11131. //
  11132. (pSrcRect + i)->left = pdm->dmPosition.x;
  11133. (pSrcRect + i)->top = pdm->dmPosition.y;
  11134. (pSrcRect + i)->right = pdm->dmPosition.x + pdm->dmPelsWidth;
  11135. (pSrcRect + i)->bottom = pdm->dmPosition.y + pdm->dmPelsHeight;
  11136. if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  11137. {
  11138. }
  11139. else
  11140. {
  11141. //
  11142. // Find a primary if we don't already have one.
  11143. // The first device with 0,0 as the origin will be it.
  11144. //
  11145. if ( (primaryPhysDisp == NULL) &&
  11146. (pdm->dmPosition.x == 0) &&
  11147. (pdm->dmPosition.y == 0) &&
  11148. ((pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_REMOVABLE) == 0))
  11149. {
  11150. primary = i;
  11151. primaryPhysDisp = pdo.ppdev->pGraphicsDevice;
  11152. }
  11153. ci++;
  11154. }
  11155. }
  11156. RtlCopyMemory(pDstRect, pSrcRect, size);
  11157. //
  11158. // Set the primary
  11159. //
  11160. PDEVOBJ pdo(pmdev->Dev[primary].hdev);
  11161. pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
  11162. //
  11163. // NOTE
  11164. // CUDR_NOSNAPTOGRID == 1 in winuser.w
  11165. //
  11166. if (AlignRects(pDstRect, ci, primary, 1) == FALSE)
  11167. {
  11168. //
  11169. // Devices could not be aligned.
  11170. //
  11171. }
  11172. if (!RtlEqualMemory(pDstRect, pSrcRect, ci * sizeof(RECT)))
  11173. {
  11174. //
  11175. // Devices were repositioned
  11176. //
  11177. WARNING("GDI DDML: Device positions are adjusted");
  11178. }
  11179. //
  11180. // Let's save all these rectangles
  11181. //
  11182. TRACE_INIT(("Drv_Trace: DrvCreateMDEV: Reseting device positions\n"));
  11183. for (i = 0; i < pmdev->chdev; i++)
  11184. {
  11185. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  11186. TRACE_INIT(("\t%ws: ", pdo.ppdev->pGraphicsDevice->szNtDeviceName));
  11187. //
  11188. // Set the surface's origin
  11189. //
  11190. pdo.ppdev->ptlOrigin = *((PPOINTL) (pDstRect + i));
  11191. //
  11192. // Notify the surface's origin to driver.
  11193. //
  11194. if (PPFNDRV(pdo,Notify))
  11195. {
  11196. PPFNDRV(pdo,Notify)(pdo.pSurface()->pSurfobj(),
  11197. DN_DEVICE_ORIGIN,
  11198. (PVOID)(&(pdo.ppdev->ptlOrigin)));
  11199. }
  11200. //
  11201. // Save the rectangle back into the mdev structure.
  11202. //
  11203. pmdev->Dev[i].rect = *(pDstRect + i);
  11204. #if DBG_BASIC
  11205. DbgPrint("GDI DDML: Device %d, position %d, %d, %d, %d, rotation %lu\n",
  11206. i,
  11207. pdo.pptlOrigin()->x,
  11208. pdo.pptlOrigin()->y,
  11209. pdo.pptlOrigin()->x +
  11210. pdo.ppdev->ppdevDevmode->dmPelsWidth,
  11211. pdo.pptlOrigin()->y +
  11212. pdo.ppdev->ppdevDevmode->dmPelsHeight,
  11213. pdo.ppdev->ppdevDevmode->dmDisplayOrientation * 90
  11214. );
  11215. if (pmdev->Dev[i].rect.left != pdo.pptlOrigin()->x)
  11216. {
  11217. DbgPrint("GDI DDML: Inconsistent rect left (%d) - origin left (%d)\n",
  11218. pmdev->Dev[i].rect.left,pdo.pptlOrigin()->x);
  11219. }
  11220. if (pmdev->Dev[i].rect.top != pdo.pptlOrigin()->y)
  11221. {
  11222. DbgPrint("GDI DDML: Inconsistent rect top (%d) - origin top (%d)\n",
  11223. pmdev->Dev[i].rect.top,pdo.pptlOrigin()->y);
  11224. }
  11225. if ((ULONG) pmdev->Dev[i].rect.right !=
  11226. pdo.pptlOrigin()->x + pdo.ppdev->ppdevDevmode->dmPelsWidth)
  11227. {
  11228. DbgPrint("GDI DDML: Inconsistent rect right (%d) - devmode right (%d)\n",
  11229. pmdev->Dev[i].rect.right,
  11230. pdo.pptlOrigin()->x + pdo.ppdev->ppdevDevmode->dmPelsWidth);
  11231. }
  11232. if ((ULONG) pmdev->Dev[i].rect.bottom !=
  11233. pdo.pptlOrigin()->y + pdo.ppdev->ppdevDevmode->dmPelsHeight)
  11234. {
  11235. DbgPrint("GDI DDML: Inconsistent rect bottom (%d) - devmode bottom (%d)\n",
  11236. pmdev->Dev[i].rect.bottom,
  11237. pdo.pptlOrigin()->y + pdo.ppdev->ppdevDevmode->dmPelsHeight);
  11238. }
  11239. #endif
  11240. }
  11241. }
  11242. if (pSrcRect)
  11243. {
  11244. VFREEMEM(pSrcRect);
  11245. }
  11246. if (pDstRect)
  11247. {
  11248. VFREEMEM(pDstRect);
  11249. }
  11250. }
  11251. }
  11252. if (!NT_SUCCESS(retStatus))
  11253. {
  11254. //
  11255. // Delete all the hdevs we have created. and restore the old
  11256. // ones.
  11257. //
  11258. DrvBackoutMDEV(pmdev);
  11259. VFREEMEM(pmdev);
  11260. pmdev = NULL;
  11261. }
  11262. #if TEXTURE_DEMO
  11263. pmdev = pmdevSetupTextureDemo(pmdev);
  11264. #endif
  11265. //
  11266. // Dump the MDEV structure.
  11267. //
  11268. TRACE_INIT(("DrvCreateMDEV: Resulting MDEV\n"));
  11269. TRACE_INIT(("pmdev = %08lx\n", pmdev));
  11270. if (pmdev)
  11271. {
  11272. ULONG i;
  11273. for (i = 0; i < pmdev->chdev; i++)
  11274. {
  11275. TRACE_INIT(("\t[%d].hdev = %08lx\n", i, pmdev->Dev[i].hdev));
  11276. TRACE_INIT(("\t[%d].rect = %d, %d, %d, %d,\n", i,
  11277. pmdev->Dev[i].rect.left, pmdev->Dev[i].rect.top,
  11278. pmdev->Dev[i].rect.right, pmdev->Dev[i].rect.bottom));
  11279. }
  11280. }
  11281. return (pmdev);
  11282. }
  11283. /***************************************************************************\
  11284. * DrvSetBaseVideo
  11285. *
  11286. * Initialize the graphics components of the system
  11287. *
  11288. * andreva Created
  11289. \***************************************************************************/
  11290. VOID
  11291. DrvSetBaseVideo(
  11292. BOOL bSet
  11293. )
  11294. {
  11295. gbBaseVideo = bSet;
  11296. }
  11297. /***************************************************************************\
  11298. * DrvCheckUpgradeSettings
  11299. *
  11300. * Check first boot from upgrade. If so, get last settings and move it
  11301. * into normal setting registry. Otherwise, check if have registry settings
  11302. * already, if not, move preferred mode into normal setting registry.
  11303. *
  11304. * dennyd Created
  11305. \***************************************************************************/
  11306. DEFINE_GUID(GUID_DISPLAY_ADAPTER_INTERFACE, 0x5b45201d, 0xf2f2, 0x4f3b, 0x85, 0xbb, 0x30, 0xff, 0x1f, 0x95, 0x35, 0x99);
  11307. VOID
  11308. DrvCheckUpgradeSettings(VOID)
  11309. {
  11310. PGRAPHICS_DEVICE PhysDisp;
  11311. PWSTR SymbolicLinkList;
  11312. UNICODE_STRING SymbolicLinkName;
  11313. HANDLE hkRegistry = NULL;
  11314. NTSTATUS Status;
  11315. USHORT DualviewIndex;
  11316. DEVMODEW devMode;
  11317. BOOL bUpgraded;
  11318. UNICODE_STRING SubKeyName;
  11319. HANDLE hkSubKey = NULL;
  11320. OBJECT_ATTRIBUTES ObjectAttributes;
  11321. DWORD UsePreferredMode;
  11322. for (PhysDisp = gpGraphicsDeviceList;
  11323. PhysDisp != NULL;
  11324. PhysDisp = PhysDisp->pNextGraphicsDevice)
  11325. {
  11326. GUID Guid = GUID_DISPLAY_ADAPTER_INTERFACE;
  11327. bUpgraded = FALSE;
  11328. UsePreferredMode = 0;
  11329. DualviewIndex = 0;
  11330. if (PhysDisp->pPhysDeviceHandle == NULL)
  11331. continue;
  11332. //
  11333. // Check if it's DualView second, assign an index to it
  11334. //
  11335. if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW)
  11336. {
  11337. PGRAPHICS_DEVICE PhysDisp1;
  11338. for (PhysDisp1 = gpGraphicsDeviceList;
  11339. PhysDisp1 != PhysDisp;
  11340. PhysDisp1 = PhysDisp1->pNextGraphicsDevice)
  11341. {
  11342. if ((PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  11343. (PhysDisp->pPhysDeviceHandle == PhysDisp1->pPhysDeviceHandle))
  11344. {
  11345. DualviewIndex++;
  11346. }
  11347. }
  11348. }
  11349. if (NT_SUCCESS(IoGetDeviceInterfaces(&Guid,
  11350. (PDEVICE_OBJECT)PhysDisp->pPhysDeviceHandle,
  11351. 0,
  11352. &SymbolicLinkList)) )
  11353. {
  11354. if (SymbolicLinkList[0] != L'\0')
  11355. {
  11356. WCHAR wstrSubKey[4];
  11357. RtlInitUnicodeString(&SymbolicLinkName, SymbolicLinkList);
  11358. if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&SymbolicLinkName,
  11359. KEY_ALL_ACCESS,
  11360. &hkRegistry)))
  11361. {
  11362. ULONG defaultValue = 0, Attached;
  11363. //
  11364. // Read and delete the display settings
  11365. //
  11366. RtlZeroMemory(&devMode, sizeof(devMode));
  11367. swprintf(wstrSubKey, L"%d", DualviewIndex);
  11368. RTL_QUERY_REGISTRY_TABLE QueryTable[] =
  11369. {
  11370. {NULL, RTL_QUERY_REGISTRY_SUBKEY,
  11371. wstrSubKey, NULL, REG_NONE, NULL, 0},
  11372. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, L"UsePreferredMode",
  11373. &UsePreferredMode, REG_DWORD, &defaultValue, 4},
  11374. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[0],
  11375. &devMode.dmBitsPerPel, REG_DWORD, &defaultValue, 4},
  11376. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[1],
  11377. &devMode.dmPelsWidth, REG_DWORD, &defaultValue, 4},
  11378. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[2],
  11379. &devMode.dmPelsHeight, REG_DWORD, &defaultValue, 4},
  11380. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[3],
  11381. &devMode.dmDisplayFrequency, REG_DWORD, &defaultValue, 4},
  11382. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[4],
  11383. &devMode.dmDisplayFlags, REG_DWORD, &defaultValue, 4},
  11384. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[7],
  11385. &devMode.dmDisplayOrientation, REG_DWORD, &defaultValue, 4},
  11386. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[8],
  11387. &devMode.dmDisplayFixedOutput, REG_DWORD, &defaultValue, 4},
  11388. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[9],
  11389. &devMode.dmPosition.x, REG_DWORD, &defaultValue, 4},
  11390. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[10],
  11391. &devMode.dmPosition.y, REG_DWORD, &defaultValue, 4},
  11392. {NULL, RTL_QUERY_REGISTRY_DIRECT|RTL_QUERY_REGISTRY_DELETE, DefaultSettings[11],
  11393. &Attached, REG_DWORD, &defaultValue, 4},
  11394. {NULL, 0, NULL}
  11395. };
  11396. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  11397. (PWSTR)hkRegistry,
  11398. &QueryTable[0],
  11399. NULL,
  11400. NULL)) &&
  11401. (devMode.dmPelsWidth != 0) &&
  11402. (!UsePreferredMode)
  11403. )
  11404. {
  11405. if (Attached) {
  11406. devMode.dmFields |= DM_POSITION;
  11407. }
  11408. DrvUpdateDisplayDriverParameters(PhysDisp,
  11409. &devMode,
  11410. (Attached == 0),
  11411. TRUE);
  11412. bUpgraded = TRUE;
  11413. }
  11414. //
  11415. // Delete the subkey containing the display settings
  11416. //
  11417. RtlInitUnicodeString(&SubKeyName, wstrSubKey);
  11418. InitializeObjectAttributes(&ObjectAttributes,
  11419. &SubKeyName,
  11420. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  11421. hkRegistry,
  11422. NULL);
  11423. if (NT_SUCCESS(ZwOpenKey(&hkSubKey,
  11424. KEY_ALL_ACCESS,
  11425. &ObjectAttributes))
  11426. )
  11427. {
  11428. ZwDeleteKey(hkSubKey);
  11429. }
  11430. //
  11431. // Close the device interface registry key
  11432. //
  11433. ZwClose(hkRegistry);
  11434. }
  11435. }
  11436. ExFreePool((PVOID)SymbolicLinkList);
  11437. }
  11438. if (PhysDisp->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) {
  11439. continue;
  11440. }
  11441. //
  11442. // Check if there are still registry settings.
  11443. // If not, put preferred mode there.
  11444. //
  11445. PDEVMODEW pDevmode = (PDEVMODEW) PALLOCNOZ(sizeof(DEVMODEW) + MAXUSHORT,
  11446. GDITAG_DEVMODE);
  11447. if (pDevmode == NULL) {
  11448. continue;
  11449. }
  11450. RtlZeroMemory(pDevmode, sizeof(DEVMODEW));
  11451. pDevmode->dmSize = 0xDDDD;
  11452. pDevmode->dmDriverExtra = MAXUSHORT;
  11453. if (UsePreferredMode ||
  11454. (!bUpgraded &&
  11455. (!NT_SUCCESS(DrvGetDisplayDriverParameters(PhysDisp,
  11456. pDevmode,
  11457. FALSE,
  11458. FALSE)) ||
  11459. (pDevmode->dmPelsWidth == 0)
  11460. )
  11461. )
  11462. )
  11463. {
  11464. RtlZeroMemory(pDevmode, sizeof(DEVMODEW));
  11465. pDevmode->dmSize = sizeof(DEVMODEW);
  11466. if (NT_SUCCESS(DrvGetPreferredMode(pDevmode, PhysDisp)))
  11467. {
  11468. pDevmode->dmBitsPerPel = 32;
  11469. pDevmode->dmFields |= DM_BITSPERPEL;
  11470. DrvUpdateDisplayDriverParameters(PhysDisp,
  11471. pDevmode,
  11472. FALSE,
  11473. TRUE);
  11474. }
  11475. }
  11476. VFREEMEM(pDevmode);
  11477. }
  11478. }
  11479. /***************************************************************************\
  11480. * DrvInitConsole
  11481. *
  11482. * Initialize the graphics components of the system
  11483. *
  11484. * andreva Created
  11485. \***************************************************************************/
  11486. VOID
  11487. DrvInitConsole(
  11488. BOOL bEnumerationNeeded)
  11489. {
  11490. UNICODE_STRING UnicodeString;
  11491. OBJECT_ATTRIBUTES ObjectAttributes;
  11492. HANDLE hkRegistry = NULL;
  11493. NTSTATUS Status;
  11494. PGRAPHICS_DEVICE PhysDisp;
  11495. PVOID RegistrationHandle;
  11496. /*****************************************************************
  11497. *****************************************************************
  11498. BaseVideo
  11499. *****************************************************************
  11500. *****************************************************************/
  11501. //
  11502. // Basevideo is considered a primary device in that the user will run
  11503. // the vga driver. This does override any other primary selection
  11504. // the user may have put in the registry.
  11505. //
  11506. RtlInitUnicodeString(&UnicodeString,
  11507. L"\\Registry\\Machine\\System\\CurrentControlSet\\"
  11508. L"Control\\GraphicsDrivers\\BaseVideo");
  11509. InitializeObjectAttributes(&ObjectAttributes,
  11510. &UnicodeString,
  11511. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  11512. NULL,
  11513. NULL);
  11514. Status = ZwOpenKey(&hkRegistry,
  11515. KEY_READ,
  11516. &ObjectAttributes);
  11517. #ifdef _HYDRA_
  11518. /*
  11519. * No base video for WinStations
  11520. */
  11521. if ( !G_fConsole )
  11522. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  11523. #endif
  11524. if (NT_SUCCESS( Status))
  11525. {
  11526. TRACE_INIT(("Drv_Trace: DrvInitConsole: Basevideo - FOUND\n"));
  11527. DrvSetBaseVideo(TRUE);
  11528. if (hkRegistry)
  11529. ZwCloseKey(hkRegistry);
  11530. }
  11531. else
  11532. {
  11533. TRACE_INIT(("Drv_Trace: DrvInitConsole: Basevideo - NOT FOUND\n"));
  11534. DrvSetBaseVideo(FALSE);
  11535. }
  11536. /*****************************************************************
  11537. *****************************************************************
  11538. Device List
  11539. *****************************************************************
  11540. *****************************************************************/
  11541. RtlZeroMemory(&gFullscreenGraphicsDevice, sizeof(GRAPHICS_DEVICE));
  11542. RtlZeroMemory(&gFeFullscreenGraphicsDevice, sizeof(GRAPHICS_DEVICE));
  11543. //
  11544. // Register for new device notifucations
  11545. //
  11546. #if 0
  11547. TRACE_INIT(("Drv_Trace: DrvInitConsole: Registering GUIDs\n"));
  11548. _asm {int 3};
  11549. Status = IoRegisterPlugPlayNotification (
  11550. EventCategoryDeviceInterfaceChange,
  11551. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  11552. (LPGUID) &GUID_DISPLAY_DEVICE_INTERFACE_STANDARD,
  11553. gpWin32kDriverObject,
  11554. (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DrvNewDisplayDevice,
  11555. NULL,
  11556. &RegistrationHandle);
  11557. if (!NT_SUCCESS(Status))
  11558. {
  11559. ASSERTGDI(FALSE, "IoRegisterPlugPlayNotification(display) failed");
  11560. return;
  11561. }
  11562. Status = IoRegisterPlugPlayNotification (
  11563. EventCategoryDeviceInterfaceChange,
  11564. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  11565. (LPGUID) &GUID_DISPLAY_OUTPUT_INTERFACE_STANDARD,
  11566. gpWin32kDriverObject,
  11567. (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DrvNewDisplayOutput,
  11568. NULL,
  11569. &RegistrationHandle);
  11570. if (!NT_SUCCESS(Status))
  11571. {
  11572. ASSERTGDI(FALSE, "IoRegisterPlugPlayNotification(output) failed");
  11573. return;
  11574. }
  11575. #endif
  11576. DrvUpdateGraphicsDeviceList(TRUE, bEnumerationNeeded, gProtocolType == PROTOCOL_CONSOLE);
  11577. DrvCheckUpgradeSettings();
  11578. #if 0
  11579. DrvGetMirrorDrivers();
  11580. #endif
  11581. return;
  11582. }
  11583. /***************************************************************************\
  11584. * DrvSetSharedDevLock
  11585. *
  11586. * routine to share devlock between parent and children.
  11587. *
  11588. * 05-Mar-1998 hideyukn Created
  11589. \***************************************************************************/
  11590. VOID
  11591. DrvSetSharedDevLock(PMDEV pmdev)
  11592. {
  11593. PDEVOBJ pdoParent(pmdev->hdevParent);
  11594. // Parent's DEVLOCK should not be shared.
  11595. ASSERTGDI(!pdoParent.bUseParentDevLock(),
  11596. "DrvSetSharedDevLock():Parent PDEV has shared devlock\n");
  11597. for (ULONG i = 0; i < pmdev->chdev; i++)
  11598. {
  11599. PDEVOBJ pdo(pmdev->Dev[i].hdev);
  11600. // Set Parent PDEV as parent to each of the PDEVs that we'll manage.
  11601. pdo.ppdev->ppdevParent = (PDEV *) pmdev->hdevParent;
  11602. // Switch to use the shared DEVLOCK with parent.
  11603. pdo.vUseParentDevLock();
  11604. }
  11605. }
  11606. /***************************************************************************\
  11607. * DrvRealizeHalftonePalette
  11608. *
  11609. * routine to realize halftone palette onto given device.
  11610. *
  11611. * 22-Apr-1998 hideyukn Created
  11612. \***************************************************************************/
  11613. PPALETTE gppalHalftone = NULL;
  11614. ULONG gulPalTimeForDDML = 0;
  11615. PPALETTE
  11616. DrvRealizeHalftonePalette(HDEV hdevPalette, BOOL bForce)
  11617. {
  11618. BOOL bRet = FALSE;
  11619. PDEVOBJ pdoPalette(hdevPalette);
  11620. XEPALOBJ palSurfObj(pdoPalette.ppalSurf());
  11621. if (bForce || (gulPalTimeForDDML != palSurfObj.ulTime()))
  11622. {
  11623. //
  11624. // Create display DC for palette device.
  11625. //
  11626. HDC hdcDevice = GreCreateDisplayDC(hdevPalette,DCTYPE_DIRECT,FALSE);
  11627. if (hdcDevice)
  11628. {
  11629. if (gppalHalftone == NULL)
  11630. {
  11631. //
  11632. // Create Win98 compatible halftone palette.
  11633. //
  11634. HPALETTE hPalette = GreCreateCompatibleHalftonePalette(hdcDevice);
  11635. if (hPalette)
  11636. {
  11637. EPALOBJ palObj(hPalette);
  11638. if (GreSetPaletteOwner(hPalette, OBJECT_OWNER_PUBLIC))
  11639. {
  11640. //
  11641. // Put it into Global variable.
  11642. //
  11643. gppalHalftone = palObj.ppalGet();
  11644. }
  11645. else
  11646. {
  11647. bDeletePalette((HPAL)hPalette,TRUE);
  11648. }
  11649. }
  11650. else
  11651. {
  11652. WARNING("DrvRealizeHalftonePalette():Failed on GreCreateCompatibleHalftonePalette()");
  11653. }
  11654. }
  11655. if (gppalHalftone)
  11656. {
  11657. //
  11658. // Selet the global halftone palette into the palette device.
  11659. //
  11660. HPALETTE hPalOld = GreSelectPalette(hdcDevice,
  11661. (HPALETTE)gppalHalftone->hGet(),
  11662. TRUE); // ForceBackgound
  11663. if (hPalOld)
  11664. {
  11665. XEPALOBJ palHTObj(gppalHalftone);
  11666. //
  11667. // Strip translation table.
  11668. //
  11669. palHTObj.vMakeNoXlate();
  11670. //
  11671. // Realize halftone palette on device. (device palette might be changed)
  11672. //
  11673. if (GreRealizePalette(hdcDevice))
  11674. {
  11675. KdPrint(("DrvRealizeHalftonePalette():Device palette has been changed\n"));
  11676. }
  11677. //
  11678. // Update palette time.
  11679. //
  11680. gulPalTimeForDDML = palSurfObj.ulTime();
  11681. //
  11682. // Select back old one.
  11683. //
  11684. GreSelectPalette(hdcDevice,hPalOld,FALSE);
  11685. bRet = TRUE;
  11686. }
  11687. else
  11688. {
  11689. WARNING("DrvRealizeHalftonePalette():Failed on GreSelectPalette()");
  11690. }
  11691. }
  11692. else
  11693. {
  11694. WARNING("DrvRealizeHalftonePalette():gppalHalftone is NULL");
  11695. }
  11696. bDeleteDCInternal(hdcDevice,TRUE,FALSE);
  11697. }
  11698. else
  11699. {
  11700. WARNING("DrvRealizeHalftonePalette():Failed on GreCreateDisplayDC()");
  11701. }
  11702. }
  11703. else
  11704. {
  11705. //
  11706. // Realization is still effective.
  11707. //
  11708. bRet = TRUE;
  11709. }
  11710. //
  11711. // If we could not have halftone palette, just use default palette.
  11712. //
  11713. return (bRet ? gppalHalftone : ppalDefault);
  11714. }
  11715. /***************************************************************************\
  11716. * DrvSetSharedPalette
  11717. *
  11718. * routine to share palette between parent and children.
  11719. *
  11720. * 22-Apr-1998 hideyukn Created
  11721. \***************************************************************************/
  11722. BOOL MulSetPalette(DHPDEV,PALOBJ *,FLONG,ULONG,ULONG);
  11723. HDEV
  11724. DrvSetSharedPalette(PMDEV pmdev)
  11725. {
  11726. HDEV hdevPalette = NULL;
  11727. //
  11728. // ToddLa's law - Palette should be shared with all paletaized monitors.
  11729. //
  11730. PDEVOBJ pdoParent(pmdev->hdevParent);
  11731. //ASSERTGDI((PPFNDRV(pdoParent,SetPalette)) == MulSetPalette,
  11732. // "DrvSetSharedPalette(): SetPalette != MulSetPalette\n");
  11733. PPALETTE ppalShared = NULL;
  11734. if (pdoParent.bIsPalManaged())
  11735. {
  11736. //
  11737. // If parent is palette device, we shared it
  11738. // with all paletaized children.
  11739. //
  11740. ppalShared = pdoParent.ppalSurf();
  11741. //
  11742. // Remember the hdev which owns palette.
  11743. //
  11744. hdevPalette = pdoParent.hdev();
  11745. }
  11746. for (UINT i = 0; i < pmdev->chdev; i++)
  11747. {
  11748. PDEVOBJ pdoChild(pmdev->Dev[i].hdev);
  11749. if (pdoChild.bIsPalManaged())
  11750. {
  11751. //
  11752. // Change pointer to DrvSetPalette to
  11753. // DDML, so that palette can be changed
  11754. // to a specific hdev, will be dispatch
  11755. // to every paletaized device.
  11756. //
  11757. pdoChild.pfnSetPalette(MulSetPalette);
  11758. if (ppalShared == NULL)
  11759. {
  11760. //
  11761. // Parent is not palette device, but
  11762. // this is palette device which we
  11763. // encounter first in the children,
  11764. // so we will share this palette.
  11765. //
  11766. ppalShared = pdoChild.ppalSurf();
  11767. //
  11768. // Remember the hdev which owns palette.
  11769. //
  11770. hdevPalette = pdoChild.hdev();
  11771. }
  11772. else if (pdoChild.ppalSurf() != ppalShared)
  11773. {
  11774. //
  11775. // If the palette in hdev is already same as
  11776. // parent (mostly it is primary device, if
  11777. // primary is palette device.), don't
  11778. // need to update it. Otherwise update it here.
  11779. //
  11780. XEPALOBJ palChild(pdoChild.ppalSurf());
  11781. //
  11782. // Set colour table to shared palette.
  11783. //
  11784. palChild.apalColorSet(ppalShared);
  11785. }
  11786. }
  11787. }
  11788. return (hdevPalette);
  11789. }
  11790. /***************************************************************************\
  11791. * DrvTransferGdiObjects()
  11792. *
  11793. * Transfer belonging gdi object from a hdev to other.
  11794. *
  11795. * 04-Jul-1998 hideyukn Created
  11796. \***************************************************************************/
  11797. #define DRV_TRANS_DC_TYPE 0x0001
  11798. #define DRV_TRANS_SURF_TYPE 0x0002
  11799. #define DRV_TRANS_DRVOBJ_TYPE 0x0004
  11800. #define DRV_TRANS_WNDOBJ_TYPE 0x0008
  11801. #define DRV_TRANS_ALL_TYPE 0x000F
  11802. #define DRV_TRANS_TO_CLONE 0x1000
  11803. VOID
  11804. DrvTransferGdiObjects(HDEV hdevNew, HDEV hdevOld, ULONG ulFlags)
  11805. {
  11806. //
  11807. // 1) Change owner of DC_TYPE object.
  11808. //
  11809. // 2) Change owner of SURF_TYPE object.
  11810. //
  11811. // + ATI driver, for example, creates engine
  11812. // bitmap for thier banking, off-screen
  11813. // bitmap and ..., so need to change owner
  11814. // of those bitmap to clone's hdev.
  11815. //
  11816. // 3) Change owner of DRVOBJ_TYPE object.
  11817. //
  11818. // 4) Exchange WNDOBJ.
  11819. //
  11820. PDEVOBJ pdoNew(hdevNew);
  11821. PDEVOBJ pdoOld(hdevOld);
  11822. ASSERTGDI(pdoNew.pSurface() == pdoOld.pSurface(),
  11823. "DrvTransferGdiObjects():pSurface does not match\n");
  11824. ASSERTGDI(pdoNew.dhpdev() == pdoOld.dhpdev(),
  11825. "DrvTransferGdiObjects():dhpdev does not match\n");
  11826. GreAcquireHmgrSemaphore();
  11827. HOBJ hobj = 0;
  11828. //
  11829. // Transfer DC which own by hdevCloned to hdevClone.
  11830. //
  11831. if (ulFlags & DRV_TRANS_DC_TYPE)
  11832. {
  11833. PDC pdc = NULL;
  11834. hobj = 0;
  11835. while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
  11836. {
  11837. hobj = (HOBJ) pdc->hGet();
  11838. if ((HDEV)pdc->ppdev() == hdevOld)
  11839. {
  11840. KdPrint(("Transfer DC %x - hdevNew %x hdevOld %x \n",
  11841. pdc->hGet(),hdevNew,hdevOld));
  11842. pdc->ppdev((PDEV *)pdoNew.hdev());
  11843. if (ulFlags & DRV_TRANS_TO_CLONE)
  11844. {
  11845. pdc->fsSet(DC_IN_CLONEPDEV);
  11846. }
  11847. else
  11848. {
  11849. pdc->fsClr(DC_IN_CLONEPDEV);
  11850. }
  11851. pdoNew.vReferencePdev();
  11852. pdoOld.vUnreferencePdev();
  11853. }
  11854. }
  11855. }
  11856. //
  11857. // Transfer surface which own by old pdev to new pdev.
  11858. //
  11859. if (ulFlags & DRV_TRANS_SURF_TYPE)
  11860. {
  11861. SURFACE *pSurface = NULL;
  11862. hobj = 0;
  11863. while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
  11864. {
  11865. hobj = (HOBJ) pSurface->hGet();
  11866. if ((pSurface->hdev() == hdevOld) /* && pSurface->bDriverCreated() */)
  11867. {
  11868. KdPrint(("Transfer surface %x - hdevNew %x hdevOld %x \n",
  11869. pSurface->hGet(),hdevNew,hdevOld));
  11870. pSurface->hdev(hdevNew);
  11871. }
  11872. }
  11873. }
  11874. //
  11875. // Transfer DRVOBJ.
  11876. //
  11877. if (ulFlags & DRV_TRANS_DRVOBJ_TYPE)
  11878. {
  11879. DRVOBJ *pdrvo = NULL;
  11880. hobj = 0;
  11881. while (pdrvo = (DRVOBJ*) HmgSafeNextObjt(hobj, DRVOBJ_TYPE))
  11882. {
  11883. hobj = (HOBJ) pdrvo->hGet();
  11884. if (pdrvo->hdev == hdevOld)
  11885. {
  11886. KdPrint(("Transfer drvobj %x - hdevNew %x hdevOld %x \n",
  11887. pdrvo->hGet(),hdevNew,hdevOld));
  11888. pdrvo->hdev = hdevNew;
  11889. pdoNew.vReferencePdev();
  11890. pdoOld.vUnreferencePdev();
  11891. }
  11892. }
  11893. }
  11894. //
  11895. // Transfer WNDOBJ.
  11896. //
  11897. if (ulFlags & DRV_TRANS_WNDOBJ_TYPE)
  11898. {
  11899. vTransferWndObjs(pdoNew.pSurface(),pdoOld.hdev(),pdoNew.hdev());
  11900. }
  11901. GreReleaseHmgrSemaphore();
  11902. }
  11903. /***************************************************************************\
  11904. * DrvEnableDirectDrawForModeChange()
  11905. *
  11906. * 01-Aug-1998 hideyukn Created
  11907. \***************************************************************************/
  11908. VOID
  11909. DrvEnableDirectDrawForModeChange(
  11910. HDEV *phdevList,
  11911. BOOL bAlloc
  11912. )
  11913. {
  11914. ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock),
  11915. "ShareDevlock must be held be before calling EnableDirectDraw");
  11916. ULONG chdev = (ULONG)(ULONG_PTR)(*phdevList);
  11917. HDEV *phdev = phdevList + 1;
  11918. for (ULONG i = 0; i < chdev; i++)
  11919. {
  11920. GreResumeDirectDraw(*phdev, FALSE);
  11921. phdev++;
  11922. }
  11923. if (bAlloc)
  11924. {
  11925. VFREEMEM(phdevList);
  11926. }
  11927. }
  11928. /***************************************************************************\
  11929. * DrvDisableDirectDrawForModeChange()
  11930. *
  11931. * 01-Aug-1998 hideyukn Created
  11932. \***************************************************************************/
  11933. HDEV *
  11934. DrvDisableDirectDrawForModeChange(
  11935. PMDEV pmdev1,
  11936. PMDEV pmdev2,
  11937. HDEV *phdevQuickList,
  11938. ULONG chdevQuickList
  11939. )
  11940. {
  11941. HDEV *phdevList, *phdev;
  11942. ULONG chdevList;
  11943. ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock),
  11944. "ShareDevlock must be held be before calling DisableDirectDraw");
  11945. chdevList = pmdev1->chdev + pmdev2->chdev + 2;
  11946. if (chdevQuickList >= chdevList)
  11947. {
  11948. phdevList = phdevQuickList;
  11949. }
  11950. else
  11951. {
  11952. phdevList = (HDEV *)PALLOCNOZ(chdevList * sizeof(HDEV), 'pmtG');
  11953. if (phdevList == NULL)
  11954. {
  11955. return (NULL);
  11956. }
  11957. }
  11958. phdev = phdevList + 1;
  11959. chdevList = 0;
  11960. if (pmdev1->hdevParent)
  11961. {
  11962. *phdev = pmdev1->hdevParent;
  11963. phdev++; chdevList++;
  11964. }
  11965. for (ULONG i = 0; i < pmdev1->chdev; i++)
  11966. {
  11967. *phdev = pmdev1->Dev[i].hdev;
  11968. phdev++; chdevList++;
  11969. }
  11970. if (pmdev2->hdevParent)
  11971. {
  11972. *phdev = pmdev2->hdevParent;
  11973. phdev++; chdevList++;
  11974. }
  11975. for (i = 0; i < pmdev2->chdev; i++)
  11976. {
  11977. *phdev = pmdev2->Dev[i].hdev;
  11978. phdev++; chdevList++;
  11979. }
  11980. *phdevList = (HDEV)ULongToPtr( chdevList );
  11981. for (i = 0; i < chdevList; i++)
  11982. {
  11983. PDEVOBJ pdo(phdevList[i+1]);
  11984. // Devlock must *not* be held.
  11985. pdo.vAssertNoDevLock();
  11986. GreSuspendDirectDrawEx(phdevList[i+1], DXG_SR_DDRAW_MODECHANGE);
  11987. }
  11988. return (phdevList);
  11989. }
  11990. //
  11991. // This function checks which Dualview Views will be attached. Then send a SWITCH_DUALVIEW
  11992. // notification to driver for setting of Video memory.
  11993. // It also checks if current DUALVIEW attachment state will be changed. The caller can decide
  11994. // if a PDEV can be reused or not.
  11995. //
  11996. // Return Value:
  11997. // DualviewNoSwitch: The DUALVIEW attachment state remains same
  11998. // DualviewSwitch: The DUALVIEW attachment state will be changed.
  11999. // DualviewFail: The DUALVIEW attachment state will be changed.
  12000. // And related PhysDisps have outstanding refcount and may get reused later
  12001. //
  12002. typedef enum _DUALVIEW_STATE {
  12003. DualviewNoSwitch = 0,
  12004. DualviewSwitch,
  12005. DualviewFail
  12006. } DUALVIEW_STATE;
  12007. DUALVIEW_STATE
  12008. CheckAndNotifyDualView(
  12009. PUNICODE_STRING pstrDeviceName,
  12010. PMDEV pMdevOrg,
  12011. MODE PreviousMode
  12012. )
  12013. {
  12014. PGRAPHICS_DEVICE PhysDisp;
  12015. ULONG bResetAll, bytesReturned;
  12016. ULONG primary, attach = 0;
  12017. ULONG numDualViews = 0, i, j;
  12018. BOOL bNoneToAttach = TRUE, bNoneAttached = TRUE;
  12019. BOOL bChangeDualviewState = FALSE, bHasOutstanding = FALSE;
  12020. DUALVIEW_STATE retVal;
  12021. typedef struct
  12022. {
  12023. PGRAPHICS_DEVICE PhysDisp;
  12024. ULONG Attached;
  12025. ULONG ToAttach;
  12026. } ATTACHPHYSDISP, *PATTACHPHYSDISP;
  12027. for (PhysDisp = gpGraphicsDeviceList;
  12028. PhysDisp != NULL;
  12029. PhysDisp = PhysDisp->pNextGraphicsDevice)
  12030. {
  12031. if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW)
  12032. {
  12033. numDualViews++;
  12034. }
  12035. }
  12036. if (numDualViews == 0)
  12037. return DualviewNoSwitch;
  12038. PATTACHPHYSDISP AttachPhysDisp = (PATTACHPHYSDISP) PALLOCMEM(sizeof(ATTACHPHYSDISP)*numDualViews, GDITAG_DRVSUP);
  12039. if (AttachPhysDisp == NULL)
  12040. return DualviewFail;
  12041. numDualViews = 0;
  12042. for (PhysDisp = gpGraphicsDeviceList;
  12043. PhysDisp != NULL;
  12044. PhysDisp = PhysDisp->pNextGraphicsDevice)
  12045. {
  12046. if (PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT))
  12047. {
  12048. continue;
  12049. }
  12050. if(!GetPrimaryAttachFlags(PhysDisp, &primary, &attach))
  12051. {
  12052. VFREEMEM(AttachPhysDisp);
  12053. return DualviewFail;
  12054. }
  12055. if (attach)
  12056. {
  12057. bNoneToAttach = FALSE;
  12058. }
  12059. if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW)
  12060. {
  12061. AttachPhysDisp[numDualViews].PhysDisp = PhysDisp;
  12062. AttachPhysDisp[numDualViews].ToAttach = (attach) ? 1 : 0;
  12063. //
  12064. // Check if the PhysDisp is already attached in pMdevOrg
  12065. //
  12066. AttachPhysDisp[numDualViews].Attached = 0;
  12067. if (pMdevOrg)
  12068. {
  12069. for (i = 0; i < pMdevOrg->chdev; i++)
  12070. {
  12071. PDEVOBJ po(pMdevOrg->Dev[i].hdev);
  12072. if ((po.ppdev->pGraphicsDevice) == PhysDisp)
  12073. {
  12074. AttachPhysDisp[numDualViews].Attached = 1;
  12075. bNoneAttached = FALSE;
  12076. }
  12077. }
  12078. }
  12079. numDualViews++;
  12080. }
  12081. }
  12082. //
  12083. // A little patch for Attach flag from Registry. If all of PhysDisp are NotAttach
  12084. // in registry, CreateMDEV will pick the first PhysDisp to Attach. It is a typical
  12085. // situation right after clean setup.
  12086. //
  12087. if (bNoneToAttach)
  12088. {
  12089. for (PhysDisp = gpGraphicsDeviceList;
  12090. PhysDisp != NULL;
  12091. PhysDisp = PhysDisp->pNextGraphicsDevice)
  12092. {
  12093. if (!(PhysDisp->stateFlags & (DISPLAY_DEVICE_MIRRORING_DRIVER | DISPLAY_DEVICE_DISCONNECT)))
  12094. {
  12095. if (PhysDisp->stateFlags & DISPLAY_DEVICE_DUALVIEW)
  12096. {
  12097. AttachPhysDisp[0].ToAttach = 1;
  12098. }
  12099. break;
  12100. }
  12101. }
  12102. }
  12103. if (!pstrDeviceName)
  12104. {
  12105. for (i = 0; i < numDualViews; i++)
  12106. {
  12107. if (AttachPhysDisp[i].Attached != AttachPhysDisp[i].ToAttach || pMdevOrg == NULL)
  12108. {
  12109. bChangeDualviewState = TRUE;
  12110. }
  12111. }
  12112. }
  12113. else
  12114. {
  12115. //
  12116. // Never allow ChangeDisplaySettings("\\.\DisplayX") to attach/detach one of Dualview
  12117. //
  12118. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
  12119. if (PhysDisp)
  12120. {
  12121. for (i = 0; i < numDualViews; i++)
  12122. {
  12123. if (PhysDisp == AttachPhysDisp[i].PhysDisp)
  12124. {
  12125. if (AttachPhysDisp[i].Attached != AttachPhysDisp[i].ToAttach || pMdevOrg == NULL)
  12126. {
  12127. bChangeDualviewState = TRUE;
  12128. bHasOutstanding = TRUE;
  12129. }
  12130. break;
  12131. }
  12132. }
  12133. }
  12134. }
  12135. if (bChangeDualviewState)
  12136. {
  12137. if (bHasOutstanding)
  12138. {
  12139. retVal = DualviewFail;
  12140. //
  12141. // If we cannot change mode due to Dualview, restore the original
  12142. // attch state in case of surprise mode change later. Since CPL
  12143. // won't restore te attach flag.
  12144. //
  12145. if (pMdevOrg)
  12146. {
  12147. for (i = 0; i < numDualViews; i++) {
  12148. DrvUpdateAttachFlag(PhysDisp, AttachPhysDisp[i].Attached);
  12149. }
  12150. }
  12151. }
  12152. else
  12153. {
  12154. retVal = DualviewSwitch;
  12155. //
  12156. // Send driver the Dualview state change notification
  12157. //
  12158. if (!pstrDeviceName)
  12159. {
  12160. for (i = 0; i < numDualViews; i++) {
  12161. GreDeviceIoControl(AttachPhysDisp[i].PhysDisp->pDeviceHandle,
  12162. IOCTL_VIDEO_SWITCH_DUALVIEW,
  12163. &(AttachPhysDisp[i].ToAttach),
  12164. sizeof(ULONG),
  12165. NULL,
  12166. 0,
  12167. &bytesReturned);
  12168. }
  12169. }
  12170. else
  12171. {
  12172. ASSERTGDI(FALSE, "Trying to attach/detach a view by ChangeDisplaySettings(DisplayX)\n");
  12173. }
  12174. }
  12175. }
  12176. else {
  12177. retVal = DualviewNoSwitch;
  12178. }
  12179. //
  12180. // After sending the notification, the the driver may change mode list internally.
  12181. // Force PhysDisp to update mode list here
  12182. //
  12183. for (i = 0; i < numDualViews; i++)
  12184. {
  12185. DrvBuildDevmodeList(AttachPhysDisp[i].PhysDisp, TRUE);
  12186. }
  12187. VFREEMEM(AttachPhysDisp);
  12188. return retVal;
  12189. }
  12190. /***************************************************************************\
  12191. * DrvChangeDisplaySettings
  12192. *
  12193. * Routines to change the settings of a display device.
  12194. *
  12195. * andreva Created
  12196. \***************************************************************************/
  12197. BOOL MulEnableDriver(ULONG,ULONG,PDRVENABLEDATA);
  12198. BOOL PanEnableDriver(ULONG,ULONG,PDRVENABLEDATA);
  12199. LONG
  12200. DrvChangeDisplaySettings(
  12201. PUNICODE_STRING pstrDeviceName,
  12202. HDEV hdevPrimary,
  12203. LPDEVMODEW lpDevMode,
  12204. PVOID pDesktopId,
  12205. MODE PreviousMode,
  12206. BOOL bUpdateRegistry,
  12207. BOOL bSetMode,
  12208. PMDEV pOrgMdev,
  12209. PMDEV *pNewMdev,
  12210. DWORD PruneFlag,
  12211. BOOL bTryClosest
  12212. )
  12213. {
  12214. GDIFunctionID(DrvChangeDisplaySettings);
  12215. PGRAPHICS_DEVICE PhysDisp = NULL;
  12216. UNICODE_STRING DeviceName;
  12217. PDEVMODEW pdevmodeInformation = NULL;
  12218. BOOL bDetach = FALSE;
  12219. LONG status = GRE_DISP_CHANGE_SUCCESSFUL;
  12220. ULONG defaultValue = 0;
  12221. ULONG disableAll;
  12222. ULONG i, j;
  12223. PMDEV pmdev;
  12224. BOOL bPrune = (PruneFlag != GRE_RAWMODE);
  12225. #if DBG
  12226. ULONG oldTrace;
  12227. #endif
  12228. RTL_QUERY_REGISTRY_TABLE QueryTable[] =
  12229. {
  12230. {NULL, RTL_QUERY_REGISTRY_DIRECT, L"DisableAll", &disableAll,
  12231. REG_DWORD, &defaultValue, 4},
  12232. {NULL, 0, NULL}
  12233. };
  12234. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Enter\n"));
  12235. *pNewMdev = NULL;
  12236. gbInvalidateDualView = FALSE;
  12237. //
  12238. // Let's find the device on which the operation must be performed.
  12239. //
  12240. if (pstrDeviceName)
  12241. {
  12242. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
  12243. if (PhysDisp == NULL)
  12244. {
  12245. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Device\n"));
  12246. return GRE_DISP_CHANGE_BADPARAM;
  12247. }
  12248. }
  12249. else
  12250. {
  12251. //
  12252. // If (NULL, NULL) is passed in, then we want to change the
  12253. // default desktop back to what it was ...
  12254. // Otherwise, for compatibility, (NULL, DEVMODE) affect only the
  12255. // primary device.
  12256. //
  12257. if (lpDevMode)
  12258. {
  12259. PDEVOBJ pdo(hdevPrimary);
  12260. if (pdo.bValid())
  12261. {
  12262. PhysDisp = pdo.ppdev->pGraphicsDevice;
  12263. }
  12264. if (PhysDisp == NULL)
  12265. {
  12266. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Device\n"));
  12267. return GRE_DISP_CHANGE_BADPARAM;
  12268. }
  12269. }
  12270. }
  12271. if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER)
  12272. {
  12273. ASSERTGDI(FALSE, "Trying to change settings for DDML layer\n");
  12274. return GRE_DISP_CHANGE_BADPARAM;
  12275. }
  12276. if (PhysDisp != NULL)
  12277. {
  12278. if (PruneFlag == GRE_DEFAULT)
  12279. bPrune = DrvGetPruneFlag(PhysDisp);
  12280. RtlInitUnicodeString(&DeviceName, PhysDisp->szWinDeviceName);
  12281. pstrDeviceName = &DeviceName;
  12282. if (lpDevMode != NULL)
  12283. {
  12284. #if DBG
  12285. //
  12286. // less debug output for DirectDraw :
  12287. //
  12288. oldTrace = GreTraceDisplayDriverLoad;
  12289. if (!bUpdateRegistry && !bSetMode) {
  12290. GreTraceDisplayDriverLoad &= 0xFFFFFFF0;
  12291. }
  12292. #endif
  12293. //
  12294. // Get the new DEVMODE.
  12295. //
  12296. if (!NT_SUCCESS(DrvProbeAndCaptureDevmode(PhysDisp,
  12297. &pdevmodeInformation,
  12298. &bDetach,
  12299. lpDevMode,
  12300. FALSE,
  12301. PreviousMode,
  12302. bPrune,
  12303. bTryClosest,
  12304. FALSE)))
  12305. {
  12306. if (pdevmodeInformation)
  12307. {
  12308. VFREEMEM(pdevmodeInformation);
  12309. }
  12310. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - Bad Devmode\n"));
  12311. return GRE_DISP_CHANGE_BADMODE;
  12312. }
  12313. if (lpDevMode->dmFields == 0)
  12314. bTryClosest = TRUE;
  12315. #if DBG
  12316. GreTraceDisplayDriverLoad = oldTrace;
  12317. #endif
  12318. }
  12319. else{ // For registry settings, always use closest
  12320. bTryClosest = TRUE;
  12321. }
  12322. }
  12323. //
  12324. // At this point we have validated all data.
  12325. // So if the user just tested the mode, the call would now be successful
  12326. //
  12327. // Let's see if we actually need to do something with this mode.
  12328. //
  12329. //
  12330. // Write the data to the registry.
  12331. //
  12332. // This is not supported for the vgacompatible device - so it should just fail.
  12333. //
  12334. if (bUpdateRegistry && (PhysDisp != NULL) && (lpDevMode != NULL) && (gProtocolType == PROTOCOL_CONSOLE))
  12335. {
  12336. //
  12337. // Check if the Administrator has disabled this privilege.
  12338. // It is on by default.
  12339. //
  12340. disableAll = 0;
  12341. RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
  12342. L"GraphicsDrivers\\PermanentSettingChanges",
  12343. &QueryTable[0],
  12344. NULL,
  12345. NULL);
  12346. if (disableAll)
  12347. {
  12348. status = GRE_DISP_CHANGE_NOTUPDATED;
  12349. }
  12350. else
  12351. {
  12352. NTSTATUS retStatus = DrvUpdateDisplayDriverParameters(PhysDisp, pdevmodeInformation, bDetach, TRUE);
  12353. if (!NT_SUCCESS(retStatus))
  12354. {
  12355. status = GRE_DISP_CHANGE_BADMODE;
  12356. if (retStatus == STATUS_INVALID_PARAMETER_4)
  12357. {
  12358. status = GRE_DISP_CHANGE_BADPARAM;
  12359. }
  12360. }
  12361. }
  12362. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Save Params status %d\n", status));
  12363. }
  12364. //
  12365. // Set the mode dynamically
  12366. //
  12367. if (bSetMode && (status == GRE_DISP_CHANGE_SUCCESSFUL))
  12368. {
  12369. ASSERTGDI(pOrgMdev == NULL || DrvQueryMDEVPowerState(pOrgMdev),
  12370. "DrvChangeDisplaySettings called with powered off MDEV.\n");
  12371. #if MDEV_STACK_TRACE_LENGTH
  12372. LONG lMDEVTraceEntry, lMDEVTraceEntryNext;
  12373. ULONG StackEntries, UserStackEntry;
  12374. do
  12375. {
  12376. lMDEVTraceEntry = glMDEVTrace;
  12377. lMDEVTraceEntryNext = lMDEVTraceEntry + 1;
  12378. if (lMDEVTraceEntryNext >= gcMDEVTraceLength) lMDEVTraceEntryNext = 0;
  12379. } while (InterlockedCompareExchange(&glMDEVTrace, lMDEVTraceEntryNext, lMDEVTraceEntry) != lMDEVTraceEntry);
  12380. RtlZeroMemory(&gMDEVTrace[lMDEVTraceEntry],
  12381. sizeof(gMDEVTrace[lMDEVTraceEntry]));
  12382. gMDEVTrace[lMDEVTraceEntry].pMDEV = pOrgMdev;
  12383. gMDEVTrace[lMDEVTraceEntry].API = DrvChangeDisplaySettings_SetMode;
  12384. StackEntries = sizeof(gMDEVTrace[lMDEVTraceEntry].Trace)/sizeof(gMDEVTrace[lMDEVTraceEntry].Trace[0]);
  12385. UserStackEntry = RtlWalkFrameChain((PVOID *)gMDEVTrace[lMDEVTraceEntry].Trace,
  12386. StackEntries,
  12387. 0);
  12388. StackEntries -= UserStackEntry;
  12389. RtlWalkFrameChain((PVOID *)&gMDEVTrace[lMDEVTraceEntry].Trace[UserStackEntry],
  12390. StackEntries,
  12391. 1);
  12392. #endif
  12393. //
  12394. // First things first, acquire share dev lock. This must
  12395. // be acquired before any other dev locks are acquired.
  12396. //
  12397. GreAcquireSemaphoreEx(ghsemShareDevLock, SEMORDER_SHAREDEVLOCK, NULL);
  12398. CModeChangeInProgress mcip;
  12399. //
  12400. // Check if there are restrictions on changing the resolution
  12401. // dymanically
  12402. // Restriction don't apply for booting the machine though ...
  12403. //
  12404. pmdev = NULL;
  12405. status = GRE_DISP_CHANGE_FAILED;
  12406. disableAll = 0;
  12407. RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
  12408. L"GraphicsDrivers\\TemporarySettingChanges",
  12409. &QueryTable[0],
  12410. NULL,
  12411. NULL);
  12412. if ((disableAll == 0) || (pOrgMdev == NULL))
  12413. {
  12414. //
  12415. // Lets create a new MDEV
  12416. //
  12417. if (pOrgMdev)
  12418. {
  12419. PDEVOBJ pdoTmp(pOrgMdev->hdevParent);
  12420. ASSERTGDI(pdoTmp.cPdevRefs() > 10,
  12421. "curent MDEV is not the main one !\n");
  12422. //
  12423. // Dualview preprocess. We probe the registry first to see if
  12424. // the second view is about to be attached. The we notify the miniport
  12425. // before the first PDEV is created.
  12426. //
  12427. // If DUALVIEW attachment state changes, all PDEVs has to be regenerated.
  12428. // Even a PDEV with same settings cannot be reused.
  12429. //
  12430. // However, if there is D3D running, a PDEV cannot be simply regenerated
  12431. // due to ALT-TAB feature (a PDEV has an extra refcount for D3D apps). We
  12432. // cannot do anything but fail
  12433. //
  12434. switch (CheckAndNotifyDualView(pstrDeviceName, pOrgMdev, PreviousMode))
  12435. {
  12436. case DualviewNoSwitch:
  12437. gbInvalidateDualView = FALSE;
  12438. break;
  12439. case DualviewSwitch:
  12440. gbInvalidateDualView = TRUE;
  12441. bTryClosest = TRUE;
  12442. break;
  12443. default:
  12444. mcip.vDone();
  12445. GreReleaseSemaphoreEx(ghsemShareDevLock);
  12446. return GRE_DISP_CHANGE_BADDUALVIEW;
  12447. }
  12448. //
  12449. // Disable current MDEV.
  12450. //
  12451. // FALSE here, means ONLY meta PDEV will be disabled in
  12452. // multi monitor case. And hardware will not be disabled
  12453. // in single monitor cases.
  12454. //
  12455. if (DrvDisableMDEV(pOrgMdev, FALSE))
  12456. {
  12457. //
  12458. // Create new MDEV
  12459. //
  12460. // If we will create new HDEV which device is used
  12461. // in current (= old) MDEV. HDEV in old MDEV will
  12462. // be disabled, and stored in MDEV.Dev[x].Reserved
  12463. // for recover current config in error case later.
  12464. //
  12465. pmdev = DrvCreateMDEV(pstrDeviceName,
  12466. pdevmodeInformation,
  12467. pDesktopId,
  12468. 0,
  12469. pOrgMdev,
  12470. KernelMode,
  12471. PruneFlag,
  12472. bTryClosest);
  12473. if (!pmdev)
  12474. {
  12475. // At this point, we have failed to create MDEV based on
  12476. // new configuration, so status continue to keep
  12477. // GRE_DISP_CHANGE_FAILED. And re-enable original MDEV.
  12478. //
  12479. DrvEnableMDEV(pOrgMdev, FALSE);
  12480. }
  12481. else
  12482. {
  12483. //
  12484. // At this point, we have all the hdevs involved in the
  12485. // switch.
  12486. //
  12487. // On entering this functions
  12488. // pOrgMdev - list of original hdevs
  12489. // pmdev - list of new hdevs
  12490. // reserved fields have the hdevs that were disabled
  12491. //
  12492. // On exit
  12493. // pmdev - list of old (permanent) and new hdevs for user
  12494. // pOrgMdev - unused
  12495. //
  12496. status = GRE_DISP_CHANGE_NO_CHANGE;
  12497. //
  12498. // Determine if anything changed in the two structures
  12499. //
  12500. if (pmdev->chdev != pOrgMdev->chdev)
  12501. {
  12502. status = GRE_DISP_CHANGE_SUCCESSFUL;
  12503. }
  12504. else
  12505. {
  12506. for (i=0 ; i <pmdev->chdev; i++)
  12507. {
  12508. if ((pmdev->Dev[i].hdev != pOrgMdev->Dev[i].hdev) ||
  12509. (!RtlEqualMemory(&(pmdev->Dev[i].rect),
  12510. &(pOrgMdev->Dev[i].rect),
  12511. sizeof(RECT))))
  12512. {
  12513. status = GRE_DISP_CHANGE_SUCCESSFUL;
  12514. }
  12515. }
  12516. }
  12517. }
  12518. }
  12519. }
  12520. else
  12521. {
  12522. TRACE_INIT(("DrvChangeDisplaySettings - no original MDEV, create one\n"));
  12523. //
  12524. // Dualview preprocess.
  12525. //
  12526. CheckAndNotifyDualView(pstrDeviceName, NULL, PreviousMode);
  12527. gbInvalidateDualView = TRUE;
  12528. pmdev = DrvCreateMDEV(pstrDeviceName,
  12529. pdevmodeInformation,
  12530. pDesktopId,
  12531. 0,
  12532. NULL,
  12533. KernelMode,
  12534. PruneFlag,
  12535. bTryClosest);
  12536. if (pmdev)
  12537. {
  12538. status = GRE_DISP_CHANGE_SUCCESSFUL;
  12539. }
  12540. }
  12541. }
  12542. *pNewMdev = pmdev;
  12543. //
  12544. // If everything worked, but the two structures are not identical, do
  12545. // the switching around.
  12546. //
  12547. // Handle the four seperate case :
  12548. // 1-1, 1-many, many-1 and many-many
  12549. //
  12550. BOOL bSwitchError = FALSE;
  12551. HDEV hdevTmp;
  12552. HDEV hdevClone = NULL;
  12553. HDEV hdevCloned = NULL;
  12554. BOOL bSwitchParentAndChild = FALSE;
  12555. BOOL bEnableClone = FALSE;
  12556. if (status == GRE_DISP_CHANGE_SUCCESSFUL)
  12557. {
  12558. ULONG iClonehdev = 0;
  12559. HDEV *phdevDDLock = NULL;
  12560. HDEV ahdevDDLockQuick[7];
  12561. MULTIDEVLOCKOBJ mdloMdev;
  12562. MULTIDEVLOCKOBJ mdloOrgMdev;
  12563. HSEMAPHORE hsemCloneHdevDevLock = NULL;
  12564. HSEMAPHORE hsemOrgMdevDevLock = NULL;
  12565. HSEMAPHORE hsemOrgMdevPointer = NULL;
  12566. if (pOrgMdev)
  12567. {
  12568. BOOL bLockSemaphore = FALSE;
  12569. //
  12570. // Disable DirectDraw on both MDEV's. This must be done
  12571. // before we acquire the Devlock.
  12572. //
  12573. phdevDDLock = DrvDisableDirectDrawForModeChange(
  12574. pOrgMdev,pmdev,
  12575. (HDEV *)ahdevDDLockQuick,
  12576. sizeof(ahdevDDLockQuick)/sizeof(HDEV));
  12577. if (phdevDDLock == NULL)
  12578. {
  12579. bSwitchError = TRUE;
  12580. }
  12581. else
  12582. {
  12583. //
  12584. // The following lock rules must be abided, otherwise deadlocks may
  12585. // arise:
  12586. //
  12587. // o DevLock must be acquired after the ShareDevLock
  12588. // o Pointer lock must be acquired after Devlock (GreSetPointer);
  12589. // o RFont list lock must be acquired after Devlock (TextOut);
  12590. // o Handle manager lock must be acquired after Devlock (old
  12591. // CvtDFB2DIB);
  12592. // o Handle manager lock must be acquired after Palette Semaphore
  12593. // (GreSetPaletteEntries)
  12594. // o Palette Semaphore must be acquired after Devlock (BitBlt)
  12595. // o Palette Semaphore must be acquired after driver semaphore
  12596. // (bDeletePalette)
  12597. //
  12598. // So we acquire locks in the following order (note that the
  12599. // vAssertDynaLock() routines should be modified if this list ever
  12600. // changes):
  12601. //
  12602. //
  12603. // At this point, we have *not* ssyned devlock for new MDEV, yet,
  12604. // so lock all children. During the mode change. we don't want to
  12605. // anything change in its children.
  12606. //
  12607. mdloOrgMdev.vInit(pOrgMdev);
  12608. mdloMdev.vInit(pmdev);
  12609. if (mdloMdev.bValid() && mdloOrgMdev.bValid())
  12610. {
  12611. PDEVOBJ pdoTmp;
  12612. pdoTmp.vInit(pOrgMdev->hdevParent);
  12613. hsemOrgMdevDevLock = pdoTmp.hsemDevLock();
  12614. hsemOrgMdevPointer = pdoTmp.hsemPointer();
  12615. //
  12616. // Lock the parent of MDEV.
  12617. //
  12618. GreAcquireSemaphoreEx(hsemOrgMdevDevLock, SEMORDER_DEVLOCK, NULL);
  12619. //
  12620. // Lock the pointer in old mdev's parent.
  12621. //
  12622. GreAcquireSemaphoreEx(hsemOrgMdevPointer, SEMORDER_POINTER, hsemOrgMdevDevLock);
  12623. //
  12624. // Lock the children in MDEVs
  12625. //
  12626. mdloOrgMdev.vLock(); // No drawing to any dynamic surfaces
  12627. mdloMdev.vLock(); // No drawing to any dynamic surfaces
  12628. // WinBug #301042 3-1-2001 jasonha
  12629. // GDI: SPRITESTATE duplicated and inconsistent when cloning
  12630. // When cloning is used two PDEV (and therefore two SPRITESTATEs)
  12631. // try to manage the same display (psoScreen). Hooking one
  12632. // while 'Inside' the other will confuse the state. Hooking
  12633. // will only change if there are visible sprites; so we
  12634. // will temporarily hide them all. Later we will unhide all
  12635. // sprites on the whichever MDEV will remain active.
  12636. //
  12637. // Hide all sprites
  12638. //
  12639. vSpHideSprites(pOrgMdev->hdevParent, TRUE);
  12640. //
  12641. // Fixup new and old MDEVs.
  12642. //
  12643. if ((pmdev->chdev == 1) && (pOrgMdev->chdev != 1))
  12644. {
  12645. //
  12646. // Many to 1
  12647. //
  12648. for (i=0 ; i <pOrgMdev->chdev; i++)
  12649. {
  12650. if (pOrgMdev->Dev[i].hdev == pmdev->Dev[0].hdev)
  12651. {
  12652. TRACE_INIT(("DrvChangeDisplaySettings: creating clone\n"));
  12653. //
  12654. // DrvCreateCloneHDEV will creates exactly same HDEV with
  12655. // different handle.
  12656. //
  12657. hdevClone = DrvCreateCloneHDEV(
  12658. pmdev->Dev[0].hdev,
  12659. DRV_CLONE_DEREFERENCE_ORG);
  12660. if (hdevClone)
  12661. {
  12662. //
  12663. // Replace the hdev with clone, and save original
  12664. // into reserved fields for later to back out
  12665. // mode change if error happens.
  12666. //
  12667. pOrgMdev->Dev[i].hdev = hdevClone;
  12668. pOrgMdev->Dev[i].Reserved = pmdev->Dev[0].hdev;
  12669. hdevCloned = pmdev->Dev[0].hdev;
  12670. iClonehdev = i;
  12671. }
  12672. else
  12673. {
  12674. bSwitchError = TRUE;
  12675. }
  12676. //
  12677. // Shouldn't be another same HDEV in MDEV,
  12678. // so, just go out loop here...
  12679. //
  12680. break;
  12681. }
  12682. }
  12683. }
  12684. else if ((pmdev->chdev != 1) && (pOrgMdev->chdev == 1))
  12685. {
  12686. //
  12687. // 1 to Many
  12688. //
  12689. //
  12690. // [Case 1] - Attach new monitor, and some change has been made on existing
  12691. //
  12692. // At this case, new MDEV will everything new HDEV, like...
  12693. //
  12694. // Org MDEV - ATI: 800x600 8bpp (HDEV is A)
  12695. //
  12696. // New MDEV - ATI: 1024x768 24bpp (HDEV is B)
  12697. // MGA: 1024x768 32bpp (HDEV is C)
  12698. // Parent: Created based on B and C (HDEV is D)
  12699. // then,
  12700. //
  12701. // 1) mode change between "A" and "D".
  12702. // 2) flip handle (set "A" to where "D" is, and set "D" to where "A" is).
  12703. //
  12704. // So that finally "A" becomes a parent of "B" and "C". then delete "D".
  12705. //
  12706. // [Case 2] - Attach new monitor.
  12707. //
  12708. // At this case, new MDEV will contains previous HDEV, since original
  12709. // monitor is nothing changed, so it looks like...
  12710. //
  12711. // Org MDEV - ATI: 1024x768 24bpp (HDEV is A)
  12712. //
  12713. // New MDEV - ATI: 1024x768 24bpp (HDEV is A)
  12714. // MGA: 1024x768 32bpp (HDEV is C)
  12715. // Parent: Created based on A and C (HDEV is D)
  12716. //
  12717. // In this case, we can *not* mode change, because if we do mode
  12718. // change between "A" and "D", then we flip the handle, "A"
  12719. // becomes a parent of "A" and "C" (since when we create "D", it
  12720. // children are "A" and "C". when we create parent, parent can know
  12721. // and cache into thier local, who is thier children.
  12722. // (see Multi.cxx MulEnablePDEV()) "A" can not be a parent of "A".
  12723. //
  12724. // Thus, how we do there is just create a clone (= "B") of "A", and replace
  12725. // "A" with "B" in new MDEV, so new MDEV will be like,
  12726. //
  12727. // New MDEV - ATI: 1024x768 24bpp (HDEV is B) (clone of A)
  12728. // MGA: 1024x768 32bpp (HDEV is C)
  12729. // Parent: Created based on B and C (HDEV is D)
  12730. //
  12731. // Of course we can do notify to parent driver to one of thier
  12732. // child "A" is replaced with "D" and do same for new MDEV, to
  12733. // avoid to create clone. But it too complex to re-initialized
  12734. // parent "A" based on "D" and "C", and what-else will problem later on.
  12735. // So here we just create a clone, so that we can take a same
  12736. // code path as 1) except create a clone, here.
  12737. //
  12738. // Then, (actually here is same as case 1)
  12739. //
  12740. // 1) mode change between "A" and "D".
  12741. // 2) flip handle (set "A" to where "D" is, and set "D" to where "A" is).
  12742. //
  12743. // So that finally "A" becomes a parent of "B" and "C". then delete "D".
  12744. //
  12745. //
  12746. // Do we have any re-used original HDEV in new MDEV ?
  12747. //
  12748. for (i=0 ; i <pmdev->chdev; i++)
  12749. {
  12750. if (pmdev->Dev[i].hdev == pOrgMdev->Dev[0].hdev)
  12751. {
  12752. TRACE_INIT(("DrvChangeDisplaySettings: creating clone\n"));
  12753. //
  12754. // DrvCreateCloneHDEV will creates exactly same HDEV with
  12755. // different handle.
  12756. //
  12757. hdevClone = DrvCreateCloneHDEV(
  12758. pOrgMdev->Dev[0].hdev,
  12759. DRV_CLONE_DEREFERENCE_ORG);
  12760. if (hdevClone)
  12761. {
  12762. //
  12763. // Replace the hdev with clone, and save original
  12764. // into reserved fields for later to back out
  12765. // mode change if error happens.
  12766. //
  12767. pmdev->Dev[i].hdev = hdevClone;
  12768. pmdev->Dev[i].Reserved = pOrgMdev->Dev[0].hdev;
  12769. hdevCloned = pOrgMdev->Dev[0].hdev;
  12770. //
  12771. // Later we need copy data to Clone from Cloned.
  12772. //
  12773. bEnableClone = TRUE;
  12774. }
  12775. else
  12776. {
  12777. bSwitchError = TRUE;
  12778. }
  12779. //
  12780. // Shouldn't be another same HDEV in MDEV,
  12781. // so, just go out loop here...
  12782. //
  12783. break;
  12784. }
  12785. }
  12786. if (bSwitchError == FALSE)
  12787. {
  12788. //
  12789. // We will switch between parent and children
  12790. //
  12791. bSwitchParentAndChild = TRUE;
  12792. }
  12793. }
  12794. else
  12795. {
  12796. //
  12797. // 1 to 1, Many to Many
  12798. //
  12799. }
  12800. if (hdevClone)
  12801. {
  12802. pdoTmp.vInit(hdevClone);
  12803. hsemCloneHdevDevLock = pdoTmp.hsemDevLock();
  12804. //
  12805. // If we creates any clone device, hold devlock here.
  12806. //
  12807. GreAcquireSemaphoreEx(hsemCloneHdevDevLock, SEMORDER_DEVLOCK, NULL);
  12808. }
  12809. if (bSwitchError == FALSE)
  12810. {
  12811. //
  12812. // Lock rest of semaphores which we should hold during mode change.
  12813. //
  12814. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL); // No driver loading/unloading
  12815. GreAcquireSemaphoreEx(ghsemPalette, SEMORDER_DRIVERMGMT, NULL); // No SaveDC/RestoreDC
  12816. GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL); // Nobody else uses the font table
  12817. GreAcquireSemaphoreEx(ghsemRFONTList, SEMORDER_RFONTLIST, NULL); // Nobody else uses the RFONT list
  12818. //
  12819. // Lock handle manager to prevent new handle being created, or
  12820. // deleting existing handle. so that we can safely walk through
  12821. // handle manager list.
  12822. //
  12823. GreAcquireHmgrSemaphore();
  12824. bLockSemaphore = TRUE;
  12825. }
  12826. }
  12827. else
  12828. {
  12829. bSwitchError = TRUE;
  12830. }
  12831. }
  12832. if (bSwitchError == FALSE)
  12833. {
  12834. ASSERTGDI(bLockSemaphore == TRUE,
  12835. "DrvChangeDisplaySettings(): Semaphores is not locked\n");
  12836. //
  12837. // Do the mode change for children device.
  12838. //
  12839. if (pmdev->chdev == 1)
  12840. {
  12841. if (pOrgMdev->chdev == 1)
  12842. {
  12843. //
  12844. // 1 to 1
  12845. //
  12846. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change 1 -> 1.\n"));
  12847. if (bDynamicModeChange(pOrgMdev->Dev[0].hdev,
  12848. pmdev->Dev[0].hdev) == TRUE)
  12849. {
  12850. hdevTmp = pOrgMdev->Dev[0].hdev;
  12851. pOrgMdev->Dev[0].hdev = pmdev->Dev[0].hdev;
  12852. pmdev->Dev[0].hdev = hdevTmp;
  12853. }
  12854. else
  12855. {
  12856. // Error occured
  12857. bSwitchError = TRUE;
  12858. }
  12859. }
  12860. else
  12861. {
  12862. //
  12863. // Many to 1
  12864. //
  12865. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change Many -> 1.\n"));
  12866. if (bSwitchError == FALSE)
  12867. {
  12868. #ifdef DONT_CHECKIN
  12869. if (hdevClone)
  12870. {
  12871. //
  12872. // Transfer DC_TYPE objects to clone.
  12873. //
  12874. DrvTransferGdiObjects(pOrgMdev->Dev[iClonehdev].hdev,
  12875. pmdev->Dev[0].hdev,
  12876. DRV_TRANS_DC_TYPE |
  12877. DRV_TRANS_TO_CLONE);
  12878. }
  12879. #endif
  12880. if (bDynamicModeChange(pOrgMdev->hdevParent,
  12881. pmdev->Dev[0].hdev) == TRUE)
  12882. {
  12883. hdevTmp = pOrgMdev->hdevParent;
  12884. pOrgMdev->hdevParent = pmdev->Dev[0].hdev;
  12885. pmdev->Dev[0].hdev = hdevTmp;
  12886. if (hdevClone)
  12887. {
  12888. hdevCloned = hdevTmp;
  12889. #ifdef DONT_CHECKIN
  12890. //
  12891. // Transfer back DC_TYPE objects in clone to original.
  12892. //
  12893. DrvTransferGdiObjects(pmdev->Dev[0].hdev,
  12894. pOrgMdev->Dev[iClonehdev].hdev,
  12895. DRV_TRANS_DC_TYPE);
  12896. #endif
  12897. }
  12898. }
  12899. else
  12900. {
  12901. // Error occured
  12902. bSwitchError = TRUE;
  12903. }
  12904. }
  12905. }
  12906. }
  12907. else
  12908. {
  12909. if (pOrgMdev->chdev == 1)
  12910. {
  12911. //
  12912. // 1 to Many
  12913. //
  12914. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change 1 -> Many.\n"));
  12915. }
  12916. else
  12917. {
  12918. //
  12919. // Many to Many
  12920. //
  12921. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Mode Change Many -> Many.\n"));
  12922. for (i=0 ; i <pmdev->chdev; i++)
  12923. {
  12924. PDEVOBJ pdo1(pmdev->Dev[i].hdev);
  12925. for (j=0 ; j <pOrgMdev->chdev; j++)
  12926. {
  12927. PDEVOBJ pdo2(pOrgMdev->Dev[j].hdev);
  12928. if (pdo1.ppdev->pGraphicsDevice == pdo2.ppdev->pGraphicsDevice)
  12929. {
  12930. if (pmdev->Dev[i].hdev == pOrgMdev->Dev[j].hdev)
  12931. {
  12932. // Same hdev, nothing need to do.
  12933. }
  12934. else if (bDynamicModeChange(pOrgMdev->Dev[j].hdev,
  12935. pmdev->Dev[i].hdev) == TRUE)
  12936. {
  12937. hdevTmp = pOrgMdev->Dev[j].hdev;
  12938. pOrgMdev->Dev[j].hdev = pmdev->Dev[i].hdev;
  12939. pmdev->Dev[i].hdev = hdevTmp;
  12940. }
  12941. else
  12942. {
  12943. // Error occured
  12944. bSwitchError = TRUE;
  12945. }
  12946. break;
  12947. }
  12948. }
  12949. }
  12950. }
  12951. }
  12952. //
  12953. // Release handle manager lock.
  12954. //
  12955. GreReleaseHmgrSemaphore();
  12956. //
  12957. // Now, we are finished all mode changes for parent and children
  12958. // so we are safe to unlock it.
  12959. //
  12960. GreReleaseSemaphoreEx(ghsemRFONTList);
  12961. GreReleaseSemaphoreEx(ghsemPublicPFT);
  12962. GreReleaseSemaphoreEx(ghsemPalette);
  12963. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  12964. //
  12965. // Mark as unlocked.
  12966. //
  12967. bLockSemaphore = FALSE;
  12968. }
  12969. }
  12970. //
  12971. // If we need to create a new parent and do a switch, now is
  12972. // the time.
  12973. //
  12974. if (bSwitchError == FALSE)
  12975. {
  12976. //
  12977. // Setup the parent hdev for old MDEV (if old MDEV is provided).
  12978. //
  12979. if (pOrgMdev)
  12980. {
  12981. if (pOrgMdev->chdev == 1)
  12982. {
  12983. //
  12984. // 1 to 1, 1 to Many.
  12985. //
  12986. pOrgMdev->hdevParent = pOrgMdev->Dev[0].hdev;
  12987. pOrgMdev->Reserved = pOrgMdev->Dev[0].Reserved; // actually not nessesary...
  12988. }
  12989. else
  12990. {
  12991. //
  12992. // Many to 1, Many to Many.
  12993. //
  12994. }
  12995. }
  12996. //
  12997. // Setup the parent hdev for new MDEV.
  12998. //
  12999. if (pmdev->chdev == 1)
  13000. {
  13001. //
  13002. // 1 to 1, Many to 1.
  13003. //
  13004. TRACE_INIT(("Drv_Trace: DrvCompleteMDEV: Single Device\n"));
  13005. pmdev->hdevParent = pmdev->Dev[0].hdev;
  13006. pmdev->Reserved = pmdev->Dev[0].Reserved;
  13007. }
  13008. else
  13009. {
  13010. //
  13011. // 1 to Many, Many to Many.
  13012. //
  13013. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings: Create new Parent MDEV (Many/1 -> Many)\n"));
  13014. //
  13015. // If we have more than one device that is attached to the
  13016. // desktop, then we need to create the META structure for
  13017. // that device, initialize it, and use that as the primary
  13018. // device.
  13019. //
  13020. DRV_NAMES drvName;
  13021. HDEV hdevDisabled;
  13022. TRACE_INIT(("Drv_Trace: DrvCompleteMDEV: Create HMDEV\n"));
  13023. drvName.cNames = 1;
  13024. drvName.D[0].hDriver = NULL;
  13025. drvName.D[0].lpDisplayName = (LPWSTR)MulEnableDriver;
  13026. pmdev->hdevParent = hCreateHDEV((PGRAPHICS_DEVICE) DDML_DRIVER,
  13027. &drvName,
  13028. ((PDEVMODEW)(pmdev)),
  13029. pmdev->pDesktopId,
  13030. DRIVER_CAPABLE_ALL,
  13031. DRIVER_ACCELERATIONS_FULL,
  13032. TRUE, // ignored in this case
  13033. GCH_DDML,
  13034. &hdevDisabled);
  13035. if (!pmdev->hdevParent)
  13036. {
  13037. RIP("Drv_Trace: DrvCompleteMDEV: DDML failed");
  13038. bSwitchError = TRUE;
  13039. }
  13040. else
  13041. {
  13042. if (pOrgMdev != NULL)
  13043. {
  13044. PDEVOBJ pdoParent(pmdev->hdevParent);
  13045. HSEMAPHORE hsemParentDevLock = pdoParent.hsemDevLock();
  13046. //
  13047. // During the mode change devlock should be hold for parent
  13048. //
  13049. GreAcquireSemaphoreEx(hsemParentDevLock, SEMORDER_DEVLOCK, NULL);
  13050. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  13051. GreAcquireSemaphoreEx(ghsemPalette, SEMORDER_PALETTE, NULL);
  13052. GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL); // Nobody else uses the font table
  13053. GreAcquireSemaphoreEx(ghsemRFONTList, SEMORDER_RFONTLIST, NULL);
  13054. GreAcquireHmgrSemaphore();
  13055. if (bSwitchParentAndChild)
  13056. {
  13057. //
  13058. // Mode change between new parent (meta) HDEV and
  13059. // old HDEV, so that old HDEV becomes new parent
  13060. // (meta) HDEV which has children.
  13061. //
  13062. if (bDynamicModeChange(pOrgMdev->Dev[0].hdev,
  13063. pmdev->hdevParent) == TRUE)
  13064. {
  13065. hdevTmp = pmdev->hdevParent;
  13066. pmdev->hdevParent = pOrgMdev->Dev[0].hdev;
  13067. pOrgMdev->hdevParent = hdevTmp;
  13068. pOrgMdev->Dev[0].hdev = hdevTmp;
  13069. if (hdevClone)
  13070. {
  13071. hdevCloned = hdevTmp;
  13072. }
  13073. }
  13074. else
  13075. {
  13076. // Error occured
  13077. bSwitchError = TRUE;
  13078. }
  13079. }
  13080. else
  13081. {
  13082. //
  13083. // Switch the mode between parents (DDML).
  13084. //
  13085. if (bDynamicModeChange(pOrgMdev->hdevParent,
  13086. pmdev->hdevParent) == TRUE)
  13087. {
  13088. hdevTmp = pOrgMdev->hdevParent;
  13089. pOrgMdev->hdevParent = pmdev->hdevParent;
  13090. pmdev->hdevParent = hdevTmp;
  13091. }
  13092. else
  13093. {
  13094. // Error occured
  13095. bSwitchError = TRUE;
  13096. }
  13097. }
  13098. //
  13099. // Release semaphores.
  13100. //
  13101. GreReleaseHmgrSemaphore();
  13102. GreReleaseSemaphoreEx(ghsemRFONTList);
  13103. GreReleaseSemaphoreEx(ghsemPublicPFT); // Nobody else uses the font table
  13104. GreReleaseSemaphoreEx(ghsemPalette);
  13105. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  13106. GreReleaseSemaphoreEx(hsemParentDevLock);
  13107. }
  13108. }
  13109. }
  13110. }
  13111. //
  13112. // Below code is only for mode change case.
  13113. //
  13114. if (pOrgMdev)
  13115. {
  13116. //
  13117. // Finalize clone hdev stuff (if created)
  13118. //
  13119. if ((bSwitchError == FALSE) && hdevClone && hdevCloned)
  13120. {
  13121. PDEV *pdevNew = (PDEV *) hdevClone;
  13122. PDEV *pdevOld = (PDEV *) hdevCloned;
  13123. PDEVOBJ pdoNew(hdevClone);
  13124. PDEVOBJ pdoOld(hdevCloned);
  13125. ASSERTGDI(pdevOld->pSurface != NULL,
  13126. "DrvChangeDisplaySettings():Original has null surface\n");
  13127. ASSERTGDI(pdevNew->pSurface == pdevOld->pSurface,
  13128. "DrvChangeDisplaySettings():Clone has wrong surface\n");
  13129. ASSERTGDI(pdevNew->dhpdev == pdevOld->dhpdev,
  13130. "DrvChangeDisplaySettings():Clone has wrong dhpdev\n");
  13131. ASSERTGDI(!pdoOld.bCloneDriver(),
  13132. "DrvChangeDisplaySettings():Original should not marked as clone\n");
  13133. ASSERTGDI(pdoNew.bCloneDriver(),
  13134. "DrvChangeDisplaySettings():Clone should have marked as clone\n");
  13135. ASSERTGDI(pdevOld->pGraphicsDevice == pdevNew->pGraphicsDevice,
  13136. "DrvChangeDisplaySettings():Clone should have same graphics device\n");
  13137. if (bEnableClone)
  13138. {
  13139. //
  13140. // Inform the driver that the PDEV is complete.
  13141. //
  13142. TRACE_INIT(("DrvChangeDisplaySettings(): Enabling clone pdev\n"));
  13143. //
  13144. // Transfer device surface to clone from cloned PDEV.
  13145. //
  13146. pdevNew->pSurface = pdevOld->pSurface;
  13147. //
  13148. // Set new hdev into surface.
  13149. //
  13150. if (pdevNew->pSurface)
  13151. {
  13152. pdevNew->pSurface->hdev(pdoNew.hdev());
  13153. }
  13154. //
  13155. // Transsfer dhpdev from cloned to clone
  13156. //
  13157. pdevNew->dhpdev = pdevOld->dhpdev;
  13158. //
  13159. // Transfer DirectDraw driver state from cloned to clone.
  13160. //
  13161. DxDdDynamicModeChange(pdoOld.hdev(), pdoNew.hdev(), DXG_MODECHANGE_TRANSFER);
  13162. //
  13163. // Transfer other surface and other objects which own by hdevCloned to hdevClone.
  13164. //
  13165. // Transfer the objects belonging to cloned pdev to clone,
  13166. // transfer between clone and cloned is completely seemless
  13167. // from driver. So we need to change owner of those object
  13168. // by ourselves.
  13169. //
  13170. DrvTransferGdiObjects(pdoNew.hdev(),pdoOld.hdev(),DRV_TRANS_ALL_TYPE);
  13171. //
  13172. // Invalidate surface in cloned pdev, so that this won't deleted.
  13173. //
  13174. pdevOld->pSurface = NULL;
  13175. //
  13176. // Invalidate dhpdev in cloned.
  13177. //
  13178. pdevOld->dhpdev = NULL;
  13179. //
  13180. // Now, clone device has everything grab from original, so
  13181. // mark original as clone, and mark clone as original.
  13182. //
  13183. pdoOld.bCloneDriver(TRUE);
  13184. pdoNew.bCloneDriver(FALSE);
  13185. //
  13186. // Disabling old pdev.
  13187. //
  13188. pdoOld.bDisabled(TRUE);
  13189. //
  13190. // call device driver to let them knows new hdev.
  13191. //
  13192. pdoNew.CompletePDEV(pdoNew.dhpdev(),pdoNew.hdev());
  13193. //
  13194. // Make sure pdoOld which going to be delete, does not have any reference.
  13195. //
  13196. // KdPrint(("GDI DDML: 1 to Many monitor video mode change\n"));
  13197. // KdPrint(("GDI DDML: Open ref count in ppdevOld = %d\n", pdevOld->cPdevOpenRefs));
  13198. // KdPrint(("GDI DDML: Pdev ref count in ppdevOld = %d\n", pdevOld->cPdevRefs));
  13199. }
  13200. else
  13201. {
  13202. TRACE_INIT(("DrvChangeDisplaySettings(): Disabling clone pdev\n"));
  13203. //
  13204. // Clone was created for temporary purpose.
  13205. //
  13206. // Invalidate surface in clone pdev, so that this won't deleted.
  13207. //
  13208. pdevNew->pSurface = NULL;
  13209. //
  13210. // Disable clone PDEV.
  13211. //
  13212. pdoNew.bDisabled(TRUE);
  13213. // KdPrint(("GDI DDML: Many to 1 monitor video mode change\n"));
  13214. // KdPrint(("GDI DDML: Open ref count in ppdevOld = %d\n", pdevNew->cPdevOpenRefs));
  13215. // KdPrint(("GDI DDML: Pdev ref count in ppdevOld = %d\n", pdevNew->cPdevRefs));
  13216. }
  13217. }
  13218. //
  13219. // Disable old parant pdev if its meta driver.
  13220. // Since meta PDEV never be reused in new MDEV.
  13221. //
  13222. PDEVOBJ pdoOldParent(pOrgMdev->hdevParent);
  13223. if (pdoOldParent.bMetaDriver())
  13224. {
  13225. pdoOldParent.bDisabled(TRUE);
  13226. }
  13227. //
  13228. // Reactivate sprites on whichever MDEV will be used
  13229. //
  13230. vSpHideSprites(((bSwitchError == FALSE) ? pmdev : pOrgMdev)->hdevParent, FALSE);
  13231. //
  13232. // If we hold clone's devlock, now safe to release.
  13233. //
  13234. if (hsemCloneHdevDevLock)
  13235. {
  13236. GreReleaseSemaphoreEx(hsemCloneHdevDevLock);
  13237. }
  13238. //
  13239. // Release MDEV's lock.
  13240. //
  13241. mdloMdev.vUnlock();
  13242. mdloOrgMdev.vUnlock();
  13243. }
  13244. //
  13245. // Finalize new MDEV.
  13246. //
  13247. if (bSwitchError == FALSE)
  13248. {
  13249. PDEVOBJ poP(pmdev->hdevParent);
  13250. if (pmdev->chdev != 1)
  13251. {
  13252. HDEV hdevPalette;
  13253. //
  13254. // Do devlock sharing
  13255. //
  13256. DrvSetSharedDevLock(pmdev);
  13257. //
  13258. // Do palette sharing
  13259. //
  13260. hdevPalette = DrvSetSharedPalette(pmdev);
  13261. if (!poP.bIsPalManaged() && hdevPalette)
  13262. {
  13263. //
  13264. // If parent is not pal-managed, but if there is any
  13265. // pal-managed device, realize halftone palette on there.
  13266. //
  13267. DrvRealizeHalftonePalette(hdevPalette,TRUE);
  13268. }
  13269. }
  13270. else
  13271. {
  13272. //
  13273. // For single monitor case, make sure ppdevParent points itself.
  13274. //
  13275. PPDEV ppdev = (PPDEV) poP.hdev();
  13276. XEPALOBJ palObj(poP.ppalSurf());
  13277. if (ppdev->ppdevParent != ppdev)
  13278. {
  13279. WARNING("ChangeDisplaySettings: ppdev->parent != ppdev, fixing it\n");
  13280. ppdev->ppdevParent = ppdev;
  13281. }
  13282. //
  13283. // Correct palette pointer to driver entry.
  13284. //
  13285. poP.pfnSetPalette(PPFNDRV(poP, SetPalette));
  13286. //
  13287. // Unshared palette table entry.
  13288. //
  13289. palObj.apalResetColorTable();
  13290. }
  13291. }
  13292. if (hsemOrgMdevDevLock)
  13293. {
  13294. ASSERTGDI(hsemOrgMdevPointer,
  13295. "DrvChangeDisplaySettings():Pointer Lock is NULL\n");
  13296. if (bSwitchError == FALSE)
  13297. {
  13298. PDEVOBJ pdoParent(pmdev->hdevParent);
  13299. //
  13300. // If mode change has been successfully done, make sure the primary
  13301. // devlock has not been changed through the mode change.
  13302. //
  13303. ASSERTGDI(hsemOrgMdevDevLock == pdoParent.hsemDevLock(),
  13304. "DrvChangeDisplaySettings():DevLock has been changed !\n");
  13305. }
  13306. //
  13307. // Unlock the pointer
  13308. //
  13309. GreReleaseSemaphoreEx(hsemOrgMdevPointer);
  13310. //
  13311. // Unlock the parent of MDEV.
  13312. //
  13313. GreReleaseSemaphoreEx(hsemOrgMdevDevLock);
  13314. }
  13315. //
  13316. // Resume DirectDraw, this can not do while devlock is hold
  13317. //
  13318. if (phdevDDLock)
  13319. {
  13320. DrvEnableDirectDrawForModeChange(
  13321. phdevDDLock,
  13322. phdevDDLock != ahdevDDLockQuick);
  13323. }
  13324. //
  13325. // If we succeed, return the new data strucutre.
  13326. //
  13327. if (bSwitchError == FALSE)
  13328. {
  13329. PDEVOBJ pdo;
  13330. //
  13331. // Dump the old MDEV structure.
  13332. //
  13333. if (pOrgMdev != NULL)
  13334. {
  13335. TRACE_INIT(("OLD pmdev = %08lx\n", pOrgMdev));
  13336. TRACE_INIT(("\tOLD hdevParent = %08lx\n", pOrgMdev->hdevParent));
  13337. TRACE_INIT(("\tOLD chdev = %d\n", pOrgMdev->chdev));
  13338. for (i = 0; i < pOrgMdev->chdev; i++)
  13339. {
  13340. pdo.vInit(pOrgMdev->Dev[i].hdev);
  13341. TRACE_INIT(("\tOLD [%d].hdev = %08lx\n", i, pOrgMdev->Dev[i].hdev));
  13342. ASSERTGDI(pdo.ppdev->pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER,
  13343. "OLD MDEV has DDML_DRIVER as child hdev");
  13344. //
  13345. // Unmark old MDEV as part of the desktop.
  13346. //
  13347. pdo.ppdev->pGraphicsDevice->stateFlags &= ~DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
  13348. }
  13349. }
  13350. //
  13351. // Clear the primary flag
  13352. //
  13353. for (PGRAPHICS_DEVICE PhysDispTemp = gpGraphicsDeviceList;
  13354. PhysDispTemp != NULL;
  13355. PhysDispTemp = PhysDispTemp->pNextGraphicsDevice)
  13356. {
  13357. PhysDispTemp->stateFlags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
  13358. }
  13359. //
  13360. // Dump the new MDEV structure.
  13361. //
  13362. TRACE_INIT(("NEW pmdev = %08lx\n", pmdev));
  13363. TRACE_INIT(("\tNEW hdevParent = %08lx\n", pmdev->hdevParent));
  13364. TRACE_INIT(("\tNEW chdev = %d\n", pmdev->chdev));
  13365. for (i = 0; i < pmdev->chdev; i++)
  13366. {
  13367. pdo.vInit(pmdev->Dev[i].hdev);
  13368. PDEVMODEW pdm = pdo.ppdev->ppdevDevmode;
  13369. TRACE_INIT(("\tNEW [%d].hdev = %08lx\n", i, pmdev->Dev[i].hdev));
  13370. TRACE_INIT(("\tNEW [%d].rect = %d, %d, %d, %d,\n", i,
  13371. pmdev->Dev[i].rect.left, pmdev->Dev[i].rect.top,
  13372. pmdev->Dev[i].rect.right, pmdev->Dev[i].rect.bottom));
  13373. ASSERTGDI(pdo.ppdev->pGraphicsDevice != (PGRAPHICS_DEVICE) DDML_DRIVER,
  13374. "NEW MDEV has DDML_DRIVER as child hdev");
  13375. //
  13376. // Mark new MDEV as part of the desktop.
  13377. //
  13378. pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
  13379. //
  13380. // Adjust the position and mark the primary device
  13381. //
  13382. pdm->dmPosition.x = pmdev->Dev[i].rect.left;
  13383. pdm->dmPosition.y = pmdev->Dev[i].rect.top;
  13384. if ((pdm->dmPosition.x == 0) &&
  13385. (pdm->dmPosition.y == 0))
  13386. {
  13387. pdo.ppdev->pGraphicsDevice->stateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
  13388. }
  13389. }
  13390. //
  13391. // Update the DeviceCaps for the new HDEV
  13392. //
  13393. GreUpdateSharedDevCaps(pmdev->hdevParent);
  13394. }
  13395. else
  13396. {
  13397. //
  13398. // We had a problem with the mode switch.
  13399. // Revert to the old configuration.
  13400. //
  13401. // We must make sure pOrgMdev is still what is
  13402. // currently active.
  13403. //
  13404. // ISSUE: Is this multmon safe ?? shared devlock ??
  13405. // ISSUE: Is this clone-pdev safe ?? (of course, no).
  13406. DrvBackoutMDEV(pmdev);
  13407. VFREEMEM(pmdev);
  13408. *pNewMdev = NULL;
  13409. if (pOrgMdev != NULL)
  13410. {
  13411. DrvEnableMDEV(pOrgMdev, FALSE);
  13412. }
  13413. gcFailedModeChanges++;
  13414. status = GRE_DISP_CHANGE_RESTART;
  13415. }
  13416. }
  13417. else if (status == GRE_DISP_CHANGE_NO_CHANGE)
  13418. {
  13419. //
  13420. // If nothing has been changed, just copy Parent HDEV from original.
  13421. //
  13422. pmdev->hdevParent = pOrgMdev->hdevParent;
  13423. pmdev->Reserved = pOrgMdev->Reserved;
  13424. //
  13425. // If parent HDEV is DDML, Increment OpenRef count. otheriwse parent
  13426. // hdev is same as its child, so OpenRef is already incremented in
  13427. // hCreateHDEV().
  13428. //
  13429. if (pmdev->chdev > 1)
  13430. {
  13431. GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
  13432. PDEVOBJ pdo(pmdev->hdevParent);
  13433. pdo.ppdev->cPdevOpenRefs++;
  13434. pdo.ppdev->cPdevRefs++;
  13435. GreReleaseSemaphoreEx(ghsemDriverMgmt);
  13436. }
  13437. ASSERTGDI(pmdev->chdev == pOrgMdev->chdev,
  13438. "DrvChangeDisplaySettings():Status is no change, but chdev is different\n");
  13439. ASSERTGDI(pmdev->pDesktopId == pOrgMdev->pDesktopId,
  13440. "DrvChangeDisplaySettings():Status is no change, but pDesktopId is different\n");
  13441. }
  13442. //
  13443. // Reenable the HDEVs (whether we fail or succeed) so
  13444. // DirectDraw and other functionality is reestablished.
  13445. //
  13446. // If the call succeeded, the destroy the old HDEVs
  13447. //
  13448. if (pOrgMdev)
  13449. {
  13450. if ( (status == GRE_DISP_CHANGE_SUCCESSFUL) ||
  13451. (status == GRE_DISP_CHANGE_NO_CHANGE) )
  13452. {
  13453. //
  13454. // Enable new MDEV.
  13455. //
  13456. DrvEnableMDEV(pmdev, FALSE);
  13457. //
  13458. // ISSUE: Reset the state of the DISPLAY_DEVICE_ flags when we
  13459. // destroy the pdev on the device.
  13460. //
  13461. if (status == GRE_DISP_CHANGE_SUCCESSFUL)
  13462. {
  13463. //
  13464. // When we are success to do mode change,
  13465. // In multi monitor system, it is possible
  13466. // to happen pOrgMdev still contains "enabled"
  13467. // device. Because ,for example, system has 2
  13468. // monitors attached, but only 1 monitor enabled,
  13469. // other one is disabled. so User decided to enable
  13470. // one and disable 'currently enabled' monitor.
  13471. // In this case, we do '1 -> 1' mode change, since
  13472. // there is only 1 monitor before and after mode change.
  13473. // and CreateHDEV() only disable display when it is
  13474. // same pGraphicsDevice. thus this case, old display
  13475. // will be disabled.
  13476. // So here, we scan hdev in Old MDEV, and if there is
  13477. // 'enabled' device which is not used in New MDEV, we
  13478. // disable it.
  13479. //
  13480. for (i = 0; i < pOrgMdev->chdev; i++)
  13481. {
  13482. PDEV *pdevOld = (PDEV *) pOrgMdev->Dev[i].hdev;
  13483. //
  13484. // Dualview has already been cleared and disabled
  13485. //
  13486. if ((pdevOld->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_DUALVIEW) &&
  13487. gbInvalidateDualView)
  13488. {
  13489. continue;
  13490. }
  13491. for (j = 0; j < pmdev->chdev; j++)
  13492. {
  13493. PDEV *pdevNew = (PDEV *) pmdev->Dev[j].hdev;
  13494. //
  13495. // Don't disable this old pdev \ device if we
  13496. // are still using it
  13497. //
  13498. if ((pdevOld->pGraphicsDevice ==
  13499. pdevNew->pGraphicsDevice)
  13500. ||
  13501. (pdevOld->pGraphicsDevice->pVgaDevice &&
  13502. pdevNew->pGraphicsDevice->pVgaDevice))
  13503. {
  13504. break;
  13505. }
  13506. }
  13507. if (j == pmdev->chdev)
  13508. {
  13509. DrvDisableDisplay(pOrgMdev->Dev[i].hdev, TRUE);
  13510. }
  13511. }
  13512. }
  13513. //
  13514. // Get rid of old MDEV.
  13515. //
  13516. DrvDestroyMDEV(pOrgMdev);
  13517. }
  13518. }
  13519. mcip.vDone();
  13520. GreReleaseSemaphoreEx(ghsemShareDevLock);
  13521. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Mode Switch status %d\n", status));
  13522. }
  13523. if (pdevmodeInformation)
  13524. {
  13525. VFREEMEM(pdevmodeInformation);
  13526. }
  13527. TRACE_INIT(("Drv_Trace: DrvChangeDisplaySettings - Leave - status = %d\n", status));
  13528. gbInvalidateDualView = FALSE;
  13529. return status;
  13530. }
  13531. /***************************************************************************\
  13532. * DrvSetVideoParameters
  13533. *
  13534. * Routine used to pass video parameters structure down to video miniports.
  13535. *
  13536. * ericks Created
  13537. \***************************************************************************/
  13538. LONG
  13539. DrvSetVideoParameters(
  13540. PUNICODE_STRING pstrDeviceName,
  13541. HDEV hdevPrimary,
  13542. MODE PreviousMode,
  13543. PVOID lParam
  13544. )
  13545. {
  13546. NTSTATUS status = GRE_DISP_CHANGE_BADPARAM;
  13547. PGRAPHICS_DEVICE PhysDisp = NULL;
  13548. if (pstrDeviceName)
  13549. {
  13550. PhysDisp = DrvGetDeviceFromName(pstrDeviceName, PreviousMode);
  13551. if (PhysDisp == NULL)
  13552. {
  13553. TRACE_INIT(("Drv_Trace: DrvSetVideoParameters - Leave - Bad Device\n"));
  13554. return GRE_DISP_CHANGE_BADPARAM;
  13555. }
  13556. }
  13557. else
  13558. {
  13559. PDEVOBJ pdo(hdevPrimary);
  13560. if (pdo.bValid())
  13561. {
  13562. PhysDisp = pdo.ppdev->pGraphicsDevice;
  13563. }
  13564. if (PhysDisp == NULL)
  13565. {
  13566. TRACE_INIT(("Drv_Trace: DrvSetVideoParameters - Leave - Bad Device\n"));
  13567. return GRE_DISP_CHANGE_BADPARAM;
  13568. }
  13569. }
  13570. if (PhysDisp == (PGRAPHICS_DEVICE) DDML_DRIVER)
  13571. {
  13572. ASSERTGDI(FALSE, "Trying to change TV settings for DDML layer\n");
  13573. return GRE_DISP_CHANGE_BADPARAM;
  13574. }
  13575. if (PhysDisp != NULL) {
  13576. ULONG bytesReturned;
  13577. PVIDEOPARAMETERS CapturedData;
  13578. CapturedData = (PVIDEOPARAMETERS) PALLOCNOZ(2 * sizeof(VIDEOPARAMETERS),
  13579. GDITAG_DRVSUP);
  13580. if (CapturedData == NULL) {
  13581. return GRE_DISP_CHANGE_FAILED;
  13582. }
  13583. //
  13584. // Make sure lParam is valid!
  13585. //
  13586. __try {
  13587. ProbeForRead(lParam, sizeof(VIDEOPARAMETERS), sizeof(UCHAR));
  13588. memcpy(CapturedData, lParam, sizeof(VIDEOPARAMETERS));
  13589. } __except (EXCEPTION_EXECUTE_HANDLER) {
  13590. VFREEMEM(CapturedData);
  13591. return GRE_DISP_CHANGE_BADPARAM;
  13592. }
  13593. status = GreDeviceIoControl(PhysDisp->pDeviceHandle,
  13594. IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS,
  13595. CapturedData,
  13596. sizeof(VIDEOPARAMETERS),
  13597. CapturedData,
  13598. sizeof(VIDEOPARAMETERS),
  13599. &bytesReturned);
  13600. if (status != NO_ERROR) {
  13601. status = GRE_DISP_CHANGE_BADPARAM;
  13602. } else {
  13603. ASSERTGDI(bytesReturned == sizeof(VIDEOPARAMETERS),
  13604. "DrvSetVideoParameters: Not enough data returned\n");
  13605. }
  13606. __try {
  13607. memcpy(lParam, CapturedData, sizeof(VIDEOPARAMETERS));
  13608. } __except (EXCEPTION_EXECUTE_HANDLER) {
  13609. status = GRE_DISP_CHANGE_BADPARAM;
  13610. }
  13611. VFREEMEM(CapturedData);
  13612. }
  13613. return status;
  13614. }
  13615. /***************************************************************************\
  13616. * NtGdiGetMonitorID
  13617. *
  13618. * Return Monitor ID for the given HDC.
  13619. *
  13620. * 14-Dec-1998 hideyukn Created
  13621. \***************************************************************************/
  13622. BOOL NtGdiGetMonitorID
  13623. (
  13624. HDC hdc,
  13625. DWORD dwSize,
  13626. LPWSTR pszMonitorID
  13627. )
  13628. {
  13629. BOOL bRet = FALSE;
  13630. NTSTATUS Status;
  13631. DISPLAY_DEVICEW DisplayDevice;
  13632. //
  13633. // We don't want the session to switch from local to remote or remote to local
  13634. // while we are enumerating display device. Device lock won't prevent this from
  13635. // hapening so we need to grab the User session switch lock.
  13636. //
  13637. Status = UserSessionSwitchEnterCrit();
  13638. if (Status != STATUS_SUCCESS) {
  13639. return FALSE;
  13640. }
  13641. XDCOBJ dco(hdc);
  13642. if (dco.bValid())
  13643. {
  13644. PDEVOBJ pdo(dco.hdev());
  13645. DEVLOCKOBJ dlo(pdo);
  13646. if (dlo.bValid())
  13647. {
  13648. PGRAPHICS_DEVICE pGraphicsDevice = NULL;
  13649. if (pdo.bMetaDriver())
  13650. {
  13651. //
  13652. // If this is meta driver, use primary.
  13653. //
  13654. PVDEV pvdev = (PVDEV) pdo.dhpdev();
  13655. pGraphicsDevice = ((PPDEV)(pvdev->hdevPrimary))->pGraphicsDevice;
  13656. }
  13657. else
  13658. {
  13659. pGraphicsDevice = ((PPDEV)pdo.hdev())->pGraphicsDevice;
  13660. }
  13661. if (pGraphicsDevice)
  13662. {
  13663. UNICODE_STRING DeviceName;
  13664. NTSTATUS NtStatus;
  13665. RtlInitUnicodeString(&DeviceName, pGraphicsDevice->szWinDeviceName);
  13666. DisplayDevice.cb = sizeof(DisplayDevice);
  13667. //
  13668. // Get monitor data attached to this display device.
  13669. //
  13670. NtStatus = DrvEnumDisplayDevices(&DeviceName,NULL,0,&DisplayDevice,NULL,KernelMode);
  13671. if (NT_SUCCESS(NtStatus))
  13672. {
  13673. bRet = TRUE;
  13674. }
  13675. }
  13676. }
  13677. dco.vUnlockFast();
  13678. }
  13679. if (bRet)
  13680. {
  13681. DWORD dwLenToBeCopied = (wcslen(DisplayDevice.DeviceID) + 1) * sizeof(WCHAR);
  13682. if (dwLenToBeCopied <= dwSize)
  13683. {
  13684. __try
  13685. {
  13686. ProbeForWrite(pszMonitorID, dwSize, sizeof(BYTE));
  13687. RtlCopyMemory(pszMonitorID,DisplayDevice.DeviceID,dwLenToBeCopied);
  13688. }
  13689. __except(EXCEPTION_EXECUTE_HANDLER)
  13690. {
  13691. WARNINGX(64);
  13692. bRet = FALSE;
  13693. }
  13694. }
  13695. else
  13696. {
  13697. bRet = FALSE;
  13698. }
  13699. }
  13700. //
  13701. // Release the session switch lock.
  13702. //
  13703. UserSessionSwitchLeaveCrit();
  13704. return (bRet);
  13705. }
  13706. #ifdef _HYDRA_
  13707. //
  13708. //!!! Currently, the graphics device list (see drvsup.cxx) is allocated
  13709. //!!! per-Hydra session. AndreVa has proposed that they be allocated
  13710. //!!! globally. He's probably right, but until this changes we need to
  13711. //!!! clean them up during Hydra shutdown.
  13712. //!!!
  13713. //!!! To enable cleanup of the per-Hydra graphics device lists, define
  13714. //!!! _PER_SESSION_GDEVLIST_ in muclean.hxx.
  13715. //
  13716. #ifdef _PER_SESSION_GDEVLIST_
  13717. /******************************Public*Routine******************************\
  13718. * MultiUserDrvCleanupGraphicsDeviceList
  13719. *
  13720. * For MultiUserNtGreCleanup (Hydra) cleanup.
  13721. *
  13722. * Cleanup the graphics device list.
  13723. *
  13724. * History:
  13725. * 21-Feb-1998 -by- Gilman Wong [gilmanw]
  13726. * Wrote it.
  13727. \**************************************************************************/
  13728. VOID
  13729. DrvCleanupOneGraphicsDevice(PGRAPHICS_DEVICE PhysDispVictim)
  13730. {
  13731. //
  13732. // Delete the graphics device data buffers if they exist.
  13733. //
  13734. if (PhysDispVictim->devmodeInfo)
  13735. VFREEMEM(PhysDispVictim->devmodeInfo);
  13736. if (PhysDispVictim->devmodeMarks)
  13737. VFREEMEM(PhysDispVictim->devmodeMarks);
  13738. if (PhysDispVictim->DeviceDescription)
  13739. VFREEMEM(PhysDispVictim->DeviceDescription);
  13740. if (PhysDispVictim->DisplayDriverNames)
  13741. VFREEMEM(PhysDispVictim->DisplayDriverNames);
  13742. if (PhysDispVictim->MonitorDevices)
  13743. VFREEMEM(PhysDispVictim->MonitorDevices);
  13744. if (PhysDispVictim->pFileObject)
  13745. ObDereferenceObject(PhysDispVictim->pFileObject);
  13746. VFREEMEM(PhysDispVictim);
  13747. }
  13748. VOID
  13749. DrvCleanupGraphicsDeviceList(PGRAPHICS_DEVICE pGraphicsDeviceList)
  13750. {
  13751. PGRAPHICS_DEVICE PhysDispVictim;
  13752. PGRAPHICS_DEVICE PhysDispNext;
  13753. //
  13754. // Run the list and delete resources.
  13755. //
  13756. for (PhysDispVictim = pGraphicsDeviceList;
  13757. PhysDispVictim != NULL;
  13758. PhysDispVictim = PhysDispNext)
  13759. {
  13760. PhysDispNext = PhysDispVictim->pNextGraphicsDevice;
  13761. //
  13762. // Does this graphics device have a VGA device chained off of it
  13763. // (and is it not self referential)?
  13764. //
  13765. if ((PhysDispVictim->pVgaDevice) &&
  13766. (PhysDispVictim->pVgaDevice != PhysDispVictim) &&
  13767. (PhysDispVictim->pVgaDevice != &gFullscreenGraphicsDevice) &&
  13768. (PhysDispVictim->pVgaDevice != gPhysDispVGA))
  13769. {
  13770. DrvCleanupOneGraphicsDevice(PhysDispVictim->pVgaDevice);
  13771. }
  13772. if ((PhysDispVictim != &gFullscreenGraphicsDevice) &&
  13773. (PhysDispVictim != gPhysDispVGA))
  13774. {
  13775. DrvCleanupOneGraphicsDevice(PhysDispVictim);
  13776. }
  13777. }
  13778. }
  13779. VOID
  13780. MultiUserDrvCleanupGraphicsDeviceList()
  13781. {
  13782. // Cleanup local graphics device list
  13783. DrvCleanupGraphicsDeviceList(gpLocalGraphicsDeviceList);
  13784. gpLocalGraphicsDeviceList = NULL;
  13785. // Cleanup remote graphics device list
  13786. DrvCleanupGraphicsDeviceList(gpRemoteGraphicsDeviceList);
  13787. gpRemoteGraphicsDeviceList = NULL;
  13788. gpGraphicsDeviceList = NULL;
  13789. //
  13790. // If WinStation, cleanup driver name allocated in
  13791. // GreMultiUserInitSession (misc.cxx).
  13792. //
  13793. if (!G_fConsole)
  13794. {
  13795. //
  13796. // If we never made it to GreMultiUserInitSession then don't
  13797. // call FreePool on a static variable (look in misc.cxx)
  13798. //
  13799. if (G_DisplayDriverNames && G_RemoteVideoFileObject != NULL)
  13800. {
  13801. GdiFreePool(G_DisplayDriverNames);
  13802. }
  13803. }
  13804. if (gPhysDispVGA)
  13805. {
  13806. DrvCleanupOneGraphicsDevice(gPhysDispVGA);
  13807. gPhysDispVGA = NULL;
  13808. }
  13809. if (gFullscreenGraphicsDevice.devmodeInfo)
  13810. {
  13811. VFREEMEM(gFullscreenGraphicsDevice.devmodeInfo);
  13812. gFullscreenGraphicsDevice.devmodeInfo = NULL;
  13813. }
  13814. if (gFullscreenGraphicsDevice.devmodeMarks)
  13815. {
  13816. VFREEMEM(gFullscreenGraphicsDevice.devmodeMarks);
  13817. gFullscreenGraphicsDevice.devmodeMarks = NULL;
  13818. }
  13819. }
  13820. BOOL
  13821. DrvIsProtocolAlreadyKnown(VOID)
  13822. {
  13823. PGRAPHICS_DEVICE PhysDisp = gpGraphicsDeviceList;
  13824. while (PhysDisp != NULL) {
  13825. if (gProtocolType == PhysDisp->ProtocolType) {
  13826. return TRUE;
  13827. }
  13828. PhysDisp = PhysDisp->pNextGraphicsDevice;
  13829. }
  13830. return FALSE;
  13831. }
  13832. #endif
  13833. #endif