xref: /reactos/win32ss/gdi/eng/device.c (revision 42914af2)
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