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
;
36 EngpRegisterGraphicsDevice(
37 _In_ PUNICODE_STRING pustrDeviceName
,
38 _In_ PUNICODE_STRING pustrDiplayDrivers
,
39 _In_ PUNICODE_STRING pustrDescription
,
40 _In_ PDEVMODEW pdmDefault
)
42 PGRAPHICS_DEVICE pGraphicsDevice
;
43 PDEVICE_OBJECT pDeviceObject
;
44 PFILE_OBJECT pFileObject
;
47 ULONG i
, cj
, cModes
= 0;
51 PDEVMODEW pdm
, pdmEnd
;
53 BOOLEAN bModeMatch
= FALSE
;
55 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName
);
57 /* Allocate a GRAPHICS_DEVICE structure */
58 pGraphicsDevice
= ExAllocatePoolWithTag(PagedPool
,
59 sizeof(GRAPHICS_DEVICE
),
63 ERR("ExAllocatePoolWithTag failed\n");
67 /* Try to open the driver */
68 Status
= IoGetDeviceObjectPointer(pustrDeviceName
,
69 FILE_READ_DATA
| FILE_WRITE_DATA
,
72 if (!NT_SUCCESS(Status
))
74 ERR("Could not open driver %wZ, 0x%lx\n", pustrDeviceName
, Status
);
75 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
79 /* Enable the device */
80 EngFileWrite(pFileObject
, &bEnable
, sizeof(BOOL
), &cjWritten
);
82 /* Copy the device and file object pointers */
83 pGraphicsDevice
->DeviceObject
= pDeviceObject
;
84 pGraphicsDevice
->FileObject
= pFileObject
;
86 /* Copy device name */
87 RtlStringCbCopyNW(pGraphicsDevice
->szNtDeviceName
,
88 sizeof(pGraphicsDevice
->szNtDeviceName
),
89 pustrDeviceName
->Buffer
,
90 pustrDeviceName
->Length
);
92 /* Create a win device name (FIXME: virtual devices!) */
93 swprintf(pGraphicsDevice
->szWinDeviceName
, L
"\\\\.\\DISPLAY%d", (int)giDevNum
);
95 /* Allocate a buffer for the strings */
96 cj
= pustrDiplayDrivers
->Length
+ pustrDescription
->Length
+ sizeof(WCHAR
);
97 pwsz
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_DRVSUP
);
100 ERR("Could not allocate string buffer\n");
101 ASSERT(FALSE
); // FIXME
102 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
106 /* Copy display driver names */
107 pGraphicsDevice
->pDiplayDrivers
= pwsz
;
108 RtlCopyMemory(pGraphicsDevice
->pDiplayDrivers
,
109 pustrDiplayDrivers
->Buffer
,
110 pustrDiplayDrivers
->Length
);
112 /* Copy description */
113 pGraphicsDevice
->pwszDescription
= pwsz
+ pustrDiplayDrivers
->Length
/ sizeof(WCHAR
);
114 RtlCopyMemory(pGraphicsDevice
->pwszDescription
,
115 pustrDescription
->Buffer
,
116 pustrDescription
->Length
);
117 pGraphicsDevice
->pwszDescription
[pustrDescription
->Length
/sizeof(WCHAR
)] = 0;
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 TRACE("trying driver: %ls\n", pwsz
);
132 /* Try to load the display driver */
133 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
136 ERR("Could not load driver: '%ls'\n", pwsz
);
140 /* Get the mode list from the driver */
141 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pDeviceObject
);
144 ERR("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 ERR("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 ERR("No devmode list\n");
185 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
189 TRACE("Looking for mode %lux%lux%lu(%lu Hz)\n",
190 pdmDefault
->dmPelsWidth
,
191 pdmDefault
->dmPelsHeight
,
192 pdmDefault
->dmBitsPerPel
,
193 pdmDefault
->dmDisplayFrequency
);
195 /* Loop through all DEVMODEINFOs */
196 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
198 pdminfo
= pdminfo
->pdmiNext
)
200 /* Calculate End of the DEVMODEs */
201 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
203 /* Loop through the DEVMODEs */
204 for (pdm
= pdminfo
->adevmode
;
205 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
206 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
208 TRACE(" %S has mode %lux%lux%lu(%lu Hz)\n",
213 pdm
->dmDisplayFrequency
);
214 /* Compare with the default entry */
216 pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
217 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
218 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
)
220 pGraphicsDevice
->iDefaultMode
= i
;
221 pGraphicsDevice
->iCurrentMode
= i
;
222 TRACE("Found default entry: %lu '%ls'\n", i
, pdm
->dmDeviceName
);
223 if (pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
225 /* Uh oh, even the display frequency matches. */
230 /* Initialize the entry */
231 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
232 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
238 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
240 /* Insert the device into the global list */
241 pGraphicsDevice
->pNextGraphicsDevice
= NULL
;
242 if (gpGraphicsDeviceLast
)
243 gpGraphicsDeviceLast
->pNextGraphicsDevice
= pGraphicsDevice
;
244 gpGraphicsDeviceLast
= pGraphicsDevice
;
245 if (!gpGraphicsDeviceFirst
)
246 gpGraphicsDeviceFirst
= pGraphicsDevice
;
248 /* Increment device number */
252 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
253 TRACE("Prepared %lu modes for %ls\n", cModes
, pGraphicsDevice
->pwszDescription
);
255 return pGraphicsDevice
;
261 EngpFindGraphicsDevice(
262 _In_opt_ PUNICODE_STRING pustrDevice
,
266 UNICODE_STRING ustrCurrent
;
267 PGRAPHICS_DEVICE pGraphicsDevice
;
269 TRACE("EngpFindGraphicsDevice('%wZ', %lu, 0x%lx)\n",
270 pustrDevice
, iDevNum
, dwFlags
);
273 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
275 if (pustrDevice
&& pustrDevice
->Buffer
)
277 /* Loop through the list of devices */
278 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
280 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
282 /* Compare the device name */
283 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
284 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
292 /* Loop through the list of devices */
293 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
294 pGraphicsDevice
&& i
< iDevNum
;
295 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
299 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
301 return pGraphicsDevice
;
308 _In_ PFILE_OBJECT pFileObject
,
309 _In_ ULONG ulMajorFunction
,
310 _In_reads_(nBufferSize
) PVOID lpBuffer
,
311 _In_ SIZE_T nBufferSize
,
312 _In_ ULONGLONG ullStartOffset
,
313 _Out_ PULONG_PTR lpInformation
)
315 PDEVICE_OBJECT pDeviceObject
;
318 IO_STATUS_BLOCK Iosb
;
320 LARGE_INTEGER liStartOffset
;
322 /* Get corresponding device object */
323 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
326 return STATUS_INVALID_PARAMETER
;
329 /* Initialize an event */
330 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
333 liStartOffset
.QuadPart
= ullStartOffset
;
334 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
343 return STATUS_INSUFFICIENT_RESOURCES
;
346 /* Call the driver */
347 Status
= IoCallDriver(pDeviceObject
, pIrp
);
349 /* Wait if neccessary */
350 if (STATUS_PENDING
== Status
)
352 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
353 Status
= Iosb
.Status
;
356 /* Return information to the caller about the operation. */
357 *lpInformation
= Iosb
.Information
;
359 /* Return NTSTATUS */
366 _In_ PFILE_OBJECT pFileObject
,
367 _In_reads_(nLength
) PVOID lpBuffer
,
369 _Out_ PSIZE_T lpBytesWritten
)
373 status
= EngpFileIoRequest(pFileObject
,
379 if (!NT_SUCCESS(status
))
389 _In_ PFILE_OBJECT pFileObject
,
390 _In_ DWORD dwIoControlCode
,
391 _In_reads_(nInBufferSize
) PVOID lpInBuffer
,
392 _In_ SIZE_T nInBufferSize
,
393 _Out_writes_(nOutBufferSize
) PVOID lpOutBuffer
,
394 _In_ SIZE_T nOutBufferSize
,
395 _Out_ PULONG_PTR lpInformation
)
397 PDEVICE_OBJECT pDeviceObject
;
400 IO_STATUS_BLOCK Iosb
;
403 /* Get corresponding device object */
404 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
407 return STATUS_INVALID_PARAMETER
;
410 /* Initialize an event */
411 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
413 /* Build IO control IRP */
414 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
417 (ULONG
)nInBufferSize
,
419 (ULONG
)nOutBufferSize
,
425 return STATUS_INSUFFICIENT_RESOURCES
;
428 /* Call the driver */
429 Status
= IoCallDriver(pDeviceObject
, pIrp
);
431 /* Wait if neccessary */
432 if (Status
== STATUS_PENDING
)
434 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
435 Status
= Iosb
.Status
;
438 /* Return information to the caller about the operation. */
439 *lpInformation
= Iosb
.Information
;
441 /* This function returns NTSTATUS */
453 _In_ DWORD dwIoControlCode
,
454 _In_reads_bytes_opt_(cjInBufferSize
) LPVOID lpInBuffer
,
455 _In_ DWORD cjInBufferSize
,
456 _Out_writes_bytes_opt_(cjOutBufferSize
) LPVOID lpOutBuffer
,
457 _In_ DWORD cjOutBufferSize
,
458 _Out_ LPDWORD lpBytesReturned
)
463 IO_STATUS_BLOCK Iosb
;
464 PDEVICE_OBJECT DeviceObject
;
466 TRACE("EngDeviceIoControl() called\n");
468 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
470 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
472 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
481 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
483 Status
= IoCallDriver(DeviceObject
, Irp
);
485 if (Status
== STATUS_PENDING
)
487 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
488 Status
= Iosb
.Status
;
491 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
494 /* Return information to the caller about the operation. */
495 *lpBytesReturned
= (DWORD
)Iosb
.Information
;
497 /* Convert NT status values to win32 error codes. */
500 case STATUS_INSUFFICIENT_RESOURCES
:
501 return ERROR_NOT_ENOUGH_MEMORY
;
503 case STATUS_BUFFER_OVERFLOW
:
504 return ERROR_MORE_DATA
;
506 case STATUS_NOT_IMPLEMENTED
:
507 return ERROR_INVALID_FUNCTION
;
509 case STATUS_INVALID_PARAMETER
:
510 return ERROR_INVALID_PARAMETER
;
512 case STATUS_BUFFER_TOO_SMALL
:
513 return ERROR_INSUFFICIENT_BUFFER
;
515 case STATUS_DEVICE_DOES_NOT_EXIST
:
516 return ERROR_DEV_NOT_EXIST
;
519 return ERROR_IO_PENDING
;