2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Device Functions
5 * FILE: win32ss/gdi/eng/device.c
6 * PROGRAMER: Jason Filby
11 DBG_DEFAULT_CHANNEL(EngDev
)
13 PGRAPHICS_DEVICE gpPrimaryGraphicsDevice
;
14 PGRAPHICS_DEVICE gpVgaGraphicsDevice
;
16 static PGRAPHICS_DEVICE gpGraphicsDeviceFirst
= NULL
;
17 static PGRAPHICS_DEVICE gpGraphicsDeviceLast
= NULL
;
18 static HSEMAPHORE ghsemGraphicsDeviceList
;
19 static ULONG giDevNum
= 1;
26 ghsemGraphicsDeviceList
= EngCreateSemaphore();
27 if (!ghsemGraphicsDeviceList
)
28 return STATUS_INSUFFICIENT_RESOURCES
;
30 return STATUS_SUCCESS
;
34 EngpPopulateDeviceModeList(
35 _Inout_ PGRAPHICS_DEVICE pGraphicsDevice
,
36 _In_ PDEVMODEW pdmDefault
)
41 PDEVMODEW pdm
, pdmEnd
;
43 BOOLEAN bModeMatch
= FALSE
;
45 ASSERT(pGraphicsDevice
->pdevmodeInfo
== NULL
);
46 ASSERT(pGraphicsDevice
->pDevModeList
== NULL
);
48 pwsz
= pGraphicsDevice
->pDiplayDrivers
;
50 /* Loop through the driver names
51 * This is a REG_MULTI_SZ string */
52 for (; *pwsz
; pwsz
+= wcslen(pwsz
) + 1)
54 /* Try to load the display driver */
55 TRACE("Trying driver: %ls\n", pwsz
);
56 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
59 ERR("Could not load driver: '%ls'\n", pwsz
);
63 /* Get the mode list from the driver */
64 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pGraphicsDevice
->DeviceObject
);
67 ERR("Could not get mode list for '%ls'\n", pwsz
);
71 /* Attach the mode info to the device */
72 pdminfo
->pdmiNext
= pGraphicsDevice
->pdevmodeInfo
;
73 pGraphicsDevice
->pdevmodeInfo
= pdminfo
;
75 /* Loop all DEVMODEs */
76 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
77 for (pdm
= pdminfo
->adevmode
;
78 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
79 pdm
= (DEVMODEW
*)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
81 /* Count this DEVMODE */
84 /* Some drivers like the VBox driver don't fill the dmDeviceName
85 with the name of the display driver. So fix that here. */
86 RtlStringCbCopyW(pdm
->dmDeviceName
, sizeof(pdm
->dmDeviceName
), pwsz
);
89 // FIXME: release the driver again until it's used?
92 if (!pGraphicsDevice
->pdevmodeInfo
|| cModes
== 0)
98 /* Allocate an index buffer */
99 pGraphicsDevice
->cDevModes
= cModes
;
100 pGraphicsDevice
->pDevModeList
= ExAllocatePoolWithTag(PagedPool
,
101 cModes
* sizeof(DEVMODEENTRY
),
103 if (!pGraphicsDevice
->pDevModeList
)
105 ERR("No devmode list\n");
109 TRACE("Looking for mode %lux%lux%lu(%lu Hz)\n",
110 pdmDefault
->dmPelsWidth
,
111 pdmDefault
->dmPelsHeight
,
112 pdmDefault
->dmBitsPerPel
,
113 pdmDefault
->dmDisplayFrequency
);
115 /* Loop through all DEVMODEINFOs */
116 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
118 pdminfo
= pdminfo
->pdmiNext
)
120 /* Calculate End of the DEVMODEs */
121 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
123 /* Loop through the DEVMODEs */
124 for (pdm
= pdminfo
->adevmode
;
125 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
126 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
128 TRACE(" %S has mode %lux%lux%lu(%lu Hz)\n",
133 pdm
->dmDisplayFrequency
);
134 /* Compare with the default entry */
136 pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
137 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
138 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
)
140 pGraphicsDevice
->iDefaultMode
= i
;
141 pGraphicsDevice
->iCurrentMode
= i
;
142 TRACE("Found default entry: %lu '%ls'\n", i
, pdm
->dmDeviceName
);
143 if (pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
145 /* Uh oh, even the display frequency matches. */
150 /* Initialize the entry */
151 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
152 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
161 EngpRegisterGraphicsDevice(
162 _In_ PUNICODE_STRING pustrDeviceName
,
163 _In_ PUNICODE_STRING pustrDiplayDrivers
,
164 _In_ PUNICODE_STRING pustrDescription
,
165 _In_ PDEVMODEW pdmDefault
)
167 PGRAPHICS_DEVICE pGraphicsDevice
;
168 PDEVICE_OBJECT pDeviceObject
;
169 PFILE_OBJECT pFileObject
;
176 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName
);
178 /* Allocate a GRAPHICS_DEVICE structure */
179 pGraphicsDevice
= ExAllocatePoolWithTag(PagedPool
,
180 sizeof(GRAPHICS_DEVICE
),
182 if (!pGraphicsDevice
)
184 ERR("ExAllocatePoolWithTag failed\n");
188 /* Try to open and enable the device */
189 Status
= IoGetDeviceObjectPointer(pustrDeviceName
,
190 FILE_READ_DATA
| FILE_WRITE_DATA
,
193 if (!NT_SUCCESS(Status
))
195 ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName
, Status
);
196 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
200 /* Enable the device */
201 EngFileWrite(pFileObject
, &bEnable
, sizeof(BOOL
), &cjWritten
);
203 /* Copy the device and file object pointers */
204 pGraphicsDevice
->DeviceObject
= pDeviceObject
;
205 pGraphicsDevice
->FileObject
= pFileObject
;
207 /* Copy the device name */
208 RtlStringCbCopyNW(pGraphicsDevice
->szNtDeviceName
,
209 sizeof(pGraphicsDevice
->szNtDeviceName
),
210 pustrDeviceName
->Buffer
,
211 pustrDeviceName
->Length
);
213 /* Create a Win32 device name (FIXME: virtual devices!) */
214 RtlStringCbPrintfW(pGraphicsDevice
->szWinDeviceName
,
215 sizeof(pGraphicsDevice
->szWinDeviceName
),
219 /* Allocate a buffer for the strings */
220 cj
= pustrDiplayDrivers
->Length
+ pustrDescription
->Length
+ sizeof(WCHAR
);
221 pwsz
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_DRVSUP
);
224 ERR("Could not allocate string buffer\n");
225 ASSERT(FALSE
); // FIXME
226 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
230 /* Copy the display driver names */
231 pGraphicsDevice
->pDiplayDrivers
= pwsz
;
232 RtlCopyMemory(pGraphicsDevice
->pDiplayDrivers
,
233 pustrDiplayDrivers
->Buffer
,
234 pustrDiplayDrivers
->Length
);
236 /* Copy the description */
237 pGraphicsDevice
->pwszDescription
= pwsz
+ pustrDiplayDrivers
->Length
/ sizeof(WCHAR
);
238 RtlCopyMemory(pGraphicsDevice
->pwszDescription
,
239 pustrDescription
->Buffer
,
240 pustrDescription
->Length
);
241 pGraphicsDevice
->pwszDescription
[pustrDescription
->Length
/sizeof(WCHAR
)] = 0;
243 /* Initialize the pdevmodeInfo list and default index */
244 pGraphicsDevice
->pdevmodeInfo
= NULL
;
245 pGraphicsDevice
->iDefaultMode
= 0;
246 pGraphicsDevice
->iCurrentMode
= 0;
248 // FIXME: initialize state flags
249 pGraphicsDevice
->StateFlags
= 0;
251 /* Create the mode list */
252 pGraphicsDevice
->pDevModeList
= NULL
;
253 if (!EngpPopulateDeviceModeList(pGraphicsDevice
, pdmDefault
))
255 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
260 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
262 /* Insert the device into the global list */
263 pGraphicsDevice
->pNextGraphicsDevice
= NULL
;
264 if (gpGraphicsDeviceLast
)
265 gpGraphicsDeviceLast
->pNextGraphicsDevice
= pGraphicsDevice
;
266 gpGraphicsDeviceLast
= pGraphicsDevice
;
267 if (!gpGraphicsDeviceFirst
)
268 gpGraphicsDeviceFirst
= pGraphicsDevice
;
270 /* Increment the device number */
274 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
275 TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice
->cDevModes
, pGraphicsDevice
->pwszDescription
);
277 return pGraphicsDevice
;
282 EngpFindGraphicsDevice(
283 _In_opt_ PUNICODE_STRING pustrDevice
,
287 UNICODE_STRING ustrCurrent
;
288 PGRAPHICS_DEVICE pGraphicsDevice
;
290 TRACE("EngpFindGraphicsDevice('%wZ', %lu, 0x%lx)\n",
291 pustrDevice
, iDevNum
, dwFlags
);
294 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
296 if (pustrDevice
&& pustrDevice
->Buffer
)
298 /* Loop through the list of devices */
299 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
301 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
303 /* Compare the device name */
304 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
305 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
313 /* Loop through the list of devices */
314 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
315 pGraphicsDevice
&& i
< iDevNum
;
316 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
320 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
322 return pGraphicsDevice
;
328 _In_ PFILE_OBJECT pFileObject
,
329 _In_ ULONG ulMajorFunction
,
330 _In_reads_(nBufferSize
) PVOID lpBuffer
,
331 _In_ SIZE_T nBufferSize
,
332 _In_ ULONGLONG ullStartOffset
,
333 _Out_ PULONG_PTR lpInformation
)
335 PDEVICE_OBJECT pDeviceObject
;
338 IO_STATUS_BLOCK Iosb
;
340 LARGE_INTEGER liStartOffset
;
342 /* Get corresponding device object */
343 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
346 return STATUS_INVALID_PARAMETER
;
349 /* Initialize an event */
350 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
353 liStartOffset
.QuadPart
= ullStartOffset
;
354 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
363 return STATUS_INSUFFICIENT_RESOURCES
;
366 /* Call the driver */
367 Status
= IoCallDriver(pDeviceObject
, pIrp
);
369 /* Wait if neccessary */
370 if (STATUS_PENDING
== Status
)
372 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
373 Status
= Iosb
.Status
;
376 /* Return information to the caller about the operation. */
377 *lpInformation
= Iosb
.Information
;
379 /* Return NTSTATUS */
386 _In_ PFILE_OBJECT pFileObject
,
387 _In_reads_(nLength
) PVOID lpBuffer
,
389 _Out_ PSIZE_T lpBytesWritten
)
393 status
= EngpFileIoRequest(pFileObject
,
399 if (!NT_SUCCESS(status
))
409 _In_ PFILE_OBJECT pFileObject
,
410 _In_ DWORD dwIoControlCode
,
411 _In_reads_(nInBufferSize
) PVOID lpInBuffer
,
412 _In_ SIZE_T nInBufferSize
,
413 _Out_writes_(nOutBufferSize
) PVOID lpOutBuffer
,
414 _In_ SIZE_T nOutBufferSize
,
415 _Out_ PULONG_PTR lpInformation
)
417 PDEVICE_OBJECT pDeviceObject
;
420 IO_STATUS_BLOCK Iosb
;
423 /* Get corresponding device object */
424 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
427 return STATUS_INVALID_PARAMETER
;
430 /* Initialize an event */
431 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
433 /* Build IO control IRP */
434 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
437 (ULONG
)nInBufferSize
,
439 (ULONG
)nOutBufferSize
,
445 return STATUS_INSUFFICIENT_RESOURCES
;
448 /* Call the driver */
449 Status
= IoCallDriver(pDeviceObject
, pIrp
);
451 /* Wait if neccessary */
452 if (Status
== STATUS_PENDING
)
454 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
455 Status
= Iosb
.Status
;
458 /* Return information to the caller about the operation. */
459 *lpInformation
= Iosb
.Information
;
461 /* This function returns NTSTATUS */
473 _In_ DWORD dwIoControlCode
,
474 _In_reads_bytes_opt_(cjInBufferSize
) LPVOID lpInBuffer
,
475 _In_ DWORD cjInBufferSize
,
476 _Out_writes_bytes_opt_(cjOutBufferSize
) LPVOID lpOutBuffer
,
477 _In_ DWORD cjOutBufferSize
,
478 _Out_ LPDWORD lpBytesReturned
)
483 IO_STATUS_BLOCK Iosb
;
484 PDEVICE_OBJECT DeviceObject
;
486 TRACE("EngDeviceIoControl() called\n");
490 return ERROR_INVALID_HANDLE
;
493 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
495 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
497 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
506 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
508 Status
= IoCallDriver(DeviceObject
, Irp
);
510 if (Status
== STATUS_PENDING
)
512 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
513 Status
= Iosb
.Status
;
516 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
519 /* Return information to the caller about the operation. */
520 *lpBytesReturned
= (DWORD
)Iosb
.Information
;
522 /* Convert NT status values to win32 error codes. */
525 case STATUS_INSUFFICIENT_RESOURCES
:
526 return ERROR_NOT_ENOUGH_MEMORY
;
528 case STATUS_BUFFER_OVERFLOW
:
529 return ERROR_MORE_DATA
;
531 case STATUS_NOT_IMPLEMENTED
:
532 return ERROR_INVALID_FUNCTION
;
534 case STATUS_INVALID_PARAMETER
:
535 return ERROR_INVALID_PARAMETER
;
537 case STATUS_BUFFER_TOO_SMALL
:
538 return ERROR_INSUFFICIENT_BUFFER
;
540 case STATUS_DEVICE_DOES_NOT_EXIST
:
541 return ERROR_DEV_NOT_EXIST
;
544 return ERROR_IO_PENDING
;