1c2c66affSColin Finck /*
2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory
3c2c66affSColin Finck * PROJECT: ReactOS kernel
4c2c66affSColin Finck * PURPOSE: GDI Driver Device Functions
5c2c66affSColin Finck * FILE: win32ss/gdi/eng/device.c
6c2c66affSColin Finck * PROGRAMER: Jason Filby
7c2c66affSColin Finck * Timo Kreuzer
8c2c66affSColin Finck */
9c2c66affSColin Finck
10c2c66affSColin Finck #include <win32k.h>
110ad65796SHermès Bélusca-Maïto #include <ntddvdeo.h>
120ad65796SHermès Bélusca-Maïto
130ad65796SHermès Bélusca-Maïto DBG_DEFAULT_CHANNEL(EngDev);
14c2c66affSColin Finck
15b4e781d7SHervé Poussineau static PGRAPHICS_DEVICE gpPrimaryGraphicsDevice;
166e71e942SHervé Poussineau static PGRAPHICS_DEVICE gpVgaGraphicsDevice;
17c2c66affSColin Finck
18c2c66affSColin Finck static PGRAPHICS_DEVICE gpGraphicsDeviceFirst = NULL;
19c2c66affSColin Finck static PGRAPHICS_DEVICE gpGraphicsDeviceLast = NULL;
20c2c66affSColin Finck static HSEMAPHORE ghsemGraphicsDeviceList;
21c2c66affSColin Finck static ULONG giDevNum = 1;
22c2c66affSColin Finck
235c7ce447SVictor Perevertkin CODE_SEG("INIT")
24c2c66affSColin Finck NTSTATUS
25c2c66affSColin Finck NTAPI
InitDeviceImpl(VOID)26c2c66affSColin Finck InitDeviceImpl(VOID)
27c2c66affSColin Finck {
28c2c66affSColin Finck ghsemGraphicsDeviceList = EngCreateSemaphore();
29c2c66affSColin Finck if (!ghsemGraphicsDeviceList)
30c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
31c2c66affSColin Finck
32c2c66affSColin Finck return STATUS_SUCCESS;
33c2c66affSColin Finck }
34c2c66affSColin Finck
35ea30b963SHervé Poussineau static
36ea30b963SHervé Poussineau BOOLEAN
EngpHasVgaDriver(_In_ PGRAPHICS_DEVICE pGraphicsDevice)37ea30b963SHervé Poussineau EngpHasVgaDriver(
38ea30b963SHervé Poussineau _In_ PGRAPHICS_DEVICE pGraphicsDevice)
39ea30b963SHervé Poussineau {
40ea30b963SHervé Poussineau WCHAR awcDeviceKey[256], awcServiceName[100];
41ea30b963SHervé Poussineau PWSTR lastBkSlash;
42ea30b963SHervé Poussineau NTSTATUS Status;
43ea30b963SHervé Poussineau ULONG cbValue;
44ea30b963SHervé Poussineau HKEY hkey;
45ea30b963SHervé Poussineau
46ea30b963SHervé Poussineau /* Open the key for the adapters */
47ea30b963SHervé Poussineau Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey);
48ea30b963SHervé Poussineau if (!NT_SUCCESS(Status))
49ea30b963SHervé Poussineau {
50ea30b963SHervé Poussineau ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: 0x%08lx\n", Status);
51ea30b963SHervé Poussineau return FALSE;
52ea30b963SHervé Poussineau }
53ea30b963SHervé Poussineau
54ea30b963SHervé Poussineau /* Read the name of the device key */
55ea30b963SHervé Poussineau cbValue = sizeof(awcDeviceKey);
56ea30b963SHervé Poussineau Status = RegQueryValue(hkey, pGraphicsDevice->szNtDeviceName, REG_SZ, awcDeviceKey, &cbValue);
57ea30b963SHervé Poussineau ZwClose(hkey);
58ea30b963SHervé Poussineau if (!NT_SUCCESS(Status))
59ea30b963SHervé Poussineau {
60ea30b963SHervé Poussineau ERR("Could not read '%S' registry value: 0x%08lx\n", Status);
61ea30b963SHervé Poussineau return FALSE;
62ea30b963SHervé Poussineau }
63ea30b963SHervé Poussineau
64ea30b963SHervé Poussineau /* Replace 'DeviceN' by 'Video' */
65ea30b963SHervé Poussineau lastBkSlash = wcsrchr(awcDeviceKey, L'\\');
66ea30b963SHervé Poussineau if (!lastBkSlash)
67ea30b963SHervé Poussineau {
68ea30b963SHervé Poussineau ERR("Invalid registry key '%S'\n", lastBkSlash);
69ea30b963SHervé Poussineau return FALSE;
70ea30b963SHervé Poussineau }
71ea30b963SHervé Poussineau if (!NT_SUCCESS(RtlStringCchCopyW(lastBkSlash + 1,
72ea30b963SHervé Poussineau ARRAYSIZE(awcDeviceKey) - (lastBkSlash + 1 - awcDeviceKey),
73ea30b963SHervé Poussineau L"Video")))
74ea30b963SHervé Poussineau {
75ea30b963SHervé Poussineau ERR("Failed to add 'Video' to registry key '%S'\n", awcDeviceKey);
76ea30b963SHervé Poussineau return FALSE;
77ea30b963SHervé Poussineau }
78ea30b963SHervé Poussineau
79ea30b963SHervé Poussineau /* Open device key */
80ea30b963SHervé Poussineau Status = RegOpenKey(awcDeviceKey, &hkey);
81ea30b963SHervé Poussineau if (!NT_SUCCESS(Status))
82ea30b963SHervé Poussineau {
83ea30b963SHervé Poussineau ERR("Could not open %S registry key: 0x%08lx\n", awcDeviceKey, Status);
84ea30b963SHervé Poussineau return FALSE;
85ea30b963SHervé Poussineau }
86ea30b963SHervé Poussineau
87ea30b963SHervé Poussineau /* Read service name */
88ea30b963SHervé Poussineau cbValue = sizeof(awcServiceName);
89ea30b963SHervé Poussineau Status = RegQueryValue(hkey, L"Service", REG_SZ, awcServiceName, &cbValue);
90ea30b963SHervé Poussineau ZwClose(hkey);
91ea30b963SHervé Poussineau if (!NT_SUCCESS(Status))
92ea30b963SHervé Poussineau {
93ea30b963SHervé Poussineau ERR("Could not read Service registry value in %S: 0x%08lx\n", awcDeviceKey, Status);
94ea30b963SHervé Poussineau return FALSE;
95ea30b963SHervé Poussineau }
96ea30b963SHervé Poussineau
97*42914af2SHervé Poussineau /* Device is using VGA driver if service name is 'VGASave' (case insensitive) */
98*42914af2SHervé Poussineau return (_wcsicmp(awcServiceName, L"VGASave") == 0);
99ea30b963SHervé Poussineau }
100ea30b963SHervé Poussineau
101ea30b963SHervé Poussineau /*
102b3cdb7e7SHervé Poussineau * Add a device to gpGraphicsDeviceFirst/gpGraphicsDeviceLast list (if not already present).
103b3cdb7e7SHervé Poussineau */
_Requires_lock_held_(ghsemGraphicsDeviceList)104b3cdb7e7SHervé Poussineau _Requires_lock_held_(ghsemGraphicsDeviceList)
105b3cdb7e7SHervé Poussineau static
106b3cdb7e7SHervé Poussineau VOID
107b3cdb7e7SHervé Poussineau EngpLinkGraphicsDevice(
108b3cdb7e7SHervé Poussineau _In_ PGRAPHICS_DEVICE pToAdd)
109b3cdb7e7SHervé Poussineau {
110b3cdb7e7SHervé Poussineau PGRAPHICS_DEVICE pGraphicsDevice;
111b3cdb7e7SHervé Poussineau
112b3cdb7e7SHervé Poussineau TRACE("EngLinkGraphicsDevice(%p)\n", pToAdd);
113b3cdb7e7SHervé Poussineau
114b3cdb7e7SHervé Poussineau /* Search if device is not already linked */
115b3cdb7e7SHervé Poussineau for (pGraphicsDevice = gpGraphicsDeviceFirst;
116b3cdb7e7SHervé Poussineau pGraphicsDevice;
117b3cdb7e7SHervé Poussineau pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
118b3cdb7e7SHervé Poussineau {
119b3cdb7e7SHervé Poussineau if (pGraphicsDevice == pToAdd)
120b3cdb7e7SHervé Poussineau return;
121b3cdb7e7SHervé Poussineau }
122b3cdb7e7SHervé Poussineau
123b3cdb7e7SHervé Poussineau pToAdd->pNextGraphicsDevice = NULL;
124b3cdb7e7SHervé Poussineau if (gpGraphicsDeviceLast)
125b3cdb7e7SHervé Poussineau gpGraphicsDeviceLast->pNextGraphicsDevice = pToAdd;
126b3cdb7e7SHervé Poussineau gpGraphicsDeviceLast = pToAdd;
127b3cdb7e7SHervé Poussineau if (!gpGraphicsDeviceFirst)
128b3cdb7e7SHervé Poussineau gpGraphicsDeviceFirst = pToAdd;
129b3cdb7e7SHervé Poussineau }
130b3cdb7e7SHervé Poussineau
131b3cdb7e7SHervé Poussineau /*
132ea30b963SHervé Poussineau * Remove a device from gpGraphicsDeviceFirst/gpGraphicsDeviceLast list.
133ea30b963SHervé Poussineau */
_Requires_lock_held_(ghsemGraphicsDeviceList)134ea30b963SHervé Poussineau _Requires_lock_held_(ghsemGraphicsDeviceList)
135ea30b963SHervé Poussineau static
136ea30b963SHervé Poussineau VOID
137ea30b963SHervé Poussineau EngpUnlinkGraphicsDevice(
138ea30b963SHervé Poussineau _In_ PGRAPHICS_DEVICE pToDelete)
139ea30b963SHervé Poussineau {
140ea30b963SHervé Poussineau PGRAPHICS_DEVICE pPrevGraphicsDevice = NULL;
141ea30b963SHervé Poussineau PGRAPHICS_DEVICE pGraphicsDevice = gpGraphicsDeviceFirst;
142ea30b963SHervé Poussineau
143ea30b963SHervé Poussineau TRACE("EngpUnlinkGraphicsDevice('%S')\n", pToDelete->szNtDeviceName);
144ea30b963SHervé Poussineau
145ea30b963SHervé Poussineau while (pGraphicsDevice)
146ea30b963SHervé Poussineau {
147ea30b963SHervé Poussineau if (pGraphicsDevice != pToDelete)
148ea30b963SHervé Poussineau {
149ea30b963SHervé Poussineau /* Keep current device */
150ea30b963SHervé Poussineau pPrevGraphicsDevice = pGraphicsDevice;
151ea30b963SHervé Poussineau pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
152ea30b963SHervé Poussineau }
153ea30b963SHervé Poussineau else
154ea30b963SHervé Poussineau {
15512ef61baSHervé Poussineau /* At first, link again associated VGA Device */
15612ef61baSHervé Poussineau if (pGraphicsDevice->pVgaDevice)
15712ef61baSHervé Poussineau EngpLinkGraphicsDevice(pGraphicsDevice->pVgaDevice);
15812ef61baSHervé Poussineau
159ea30b963SHervé Poussineau /* We need to remove current device */
160ea30b963SHervé Poussineau pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
161ea30b963SHervé Poussineau
162ea30b963SHervé Poussineau /* Unlink chain */
163ea30b963SHervé Poussineau if (!pPrevGraphicsDevice)
164ea30b963SHervé Poussineau gpGraphicsDeviceFirst = pToDelete->pNextGraphicsDevice;
165ea30b963SHervé Poussineau else
166ea30b963SHervé Poussineau pPrevGraphicsDevice->pNextGraphicsDevice = pToDelete->pNextGraphicsDevice;
167ea30b963SHervé Poussineau if (gpGraphicsDeviceLast == pToDelete)
168ea30b963SHervé Poussineau gpGraphicsDeviceLast = pPrevGraphicsDevice;
169ea30b963SHervé Poussineau }
170ea30b963SHervé Poussineau }
171ea30b963SHervé Poussineau }
172ea30b963SHervé Poussineau
1736739fb1bSHervé Poussineau NTSTATUS
EngpUpdateGraphicsDeviceList(VOID)1746739fb1bSHervé Poussineau EngpUpdateGraphicsDeviceList(VOID)
1756739fb1bSHervé Poussineau {
1766739fb1bSHervé Poussineau ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
177c05a45e1SOleg Dubinskiy WCHAR awcDeviceName[20], awcWinDeviceName[20];
17877e891b8STimo Kreuzer UNICODE_STRING ustrDeviceName;
1796739fb1bSHervé Poussineau WCHAR awcBuffer[256];
1806739fb1bSHervé Poussineau NTSTATUS Status;
1816739fb1bSHervé Poussineau PGRAPHICS_DEVICE pGraphicsDevice;
182ea30b963SHervé Poussineau BOOLEAN bFoundNewDevice = FALSE;
1836739fb1bSHervé Poussineau ULONG cbValue;
1846739fb1bSHervé Poussineau HKEY hkey;
1856739fb1bSHervé Poussineau
1866739fb1bSHervé Poussineau /* Open the key for the adapters */
1876739fb1bSHervé Poussineau Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey);
1886739fb1bSHervé Poussineau if (!NT_SUCCESS(Status))
1896739fb1bSHervé Poussineau {
1906739fb1bSHervé Poussineau ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status);
1916739fb1bSHervé Poussineau return Status;
1926739fb1bSHervé Poussineau }
1936739fb1bSHervé Poussineau
1946739fb1bSHervé Poussineau /* Read the name of the VGA adapter */
1956739fb1bSHervé Poussineau cbValue = sizeof(awcDeviceName);
1966739fb1bSHervé Poussineau Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
1976739fb1bSHervé Poussineau if (NT_SUCCESS(Status))
1986739fb1bSHervé Poussineau {
1996739fb1bSHervé Poussineau iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]);
2006739fb1bSHervé Poussineau ERR("VGA adapter = %lu\n", iVGACompatible);
2016739fb1bSHervé Poussineau }
2026739fb1bSHervé Poussineau
2032ea03b5bSAndriy Shevchenko /* Get the maximum number of adapters */
2046739fb1bSHervé Poussineau if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber))
2056739fb1bSHervé Poussineau {
2066739fb1bSHervé Poussineau ERR("Could not read MaxObjectNumber, defaulting to 0.\n");
2076739fb1bSHervé Poussineau }
2086739fb1bSHervé Poussineau
2096739fb1bSHervé Poussineau TRACE("Found %lu devices\n", ulMaxObjectNumber + 1);
2106739fb1bSHervé Poussineau
2116739fb1bSHervé Poussineau /* Loop through all adapters */
2126739fb1bSHervé Poussineau for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
2136739fb1bSHervé Poussineau {
2146739fb1bSHervé Poussineau /* Create the adapter's key name */
2156739fb1bSHervé Poussineau swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
216c05a45e1SOleg Dubinskiy
217c05a45e1SOleg Dubinskiy /* Create the display device name */
218c05a45e1SOleg Dubinskiy swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1);
219c05a45e1SOleg Dubinskiy RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName);
22077e891b8STimo Kreuzer
22177e891b8STimo Kreuzer /* Check if the device exists already */
222ded971c4SHervé Poussineau pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum);
22377e891b8STimo Kreuzer if (pGraphicsDevice != NULL)
22477e891b8STimo Kreuzer {
22577e891b8STimo Kreuzer continue;
22677e891b8STimo Kreuzer }
2276739fb1bSHervé Poussineau
2286739fb1bSHervé Poussineau /* Read the reg key name */
2296739fb1bSHervé Poussineau cbValue = sizeof(awcBuffer);
2306739fb1bSHervé Poussineau Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue);
2316739fb1bSHervé Poussineau if (!NT_SUCCESS(Status))
2326739fb1bSHervé Poussineau {
2336739fb1bSHervé Poussineau ERR("failed to query the registry path:0x%lx\n", Status);
2346739fb1bSHervé Poussineau continue;
2356739fb1bSHervé Poussineau }
2366739fb1bSHervé Poussineau
2376739fb1bSHervé Poussineau /* Initialize the driver for this device */
2386739fb1bSHervé Poussineau pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer);
2396739fb1bSHervé Poussineau if (!pGraphicsDevice) continue;
2406739fb1bSHervé Poussineau
2416739fb1bSHervé Poussineau /* Check if this is a VGA compatible adapter */
2426739fb1bSHervé Poussineau if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)
2436739fb1bSHervé Poussineau {
2446739fb1bSHervé Poussineau /* Save this as the VGA adapter */
245*42914af2SHervé Poussineau if (!gpVgaGraphicsDevice || !EngpHasVgaDriver(gpVgaGraphicsDevice))
24639d8a822STimo Kreuzer {
2476739fb1bSHervé Poussineau gpVgaGraphicsDevice = pGraphicsDevice;
2486739fb1bSHervé Poussineau TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice);
2496739fb1bSHervé Poussineau }
25039d8a822STimo Kreuzer }
251ea30b963SHervé Poussineau bFoundNewDevice = TRUE;
25239d8a822STimo Kreuzer
2536739fb1bSHervé Poussineau /* Set the first one as primary device */
25412ef61baSHervé Poussineau if (!gpPrimaryGraphicsDevice || EngpHasVgaDriver(gpPrimaryGraphicsDevice))
25539d8a822STimo Kreuzer {
2566739fb1bSHervé Poussineau gpPrimaryGraphicsDevice = pGraphicsDevice;
2576739fb1bSHervé Poussineau TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice);
2586739fb1bSHervé Poussineau }
2596739fb1bSHervé Poussineau }
2606739fb1bSHervé Poussineau
2616739fb1bSHervé Poussineau /* Close the device map registry key */
2626739fb1bSHervé Poussineau ZwClose(hkey);
2636739fb1bSHervé Poussineau
26412ef61baSHervé Poussineau /* Can we link VGA device to primary device? */
26512ef61baSHervé Poussineau if (gpPrimaryGraphicsDevice &&
26612ef61baSHervé Poussineau gpVgaGraphicsDevice &&
26712ef61baSHervé Poussineau gpPrimaryGraphicsDevice != gpVgaGraphicsDevice &&
26812ef61baSHervé Poussineau !gpPrimaryGraphicsDevice->pVgaDevice)
26912ef61baSHervé Poussineau {
27012ef61baSHervé Poussineau /* Yes. Remove VGA device from global list, and attach it to primary device */
27112ef61baSHervé Poussineau TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName);
27212ef61baSHervé Poussineau EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice);
27312ef61baSHervé Poussineau gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice;
27412ef61baSHervé Poussineau }
27512ef61baSHervé Poussineau
276ea30b963SHervé Poussineau if (bFoundNewDevice && gbBaseVideo)
277ea30b963SHervé Poussineau {
278ea30b963SHervé Poussineau PGRAPHICS_DEVICE pToDelete;
279ea30b963SHervé Poussineau
280ea30b963SHervé Poussineau /* Lock list */
281ea30b963SHervé Poussineau EngAcquireSemaphore(ghsemGraphicsDeviceList);
282ea30b963SHervé Poussineau
283ea30b963SHervé Poussineau /* Remove every device from linked list, except base-video one */
284ea30b963SHervé Poussineau pGraphicsDevice = gpGraphicsDeviceFirst;
285ea30b963SHervé Poussineau while (pGraphicsDevice)
286ea30b963SHervé Poussineau {
287ea30b963SHervé Poussineau if (!EngpHasVgaDriver(pGraphicsDevice))
288ea30b963SHervé Poussineau {
289ea30b963SHervé Poussineau /* Not base-video device. Remove it */
290ea30b963SHervé Poussineau pToDelete = pGraphicsDevice;
291ea30b963SHervé Poussineau TRACE("Removing non-base-video device %S (%S)\n", pToDelete->szWinDeviceName, pToDelete->szNtDeviceName);
292ea30b963SHervé Poussineau
293ea30b963SHervé Poussineau EngpUnlinkGraphicsDevice(pGraphicsDevice);
294ea30b963SHervé Poussineau pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
295ea30b963SHervé Poussineau
296ea30b963SHervé Poussineau /* Free memory */
297ea30b963SHervé Poussineau ExFreePoolWithTag(pToDelete->pDiplayDrivers, GDITAG_DRVSUP);
298ea30b963SHervé Poussineau ExFreePoolWithTag(pToDelete, GDITAG_GDEVICE);
299ea30b963SHervé Poussineau }
300ea30b963SHervé Poussineau else
301ea30b963SHervé Poussineau {
302ea30b963SHervé Poussineau pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice;
303ea30b963SHervé Poussineau }
304ea30b963SHervé Poussineau }
305ea30b963SHervé Poussineau
306ea30b963SHervé Poussineau /* Unlock list */
307ea30b963SHervé Poussineau EngReleaseSemaphore(ghsemGraphicsDeviceList);
308ea30b963SHervé Poussineau }
309ea30b963SHervé Poussineau
3106739fb1bSHervé Poussineau return STATUS_SUCCESS;
3116739fb1bSHervé Poussineau }
3126739fb1bSHervé Poussineau
3139acd895fSHervé Poussineau /* Open display settings registry key
3149acd895fSHervé Poussineau * Returns NULL in case of error. */
3159acd895fSHervé Poussineau static HKEY
EngpGetRegistryHandleFromDeviceMap(_In_ PGRAPHICS_DEVICE pGraphicsDevice)3169acd895fSHervé Poussineau EngpGetRegistryHandleFromDeviceMap(
3179acd895fSHervé Poussineau _In_ PGRAPHICS_DEVICE pGraphicsDevice)
3189acd895fSHervé Poussineau {
3199acd895fSHervé Poussineau static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
3209acd895fSHervé Poussineau HKEY hKey;
3219acd895fSHervé Poussineau WCHAR szDeviceKey[256];
3229acd895fSHervé Poussineau ULONG cbSize;
3239acd895fSHervé Poussineau NTSTATUS Status;
3249acd895fSHervé Poussineau
3259acd895fSHervé Poussineau /* Open the device map registry key */
3269acd895fSHervé Poussineau Status = RegOpenKey(KEY_VIDEO, &hKey);
3279acd895fSHervé Poussineau if (!NT_SUCCESS(Status))
3289acd895fSHervé Poussineau {
3299acd895fSHervé Poussineau ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: status 0x%08x\n", Status);
3309acd895fSHervé Poussineau return NULL;
3319acd895fSHervé Poussineau }
3329acd895fSHervé Poussineau
3339acd895fSHervé Poussineau /* Query the registry path */
3349acd895fSHervé Poussineau cbSize = sizeof(szDeviceKey);
3359acd895fSHervé Poussineau RegQueryValue(hKey,
3369acd895fSHervé Poussineau pGraphicsDevice->szNtDeviceName,
3379acd895fSHervé Poussineau REG_SZ,
3389acd895fSHervé Poussineau szDeviceKey,
3399acd895fSHervé Poussineau &cbSize);
3409acd895fSHervé Poussineau ZwClose(hKey);
3419acd895fSHervé Poussineau
3429acd895fSHervé Poussineau /* Open the registry key */
3439acd895fSHervé Poussineau Status = RegOpenKey(szDeviceKey, &hKey);
3449acd895fSHervé Poussineau if (!NT_SUCCESS(Status))
3459acd895fSHervé Poussineau {
3469acd895fSHervé Poussineau ERR("Could not open registry key '%S': status 0x%08x\n", szDeviceKey, Status);
3479acd895fSHervé Poussineau return NULL;
3489acd895fSHervé Poussineau }
3499acd895fSHervé Poussineau
3509acd895fSHervé Poussineau return hKey;
3519acd895fSHervé Poussineau }
3529acd895fSHervé Poussineau
3539acd895fSHervé Poussineau NTSTATUS
EngpGetDisplayDriverParameters(_In_ PGRAPHICS_DEVICE pGraphicsDevice,_Out_ PDEVMODEW pdm)3549acd895fSHervé Poussineau EngpGetDisplayDriverParameters(
3559acd895fSHervé Poussineau _In_ PGRAPHICS_DEVICE pGraphicsDevice,
356cd830549SHervé Poussineau _Out_ PDEVMODEW pdm)
3579acd895fSHervé Poussineau {
3589acd895fSHervé Poussineau HKEY hKey;
3599acd895fSHervé Poussineau NTSTATUS Status;
3609acd895fSHervé Poussineau RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] =
3619acd895fSHervé Poussineau {
3629acd895fSHervé Poussineau #define READ(field, str) \
3639acd895fSHervé Poussineau { \
3649acd895fSHervé Poussineau NULL, \
3659acd895fSHervé Poussineau RTL_QUERY_REGISTRY_DIRECT, \
3669acd895fSHervé Poussineau L ##str, \
3679acd895fSHervé Poussineau &pdm->field, \
3689acd895fSHervé Poussineau REG_NONE, NULL, 0 \
3699acd895fSHervé Poussineau },
3709acd895fSHervé Poussineau READ(dmBitsPerPel, "DefaultSettings.BitsPerPel")
3719acd895fSHervé Poussineau READ(dmPelsWidth, "DefaultSettings.XResolution")
3729acd895fSHervé Poussineau READ(dmPelsHeight, "DefaultSettings.YResolution")
3739acd895fSHervé Poussineau READ(dmDisplayFlags, "DefaultSettings.Flags")
3749acd895fSHervé Poussineau READ(dmDisplayFrequency, "DefaultSettings.VRefresh")
3759acd895fSHervé Poussineau READ(dmPanningWidth, "DefaultSettings.XPanning")
3769acd895fSHervé Poussineau READ(dmPanningHeight, "DefaultSettings.YPanning")
3779acd895fSHervé Poussineau READ(dmDisplayOrientation, "DefaultSettings.Orientation")
3789acd895fSHervé Poussineau READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput")
3799acd895fSHervé Poussineau READ(dmPosition.x, "Attach.RelativeX")
3809acd895fSHervé Poussineau READ(dmPosition.y, "Attach.RelativeY")
3819acd895fSHervé Poussineau #undef READ
3829acd895fSHervé Poussineau {0}
3839acd895fSHervé Poussineau };
3849acd895fSHervé Poussineau
3859acd895fSHervé Poussineau hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice);
3869acd895fSHervé Poussineau if (!hKey)
3879acd895fSHervé Poussineau return STATUS_UNSUCCESSFUL;
3889acd895fSHervé Poussineau
3899acd895fSHervé Poussineau Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
3909acd895fSHervé Poussineau (PWSTR)hKey,
3919acd895fSHervé Poussineau DisplaySettingsTable,
3929acd895fSHervé Poussineau NULL,
3939acd895fSHervé Poussineau NULL);
3949acd895fSHervé Poussineau
3959acd895fSHervé Poussineau ZwClose(hKey);
3969acd895fSHervé Poussineau return Status;
3979acd895fSHervé Poussineau }
3989acd895fSHervé Poussineau
399cd830549SHervé Poussineau DWORD
EngpGetDisplayDriverAccelerationLevel(_In_ PGRAPHICS_DEVICE pGraphicsDevice)400cd830549SHervé Poussineau EngpGetDisplayDriverAccelerationLevel(
401cd830549SHervé Poussineau _In_ PGRAPHICS_DEVICE pGraphicsDevice)
402cd830549SHervé Poussineau {
403cd830549SHervé Poussineau HKEY hKey;
404cd830549SHervé Poussineau DWORD dwAccelerationLevel = 0;
405cd830549SHervé Poussineau RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] =
406cd830549SHervé Poussineau {
407cd830549SHervé Poussineau {
408cd830549SHervé Poussineau NULL,
409cd830549SHervé Poussineau RTL_QUERY_REGISTRY_DIRECT,
410cd830549SHervé Poussineau L"Acceleration.Level",
411cd830549SHervé Poussineau &dwAccelerationLevel,
412cd830549SHervé Poussineau REG_NONE, NULL, 0
413cd830549SHervé Poussineau },
414cd830549SHervé Poussineau {0}
415cd830549SHervé Poussineau };
416cd830549SHervé Poussineau
417cd830549SHervé Poussineau hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice);
418cd830549SHervé Poussineau if (!hKey)
419cd830549SHervé Poussineau return 0;
420cd830549SHervé Poussineau
421cd830549SHervé Poussineau RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
422cd830549SHervé Poussineau (PWSTR)hKey,
423cd830549SHervé Poussineau DisplaySettingsTable,
424cd830549SHervé Poussineau NULL,
425cd830549SHervé Poussineau NULL);
426cd830549SHervé Poussineau ZwClose(hKey);
427cd830549SHervé Poussineau
428cd830549SHervé Poussineau return dwAccelerationLevel;
429cd830549SHervé Poussineau }
430cd830549SHervé Poussineau
4310ad65796SHermès Bélusca-Maïto extern VOID
4320ad65796SHermès Bélusca-Maïto UserRefreshDisplay(IN PPDEVOBJ ppdev);
4330ad65796SHermès Bélusca-Maïto
4340ad65796SHermès Bélusca-Maïto // PVIDEO_WIN32K_CALLOUT
4350ad65796SHermès Bélusca-Maïto VOID
4360ad65796SHermès Bélusca-Maïto NTAPI
VideoPortCallout(_In_ PVOID Params)4370ad65796SHermès Bélusca-Maïto VideoPortCallout(
4380ad65796SHermès Bélusca-Maïto _In_ PVOID Params)
4390ad65796SHermès Bélusca-Maïto {
4400ad65796SHermès Bélusca-Maïto /*
4410ad65796SHermès Bélusca-Maïto * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of
4420ad65796SHermès Bélusca-Maïto * a specific VideoPortCalloutThread() system thread using the same mechanism
4430ad65796SHermès Bélusca-Maïto * as the RIT/desktop/Ghost system threads.
4440ad65796SHermès Bélusca-Maïto */
4450ad65796SHermès Bélusca-Maïto
4460ad65796SHermès Bélusca-Maïto PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params;
4470ad65796SHermès Bélusca-Maïto
4480ad65796SHermès Bélusca-Maïto TRACE("VideoPortCallout(0x%p, 0x%x)\n",
4490ad65796SHermès Bélusca-Maïto CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1);
4500ad65796SHermès Bélusca-Maïto
4510ad65796SHermès Bélusca-Maïto if (!CallbackParams)
4520ad65796SHermès Bélusca-Maïto return;
4530ad65796SHermès Bélusca-Maïto
4540ad65796SHermès Bélusca-Maïto switch (CallbackParams->CalloutType)
4550ad65796SHermès Bélusca-Maïto {
4560ad65796SHermès Bélusca-Maïto case VideoFindAdapterCallout:
4570ad65796SHermès Bélusca-Maïto {
4580ad65796SHermès Bélusca-Maïto TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n",
4590ad65796SHermès Bélusca-Maïto CallbackParams->Param ? "TRUE" : "FALSE");
4600ad65796SHermès Bélusca-Maïto if (CallbackParams->Param == TRUE)
4610ad65796SHermès Bélusca-Maïto {
4620ad65796SHermès Bélusca-Maïto /* Re-enable the display */
463a0cfdcd4SHervé Poussineau UserRefreshDisplay(gpmdev->ppdevGlobal);
4640ad65796SHermès Bélusca-Maïto }
4650ad65796SHermès Bélusca-Maïto else
4660ad65796SHermès Bélusca-Maïto {
4670ad65796SHermès Bélusca-Maïto /* Disable the display */
4680ad65796SHermès Bélusca-Maïto NOTHING; // Nothing to do for the moment...
4690ad65796SHermès Bélusca-Maïto }
4700ad65796SHermès Bélusca-Maïto
4710ad65796SHermès Bélusca-Maïto CallbackParams->Status = STATUS_SUCCESS;
4720ad65796SHermès Bélusca-Maïto break;
4730ad65796SHermès Bélusca-Maïto }
4740ad65796SHermès Bélusca-Maïto
4750ad65796SHermès Bélusca-Maïto case VideoPowerNotifyCallout:
4760ad65796SHermès Bélusca-Maïto case VideoDisplaySwitchCallout:
4770ad65796SHermès Bélusca-Maïto case VideoEnumChildPdoNotifyCallout:
4780ad65796SHermès Bélusca-Maïto case VideoWakeupCallout:
4790ad65796SHermès Bélusca-Maïto case VideoChangeDisplaySettingsCallout:
4800ad65796SHermès Bélusca-Maïto case VideoPnpNotifyCallout:
4810ad65796SHermès Bélusca-Maïto case VideoDxgkDisplaySwitchCallout:
4820ad65796SHermès Bélusca-Maïto case VideoDxgkMonitorEventCallout:
4830ad65796SHermès Bélusca-Maïto case VideoDxgkFindAdapterTdrCallout:
4840ad65796SHermès Bélusca-Maïto ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType);
4850ad65796SHermès Bélusca-Maïto CallbackParams->Status = STATUS_NOT_IMPLEMENTED;
4860ad65796SHermès Bélusca-Maïto break;
4870ad65796SHermès Bélusca-Maïto
4880ad65796SHermès Bélusca-Maïto default:
4890ad65796SHermès Bélusca-Maïto ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType);
4900ad65796SHermès Bélusca-Maïto CallbackParams->Status = STATUS_UNSUCCESSFUL;
4910ad65796SHermès Bélusca-Maïto break;
4920ad65796SHermès Bélusca-Maïto }
4930ad65796SHermès Bélusca-Maïto }
4940ad65796SHermès Bélusca-Maïto
495c2c66affSColin Finck PGRAPHICS_DEVICE
496c2c66affSColin Finck NTAPI
EngpRegisterGraphicsDevice(_In_ PUNICODE_STRING pustrDeviceName,_In_ PUNICODE_STRING pustrDiplayDrivers,_In_ PUNICODE_STRING pustrDescription)497c2c66affSColin Finck EngpRegisterGraphicsDevice(
498c2c66affSColin Finck _In_ PUNICODE_STRING pustrDeviceName,
499c2c66affSColin Finck _In_ PUNICODE_STRING pustrDiplayDrivers,
500494de7c2SHervé Poussineau _In_ PUNICODE_STRING pustrDescription)
501c2c66affSColin Finck {
502c2c66affSColin Finck PGRAPHICS_DEVICE pGraphicsDevice;
503c2c66affSColin Finck PDEVICE_OBJECT pDeviceObject;
504c2c66affSColin Finck PFILE_OBJECT pFileObject;
505c2c66affSColin Finck NTSTATUS Status;
5060ad65796SHermès Bélusca-Maïto VIDEO_WIN32K_CALLBACKS Win32kCallbacks;
5070ad65796SHermès Bélusca-Maïto ULONG ulReturn;
508c2c66affSColin Finck PWSTR pwsz;
509c2c66affSColin Finck ULONG cj;
510c2c66affSColin Finck
511c2c66affSColin Finck TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName);
512c2c66affSColin Finck
513c2c66affSColin Finck /* Allocate a GRAPHICS_DEVICE structure */
5143d01a103SHervé Poussineau pGraphicsDevice = ExAllocatePoolZero(PagedPool,
515c2c66affSColin Finck sizeof(GRAPHICS_DEVICE),
516c2c66affSColin Finck GDITAG_GDEVICE);
517c2c66affSColin Finck if (!pGraphicsDevice)
518c2c66affSColin Finck {
519c2c66affSColin Finck ERR("ExAllocatePoolWithTag failed\n");
520c2c66affSColin Finck return NULL;
521c2c66affSColin Finck }
522c2c66affSColin Finck
5230ad90f83SHermès Bélusca-Maïto /* Try to open and enable the device */
524c2c66affSColin Finck Status = IoGetDeviceObjectPointer(pustrDeviceName,
525c2c66affSColin Finck FILE_READ_DATA | FILE_WRITE_DATA,
526c2c66affSColin Finck &pFileObject,
527c2c66affSColin Finck &pDeviceObject);
528c2c66affSColin Finck if (!NT_SUCCESS(Status))
529c2c66affSColin Finck {
5300ad90f83SHermès Bélusca-Maïto ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status);
531c2c66affSColin Finck ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
532c2c66affSColin Finck return NULL;
533c2c66affSColin Finck }
534c2c66affSColin Finck
535c2c66affSColin Finck /* Copy the device and file object pointers */
536c2c66affSColin Finck pGraphicsDevice->DeviceObject = pDeviceObject;
537c2c66affSColin Finck pGraphicsDevice->FileObject = pFileObject;
538c2c66affSColin Finck
5390ad65796SHermès Bélusca-Maïto /* Initialize and register the device with videoprt for Win32k callbacks */
5400ad65796SHermès Bélusca-Maïto Win32kCallbacks.PhysDisp = pGraphicsDevice;
5410ad65796SHermès Bélusca-Maïto Win32kCallbacks.Callout = VideoPortCallout;
5420ad65796SHermès Bélusca-Maïto // Reset the data being returned prior to the call.
5430ad65796SHermès Bélusca-Maïto Win32kCallbacks.bACPI = FALSE;
5440ad65796SHermès Bélusca-Maïto Win32kCallbacks.pPhysDeviceObject = NULL;
5450ad65796SHermès Bélusca-Maïto Win32kCallbacks.DualviewFlags = 0;
5460ad65796SHermès Bélusca-Maïto Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject,
5470ad65796SHermès Bélusca-Maïto IOCTL_VIDEO_INIT_WIN32K_CALLBACKS,
5480ad65796SHermès Bélusca-Maïto &Win32kCallbacks,
5490ad65796SHermès Bélusca-Maïto sizeof(Win32kCallbacks),
5500ad65796SHermès Bélusca-Maïto &Win32kCallbacks,
5510ad65796SHermès Bélusca-Maïto sizeof(Win32kCallbacks),
5520ad65796SHermès Bélusca-Maïto &ulReturn);
5530ad65796SHermès Bélusca-Maïto if (Status != ERROR_SUCCESS)
5540ad65796SHermès Bélusca-Maïto {
5550ad65796SHermès Bélusca-Maïto ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n",
5560ad65796SHermès Bélusca-Maïto pDeviceObject, Status);
5570ad65796SHermès Bélusca-Maïto }
5580ad65796SHermès Bélusca-Maïto // TODO: Set flags according to the results.
5590ad65796SHermès Bélusca-Maïto // if (Win32kCallbacks.bACPI)
5600ad65796SHermès Bélusca-Maïto // if (Win32kCallbacks.DualviewFlags & ???)
56131827c43SStanislav Motylkov pGraphicsDevice->PhysDeviceHandle = Win32kCallbacks.pPhysDeviceObject;
5620ad65796SHermès Bélusca-Maïto
56326b88af6SStanislav Motylkov /* FIXME: Enumerate children monitor devices for this video adapter
56426b88af6SStanislav Motylkov *
56526b88af6SStanislav Motylkov * - Force the adapter to re-enumerate its monitors:
56626b88af6SStanislav Motylkov * IoSynchronousInvalidateDeviceRelations(pdo, BusRelations)
56726b88af6SStanislav Motylkov *
56826b88af6SStanislav Motylkov * - Retrieve all monitor PDOs from VideoPrt:
56926b88af6SStanislav Motylkov * EngDeviceIoControl(0x%p, IOCTL_VIDEO_ENUM_MONITOR_PDO)
57026b88af6SStanislav Motylkov *
57126b88af6SStanislav Motylkov * - Initialize these fields and structures accordingly:
57226b88af6SStanislav Motylkov * pGraphicsDevice->dwMonCnt
57326b88af6SStanislav Motylkov * pGraphicsDevice->pvMonDev[0..dwMonCnt-1]
57426b88af6SStanislav Motylkov */
57526b88af6SStanislav Motylkov
576acf689a9SHermès Bélusca-Maïto /* Copy the device name */
577c2c66affSColin Finck RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName,
578c2c66affSColin Finck sizeof(pGraphicsDevice->szNtDeviceName),
579c2c66affSColin Finck pustrDeviceName->Buffer,
580c2c66affSColin Finck pustrDeviceName->Length);
581c2c66affSColin Finck
582acf689a9SHermès Bélusca-Maïto /* Create a Win32 device name (FIXME: virtual devices!) */
583acf689a9SHermès Bélusca-Maïto RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName,
584acf689a9SHermès Bélusca-Maïto sizeof(pGraphicsDevice->szWinDeviceName),
585acf689a9SHermès Bélusca-Maïto L"\\\\.\\DISPLAY%d",
586acf689a9SHermès Bélusca-Maïto (int)giDevNum);
587c2c66affSColin Finck
588c2c66affSColin Finck /* Allocate a buffer for the strings */
589c2c66affSColin Finck cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR);
590c2c66affSColin Finck pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP);
591c2c66affSColin Finck if (!pwsz)
592c2c66affSColin Finck {
593c2c66affSColin Finck ERR("Could not allocate string buffer\n");
594c2c66affSColin Finck ASSERT(FALSE); // FIXME
595c2c66affSColin Finck ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
596c2c66affSColin Finck return NULL;
597c2c66affSColin Finck }
598c2c66affSColin Finck
5990ad90f83SHermès Bélusca-Maïto /* Copy the display driver names */
600c2c66affSColin Finck pGraphicsDevice->pDiplayDrivers = pwsz;
601c2c66affSColin Finck RtlCopyMemory(pGraphicsDevice->pDiplayDrivers,
602c2c66affSColin Finck pustrDiplayDrivers->Buffer,
603c2c66affSColin Finck pustrDiplayDrivers->Length);
604c2c66affSColin Finck
6050ad90f83SHermès Bélusca-Maïto /* Copy the description */
606c2c66affSColin Finck pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR);
607c2c66affSColin Finck RtlCopyMemory(pGraphicsDevice->pwszDescription,
608c2c66affSColin Finck pustrDescription->Buffer,
609c2c66affSColin Finck pustrDescription->Length);
610c2c66affSColin Finck pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0;
611c2c66affSColin Finck
612c2c66affSColin Finck /* Lock loader */
613c2c66affSColin Finck EngAcquireSemaphore(ghsemGraphicsDeviceList);
614c2c66affSColin Finck
615c2c66affSColin Finck /* Insert the device into the global list */
616b3cdb7e7SHervé Poussineau EngpLinkGraphicsDevice(pGraphicsDevice);
617c2c66affSColin Finck
6180ad90f83SHermès Bélusca-Maïto /* Increment the device number */
619c2c66affSColin Finck giDevNum++;
620c2c66affSColin Finck
621c2c66affSColin Finck /* Unlock loader */
622c2c66affSColin Finck EngReleaseSemaphore(ghsemGraphicsDeviceList);
623c2c66affSColin Finck TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription);
624c2c66affSColin Finck
6250f6b9664SHervé Poussineau /* HACK: already in graphic mode; display wallpaper on this new display */
6260f6b9664SHervé Poussineau if (ScreenDeviceContext)
6270f6b9664SHervé Poussineau {
6280f6b9664SHervé Poussineau UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
6290f6b9664SHervé Poussineau UNICODE_STRING DisplayName;
6300f6b9664SHervé Poussineau HDC hdc;
6310f6b9664SHervé Poussineau RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName);
6320f6b9664SHervé Poussineau hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE);
6330f6b9664SHervé Poussineau IntPaintDesktop(hdc);
6340f6b9664SHervé Poussineau }
6350f6b9664SHervé Poussineau
636c2c66affSColin Finck return pGraphicsDevice;
637c2c66affSColin Finck }
638c2c66affSColin Finck
639c2c66affSColin Finck PGRAPHICS_DEVICE
640c2c66affSColin Finck NTAPI
EngpFindGraphicsDevice(_In_opt_ PUNICODE_STRING pustrDevice,_In_ ULONG iDevNum)641c2c66affSColin Finck EngpFindGraphicsDevice(
642c2c66affSColin Finck _In_opt_ PUNICODE_STRING pustrDevice,
643ded971c4SHervé Poussineau _In_ ULONG iDevNum)
644c2c66affSColin Finck {
645c2c66affSColin Finck UNICODE_STRING ustrCurrent;
646c2c66affSColin Finck PGRAPHICS_DEVICE pGraphicsDevice;
647c2c66affSColin Finck ULONG i;
648ded971c4SHervé Poussineau TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n",
649ded971c4SHervé Poussineau pustrDevice, iDevNum);
650c2c66affSColin Finck
651c2c66affSColin Finck /* Lock list */
652c2c66affSColin Finck EngAcquireSemaphore(ghsemGraphicsDeviceList);
653c2c66affSColin Finck
654c2c66affSColin Finck if (pustrDevice && pustrDevice->Buffer)
655c2c66affSColin Finck {
65626b88af6SStanislav Motylkov /* Find specified video adapter by name */
657c2c66affSColin Finck for (pGraphicsDevice = gpGraphicsDeviceFirst;
658c2c66affSColin Finck pGraphicsDevice;
659c2c66affSColin Finck pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
660c2c66affSColin Finck {
661c2c66affSColin Finck /* Compare the device name */
662c2c66affSColin Finck RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
663c2c66affSColin Finck if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE))
664c2c66affSColin Finck {
665c2c66affSColin Finck break;
666c2c66affSColin Finck }
667c2c66affSColin Finck }
66826b88af6SStanislav Motylkov
66926b88af6SStanislav Motylkov if (pGraphicsDevice)
67026b88af6SStanislav Motylkov {
67126b88af6SStanislav Motylkov /* Validate selected monitor number */
67226b88af6SStanislav Motylkov #if 0
67326b88af6SStanislav Motylkov if (iDevNum >= pGraphicsDevice->dwMonCnt)
67426b88af6SStanislav Motylkov pGraphicsDevice = NULL;
67526b88af6SStanislav Motylkov #else
67626b88af6SStanislav Motylkov /* FIXME: dwMonCnt not initialized, see EngpRegisterGraphicsDevice */
67726b88af6SStanislav Motylkov #endif
67826b88af6SStanislav Motylkov }
679c2c66affSColin Finck }
680c2c66affSColin Finck else
681c2c66affSColin Finck {
68226b88af6SStanislav Motylkov /* Select video adapter by device number */
683c2c66affSColin Finck for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0;
684c2c66affSColin Finck pGraphicsDevice && i < iDevNum;
685c2c66affSColin Finck pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++);
686c2c66affSColin Finck }
687c2c66affSColin Finck
688c2c66affSColin Finck /* Unlock list */
689c2c66affSColin Finck EngReleaseSemaphore(ghsemGraphicsDeviceList);
690c2c66affSColin Finck
691c2c66affSColin Finck return pGraphicsDevice;
692c2c66affSColin Finck }
693c2c66affSColin Finck
694c2c66affSColin Finck static
695c2c66affSColin Finck 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)696c2c66affSColin Finck EngpFileIoRequest(
697c2c66affSColin Finck _In_ PFILE_OBJECT pFileObject,
698c2c66affSColin Finck _In_ ULONG ulMajorFunction,
699c2c66affSColin Finck _In_reads_(nBufferSize) PVOID lpBuffer,
700c2c66affSColin Finck _In_ SIZE_T nBufferSize,
701c2c66affSColin Finck _In_ ULONGLONG ullStartOffset,
702c2c66affSColin Finck _Out_ PULONG_PTR lpInformation)
703c2c66affSColin Finck {
704c2c66affSColin Finck PDEVICE_OBJECT pDeviceObject;
705c2c66affSColin Finck KEVENT Event;
706c2c66affSColin Finck PIRP pIrp;
707c2c66affSColin Finck IO_STATUS_BLOCK Iosb;
708c2c66affSColin Finck NTSTATUS Status;
709c2c66affSColin Finck LARGE_INTEGER liStartOffset;
710c2c66affSColin Finck
711c2c66affSColin Finck /* Get corresponding device object */
712c2c66affSColin Finck pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
713c2c66affSColin Finck if (!pDeviceObject)
714c2c66affSColin Finck {
715c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
716c2c66affSColin Finck }
717c2c66affSColin Finck
718c2c66affSColin Finck /* Initialize an event */
719c2c66affSColin Finck KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
720c2c66affSColin Finck
721c2c66affSColin Finck /* Build IRP */
722c2c66affSColin Finck liStartOffset.QuadPart = ullStartOffset;
723c2c66affSColin Finck pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction,
724c2c66affSColin Finck pDeviceObject,
725c2c66affSColin Finck lpBuffer,
726c2c66affSColin Finck (ULONG)nBufferSize,
727c2c66affSColin Finck &liStartOffset,
728c2c66affSColin Finck &Event,
729c2c66affSColin Finck &Iosb);
730c2c66affSColin Finck if (!pIrp)
731c2c66affSColin Finck {
732c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
733c2c66affSColin Finck }
734c2c66affSColin Finck
735c2c66affSColin Finck /* Call the driver */
736c2c66affSColin Finck Status = IoCallDriver(pDeviceObject, pIrp);
737c2c66affSColin Finck
738c2c66affSColin Finck /* Wait if neccessary */
739c2c66affSColin Finck if (STATUS_PENDING == Status)
740c2c66affSColin Finck {
741c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
742c2c66affSColin Finck Status = Iosb.Status;
743c2c66affSColin Finck }
744c2c66affSColin Finck
745c2c66affSColin Finck /* Return information to the caller about the operation. */
746c2c66affSColin Finck *lpInformation = Iosb.Information;
747c2c66affSColin Finck
748c2c66affSColin Finck /* Return NTSTATUS */
749c2c66affSColin Finck return Status;
750c2c66affSColin Finck }
751c2c66affSColin Finck
752c2c66affSColin Finck VOID
753c2c66affSColin Finck APIENTRY
EngFileWrite(_In_ PFILE_OBJECT pFileObject,_In_reads_ (nLength)PVOID lpBuffer,_In_ SIZE_T nLength,_Out_ PSIZE_T lpBytesWritten)754c2c66affSColin Finck EngFileWrite(
755c2c66affSColin Finck _In_ PFILE_OBJECT pFileObject,
756c2c66affSColin Finck _In_reads_(nLength) PVOID lpBuffer,
757c2c66affSColin Finck _In_ SIZE_T nLength,
758c2c66affSColin Finck _Out_ PSIZE_T lpBytesWritten)
759c2c66affSColin Finck {
760c2c66affSColin Finck NTSTATUS status;
761c2c66affSColin Finck
762c2c66affSColin Finck status = EngpFileIoRequest(pFileObject,
763c2c66affSColin Finck IRP_MJ_WRITE,
764c2c66affSColin Finck lpBuffer,
765c2c66affSColin Finck nLength,
766c2c66affSColin Finck 0,
767c2c66affSColin Finck lpBytesWritten);
768c2c66affSColin Finck if (!NT_SUCCESS(status))
769c2c66affSColin Finck {
770c2c66affSColin Finck *lpBytesWritten = 0;
771c2c66affSColin Finck }
772c2c66affSColin Finck }
773c2c66affSColin Finck
774c2c66affSColin Finck _Success_(return>=0)
775c2c66affSColin Finck NTSTATUS
776c2c66affSColin Finck 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)777c2c66affSColin Finck EngFileIoControl(
778c2c66affSColin Finck _In_ PFILE_OBJECT pFileObject,
779c2c66affSColin Finck _In_ DWORD dwIoControlCode,
780c2c66affSColin Finck _In_reads_(nInBufferSize) PVOID lpInBuffer,
781c2c66affSColin Finck _In_ SIZE_T nInBufferSize,
782c2c66affSColin Finck _Out_writes_(nOutBufferSize) PVOID lpOutBuffer,
783c2c66affSColin Finck _In_ SIZE_T nOutBufferSize,
784c2c66affSColin Finck _Out_ PULONG_PTR lpInformation)
785c2c66affSColin Finck {
786c2c66affSColin Finck PDEVICE_OBJECT pDeviceObject;
787c2c66affSColin Finck KEVENT Event;
788c2c66affSColin Finck PIRP pIrp;
789c2c66affSColin Finck IO_STATUS_BLOCK Iosb;
790c2c66affSColin Finck NTSTATUS Status;
791c2c66affSColin Finck
792c2c66affSColin Finck /* Get corresponding device object */
793c2c66affSColin Finck pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
794c2c66affSColin Finck if (!pDeviceObject)
795c2c66affSColin Finck {
796c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
797c2c66affSColin Finck }
798c2c66affSColin Finck
799c2c66affSColin Finck /* Initialize an event */
800c2c66affSColin Finck KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
801c2c66affSColin Finck
802c2c66affSColin Finck /* Build IO control IRP */
803c2c66affSColin Finck pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode,
804c2c66affSColin Finck pDeviceObject,
805c2c66affSColin Finck lpInBuffer,
806c2c66affSColin Finck (ULONG)nInBufferSize,
807c2c66affSColin Finck lpOutBuffer,
808c2c66affSColin Finck (ULONG)nOutBufferSize,
809c2c66affSColin Finck FALSE,
810c2c66affSColin Finck &Event,
811c2c66affSColin Finck &Iosb);
812c2c66affSColin Finck if (!pIrp)
813c2c66affSColin Finck {
814c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
815c2c66affSColin Finck }
816c2c66affSColin Finck
817c2c66affSColin Finck /* Call the driver */
818c2c66affSColin Finck Status = IoCallDriver(pDeviceObject, pIrp);
819c2c66affSColin Finck
820c2c66affSColin Finck /* Wait if neccessary */
821c2c66affSColin Finck if (Status == STATUS_PENDING)
822c2c66affSColin Finck {
823c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
824c2c66affSColin Finck Status = Iosb.Status;
825c2c66affSColin Finck }
826c2c66affSColin Finck
827c2c66affSColin Finck /* Return information to the caller about the operation. */
828c2c66affSColin Finck *lpInformation = Iosb.Information;
829c2c66affSColin Finck
830c2c66affSColin Finck /* This function returns NTSTATUS */
831c2c66affSColin Finck return Status;
832c2c66affSColin Finck }
833c2c66affSColin Finck
834c2c66affSColin Finck /*
835c2c66affSColin Finck * @implemented
836c2c66affSColin Finck */
837c2c66affSColin Finck _Success_(return==0)
838c2c66affSColin Finck DWORD
839c2c66affSColin Finck 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)840c2c66affSColin Finck EngDeviceIoControl(
841c2c66affSColin Finck _In_ HANDLE hDevice,
842c2c66affSColin Finck _In_ DWORD dwIoControlCode,
843c2c66affSColin Finck _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer,
844c2c66affSColin Finck _In_ DWORD cjInBufferSize,
845c2c66affSColin Finck _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer,
846c2c66affSColin Finck _In_ DWORD cjOutBufferSize,
847c2c66affSColin Finck _Out_ LPDWORD lpBytesReturned)
848c2c66affSColin Finck {
849c2c66affSColin Finck PIRP Irp;
850c2c66affSColin Finck NTSTATUS Status;
851c2c66affSColin Finck KEVENT Event;
852c2c66affSColin Finck IO_STATUS_BLOCK Iosb;
853c2c66affSColin Finck PDEVICE_OBJECT DeviceObject;
854c2c66affSColin Finck
855c2c66affSColin Finck TRACE("EngDeviceIoControl() called\n");
856c2c66affSColin Finck
85701b580d8SPierre Schweitzer if (!hDevice)
85801b580d8SPierre Schweitzer {
85901b580d8SPierre Schweitzer return ERROR_INVALID_HANDLE;
86001b580d8SPierre Schweitzer }
86101b580d8SPierre Schweitzer
862c2c66affSColin Finck KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
863c2c66affSColin Finck
864c2c66affSColin Finck DeviceObject = (PDEVICE_OBJECT) hDevice;
865c2c66affSColin Finck
866c2c66affSColin Finck Irp = IoBuildDeviceIoControlRequest(dwIoControlCode,
867c2c66affSColin Finck DeviceObject,
868c2c66affSColin Finck lpInBuffer,
869c2c66affSColin Finck cjInBufferSize,
870c2c66affSColin Finck lpOutBuffer,
871c2c66affSColin Finck cjOutBufferSize,
872c2c66affSColin Finck FALSE,
873c2c66affSColin Finck &Event,
874c2c66affSColin Finck &Iosb);
875c2c66affSColin Finck if (!Irp) return ERROR_NOT_ENOUGH_MEMORY;
876c2c66affSColin Finck
877c2c66affSColin Finck Status = IoCallDriver(DeviceObject, Irp);
878c2c66affSColin Finck
879c2c66affSColin Finck if (Status == STATUS_PENDING)
880c2c66affSColin Finck {
881c2c66affSColin Finck (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
882c2c66affSColin Finck Status = Iosb.Status;
883c2c66affSColin Finck }
884c2c66affSColin Finck
885c2c66affSColin Finck TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status,
886c2c66affSColin Finck Iosb.Information);
887c2c66affSColin Finck
888c2c66affSColin Finck /* Return information to the caller about the operation. */
889c2c66affSColin Finck *lpBytesReturned = (DWORD)Iosb.Information;
890c2c66affSColin Finck
891c2c66affSColin Finck /* Convert NT status values to win32 error codes. */
892c2c66affSColin Finck switch (Status)
893c2c66affSColin Finck {
894c2c66affSColin Finck case STATUS_INSUFFICIENT_RESOURCES:
895c2c66affSColin Finck return ERROR_NOT_ENOUGH_MEMORY;
896c2c66affSColin Finck
897c2c66affSColin Finck case STATUS_BUFFER_OVERFLOW:
898c2c66affSColin Finck return ERROR_MORE_DATA;
899c2c66affSColin Finck
900c2c66affSColin Finck case STATUS_NOT_IMPLEMENTED:
901c2c66affSColin Finck return ERROR_INVALID_FUNCTION;
902c2c66affSColin Finck
903c2c66affSColin Finck case STATUS_INVALID_PARAMETER:
904c2c66affSColin Finck return ERROR_INVALID_PARAMETER;
905c2c66affSColin Finck
906c2c66affSColin Finck case STATUS_BUFFER_TOO_SMALL:
907c2c66affSColin Finck return ERROR_INSUFFICIENT_BUFFER;
908c2c66affSColin Finck
909c2c66affSColin Finck case STATUS_DEVICE_DOES_NOT_EXIST:
910c2c66affSColin Finck return ERROR_DEV_NOT_EXIST;
911c2c66affSColin Finck
912c2c66affSColin Finck case STATUS_PENDING:
913c2c66affSColin Finck return ERROR_IO_PENDING;
914c2c66affSColin Finck }
915c2c66affSColin Finck
916c2c66affSColin Finck return Status;
917c2c66affSColin Finck }
918c2c66affSColin Finck
919c2c66affSColin Finck /* EOF */
920