1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Device Functions
5 * FILE: win32ss/gdi/eng/device.c
6 * PROGRAMER: Jason Filby
7 * Timo Kreuzer
8 */
9
10 #include <win32k.h>
11 #include <ntddvdeo.h>
12
13 DBG_DEFAULT_CHANNEL(EngDev);
14
15 static PGRAPHICS_DEVICE gpPrimaryGraphicsDevice;
16 static PGRAPHICS_DEVICE gpVgaGraphicsDevice;
17
18 static PGRAPHICS_DEVICE gpGraphicsDeviceFirst = NULL;
19 static PGRAPHICS_DEVICE gpGraphicsDeviceLast = NULL;
20 static HSEMAPHORE ghsemGraphicsDeviceList;
21 static ULONG giDevNum = 1;
22
23 CODE_SEG("INIT")
24 NTSTATUS
25 NTAPI
InitDeviceImpl(VOID)26 InitDeviceImpl(VOID)
27 {
28 ghsemGraphicsDeviceList = EngCreateSemaphore();
29 if (!ghsemGraphicsDeviceList)
30 return STATUS_INSUFFICIENT_RESOURCES;
31
32 return STATUS_SUCCESS;
33 }
34
35 static
36 BOOLEAN
EngpHasVgaDriver(_In_ PGRAPHICS_DEVICE pGraphicsDevice)37 EngpHasVgaDriver(
38 _In_ PGRAPHICS_DEVICE pGraphicsDevice)
39 {
40 WCHAR awcDeviceKey[256], awcServiceName[100];
41 PWSTR lastBkSlash;
42 NTSTATUS Status;
43 ULONG cbValue;
44 HKEY hkey;
45
46 /* Open the key for the adapters */
47 Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey);
48 if (!NT_SUCCESS(Status))
49 {
50 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: 0x%08lx\n", Status);
51 return FALSE;
52 }
53
54 /* Read the name of the device key */
55 cbValue = sizeof(awcDeviceKey);
56 Status = RegQueryValue(hkey, pGraphicsDevice->szNtDeviceName, REG_SZ, awcDeviceKey, &cbValue);
57 ZwClose(hkey);
58 if (!NT_SUCCESS(Status))
59 {
60 ERR("Could not read '%S' registry value: 0x%08lx\n", Status);
61 return FALSE;
62 }
63
64 /* Replace 'DeviceN' by 'Video' */
65 lastBkSlash = wcsrchr(awcDeviceKey, L'\\');
66 if (!lastBkSlash)
67 {
68 ERR("Invalid registry key '%S'\n", lastBkSlash);
69 return FALSE;
70 }
71 if (!NT_SUCCESS(RtlStringCchCopyW(lastBkSlash + 1,
72 ARRAYSIZE(awcDeviceKey) - (lastBkSlash + 1 - awcDeviceKey),
73 L"Video")))
74 {
75 ERR("Failed to add 'Video' to registry key '%S'\n", awcDeviceKey);
76 return FALSE;
77 }
78
79 /* Open device key */
80 Status = RegOpenKey(awcDeviceKey, &hkey);
81 if (!NT_SUCCESS(Status))
82 {
83 ERR("Could not open %S registry key: 0x%08lx\n", awcDeviceKey, Status);
84 return FALSE;
85 }
86
87 /* Read service name */
88 cbValue = sizeof(awcServiceName);
89 Status = RegQueryValue(hkey, L"Service", REG_SZ, awcServiceName, &cbValue);
90 ZwClose(hkey);
91 if (!NT_SUCCESS(Status))
92 {
93 ERR("Could not read Service registry value in %S: 0x%08lx\n", awcDeviceKey, Status);
94 return FALSE;
95 }
96
97 /* Device is using VGA driver if service name is 'VGASave' (case insensitive) */
98 return (_wcsicmp(awcServiceName, L"VGASave") == 0);
99 }
100
101 /*
102 * Add a device to gpGraphicsDeviceFirst/gpGraphicsDeviceLast list (if not already present).
103 */
_Requires_lock_held_(ghsemGraphicsDeviceList)104 _Requires_lock_held_(ghsemGraphicsDeviceList)
105 static
106 VOID
107 EngpLinkGraphicsDevice(
108 _In_ PGRAPHICS_DEVICE pToAdd)
109 {
110 PGRAPHICS_DEVICE pGraphicsDevice;
111
112 TRACE("EngLinkGraphicsDevice(%p)\n", pToAdd);
113
114 /* Search if device is not already linked */
115 for (pGraphicsDevice = gpGraphicsDeviceFirst;
116 pGraphicsDevice;
117 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
118 {
119 if (pGraphicsDevice == pToAdd)
120 return;
121 }
122
123 pToAdd->pNextGraphicsDevice = NULL;
124 if (gpGraphicsDeviceLast)
125 gpGraphicsDeviceLast->pNextGraphicsDevice = pToAdd;
126 gpGraphicsDeviceLast = pToAdd;
127 if (!gpGraphicsDeviceFirst)
128 gpGraphicsDeviceFirst = pToAdd;
129 }
130
131 /*
132 * Remove a device from gpGraphicsDeviceFirst/gpGraphicsDeviceLast list.
133 */
_Requires_lock_held_(ghsemGraphicsDeviceList)134 _Requires_lock_held_(ghsemGraphicsDeviceList)
135 static
136 VOID
137 EngpUnlinkGraphicsDevice(
138 _In_ PGRAPHICS_DEVICE pToDelete)
139 {
140 PGRAPHICS_DEVICE pPrevGraphicsDevice = NULL;
141 PGRAPHICS_DEVICE pGraphicsDevice = gpGraphicsDeviceFirst;
142
143 TRACE("EngpUnlinkGraphicsDevice('%S')\n", pToDelete->szNtDeviceName);
144
145 while (pGraphicsDevice)
146 {
147 if (pGraphicsDevice != pToDelete)
148 {
149 /* Keep current device */
150 pPrevGraphicsDevice = pGraphicsDevice;
151 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
152 }
153 else
154 {
155 /* At first, link again associated VGA Device */
156 if (pGraphicsDevice->pVgaDevice)
157 EngpLinkGraphicsDevice(pGraphicsDevice->pVgaDevice);
158
159 /* We need to remove current device */
160 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
161
162 /* Unlink chain */
163 if (!pPrevGraphicsDevice)
164 gpGraphicsDeviceFirst = pToDelete->pNextGraphicsDevice;
165 else
166 pPrevGraphicsDevice->pNextGraphicsDevice = pToDelete->pNextGraphicsDevice;
167 if (gpGraphicsDeviceLast == pToDelete)
168 gpGraphicsDeviceLast = pPrevGraphicsDevice;
169 }
170 }
171 }
172
173 NTSTATUS
EngpUpdateGraphicsDeviceList(VOID)174 EngpUpdateGraphicsDeviceList(VOID)
175 {
176 ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
177 WCHAR awcDeviceName[20], awcWinDeviceName[20];
178 UNICODE_STRING ustrDeviceName;
179 WCHAR awcBuffer[256];
180 NTSTATUS Status;
181 PGRAPHICS_DEVICE pGraphicsDevice;
182 BOOLEAN bFoundNewDevice = FALSE;
183 ULONG cbValue;
184 HKEY hkey;
185
186 /* Open the key for the adapters */
187 Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey);
188 if (!NT_SUCCESS(Status))
189 {
190 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status);
191 return Status;
192 }
193
194 /* Read the name of the VGA adapter */
195 cbValue = sizeof(awcDeviceName);
196 Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
197 if (NT_SUCCESS(Status))
198 {
199 iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]);
200 ERR("VGA adapter = %lu\n", iVGACompatible);
201 }
202
203 /* Get the maximum number of adapters */
204 if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber))
205 {
206 ERR("Could not read MaxObjectNumber, defaulting to 0.\n");
207 }
208
209 TRACE("Found %lu devices\n", ulMaxObjectNumber + 1);
210
211 /* Loop through all adapters */
212 for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
213 {
214 /* Create the adapter's key name */
215 swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
216
217 /* Create the display device name */
218 swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1);
219 RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName);
220
221 /* Check if the device exists already */
222 pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum);
223 if (pGraphicsDevice != NULL)
224 {
225 continue;
226 }
227
228 /* Read the reg key name */
229 cbValue = sizeof(awcBuffer);
230 Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue);
231 if (!NT_SUCCESS(Status))
232 {
233 ERR("failed to query the registry path:0x%lx\n", Status);
234 continue;
235 }
236
237 /* Initialize the driver for this device */
238 pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer);
239 if (!pGraphicsDevice) continue;
240
241 /* Check if this is a VGA compatible adapter */
242 if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)
243 {
244 /* Save this as the VGA adapter */
245 if (!gpVgaGraphicsDevice || !EngpHasVgaDriver(gpVgaGraphicsDevice))
246 {
247 gpVgaGraphicsDevice = pGraphicsDevice;
248 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice);
249 }
250 }
251 bFoundNewDevice = TRUE;
252
253 /* Set the first one as primary device */
254 if (!gpPrimaryGraphicsDevice || EngpHasVgaDriver(gpPrimaryGraphicsDevice))
255 {
256 gpPrimaryGraphicsDevice = pGraphicsDevice;
257 TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice);
258 }
259 }
260
261 /* Close the device map registry key */
262 ZwClose(hkey);
263
264 /* Can we link VGA device to primary device? */
265 if (gpPrimaryGraphicsDevice &&
266 gpVgaGraphicsDevice &&
267 gpPrimaryGraphicsDevice != gpVgaGraphicsDevice &&
268 !gpPrimaryGraphicsDevice->pVgaDevice)
269 {
270 /* Yes. Remove VGA device from global list, and attach it to primary device */
271 TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName);
272 EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice);
273 gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice;
274 }
275
276 if (bFoundNewDevice && gbBaseVideo)
277 {
278 PGRAPHICS_DEVICE pToDelete;
279
280 /* Lock list */
281 EngAcquireSemaphore(ghsemGraphicsDeviceList);
282
283 /* Remove every device from linked list, except base-video one */
284 pGraphicsDevice = gpGraphicsDeviceFirst;
285 while (pGraphicsDevice)
286 {
287 if (!EngpHasVgaDriver(pGraphicsDevice))
288 {
289 /* Not base-video device. Remove it */
290 pToDelete = pGraphicsDevice;
291 TRACE("Removing non-base-video device %S (%S)\n", pToDelete->szWinDeviceName, pToDelete->szNtDeviceName);
292
293 EngpUnlinkGraphicsDevice(pGraphicsDevice);
294 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
295
296 /* Free memory */
297 ExFreePoolWithTag(pToDelete->pDiplayDrivers, GDITAG_DRVSUP);
298 ExFreePoolWithTag(pToDelete, GDITAG_GDEVICE);
299 }
300 else
301 {
302 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
303 }
304 }
305
306 /* Unlock list */
307 EngReleaseSemaphore(ghsemGraphicsDeviceList);
308 }
309
310 return STATUS_SUCCESS;
311 }
312
313 /* Open display settings registry key
314 * Returns NULL in case of error. */
315 static HKEY
EngpGetRegistryHandleFromDeviceMap(_In_ PGRAPHICS_DEVICE pGraphicsDevice)316 EngpGetRegistryHandleFromDeviceMap(
317 _In_ PGRAPHICS_DEVICE pGraphicsDevice)
318 {
319 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
320 HKEY hKey;
321 WCHAR szDeviceKey[256];
322 ULONG cbSize;
323 NTSTATUS Status;
324
325 /* Open the device map registry key */
326 Status = RegOpenKey(KEY_VIDEO, &hKey);
327 if (!NT_SUCCESS(Status))
328 {
329 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: status 0x%08x\n", Status);
330 return NULL;
331 }
332
333 /* Query the registry path */
334 cbSize = sizeof(szDeviceKey);
335 RegQueryValue(hKey,
336 pGraphicsDevice->szNtDeviceName,
337 REG_SZ,
338 szDeviceKey,
339 &cbSize);
340 ZwClose(hKey);
341
342 /* Open the registry key */
343 Status = RegOpenKey(szDeviceKey, &hKey);
344 if (!NT_SUCCESS(Status))
345 {
346 ERR("Could not open registry key '%S': status 0x%08x\n", szDeviceKey, Status);
347 return NULL;
348 }
349
350 return hKey;
351 }
352
353 NTSTATUS
EngpGetDisplayDriverParameters(_In_ PGRAPHICS_DEVICE pGraphicsDevice,_Out_ PDEVMODEW pdm)354 EngpGetDisplayDriverParameters(
355 _In_ PGRAPHICS_DEVICE pGraphicsDevice,
356 _Out_ PDEVMODEW pdm)
357 {
358 HKEY hKey;
359 NTSTATUS Status;
360 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] =
361 {
362 #define READ(field, str) \
363 { \
364 NULL, \
365 RTL_QUERY_REGISTRY_DIRECT, \
366 L ##str, \
367 &pdm->field, \
368 REG_NONE, NULL, 0 \
369 },
370 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel")
371 READ(dmPelsWidth, "DefaultSettings.XResolution")
372 READ(dmPelsHeight, "DefaultSettings.YResolution")
373 READ(dmDisplayFlags, "DefaultSettings.Flags")
374 READ(dmDisplayFrequency, "DefaultSettings.VRefresh")
375 READ(dmPanningWidth, "DefaultSettings.XPanning")
376 READ(dmPanningHeight, "DefaultSettings.YPanning")
377 READ(dmDisplayOrientation, "DefaultSettings.Orientation")
378 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput")
379 READ(dmPosition.x, "Attach.RelativeX")
380 READ(dmPosition.y, "Attach.RelativeY")
381 #undef READ
382 {0}
383 };
384
385 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice);
386 if (!hKey)
387 return STATUS_UNSUCCESSFUL;
388
389 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
390 (PWSTR)hKey,
391 DisplaySettingsTable,
392 NULL,
393 NULL);
394
395 ZwClose(hKey);
396 return Status;
397 }
398
399 DWORD
EngpGetDisplayDriverAccelerationLevel(_In_ PGRAPHICS_DEVICE pGraphicsDevice)400 EngpGetDisplayDriverAccelerationLevel(
401 _In_ PGRAPHICS_DEVICE pGraphicsDevice)
402 {
403 HKEY hKey;
404 DWORD dwAccelerationLevel = 0;
405 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] =
406 {
407 {
408 NULL,
409 RTL_QUERY_REGISTRY_DIRECT,
410 L"Acceleration.Level",
411 &dwAccelerationLevel,
412 REG_NONE, NULL, 0
413 },
414 {0}
415 };
416
417 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice);
418 if (!hKey)
419 return 0;
420
421 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
422 (PWSTR)hKey,
423 DisplaySettingsTable,
424 NULL,
425 NULL);
426 ZwClose(hKey);
427
428 return dwAccelerationLevel;
429 }
430
431 extern VOID
432 UserRefreshDisplay(IN PPDEVOBJ ppdev);
433
434 // PVIDEO_WIN32K_CALLOUT
435 VOID
436 NTAPI
VideoPortCallout(_In_ PVOID Params)437 VideoPortCallout(
438 _In_ PVOID Params)
439 {
440 /*
441 * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of
442 * a specific VideoPortCalloutThread() system thread using the same mechanism
443 * as the RIT/desktop/Ghost system threads.
444 */
445
446 PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params;
447
448 TRACE("VideoPortCallout(0x%p, 0x%x)\n",
449 CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1);
450
451 if (!CallbackParams)
452 return;
453
454 switch (CallbackParams->CalloutType)
455 {
456 case VideoFindAdapterCallout:
457 {
458 TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n",
459 CallbackParams->Param ? "TRUE" : "FALSE");
460 if (CallbackParams->Param == TRUE)
461 {
462 /* Re-enable the display */
463 UserRefreshDisplay(gpmdev->ppdevGlobal);
464 }
465 else
466 {
467 /* Disable the display */
468 NOTHING; // Nothing to do for the moment...
469 }
470
471 CallbackParams->Status = STATUS_SUCCESS;
472 break;
473 }
474
475 case VideoPowerNotifyCallout:
476 case VideoDisplaySwitchCallout:
477 case VideoEnumChildPdoNotifyCallout:
478 case VideoWakeupCallout:
479 case VideoChangeDisplaySettingsCallout:
480 case VideoPnpNotifyCallout:
481 case VideoDxgkDisplaySwitchCallout:
482 case VideoDxgkMonitorEventCallout:
483 case VideoDxgkFindAdapterTdrCallout:
484 ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType);
485 CallbackParams->Status = STATUS_NOT_IMPLEMENTED;
486 break;
487
488 default:
489 ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType);
490 CallbackParams->Status = STATUS_UNSUCCESSFUL;
491 break;
492 }
493 }
494
495 PGRAPHICS_DEVICE
496 NTAPI
EngpRegisterGraphicsDevice(_In_ PUNICODE_STRING pustrDeviceName,_In_ PUNICODE_STRING pustrDiplayDrivers,_In_ PUNICODE_STRING pustrDescription)497 EngpRegisterGraphicsDevice(
498 _In_ PUNICODE_STRING pustrDeviceName,
499 _In_ PUNICODE_STRING pustrDiplayDrivers,
500 _In_ PUNICODE_STRING pustrDescription)
501 {
502 PGRAPHICS_DEVICE pGraphicsDevice;
503 PDEVICE_OBJECT pDeviceObject;
504 PFILE_OBJECT pFileObject;
505 NTSTATUS Status;
506 VIDEO_WIN32K_CALLBACKS Win32kCallbacks;
507 ULONG ulReturn;
508 PWSTR pwsz;
509 ULONG cj;
510
511 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName);
512
513 /* Allocate a GRAPHICS_DEVICE structure */
514 pGraphicsDevice = ExAllocatePoolZero(PagedPool,
515 sizeof(GRAPHICS_DEVICE),
516 GDITAG_GDEVICE);
517 if (!pGraphicsDevice)
518 {
519 ERR("ExAllocatePoolWithTag failed\n");
520 return NULL;
521 }
522
523 /* Try to open and enable the device */
524 Status = IoGetDeviceObjectPointer(pustrDeviceName,
525 FILE_READ_DATA | FILE_WRITE_DATA,
526 &pFileObject,
527 &pDeviceObject);
528 if (!NT_SUCCESS(Status))
529 {
530 ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status);
531 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
532 return NULL;
533 }
534
535 /* Copy the device and file object pointers */
536 pGraphicsDevice->DeviceObject = pDeviceObject;
537 pGraphicsDevice->FileObject = pFileObject;
538
539 /* Initialize and register the device with videoprt for Win32k callbacks */
540 Win32kCallbacks.PhysDisp = pGraphicsDevice;
541 Win32kCallbacks.Callout = VideoPortCallout;
542 // Reset the data being returned prior to the call.
543 Win32kCallbacks.bACPI = FALSE;
544 Win32kCallbacks.pPhysDeviceObject = NULL;
545 Win32kCallbacks.DualviewFlags = 0;
546 Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject,
547 IOCTL_VIDEO_INIT_WIN32K_CALLBACKS,
548 &Win32kCallbacks,
549 sizeof(Win32kCallbacks),
550 &Win32kCallbacks,
551 sizeof(Win32kCallbacks),
552 &ulReturn);
553 if (Status != ERROR_SUCCESS)
554 {
555 ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n",
556 pDeviceObject, Status);
557 }
558 // TODO: Set flags according to the results.
559 // if (Win32kCallbacks.bACPI)
560 // if (Win32kCallbacks.DualviewFlags & ???)
561 pGraphicsDevice->PhysDeviceHandle = Win32kCallbacks.pPhysDeviceObject;
562
563 /* FIXME: Enumerate children monitor devices for this video adapter
564 *
565 * - Force the adapter to re-enumerate its monitors:
566 * IoSynchronousInvalidateDeviceRelations(pdo, BusRelations)
567 *
568 * - Retrieve all monitor PDOs from VideoPrt:
569 * EngDeviceIoControl(0x%p, IOCTL_VIDEO_ENUM_MONITOR_PDO)
570 *
571 * - Initialize these fields and structures accordingly:
572 * pGraphicsDevice->dwMonCnt
573 * pGraphicsDevice->pvMonDev[0..dwMonCnt-1]
574 */
575
576 /* Copy the device name */
577 RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName,
578 sizeof(pGraphicsDevice->szNtDeviceName),
579 pustrDeviceName->Buffer,
580 pustrDeviceName->Length);
581
582 /* Create a Win32 device name (FIXME: virtual devices!) */
583 RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName,
584 sizeof(pGraphicsDevice->szWinDeviceName),
585 L"\\\\.\\DISPLAY%d",
586 (int)giDevNum);
587
588 /* Allocate a buffer for the strings */
589 cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR);
590 pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP);
591 if (!pwsz)
592 {
593 ERR("Could not allocate string buffer\n");
594 ASSERT(FALSE); // FIXME
595 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
596 return NULL;
597 }
598
599 /* Copy the display driver names */
600 pGraphicsDevice->pDiplayDrivers = pwsz;
601 RtlCopyMemory(pGraphicsDevice->pDiplayDrivers,
602 pustrDiplayDrivers->Buffer,
603 pustrDiplayDrivers->Length);
604
605 /* Copy the description */
606 pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR);
607 RtlCopyMemory(pGraphicsDevice->pwszDescription,
608 pustrDescription->Buffer,
609 pustrDescription->Length);
610 pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0;
611
612 /* Lock loader */
613 EngAcquireSemaphore(ghsemGraphicsDeviceList);
614
615 /* Insert the device into the global list */
616 EngpLinkGraphicsDevice(pGraphicsDevice);
617
618 /* Increment the device number */
619 giDevNum++;
620
621 /* Unlock loader */
622 EngReleaseSemaphore(ghsemGraphicsDeviceList);
623 TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription);
624
625 /* HACK: already in graphic mode; display wallpaper on this new display */
626 if (ScreenDeviceContext)
627 {
628 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
629 UNICODE_STRING DisplayName;
630 HDC hdc;
631 RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName);
632 hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE);
633 IntPaintDesktop(hdc);
634 }
635
636 return pGraphicsDevice;
637 }
638
639 PGRAPHICS_DEVICE
640 NTAPI
EngpFindGraphicsDevice(_In_opt_ PUNICODE_STRING pustrDevice,_In_ ULONG iDevNum)641 EngpFindGraphicsDevice(
642 _In_opt_ PUNICODE_STRING pustrDevice,
643 _In_ ULONG iDevNum)
644 {
645 UNICODE_STRING ustrCurrent;
646 PGRAPHICS_DEVICE pGraphicsDevice;
647 ULONG i;
648 TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n",
649 pustrDevice, iDevNum);
650
651 /* Lock list */
652 EngAcquireSemaphore(ghsemGraphicsDeviceList);
653
654 if (pustrDevice && pustrDevice->Buffer)
655 {
656 /* Find specified video adapter by name */
657 for (pGraphicsDevice = gpGraphicsDeviceFirst;
658 pGraphicsDevice;
659 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
660 {
661 /* Compare the device name */
662 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
663 if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE))
664 {
665 break;
666 }
667 }
668
669 if (pGraphicsDevice)
670 {
671 /* Validate selected monitor number */
672 #if 0
673 if (iDevNum >= pGraphicsDevice->dwMonCnt)
674 pGraphicsDevice = NULL;
675 #else
676 /* FIXME: dwMonCnt not initialized, see EngpRegisterGraphicsDevice */
677 #endif
678 }
679 }
680 else
681 {
682 /* Select video adapter by device number */
683 for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0;
684 pGraphicsDevice && i < iDevNum;
685 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++);
686 }
687
688 /* Unlock list */
689 EngReleaseSemaphore(ghsemGraphicsDeviceList);
690
691 return pGraphicsDevice;
692 }
693
694 static
695 NTSTATUS
EngpFileIoRequest(_In_ PFILE_OBJECT pFileObject,_In_ ULONG ulMajorFunction,_In_reads_ (nBufferSize)PVOID lpBuffer,_In_ SIZE_T nBufferSize,_In_ ULONGLONG ullStartOffset,_Out_ PULONG_PTR lpInformation)696 EngpFileIoRequest(
697 _In_ PFILE_OBJECT pFileObject,
698 _In_ ULONG ulMajorFunction,
699 _In_reads_(nBufferSize) PVOID lpBuffer,
700 _In_ SIZE_T nBufferSize,
701 _In_ ULONGLONG ullStartOffset,
702 _Out_ PULONG_PTR lpInformation)
703 {
704 PDEVICE_OBJECT pDeviceObject;
705 KEVENT Event;
706 PIRP pIrp;
707 IO_STATUS_BLOCK Iosb;
708 NTSTATUS Status;
709 LARGE_INTEGER liStartOffset;
710
711 /* Get corresponding device object */
712 pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
713 if (!pDeviceObject)
714 {
715 return STATUS_INVALID_PARAMETER;
716 }
717
718 /* Initialize an event */
719 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
720
721 /* Build IRP */
722 liStartOffset.QuadPart = ullStartOffset;
723 pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction,
724 pDeviceObject,
725 lpBuffer,
726 (ULONG)nBufferSize,
727 &liStartOffset,
728 &Event,
729 &Iosb);
730 if (!pIrp)
731 {
732 return STATUS_INSUFFICIENT_RESOURCES;
733 }
734
735 /* Call the driver */
736 Status = IoCallDriver(pDeviceObject, pIrp);
737
738 /* Wait if neccessary */
739 if (STATUS_PENDING == Status)
740 {
741 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
742 Status = Iosb.Status;
743 }
744
745 /* Return information to the caller about the operation. */
746 *lpInformation = Iosb.Information;
747
748 /* Return NTSTATUS */
749 return Status;
750 }
751
752 VOID
753 APIENTRY
EngFileWrite(_In_ PFILE_OBJECT pFileObject,_In_reads_ (nLength)PVOID lpBuffer,_In_ SIZE_T nLength,_Out_ PSIZE_T lpBytesWritten)754 EngFileWrite(
755 _In_ PFILE_OBJECT pFileObject,
756 _In_reads_(nLength) PVOID lpBuffer,
757 _In_ SIZE_T nLength,
758 _Out_ PSIZE_T lpBytesWritten)
759 {
760 NTSTATUS status;
761
762 status = EngpFileIoRequest(pFileObject,
763 IRP_MJ_WRITE,
764 lpBuffer,
765 nLength,
766 0,
767 lpBytesWritten);
768 if (!NT_SUCCESS(status))
769 {
770 *lpBytesWritten = 0;
771 }
772 }
773
774 _Success_(return>=0)
775 NTSTATUS
776 APIENTRY
EngFileIoControl(_In_ PFILE_OBJECT pFileObject,_In_ DWORD dwIoControlCode,_In_reads_ (nInBufferSize)PVOID lpInBuffer,_In_ SIZE_T nInBufferSize,_Out_writes_ (nOutBufferSize)PVOID lpOutBuffer,_In_ SIZE_T nOutBufferSize,_Out_ PULONG_PTR lpInformation)777 EngFileIoControl(
778 _In_ PFILE_OBJECT pFileObject,
779 _In_ DWORD dwIoControlCode,
780 _In_reads_(nInBufferSize) PVOID lpInBuffer,
781 _In_ SIZE_T nInBufferSize,
782 _Out_writes_(nOutBufferSize) PVOID lpOutBuffer,
783 _In_ SIZE_T nOutBufferSize,
784 _Out_ PULONG_PTR lpInformation)
785 {
786 PDEVICE_OBJECT pDeviceObject;
787 KEVENT Event;
788 PIRP pIrp;
789 IO_STATUS_BLOCK Iosb;
790 NTSTATUS Status;
791
792 /* Get corresponding device object */
793 pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
794 if (!pDeviceObject)
795 {
796 return STATUS_INVALID_PARAMETER;
797 }
798
799 /* Initialize an event */
800 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
801
802 /* Build IO control IRP */
803 pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode,
804 pDeviceObject,
805 lpInBuffer,
806 (ULONG)nInBufferSize,
807 lpOutBuffer,
808 (ULONG)nOutBufferSize,
809 FALSE,
810 &Event,
811 &Iosb);
812 if (!pIrp)
813 {
814 return STATUS_INSUFFICIENT_RESOURCES;
815 }
816
817 /* Call the driver */
818 Status = IoCallDriver(pDeviceObject, pIrp);
819
820 /* Wait if neccessary */
821 if (Status == STATUS_PENDING)
822 {
823 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
824 Status = Iosb.Status;
825 }
826
827 /* Return information to the caller about the operation. */
828 *lpInformation = Iosb.Information;
829
830 /* This function returns NTSTATUS */
831 return Status;
832 }
833
834 /*
835 * @implemented
836 */
837 _Success_(return==0)
838 DWORD
839 APIENTRY
EngDeviceIoControl(_In_ HANDLE hDevice,_In_ DWORD dwIoControlCode,_In_reads_bytes_opt_ (cjInBufferSize)LPVOID lpInBuffer,_In_ DWORD cjInBufferSize,_Out_writes_bytes_opt_ (cjOutBufferSize)LPVOID lpOutBuffer,_In_ DWORD cjOutBufferSize,_Out_ LPDWORD lpBytesReturned)840 EngDeviceIoControl(
841 _In_ HANDLE hDevice,
842 _In_ DWORD dwIoControlCode,
843 _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer,
844 _In_ DWORD cjInBufferSize,
845 _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer,
846 _In_ DWORD cjOutBufferSize,
847 _Out_ LPDWORD lpBytesReturned)
848 {
849 PIRP Irp;
850 NTSTATUS Status;
851 KEVENT Event;
852 IO_STATUS_BLOCK Iosb;
853 PDEVICE_OBJECT DeviceObject;
854
855 TRACE("EngDeviceIoControl() called\n");
856
857 if (!hDevice)
858 {
859 return ERROR_INVALID_HANDLE;
860 }
861
862 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
863
864 DeviceObject = (PDEVICE_OBJECT) hDevice;
865
866 Irp = IoBuildDeviceIoControlRequest(dwIoControlCode,
867 DeviceObject,
868 lpInBuffer,
869 cjInBufferSize,
870 lpOutBuffer,
871 cjOutBufferSize,
872 FALSE,
873 &Event,
874 &Iosb);
875 if (!Irp) return ERROR_NOT_ENOUGH_MEMORY;
876
877 Status = IoCallDriver(DeviceObject, Irp);
878
879 if (Status == STATUS_PENDING)
880 {
881 (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
882 Status = Iosb.Status;
883 }
884
885 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status,
886 Iosb.Information);
887
888 /* Return information to the caller about the operation. */
889 *lpBytesReturned = (DWORD)Iosb.Information;
890
891 /* Convert NT status values to win32 error codes. */
892 switch (Status)
893 {
894 case STATUS_INSUFFICIENT_RESOURCES:
895 return ERROR_NOT_ENOUGH_MEMORY;
896
897 case STATUS_BUFFER_OVERFLOW:
898 return ERROR_MORE_DATA;
899
900 case STATUS_NOT_IMPLEMENTED:
901 return ERROR_INVALID_FUNCTION;
902
903 case STATUS_INVALID_PARAMETER:
904 return ERROR_INVALID_PARAMETER;
905
906 case STATUS_BUFFER_TOO_SMALL:
907 return ERROR_INSUFFICIENT_BUFFER;
908
909 case STATUS_DEVICE_DOES_NOT_EXIST:
910 return ERROR_DEV_NOT_EXIST;
911
912 case STATUS_PENDING:
913 return ERROR_IO_PENDING;
914 }
915
916 return Status;
917 }
918
919 /* EOF */
920