xref: /reactos/win32ss/gdi/eng/device.c (revision ded971c4)
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 
15c2c66affSColin Finck PGRAPHICS_DEVICE gpPrimaryGraphicsDevice;
16c2c66affSColin Finck 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
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 
356739fb1bSHervé Poussineau NTSTATUS
366739fb1bSHervé Poussineau EngpUpdateGraphicsDeviceList(VOID)
376739fb1bSHervé Poussineau {
386739fb1bSHervé Poussineau     ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
39c05a45e1SOleg Dubinskiy     WCHAR awcDeviceName[20], awcWinDeviceName[20];
4077e891b8STimo Kreuzer     UNICODE_STRING ustrDeviceName;
416739fb1bSHervé Poussineau     WCHAR awcBuffer[256];
426739fb1bSHervé Poussineau     NTSTATUS Status;
436739fb1bSHervé Poussineau     PGRAPHICS_DEVICE pGraphicsDevice;
446739fb1bSHervé Poussineau     ULONG cbValue;
456739fb1bSHervé Poussineau     HKEY hkey;
466739fb1bSHervé Poussineau 
476739fb1bSHervé Poussineau     /* Open the key for the adapters */
486739fb1bSHervé Poussineau     Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey);
496739fb1bSHervé Poussineau     if (!NT_SUCCESS(Status))
506739fb1bSHervé Poussineau     {
516739fb1bSHervé Poussineau         ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status);
526739fb1bSHervé Poussineau         return Status;
536739fb1bSHervé Poussineau     }
546739fb1bSHervé Poussineau 
556739fb1bSHervé Poussineau     /* Read the name of the VGA adapter */
566739fb1bSHervé Poussineau     cbValue = sizeof(awcDeviceName);
576739fb1bSHervé Poussineau     Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
586739fb1bSHervé Poussineau     if (NT_SUCCESS(Status))
596739fb1bSHervé Poussineau     {
606739fb1bSHervé Poussineau         iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]);
616739fb1bSHervé Poussineau         ERR("VGA adapter = %lu\n", iVGACompatible);
626739fb1bSHervé Poussineau     }
636739fb1bSHervé Poussineau 
646739fb1bSHervé Poussineau     /* Get the maximum mumber of adapters */
656739fb1bSHervé Poussineau     if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber))
666739fb1bSHervé Poussineau     {
676739fb1bSHervé Poussineau         ERR("Could not read MaxObjectNumber, defaulting to 0.\n");
686739fb1bSHervé Poussineau     }
696739fb1bSHervé Poussineau 
706739fb1bSHervé Poussineau     TRACE("Found %lu devices\n", ulMaxObjectNumber + 1);
716739fb1bSHervé Poussineau 
726739fb1bSHervé Poussineau     /* Loop through all adapters */
736739fb1bSHervé Poussineau     for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
746739fb1bSHervé Poussineau     {
756739fb1bSHervé Poussineau         /* Create the adapter's key name */
766739fb1bSHervé Poussineau         swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
77c05a45e1SOleg Dubinskiy 
78c05a45e1SOleg Dubinskiy         /* Create the display device name */
79c05a45e1SOleg Dubinskiy         swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1);
80c05a45e1SOleg Dubinskiy         RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName);
8177e891b8STimo Kreuzer 
8277e891b8STimo Kreuzer         /* Check if the device exists already */
83*ded971c4SHervé Poussineau         pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum);
8477e891b8STimo Kreuzer         if (pGraphicsDevice != NULL)
8577e891b8STimo Kreuzer         {
8677e891b8STimo Kreuzer             continue;
8777e891b8STimo Kreuzer         }
886739fb1bSHervé Poussineau 
896739fb1bSHervé Poussineau         /* Read the reg key name */
906739fb1bSHervé Poussineau         cbValue = sizeof(awcBuffer);
916739fb1bSHervé Poussineau         Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue);
926739fb1bSHervé Poussineau         if (!NT_SUCCESS(Status))
936739fb1bSHervé Poussineau         {
946739fb1bSHervé Poussineau             ERR("failed to query the registry path:0x%lx\n", Status);
956739fb1bSHervé Poussineau             continue;
966739fb1bSHervé Poussineau         }
976739fb1bSHervé Poussineau 
986739fb1bSHervé Poussineau         /* Initialize the driver for this device */
996739fb1bSHervé Poussineau         pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer);
1006739fb1bSHervé Poussineau         if (!pGraphicsDevice) continue;
1016739fb1bSHervé Poussineau 
1026739fb1bSHervé Poussineau         /* Check if this is a VGA compatible adapter */
1036739fb1bSHervé Poussineau         if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE)
1046739fb1bSHervé Poussineau         {
1056739fb1bSHervé Poussineau             /* Save this as the VGA adapter */
1066739fb1bSHervé Poussineau             if (!gpVgaGraphicsDevice)
10739d8a822STimo Kreuzer             {
1086739fb1bSHervé Poussineau                 gpVgaGraphicsDevice = pGraphicsDevice;
1096739fb1bSHervé Poussineau                 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice);
1106739fb1bSHervé Poussineau             }
11139d8a822STimo Kreuzer         }
11239d8a822STimo Kreuzer 
1136739fb1bSHervé Poussineau         /* Set the first one as primary device */
1146739fb1bSHervé Poussineau         if (!gpPrimaryGraphicsDevice)
11539d8a822STimo Kreuzer         {
1166739fb1bSHervé Poussineau             gpPrimaryGraphicsDevice = pGraphicsDevice;
1176739fb1bSHervé Poussineau             TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice);
1186739fb1bSHervé Poussineau         }
1196739fb1bSHervé Poussineau     }
1206739fb1bSHervé Poussineau 
1216739fb1bSHervé Poussineau     /* Close the device map registry key */
1226739fb1bSHervé Poussineau     ZwClose(hkey);
1236739fb1bSHervé Poussineau 
1246739fb1bSHervé Poussineau     return STATUS_SUCCESS;
1256739fb1bSHervé Poussineau }
1266739fb1bSHervé Poussineau 
127c2c66affSColin Finck BOOLEAN
128c2c66affSColin Finck EngpPopulateDeviceModeList(
129c2c66affSColin Finck     _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
130c2c66affSColin Finck     _In_ PDEVMODEW pdmDefault)
131c2c66affSColin Finck {
132c2c66affSColin Finck     PDEVMODEINFO pdminfo;
1333cb1dd8aSHervé Poussineau     PDEVMODEW pdm, pdmSelected;
13421ddeb76SHervé Poussineau     ULONG i;
135c2c66affSColin Finck 
136c2c66affSColin Finck     ASSERT(pGraphicsDevice->pdevmodeInfo == NULL);
137c2c66affSColin Finck     ASSERT(pGraphicsDevice->pDevModeList == NULL);
138c2c66affSColin Finck 
1393cb1dd8aSHervé Poussineau     if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, pdmDefault, &pdmSelected, TRUE))
140c2c66affSColin Finck     {
1413cb1dd8aSHervé Poussineau         ERR("LDEVOBJ_bProbeAndCaptureDevmode() failed\n");
142c2c66affSColin Finck         return FALSE;
143c2c66affSColin Finck     }
144c2c66affSColin Finck 
145c2c66affSColin Finck     /* Loop through all DEVMODEINFOs */
146c2c66affSColin Finck     for (pdminfo = pGraphicsDevice->pdevmodeInfo, i = 0;
147c2c66affSColin Finck          pdminfo;
148c2c66affSColin Finck          pdminfo = pdminfo->pdmiNext)
149c2c66affSColin Finck     {
150c2c66affSColin Finck         /* Loop through the DEVMODEs */
15121ddeb76SHervé Poussineau         for (i = 0; i < pGraphicsDevice->cDevModes; i++)
152c2c66affSColin Finck         {
15321ddeb76SHervé Poussineau             pdm = pGraphicsDevice->pDevModeList[i].pdm;
15421ddeb76SHervé Poussineau 
1553cb1dd8aSHervé Poussineau             /* Compare with the selected entry */
1563cb1dd8aSHervé Poussineau             if (pdm->dmSize == pdmSelected->dmSize &&
1573cb1dd8aSHervé Poussineau                 RtlCompareMemory(pdm, pdmSelected, pdm->dmSize) == pdm->dmSize)
158c2c66affSColin Finck             {
159c2c66affSColin Finck                 pGraphicsDevice->iDefaultMode = i;
160c2c66affSColin Finck                 pGraphicsDevice->iCurrentMode = i;
161c2c66affSColin Finck                 TRACE("Found default entry: %lu '%ls'\n", i, pdm->dmDeviceName);
1623cb1dd8aSHervé Poussineau                 break;
163c2c66affSColin Finck             }
164c2c66affSColin Finck         }
165c2c66affSColin Finck     }
166c2c66affSColin Finck     return TRUE;
167c2c66affSColin Finck }
168c2c66affSColin Finck 
1690ad65796SHermès Bélusca-Maïto extern VOID
1700ad65796SHermès Bélusca-Maïto UserRefreshDisplay(IN PPDEVOBJ ppdev);
1710ad65796SHermès Bélusca-Maïto 
1720ad65796SHermès Bélusca-Maïto // PVIDEO_WIN32K_CALLOUT
1730ad65796SHermès Bélusca-Maïto VOID
1740ad65796SHermès Bélusca-Maïto NTAPI
1750ad65796SHermès Bélusca-Maïto VideoPortCallout(
1760ad65796SHermès Bélusca-Maïto     _In_ PVOID Params)
1770ad65796SHermès Bélusca-Maïto {
1780ad65796SHermès Bélusca-Maïto /*
1790ad65796SHermès Bélusca-Maïto  * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of
1800ad65796SHermès Bélusca-Maïto  * a specific VideoPortCalloutThread() system thread using the same mechanism
1810ad65796SHermès Bélusca-Maïto  * as the RIT/desktop/Ghost system threads.
1820ad65796SHermès Bélusca-Maïto  */
1830ad65796SHermès Bélusca-Maïto 
1840ad65796SHermès Bélusca-Maïto     PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params;
1850ad65796SHermès Bélusca-Maïto 
1860ad65796SHermès Bélusca-Maïto     TRACE("VideoPortCallout(0x%p, 0x%x)\n",
1870ad65796SHermès Bélusca-Maïto           CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1);
1880ad65796SHermès Bélusca-Maïto 
1890ad65796SHermès Bélusca-Maïto     if (!CallbackParams)
1900ad65796SHermès Bélusca-Maïto         return;
1910ad65796SHermès Bélusca-Maïto 
1920ad65796SHermès Bélusca-Maïto     switch (CallbackParams->CalloutType)
1930ad65796SHermès Bélusca-Maïto     {
1940ad65796SHermès Bélusca-Maïto         case VideoFindAdapterCallout:
1950ad65796SHermès Bélusca-Maïto         {
1960ad65796SHermès Bélusca-Maïto             TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n",
1970ad65796SHermès Bélusca-Maïto                   CallbackParams->Param ? "TRUE" : "FALSE");
1980ad65796SHermès Bélusca-Maïto             if (CallbackParams->Param == TRUE)
1990ad65796SHermès Bélusca-Maïto             {
2000ad65796SHermès Bélusca-Maïto                 /* Re-enable the display */
2010ad65796SHermès Bélusca-Maïto                 UserRefreshDisplay(gppdevPrimary);
2020ad65796SHermès Bélusca-Maïto             }
2030ad65796SHermès Bélusca-Maïto             else
2040ad65796SHermès Bélusca-Maïto             {
2050ad65796SHermès Bélusca-Maïto                 /* Disable the display */
2060ad65796SHermès Bélusca-Maïto                 NOTHING; // Nothing to do for the moment...
2070ad65796SHermès Bélusca-Maïto             }
2080ad65796SHermès Bélusca-Maïto 
2090ad65796SHermès Bélusca-Maïto             CallbackParams->Status = STATUS_SUCCESS;
2100ad65796SHermès Bélusca-Maïto             break;
2110ad65796SHermès Bélusca-Maïto         }
2120ad65796SHermès Bélusca-Maïto 
2130ad65796SHermès Bélusca-Maïto         case VideoPowerNotifyCallout:
2140ad65796SHermès Bélusca-Maïto         case VideoDisplaySwitchCallout:
2150ad65796SHermès Bélusca-Maïto         case VideoEnumChildPdoNotifyCallout:
2160ad65796SHermès Bélusca-Maïto         case VideoWakeupCallout:
2170ad65796SHermès Bélusca-Maïto         case VideoChangeDisplaySettingsCallout:
2180ad65796SHermès Bélusca-Maïto         case VideoPnpNotifyCallout:
2190ad65796SHermès Bélusca-Maïto         case VideoDxgkDisplaySwitchCallout:
2200ad65796SHermès Bélusca-Maïto         case VideoDxgkMonitorEventCallout:
2210ad65796SHermès Bélusca-Maïto         case VideoDxgkFindAdapterTdrCallout:
2220ad65796SHermès Bélusca-Maïto             ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType);
2230ad65796SHermès Bélusca-Maïto             CallbackParams->Status = STATUS_NOT_IMPLEMENTED;
2240ad65796SHermès Bélusca-Maïto             break;
2250ad65796SHermès Bélusca-Maïto 
2260ad65796SHermès Bélusca-Maïto         default:
2270ad65796SHermès Bélusca-Maïto             ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType);
2280ad65796SHermès Bélusca-Maïto             CallbackParams->Status = STATUS_UNSUCCESSFUL;
2290ad65796SHermès Bélusca-Maïto             break;
2300ad65796SHermès Bélusca-Maïto     }
2310ad65796SHermès Bélusca-Maïto }
2320ad65796SHermès Bélusca-Maïto 
233c2c66affSColin Finck PGRAPHICS_DEVICE
234c2c66affSColin Finck NTAPI
235c2c66affSColin Finck EngpRegisterGraphicsDevice(
236c2c66affSColin Finck     _In_ PUNICODE_STRING pustrDeviceName,
237c2c66affSColin Finck     _In_ PUNICODE_STRING pustrDiplayDrivers,
238c2c66affSColin Finck     _In_ PUNICODE_STRING pustrDescription,
239c2c66affSColin Finck     _In_ PDEVMODEW pdmDefault)
240c2c66affSColin Finck {
241c2c66affSColin Finck     PGRAPHICS_DEVICE pGraphicsDevice;
242c2c66affSColin Finck     PDEVICE_OBJECT pDeviceObject;
243c2c66affSColin Finck     PFILE_OBJECT pFileObject;
244c2c66affSColin Finck     NTSTATUS Status;
2450ad65796SHermès Bélusca-Maïto     VIDEO_WIN32K_CALLBACKS Win32kCallbacks;
2460ad65796SHermès Bélusca-Maïto     ULONG ulReturn;
247c2c66affSColin Finck     PWSTR pwsz;
248c2c66affSColin Finck     ULONG cj;
249c2c66affSColin Finck 
250c2c66affSColin Finck     TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName);
251c2c66affSColin Finck 
252c2c66affSColin Finck     /* Allocate a GRAPHICS_DEVICE structure */
253c2c66affSColin Finck     pGraphicsDevice = ExAllocatePoolWithTag(PagedPool,
254c2c66affSColin Finck                                             sizeof(GRAPHICS_DEVICE),
255c2c66affSColin Finck                                             GDITAG_GDEVICE);
256c2c66affSColin Finck     if (!pGraphicsDevice)
257c2c66affSColin Finck     {
258c2c66affSColin Finck         ERR("ExAllocatePoolWithTag failed\n");
259c2c66affSColin Finck         return NULL;
260c2c66affSColin Finck     }
261c2c66affSColin Finck 
2620ad90f83SHermès Bélusca-Maïto     /* Try to open and enable the device */
263c2c66affSColin Finck     Status = IoGetDeviceObjectPointer(pustrDeviceName,
264c2c66affSColin Finck                                       FILE_READ_DATA | FILE_WRITE_DATA,
265c2c66affSColin Finck                                       &pFileObject,
266c2c66affSColin Finck                                       &pDeviceObject);
267c2c66affSColin Finck     if (!NT_SUCCESS(Status))
268c2c66affSColin Finck     {
2690ad90f83SHermès Bélusca-Maïto         ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status);
270c2c66affSColin Finck         ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
271c2c66affSColin Finck         return NULL;
272c2c66affSColin Finck     }
273c2c66affSColin Finck 
274c2c66affSColin Finck     /* Copy the device and file object pointers */
275c2c66affSColin Finck     pGraphicsDevice->DeviceObject = pDeviceObject;
276c2c66affSColin Finck     pGraphicsDevice->FileObject = pFileObject;
277c2c66affSColin Finck 
2780ad65796SHermès Bélusca-Maïto     /* Initialize and register the device with videoprt for Win32k callbacks */
2790ad65796SHermès Bélusca-Maïto     Win32kCallbacks.PhysDisp = pGraphicsDevice;
2800ad65796SHermès Bélusca-Maïto     Win32kCallbacks.Callout = VideoPortCallout;
2810ad65796SHermès Bélusca-Maïto     // Reset the data being returned prior to the call.
2820ad65796SHermès Bélusca-Maïto     Win32kCallbacks.bACPI = FALSE;
2830ad65796SHermès Bélusca-Maïto     Win32kCallbacks.pPhysDeviceObject = NULL;
2840ad65796SHermès Bélusca-Maïto     Win32kCallbacks.DualviewFlags = 0;
2850ad65796SHermès Bélusca-Maïto     Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject,
2860ad65796SHermès Bélusca-Maïto                                           IOCTL_VIDEO_INIT_WIN32K_CALLBACKS,
2870ad65796SHermès Bélusca-Maïto                                           &Win32kCallbacks,
2880ad65796SHermès Bélusca-Maïto                                           sizeof(Win32kCallbacks),
2890ad65796SHermès Bélusca-Maïto                                           &Win32kCallbacks,
2900ad65796SHermès Bélusca-Maïto                                           sizeof(Win32kCallbacks),
2910ad65796SHermès Bélusca-Maïto                                           &ulReturn);
2920ad65796SHermès Bélusca-Maïto     if (Status != ERROR_SUCCESS)
2930ad65796SHermès Bélusca-Maïto     {
2940ad65796SHermès Bélusca-Maïto         ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n",
2950ad65796SHermès Bélusca-Maïto             pDeviceObject, Status);
2960ad65796SHermès Bélusca-Maïto     }
2970ad65796SHermès Bélusca-Maïto     // TODO: Set flags according to the results.
2980ad65796SHermès Bélusca-Maïto     // if (Win32kCallbacks.bACPI)
2990ad65796SHermès Bélusca-Maïto     // if (Win32kCallbacks.DualviewFlags & ???)
3000ad65796SHermès Bélusca-Maïto     // Win32kCallbacks.pPhysDeviceObject;
3010ad65796SHermès Bélusca-Maïto 
302acf689a9SHermès Bélusca-Maïto     /* Copy the device name */
303c2c66affSColin Finck     RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName,
304c2c66affSColin Finck                       sizeof(pGraphicsDevice->szNtDeviceName),
305c2c66affSColin Finck                       pustrDeviceName->Buffer,
306c2c66affSColin Finck                       pustrDeviceName->Length);
307c2c66affSColin Finck 
308acf689a9SHermès Bélusca-Maïto     /* Create a Win32 device name (FIXME: virtual devices!) */
309acf689a9SHermès Bélusca-Maïto     RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName,
310acf689a9SHermès Bélusca-Maïto                        sizeof(pGraphicsDevice->szWinDeviceName),
311acf689a9SHermès Bélusca-Maïto                        L"\\\\.\\DISPLAY%d",
312acf689a9SHermès Bélusca-Maïto                        (int)giDevNum);
313c2c66affSColin Finck 
314c2c66affSColin Finck     /* Allocate a buffer for the strings */
315c2c66affSColin Finck     cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR);
316c2c66affSColin Finck     pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP);
317c2c66affSColin Finck     if (!pwsz)
318c2c66affSColin Finck     {
319c2c66affSColin Finck         ERR("Could not allocate string buffer\n");
320c2c66affSColin Finck         ASSERT(FALSE); // FIXME
321c2c66affSColin Finck         ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
322c2c66affSColin Finck         return NULL;
323c2c66affSColin Finck     }
324c2c66affSColin Finck 
3250ad90f83SHermès Bélusca-Maïto     /* Copy the display driver names */
326c2c66affSColin Finck     pGraphicsDevice->pDiplayDrivers = pwsz;
327c2c66affSColin Finck     RtlCopyMemory(pGraphicsDevice->pDiplayDrivers,
328c2c66affSColin Finck                   pustrDiplayDrivers->Buffer,
329c2c66affSColin Finck                   pustrDiplayDrivers->Length);
330c2c66affSColin Finck 
3310ad90f83SHermès Bélusca-Maïto     /* Copy the description */
332c2c66affSColin Finck     pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR);
333c2c66affSColin Finck     RtlCopyMemory(pGraphicsDevice->pwszDescription,
334c2c66affSColin Finck                   pustrDescription->Buffer,
335c2c66affSColin Finck                   pustrDescription->Length);
336c2c66affSColin Finck     pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0;
337c2c66affSColin Finck 
338c2c66affSColin Finck     /* Initialize the pdevmodeInfo list and default index  */
339c2c66affSColin Finck     pGraphicsDevice->pdevmodeInfo = NULL;
340c2c66affSColin Finck     pGraphicsDevice->iDefaultMode = 0;
341c2c66affSColin Finck     pGraphicsDevice->iCurrentMode = 0;
342c2c66affSColin Finck 
343c2c66affSColin Finck     // FIXME: initialize state flags
344c2c66affSColin Finck     pGraphicsDevice->StateFlags = 0;
345c2c66affSColin Finck 
346c2c66affSColin Finck     /* Create the mode list */
347c2c66affSColin Finck     pGraphicsDevice->pDevModeList = NULL;
348c2c66affSColin Finck     if (!EngpPopulateDeviceModeList(pGraphicsDevice, pdmDefault))
349c2c66affSColin Finck     {
350c2c66affSColin Finck         ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
351c2c66affSColin Finck         return NULL;
352c2c66affSColin Finck     }
353c2c66affSColin Finck 
354c2c66affSColin Finck     /* Lock loader */
355c2c66affSColin Finck     EngAcquireSemaphore(ghsemGraphicsDeviceList);
356c2c66affSColin Finck 
357c2c66affSColin Finck     /* Insert the device into the global list */
358c2c66affSColin Finck     pGraphicsDevice->pNextGraphicsDevice = NULL;
359c2c66affSColin Finck     if (gpGraphicsDeviceLast)
360c2c66affSColin Finck         gpGraphicsDeviceLast->pNextGraphicsDevice = pGraphicsDevice;
361c2c66affSColin Finck     gpGraphicsDeviceLast = pGraphicsDevice;
362c2c66affSColin Finck     if (!gpGraphicsDeviceFirst)
363c2c66affSColin Finck         gpGraphicsDeviceFirst = pGraphicsDevice;
364c2c66affSColin Finck 
3650ad90f83SHermès Bélusca-Maïto     /* Increment the device number */
366c2c66affSColin Finck     giDevNum++;
367c2c66affSColin Finck 
368c2c66affSColin Finck     /* Unlock loader */
369c2c66affSColin Finck     EngReleaseSemaphore(ghsemGraphicsDeviceList);
370c2c66affSColin Finck     TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription);
371c2c66affSColin Finck 
3720f6b9664SHervé Poussineau     /* HACK: already in graphic mode; display wallpaper on this new display */
3730f6b9664SHervé Poussineau     if (ScreenDeviceContext)
3740f6b9664SHervé Poussineau     {
3750f6b9664SHervé Poussineau         UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
3760f6b9664SHervé Poussineau         UNICODE_STRING DisplayName;
3770f6b9664SHervé Poussineau         HDC hdc;
3780f6b9664SHervé Poussineau         RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName);
3790f6b9664SHervé Poussineau         hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE);
3800f6b9664SHervé Poussineau         IntPaintDesktop(hdc);
3810f6b9664SHervé Poussineau     }
3820f6b9664SHervé Poussineau 
383c2c66affSColin Finck     return pGraphicsDevice;
384c2c66affSColin Finck }
385c2c66affSColin Finck 
386c2c66affSColin Finck PGRAPHICS_DEVICE
387c2c66affSColin Finck NTAPI
388c2c66affSColin Finck EngpFindGraphicsDevice(
389c2c66affSColin Finck     _In_opt_ PUNICODE_STRING pustrDevice,
390*ded971c4SHervé Poussineau     _In_ ULONG iDevNum)
391c2c66affSColin Finck {
392c2c66affSColin Finck     UNICODE_STRING ustrCurrent;
393c2c66affSColin Finck     PGRAPHICS_DEVICE pGraphicsDevice;
394c2c66affSColin Finck     ULONG i;
395*ded971c4SHervé Poussineau     TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n",
396*ded971c4SHervé Poussineau            pustrDevice, iDevNum);
397c2c66affSColin Finck 
398c2c66affSColin Finck     /* Lock list */
399c2c66affSColin Finck     EngAcquireSemaphore(ghsemGraphicsDeviceList);
400c2c66affSColin Finck 
401c2c66affSColin Finck     if (pustrDevice && pustrDevice->Buffer)
402c2c66affSColin Finck     {
403c2c66affSColin Finck         /* Loop through the list of devices */
404c2c66affSColin Finck         for (pGraphicsDevice = gpGraphicsDeviceFirst;
405c2c66affSColin Finck              pGraphicsDevice;
406c2c66affSColin Finck              pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
407c2c66affSColin Finck         {
408c2c66affSColin Finck             /* Compare the device name */
409c2c66affSColin Finck             RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
410c2c66affSColin Finck             if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE))
411c2c66affSColin Finck             {
412c2c66affSColin Finck                 break;
413c2c66affSColin Finck             }
414c2c66affSColin Finck         }
415c2c66affSColin Finck     }
416c2c66affSColin Finck     else
417c2c66affSColin Finck     {
418c2c66affSColin Finck         /* Loop through the list of devices */
419c2c66affSColin Finck         for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0;
420c2c66affSColin Finck              pGraphicsDevice && i < iDevNum;
421c2c66affSColin Finck              pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++);
422c2c66affSColin Finck     }
423c2c66affSColin Finck 
424c2c66affSColin Finck     /* Unlock list */
425c2c66affSColin Finck     EngReleaseSemaphore(ghsemGraphicsDeviceList);
426c2c66affSColin Finck 
427c2c66affSColin Finck     return pGraphicsDevice;
428c2c66affSColin Finck }
429c2c66affSColin Finck 
430c2c66affSColin Finck static
431c2c66affSColin Finck NTSTATUS
432c2c66affSColin Finck EngpFileIoRequest(
433c2c66affSColin Finck     _In_ PFILE_OBJECT pFileObject,
434c2c66affSColin Finck     _In_ ULONG ulMajorFunction,
435c2c66affSColin Finck     _In_reads_(nBufferSize) PVOID lpBuffer,
436c2c66affSColin Finck     _In_ SIZE_T nBufferSize,
437c2c66affSColin Finck     _In_ ULONGLONG ullStartOffset,
438c2c66affSColin Finck     _Out_ PULONG_PTR lpInformation)
439c2c66affSColin Finck {
440c2c66affSColin Finck     PDEVICE_OBJECT pDeviceObject;
441c2c66affSColin Finck     KEVENT Event;
442c2c66affSColin Finck     PIRP pIrp;
443c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
444c2c66affSColin Finck     NTSTATUS Status;
445c2c66affSColin Finck     LARGE_INTEGER liStartOffset;
446c2c66affSColin Finck 
447c2c66affSColin Finck     /* Get corresponding device object */
448c2c66affSColin Finck     pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
449c2c66affSColin Finck     if (!pDeviceObject)
450c2c66affSColin Finck     {
451c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
452c2c66affSColin Finck     }
453c2c66affSColin Finck 
454c2c66affSColin Finck     /* Initialize an event */
455c2c66affSColin Finck     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
456c2c66affSColin Finck 
457c2c66affSColin Finck     /* Build IRP */
458c2c66affSColin Finck     liStartOffset.QuadPart = ullStartOffset;
459c2c66affSColin Finck     pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction,
460c2c66affSColin Finck                                         pDeviceObject,
461c2c66affSColin Finck                                         lpBuffer,
462c2c66affSColin Finck                                         (ULONG)nBufferSize,
463c2c66affSColin Finck                                         &liStartOffset,
464c2c66affSColin Finck                                         &Event,
465c2c66affSColin Finck                                         &Iosb);
466c2c66affSColin Finck     if (!pIrp)
467c2c66affSColin Finck     {
468c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
469c2c66affSColin Finck     }
470c2c66affSColin Finck 
471c2c66affSColin Finck     /* Call the driver */
472c2c66affSColin Finck     Status = IoCallDriver(pDeviceObject, pIrp);
473c2c66affSColin Finck 
474c2c66affSColin Finck     /* Wait if neccessary */
475c2c66affSColin Finck     if (STATUS_PENDING == Status)
476c2c66affSColin Finck     {
477c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
478c2c66affSColin Finck         Status = Iosb.Status;
479c2c66affSColin Finck     }
480c2c66affSColin Finck 
481c2c66affSColin Finck     /* Return information to the caller about the operation. */
482c2c66affSColin Finck     *lpInformation = Iosb.Information;
483c2c66affSColin Finck 
484c2c66affSColin Finck     /* Return NTSTATUS */
485c2c66affSColin Finck     return Status;
486c2c66affSColin Finck }
487c2c66affSColin Finck 
488c2c66affSColin Finck VOID
489c2c66affSColin Finck APIENTRY
490c2c66affSColin Finck EngFileWrite(
491c2c66affSColin Finck     _In_ PFILE_OBJECT pFileObject,
492c2c66affSColin Finck     _In_reads_(nLength) PVOID lpBuffer,
493c2c66affSColin Finck     _In_ SIZE_T nLength,
494c2c66affSColin Finck     _Out_ PSIZE_T lpBytesWritten)
495c2c66affSColin Finck {
496c2c66affSColin Finck     NTSTATUS status;
497c2c66affSColin Finck 
498c2c66affSColin Finck     status = EngpFileIoRequest(pFileObject,
499c2c66affSColin Finck                                IRP_MJ_WRITE,
500c2c66affSColin Finck                                lpBuffer,
501c2c66affSColin Finck                                nLength,
502c2c66affSColin Finck                                0,
503c2c66affSColin Finck                                lpBytesWritten);
504c2c66affSColin Finck     if (!NT_SUCCESS(status))
505c2c66affSColin Finck     {
506c2c66affSColin Finck         *lpBytesWritten = 0;
507c2c66affSColin Finck     }
508c2c66affSColin Finck }
509c2c66affSColin Finck 
510c2c66affSColin Finck _Success_(return>=0)
511c2c66affSColin Finck NTSTATUS
512c2c66affSColin Finck APIENTRY
513c2c66affSColin Finck EngFileIoControl(
514c2c66affSColin Finck     _In_ PFILE_OBJECT pFileObject,
515c2c66affSColin Finck     _In_ DWORD dwIoControlCode,
516c2c66affSColin Finck     _In_reads_(nInBufferSize) PVOID lpInBuffer,
517c2c66affSColin Finck     _In_ SIZE_T nInBufferSize,
518c2c66affSColin Finck     _Out_writes_(nOutBufferSize) PVOID lpOutBuffer,
519c2c66affSColin Finck     _In_ SIZE_T nOutBufferSize,
520c2c66affSColin Finck     _Out_ PULONG_PTR lpInformation)
521c2c66affSColin Finck {
522c2c66affSColin Finck     PDEVICE_OBJECT pDeviceObject;
523c2c66affSColin Finck     KEVENT Event;
524c2c66affSColin Finck     PIRP pIrp;
525c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
526c2c66affSColin Finck     NTSTATUS Status;
527c2c66affSColin Finck 
528c2c66affSColin Finck     /* Get corresponding device object */
529c2c66affSColin Finck     pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
530c2c66affSColin Finck     if (!pDeviceObject)
531c2c66affSColin Finck     {
532c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
533c2c66affSColin Finck     }
534c2c66affSColin Finck 
535c2c66affSColin Finck     /* Initialize an event */
536c2c66affSColin Finck     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
537c2c66affSColin Finck 
538c2c66affSColin Finck     /* Build IO control IRP */
539c2c66affSColin Finck     pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode,
540c2c66affSColin Finck                                          pDeviceObject,
541c2c66affSColin Finck                                          lpInBuffer,
542c2c66affSColin Finck                                          (ULONG)nInBufferSize,
543c2c66affSColin Finck                                          lpOutBuffer,
544c2c66affSColin Finck                                          (ULONG)nOutBufferSize,
545c2c66affSColin Finck                                          FALSE,
546c2c66affSColin Finck                                          &Event,
547c2c66affSColin Finck                                          &Iosb);
548c2c66affSColin Finck     if (!pIrp)
549c2c66affSColin Finck     {
550c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
551c2c66affSColin Finck     }
552c2c66affSColin Finck 
553c2c66affSColin Finck     /* Call the driver */
554c2c66affSColin Finck     Status = IoCallDriver(pDeviceObject, pIrp);
555c2c66affSColin Finck 
556c2c66affSColin Finck     /* Wait if neccessary */
557c2c66affSColin Finck     if (Status == STATUS_PENDING)
558c2c66affSColin Finck     {
559c2c66affSColin Finck         KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
560c2c66affSColin Finck         Status = Iosb.Status;
561c2c66affSColin Finck     }
562c2c66affSColin Finck 
563c2c66affSColin Finck     /* Return information to the caller about the operation. */
564c2c66affSColin Finck     *lpInformation = Iosb.Information;
565c2c66affSColin Finck 
566c2c66affSColin Finck     /* This function returns NTSTATUS */
567c2c66affSColin Finck     return Status;
568c2c66affSColin Finck }
569c2c66affSColin Finck 
570c2c66affSColin Finck /*
571c2c66affSColin Finck  * @implemented
572c2c66affSColin Finck  */
573c2c66affSColin Finck _Success_(return==0)
574c2c66affSColin Finck DWORD
575c2c66affSColin Finck APIENTRY
576c2c66affSColin Finck EngDeviceIoControl(
577c2c66affSColin Finck     _In_ HANDLE hDevice,
578c2c66affSColin Finck     _In_ DWORD dwIoControlCode,
579c2c66affSColin Finck     _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer,
580c2c66affSColin Finck     _In_ DWORD cjInBufferSize,
581c2c66affSColin Finck     _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer,
582c2c66affSColin Finck     _In_ DWORD cjOutBufferSize,
583c2c66affSColin Finck     _Out_ LPDWORD lpBytesReturned)
584c2c66affSColin Finck {
585c2c66affSColin Finck     PIRP Irp;
586c2c66affSColin Finck     NTSTATUS Status;
587c2c66affSColin Finck     KEVENT Event;
588c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
589c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject;
590c2c66affSColin Finck 
591c2c66affSColin Finck     TRACE("EngDeviceIoControl() called\n");
592c2c66affSColin Finck 
59301b580d8SPierre Schweitzer     if (!hDevice)
59401b580d8SPierre Schweitzer     {
59501b580d8SPierre Schweitzer         return ERROR_INVALID_HANDLE;
59601b580d8SPierre Schweitzer     }
59701b580d8SPierre Schweitzer 
598c2c66affSColin Finck     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
599c2c66affSColin Finck 
600c2c66affSColin Finck     DeviceObject = (PDEVICE_OBJECT) hDevice;
601c2c66affSColin Finck 
602c2c66affSColin Finck     Irp = IoBuildDeviceIoControlRequest(dwIoControlCode,
603c2c66affSColin Finck                                         DeviceObject,
604c2c66affSColin Finck                                         lpInBuffer,
605c2c66affSColin Finck                                         cjInBufferSize,
606c2c66affSColin Finck                                         lpOutBuffer,
607c2c66affSColin Finck                                         cjOutBufferSize,
608c2c66affSColin Finck                                         FALSE,
609c2c66affSColin Finck                                         &Event,
610c2c66affSColin Finck                                         &Iosb);
611c2c66affSColin Finck     if (!Irp) return ERROR_NOT_ENOUGH_MEMORY;
612c2c66affSColin Finck 
613c2c66affSColin Finck     Status = IoCallDriver(DeviceObject, Irp);
614c2c66affSColin Finck 
615c2c66affSColin Finck     if (Status == STATUS_PENDING)
616c2c66affSColin Finck     {
617c2c66affSColin Finck         (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
618c2c66affSColin Finck         Status = Iosb.Status;
619c2c66affSColin Finck     }
620c2c66affSColin Finck 
621c2c66affSColin Finck     TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status,
622c2c66affSColin Finck            Iosb.Information);
623c2c66affSColin Finck 
624c2c66affSColin Finck     /* Return information to the caller about the operation. */
625c2c66affSColin Finck     *lpBytesReturned = (DWORD)Iosb.Information;
626c2c66affSColin Finck 
627c2c66affSColin Finck     /* Convert NT status values to win32 error codes. */
628c2c66affSColin Finck     switch (Status)
629c2c66affSColin Finck     {
630c2c66affSColin Finck         case STATUS_INSUFFICIENT_RESOURCES:
631c2c66affSColin Finck             return ERROR_NOT_ENOUGH_MEMORY;
632c2c66affSColin Finck 
633c2c66affSColin Finck         case STATUS_BUFFER_OVERFLOW:
634c2c66affSColin Finck             return ERROR_MORE_DATA;
635c2c66affSColin Finck 
636c2c66affSColin Finck         case STATUS_NOT_IMPLEMENTED:
637c2c66affSColin Finck             return ERROR_INVALID_FUNCTION;
638c2c66affSColin Finck 
639c2c66affSColin Finck         case STATUS_INVALID_PARAMETER:
640c2c66affSColin Finck             return ERROR_INVALID_PARAMETER;
641c2c66affSColin Finck 
642c2c66affSColin Finck         case STATUS_BUFFER_TOO_SMALL:
643c2c66affSColin Finck             return ERROR_INSUFFICIENT_BUFFER;
644c2c66affSColin Finck 
645c2c66affSColin Finck         case STATUS_DEVICE_DOES_NOT_EXIST:
646c2c66affSColin Finck             return ERROR_DEV_NOT_EXIST;
647c2c66affSColin Finck 
648c2c66affSColin Finck         case STATUS_PENDING:
649c2c66affSColin Finck             return ERROR_IO_PENDING;
650c2c66affSColin Finck     }
651c2c66affSColin Finck 
652c2c66affSColin Finck     return Status;
653c2c66affSColin Finck }
654c2c66affSColin Finck 
655c2c66affSColin Finck /* EOF */
656