2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Device Functions
5 * FILE: subsys/win32k/eng/device.c
6 * PROGRAMER: Jason Filby
15 PGRAPHICS_DEVICE gpPrimaryGraphicsDevice
;
16 PGRAPHICS_DEVICE gpVgaGraphicsDevice
;
18 static PGRAPHICS_DEVICE gpGraphicsDeviceFirst
= NULL
;
19 static PGRAPHICS_DEVICE gpGraphicsDeviceLast
= NULL
;
20 static HSEMAPHORE ghsemGraphicsDeviceList
;
21 static ULONG giDevNum
= 1;
28 ghsemGraphicsDeviceList
= EngCreateSemaphore();
29 if (!ghsemGraphicsDeviceList
)
30 return STATUS_INSUFFICIENT_RESOURCES
;
32 return STATUS_SUCCESS
;
38 EngpRegisterGraphicsDevice(
39 PUNICODE_STRING pustrDeviceName
,
40 PUNICODE_STRING pustrDiplayDrivers
,
41 PUNICODE_STRING pustrDescription
,
44 PGRAPHICS_DEVICE pGraphicsDevice
;
45 PDEVICE_OBJECT pDeviceObject
;
46 PFILE_OBJECT pFileObject
;
49 ULONG i
, cj
, cModes
= 0;
53 PDEVMODEW pdm
, pdmEnd
;
56 DPRINT("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName
);
58 /* Allocate a GRAPHICS_DEVICE structure */
59 pGraphicsDevice
= ExAllocatePoolWithTag(PagedPool
,
60 sizeof(GRAPHICS_DEVICE
),
64 DPRINT1("ExAllocatePoolWithTag failed\n");
68 /* Try to open the driver */
69 Status
= IoGetDeviceObjectPointer(pustrDeviceName
,
70 FILE_READ_DATA
| FILE_WRITE_DATA
,
73 if (!NT_SUCCESS(Status
))
75 DPRINT1("Could not open driver %wZ, 0x%lx\n", pustrDeviceName
, Status
);
76 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
80 /* Enable the device */
81 EngFileWrite(pFileObject
, &bEnable
, sizeof(BOOL
), &cjWritten
);
83 /* Copy the device and file object pointers */
84 pGraphicsDevice
->DeviceObject
= pDeviceObject
;
85 pGraphicsDevice
->FileObject
= pFileObject
;
87 /* Copy device name */
88 RtlStringCbCopyNW(pGraphicsDevice
->szNtDeviceName
,
89 sizeof(pGraphicsDevice
->szNtDeviceName
),
90 pustrDeviceName
->Buffer
,
91 pustrDeviceName
->Length
);
93 /* Create a win device name (FIXME: virtual devices!) */
94 swprintf(pGraphicsDevice
->szWinDeviceName
, L
"\\\\.\\DISPLAY%d", (int)giDevNum
);
96 /* Allocate a buffer for the strings */
97 cj
= pustrDiplayDrivers
->Length
+ pustrDescription
->Length
+ sizeof(WCHAR
);
98 pwsz
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_DRVSUP
);
101 DPRINT1("Could not allocate string buffer\n");
102 ASSERT(FALSE
); // FIXME
103 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
107 /* Copy display driver names */
108 pGraphicsDevice
->pDiplayDrivers
= pwsz
;
109 RtlCopyMemory(pGraphicsDevice
->pDiplayDrivers
,
110 pustrDiplayDrivers
->Buffer
,
111 pustrDiplayDrivers
->Length
);
113 /* Copy description */
114 pGraphicsDevice
->pwszDescription
= pwsz
+ pustrDiplayDrivers
->Length
/ sizeof(WCHAR
);
115 RtlCopyMemory(pGraphicsDevice
->pwszDescription
,
116 pustrDescription
->Buffer
,
117 pustrDescription
->Length
+ sizeof(WCHAR
));
119 /* Initialize the pdevmodeInfo list and default index */
120 pGraphicsDevice
->pdevmodeInfo
= NULL
;
121 pGraphicsDevice
->iDefaultMode
= 0;
122 pGraphicsDevice
->iCurrentMode
= 0;
124 // FIXME: initialize state flags
125 pGraphicsDevice
->StateFlags
= 0;
127 /* Loop through the driver names
128 * This is a REG_MULTI_SZ string */
129 for (; *pwsz
; pwsz
+= wcslen(pwsz
) + 1)
131 DPRINT("trying driver: %ls\n", pwsz
);
132 /* Try to load the display driver */
133 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
136 DPRINT1("Could not load driver: '%ls'\n", pwsz
);
140 /* Get the mode list from the driver */
141 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pDeviceObject
);
144 DPRINT1("Could not get mode list for '%ls'\n", pwsz
);
148 /* Attach the mode info to the device */
149 pdminfo
->pdmiNext
= pGraphicsDevice
->pdevmodeInfo
;
150 pGraphicsDevice
->pdevmodeInfo
= pdminfo
;
152 /* Loop all DEVMODEs */
153 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
154 for (pdm
= pdminfo
->adevmode
;
155 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
156 pdm
= (DEVMODEW
*)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
158 /* Count this DEVMODE */
161 /* Some drivers like the VBox driver don't fill the dmDeviceName
162 with the name of the display driver. So fix that here. */
163 wcsncpy(pdm
->dmDeviceName
, pwsz
, CCHDEVICENAME
);
164 pdm
->dmDeviceName
[CCHDEVICENAME
- 1] = 0;
167 // FIXME: release the driver again until it's used?
170 if (!pGraphicsDevice
->pdevmodeInfo
|| cModes
== 0)
172 DPRINT1("No devmodes\n");
173 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
177 /* Allocate an index buffer */
178 pGraphicsDevice
->cDevModes
= cModes
;
179 pGraphicsDevice
->pDevModeList
= ExAllocatePoolWithTag(PagedPool
,
180 cModes
* sizeof(DEVMODEENTRY
),
182 if (!pGraphicsDevice
->pDevModeList
)
184 DPRINT1("No devmode list\n");
185 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
189 /* Loop through all DEVMODEINFOs */
190 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
192 pdminfo
= pdminfo
->pdmiNext
)
194 /* Calculate End of the DEVMODEs */
195 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
197 /* Loop through the DEVMODEs */
198 for (pdm
= pdminfo
->adevmode
;
199 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
200 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
202 /* Compare with the default entry */
203 if (pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
204 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
205 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
&&
206 pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
208 pGraphicsDevice
->iDefaultMode
= i
;
209 pGraphicsDevice
->iCurrentMode
= i
;
210 DPRINT("Found default entry: %lu '%ls'\n", i
, pdm
->dmDeviceName
);
213 /* Initialize the entry */
214 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
215 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
221 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
223 /* Insert the device into the global list */
224 pGraphicsDevice
->pNextGraphicsDevice
= NULL
;
225 if (gpGraphicsDeviceLast
)
226 gpGraphicsDeviceLast
->pNextGraphicsDevice
= pGraphicsDevice
;
227 gpGraphicsDeviceLast
= pGraphicsDevice
;
228 if (!gpGraphicsDeviceFirst
)
229 gpGraphicsDeviceFirst
= pGraphicsDevice
;
231 /* Increment device number */
235 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
236 DPRINT("Prepared %lu modes for %ls\n", cModes
, pGraphicsDevice
->pwszDescription
);
238 return pGraphicsDevice
;
244 EngpFindGraphicsDevice(
245 PUNICODE_STRING pustrDevice
,
249 UNICODE_STRING ustrCurrent
;
250 PGRAPHICS_DEVICE pGraphicsDevice
;
252 DPRINT("EngpFindGraphicsDevice('%wZ', %lu, 0x%lx)\n",
253 pustrDevice
, iDevNum
, dwFlags
);
256 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
258 if (pustrDevice
&& pustrDevice
->Buffer
)
260 /* Loop through the list of devices */
261 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
263 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
265 /* Compare the device name */
266 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
267 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
275 /* Loop through the list of devices */
276 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
277 pGraphicsDevice
&& i
< iDevNum
;
278 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
282 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
284 return pGraphicsDevice
;
291 PFILE_OBJECT pFileObject
,
292 ULONG ulMajorFunction
,
295 ULONGLONG ullStartOffset
,
296 OUT PULONG_PTR lpInformation
)
298 PDEVICE_OBJECT pDeviceObject
;
301 IO_STATUS_BLOCK Iosb
;
303 LARGE_INTEGER liStartOffset
;
305 /* Get corresponding device object */
306 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
309 return STATUS_INVALID_PARAMETER
;
312 /* Initialize an event */
313 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
316 liStartOffset
.QuadPart
= ullStartOffset
;
317 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
326 return STATUS_INSUFFICIENT_RESOURCES
;
329 /* Call the driver */
330 Status
= IoCallDriver(pDeviceObject
, pIrp
);
332 /* Wait if neccessary */
333 if (STATUS_PENDING
== Status
)
335 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
336 Status
= Iosb
.Status
;
339 /* Return information to the caller about the operation. */
340 *lpInformation
= Iosb
.Information
;
342 /* Return NTSTATUS */
349 IN PFILE_OBJECT pFileObject
,
352 IN PSIZE_T lpBytesWritten
)
354 EngpFileIoRequest(pFileObject
,
365 IN PFILE_OBJECT pFileObject
,
366 IN DWORD dwIoControlCode
,
368 IN SIZE_T nInBufferSize
,
369 OUT PVOID lpOutBuffer
,
370 IN SIZE_T nOutBufferSize
,
371 OUT PULONG_PTR lpInformation
)
373 PDEVICE_OBJECT pDeviceObject
;
376 IO_STATUS_BLOCK Iosb
;
379 /* Get corresponding device object */
380 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
383 return STATUS_INVALID_PARAMETER
;
386 /* Initialize an event */
387 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
389 /* Build IO control IRP */
390 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
393 (ULONG
)nInBufferSize
,
395 (ULONG
)nOutBufferSize
,
401 return STATUS_INSUFFICIENT_RESOURCES
;
404 /* Call the driver */
405 Status
= IoCallDriver(pDeviceObject
, pIrp
);
407 /* Wait if neccessary */
408 if (Status
== STATUS_PENDING
)
410 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
411 Status
= Iosb
.Status
;
414 /* Return information to the caller about the operation. */
415 *lpInformation
= Iosb
.Information
;
417 /* This function returns NTSTATUS */
427 _In_ DWORD dwIoControlCode
,
428 _In_opt_bytecount_(cjInBufferSize
) LPVOID lpInBuffer
,
429 _In_ DWORD cjInBufferSize
,
430 _Out_opt_bytecap_(cjOutBufferSize
) LPVOID lpOutBuffer
,
431 _In_ DWORD cjOutBufferSize
,
432 _Out_ LPDWORD lpBytesReturned
)
437 IO_STATUS_BLOCK Iosb
;
438 PDEVICE_OBJECT DeviceObject
;
440 DPRINT("EngDeviceIoControl() called\n");
442 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
444 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
446 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
455 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
457 Status
= IoCallDriver(DeviceObject
, Irp
);
459 if (Status
== STATUS_PENDING
)
461 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
462 Status
= Iosb
.Status
;
465 DPRINT("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
468 /* Return information to the caller about the operation. */
469 *lpBytesReturned
= (DWORD
)Iosb
.Information
;
471 /* Convert NT status values to win32 error codes. */
474 case STATUS_INSUFFICIENT_RESOURCES
:
475 return ERROR_NOT_ENOUGH_MEMORY
;
477 case STATUS_BUFFER_OVERFLOW
:
478 return ERROR_MORE_DATA
;
480 case STATUS_NOT_IMPLEMENTED
:
481 return ERROR_INVALID_FUNCTION
;
483 case STATUS_INVALID_PARAMETER
:
484 return ERROR_INVALID_PARAMETER
;
486 case STATUS_BUFFER_TOO_SMALL
:
487 return ERROR_INSUFFICIENT_BUFFER
;
489 case STATUS_DEVICE_DOES_NOT_EXIST
:
490 return ERROR_DEV_NOT_EXIST
;
493 return ERROR_IO_PENDING
;