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;
52 PDEVMODEW pdm
, pdmEnd
;
55 DPRINT("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName
);
57 /* Allocate a GRAPHICS_DEVICE structure */
58 pGraphicsDevice
= ExAllocatePoolWithTag(PagedPool
,
59 sizeof(GRAPHICS_DEVICE
),
63 DPRINT1("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 DPRINT1("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
), &cj
);
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 DPRINT1("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
+ sizeof(WCHAR
));
118 /* Initialize the pdevmodeInfo list and default index */
119 pGraphicsDevice
->pdevmodeInfo
= NULL
;
120 pGraphicsDevice
->iDefaultMode
= 0;
121 pGraphicsDevice
->iCurrentMode
= 0;
123 // FIXME: initialize state flags
124 pGraphicsDevice
->StateFlags
= 0;
126 /* Loop through the driver names
127 * This is a REG_MULTI_SZ string */
128 for (; *pwsz
; pwsz
+= wcslen(pwsz
) + 1)
130 DPRINT("trying driver: %ls\n", pwsz
);
131 /* Try to load the display driver */
132 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
135 DPRINT1("Could not load driver: '%ls'\n", pwsz
);
139 /* Get the mode list from the driver */
140 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pDeviceObject
);
143 DPRINT1("Could not get mode list for '%ls'\n", pwsz
);
147 /* Attach the mode info to the device */
148 pdminfo
->pdmiNext
= pGraphicsDevice
->pdevmodeInfo
;
149 pGraphicsDevice
->pdevmodeInfo
= pdminfo
;
151 /* Loop all DEVMODEs */
152 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
153 for (pdm
= pdminfo
->adevmode
;
154 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
155 pdm
= (DEVMODEW
*)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
157 /* Count this DEVMODE */
160 /* Some drivers like the VBox driver don't fill the dmDeviceName
161 with the name of the display driver. So fix that here. */
162 wcsncpy(pdm
->dmDeviceName
, pwsz
, CCHDEVICENAME
);
163 pdm
->dmDeviceName
[CCHDEVICENAME
- 1] = 0;
166 // FIXME: release the driver again until it's used?
169 if (!pGraphicsDevice
->pdevmodeInfo
|| cModes
== 0)
171 DPRINT1("No devmodes\n");
172 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
176 /* Allocate an index buffer */
177 pGraphicsDevice
->cDevModes
= cModes
;
178 pGraphicsDevice
->pDevModeList
= ExAllocatePoolWithTag(PagedPool
,
179 cModes
* sizeof(DEVMODEENTRY
),
181 if (!pGraphicsDevice
->pDevModeList
)
183 DPRINT1("No devmode list\n");
184 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
188 /* Loop through all DEVMODEINFOs */
189 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
191 pdminfo
= pdminfo
->pdmiNext
)
193 /* Calculate End of the DEVMODEs */
194 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
196 /* Loop through the DEVMODEs */
197 for (pdm
= pdminfo
->adevmode
;
198 (pdm
+ 1 <= pdmEnd
) && (pdm
->dmSize
!= 0);
199 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
201 /* Compare with the default entry */
202 if (pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
203 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
204 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
&&
205 pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
207 pGraphicsDevice
->iDefaultMode
= i
;
208 pGraphicsDevice
->iCurrentMode
= i
;
209 DPRINT("Found default entry: %ld '%ls'\n", i
, pdm
->dmDeviceName
);
212 /* Initialize the entry */
213 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
214 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
220 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
222 /* Insert the device into the global list */
223 pGraphicsDevice
->pNextGraphicsDevice
= NULL
;
224 if (gpGraphicsDeviceLast
)
225 gpGraphicsDeviceLast
->pNextGraphicsDevice
= pGraphicsDevice
;
226 gpGraphicsDeviceLast
= pGraphicsDevice
;
227 if (!gpGraphicsDeviceFirst
)
228 gpGraphicsDeviceFirst
= pGraphicsDevice
;
230 /* Increment device number */
234 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
235 DPRINT("Prepared %ld modes for %ls\n", cModes
, pGraphicsDevice
->pwszDescription
);
237 return pGraphicsDevice
;
243 EngpFindGraphicsDevice(
244 PUNICODE_STRING pustrDevice
,
248 UNICODE_STRING ustrCurrent
;
249 PGRAPHICS_DEVICE pGraphicsDevice
;
251 DPRINT("EngpFindGraphicsDevice('%wZ', %ld, 0x%lx)\n",
252 pustrDevice
, iDevNum
, dwFlags
);
255 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
257 if (pustrDevice
&& pustrDevice
->Buffer
)
259 /* Loop through the list of devices */
260 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
262 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
264 /* Compare the device name */
265 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
266 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
274 /* Loop through the list of devices */
275 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
276 pGraphicsDevice
&& i
< iDevNum
;
277 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
281 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
283 return pGraphicsDevice
;
290 PFILE_OBJECT pFileObject
,
291 ULONG ulMajorFunction
,
294 ULONGLONG ullStartOffset
,
295 OUT LPDWORD lpInformation
)
297 PDEVICE_OBJECT pDeviceObject
;
300 IO_STATUS_BLOCK Iosb
;
302 LARGE_INTEGER liStartOffset
;
304 /* Get corresponding device object */
305 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
308 return STATUS_INVALID_PARAMETER
;
311 /* Initialize an event */
312 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
315 liStartOffset
.QuadPart
= ullStartOffset
;
316 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
325 return STATUS_INSUFFICIENT_RESOURCES
;
328 /* Call the driver */
329 Status
= IoCallDriver(pDeviceObject
, pIrp
);
331 /* Wait if neccessary */
332 if (STATUS_PENDING
== Status
)
334 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
335 Status
= Iosb
.Status
;
338 /* Return information to the caller about the operation. */
339 *lpInformation
= Iosb
.Information
;
341 /* Return NTSTATUS */
348 IN PFILE_OBJECT pFileObject
,
351 IN PSIZE_T lpBytesWritten
)
353 EngpFileIoRequest(pFileObject
,
364 IN PFILE_OBJECT pFileObject
,
365 IN DWORD dwIoControlCode
,
367 IN SIZE_T nInBufferSize
,
368 OUT PVOID lpOutBuffer
,
369 IN SIZE_T nOutBufferSize
,
370 OUT LPDWORD lpInformation
)
372 PDEVICE_OBJECT pDeviceObject
;
375 IO_STATUS_BLOCK Iosb
;
378 /* Get corresponding device object */
379 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
382 return STATUS_INVALID_PARAMETER
;
385 /* Initialize an event */
386 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
388 /* Build IO control IRP */
389 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
400 return STATUS_INSUFFICIENT_RESOURCES
;
403 /* Call the driver */
404 Status
= IoCallDriver(pDeviceObject
, pIrp
);
406 /* Wait if neccessary */
407 if (Status
== STATUS_PENDING
)
409 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
410 Status
= Iosb
.Status
;
413 /* Return information to the caller about the operation. */
414 *lpInformation
= Iosb
.Information
;
416 /* This function returns NTSTATUS */
426 DWORD dwIoControlCode
,
430 DWORD nOutBufferSize
,
431 DWORD
*lpBytesReturned
)
436 IO_STATUS_BLOCK Iosb
;
437 PDEVICE_OBJECT DeviceObject
;
439 DPRINT("EngDeviceIoControl() called\n");
441 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
443 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
445 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
450 nOutBufferSize
, FALSE
, &Event
, &Iosb
);
451 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
453 Status
= IoCallDriver(DeviceObject
, Irp
);
455 if (Status
== STATUS_PENDING
)
457 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
458 Status
= Iosb
.Status
;
461 DPRINT("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
464 /* Return information to the caller about the operation. */
465 *lpBytesReturned
= Iosb
.Information
;
467 /* Convert NT status values to win32 error codes. */
470 case STATUS_INSUFFICIENT_RESOURCES
:
471 return ERROR_NOT_ENOUGH_MEMORY
;
473 case STATUS_BUFFER_OVERFLOW
:
474 return ERROR_MORE_DATA
;
476 case STATUS_NOT_IMPLEMENTED
:
477 return ERROR_INVALID_FUNCTION
;
479 case STATUS_INVALID_PARAMETER
:
480 return ERROR_INVALID_PARAMETER
;
482 case STATUS_BUFFER_TOO_SMALL
:
483 return ERROR_INSUFFICIENT_BUFFER
;
485 case STATUS_DEVICE_DOES_NOT_EXIST
:
486 return ERROR_DEV_NOT_EXIST
;
489 return ERROR_IO_PENDING
;