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 DPRINT1("EngpRegisterGraphicsDevice(%S)\n", pustrDeviceName
->Buffer
);
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, 0x%lx\n", 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 wcsncpy(pGraphicsDevice
->szNtDeviceName
,
88 pustrDeviceName
->Buffer
,
89 sizeof(pGraphicsDevice
->szNtDeviceName
) / sizeof(WCHAR
));
91 /* Create a win device name (FIXME: virtual devices!) */
92 swprintf(pGraphicsDevice
->szWinDeviceName
, L
"\\\\.\\VIDEO%d", (CHAR
)giDevNum
);
94 /* Allocate a buffer for the strings */
95 cj
= pustrDiplayDrivers
->Length
+ pustrDescription
->Length
+ sizeof(WCHAR
);
96 pwsz
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_DRVSUP
);
99 DPRINT1("Could not allocate string buffer\n");
100 ASSERT(FALSE
); // FIXME
103 /* Copy display driver names */
104 pGraphicsDevice
->pDiplayDrivers
= pwsz
;
105 RtlCopyMemory(pGraphicsDevice
->pDiplayDrivers
,
106 pustrDiplayDrivers
->Buffer
,
107 pustrDiplayDrivers
->Length
);
109 /* Copy description */
110 pGraphicsDevice
->pwszDescription
= pwsz
+ pustrDiplayDrivers
->Length
/ sizeof(WCHAR
);
111 RtlCopyMemory(pGraphicsDevice
->pwszDescription
,
112 pustrDescription
->Buffer
,
113 pustrDescription
->Length
+ sizeof(WCHAR
));
115 /* Initialize the pdevmodeInfo list and default index */
116 pGraphicsDevice
->pdevmodeInfo
= NULL
;
117 pGraphicsDevice
->iDefaultMode
= 0;
118 pGraphicsDevice
->iCurrentMode
= 0;
120 // FIXME: initialize state flags
121 pGraphicsDevice
->StateFlags
= 0;
123 /* Loop through the driver names
124 * This is a REG_MULTI_SZ string */
125 for (; *pwsz
; pwsz
+= wcslen(pwsz
) + 1)
127 DPRINT1("trying driver: %ls\n", pwsz
);
128 /* Try to load the display driver */
129 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
132 DPRINT1("Could not load driver: '%ls'\n", pwsz
);
136 /* Get the mode list from the driver */
137 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pDeviceObject
);
140 DPRINT1("Could not get mode list for '%ls'\n", pwsz
);
144 /* Attach the mode info to the device */
145 pdminfo
->pdmiNext
= pGraphicsDevice
->pdevmodeInfo
;
146 pGraphicsDevice
->pdevmodeInfo
= pdminfo
;
149 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
150 for (pdm
= pdminfo
->adevmode
;
152 pdm
= (DEVMODEW
*)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
157 // FIXME: release the driver again until it's used?
160 if (!pGraphicsDevice
->pdevmodeInfo
|| cModes
== 0)
162 DPRINT1("No devmodes\n");
163 ExFreePool(pGraphicsDevice
);
167 /* Allocate an index buffer */
168 pGraphicsDevice
->cDevModes
= cModes
;
169 pGraphicsDevice
->pDevModeList
= ExAllocatePoolWithTag(PagedPool
,
170 cModes
* sizeof(DEVMODEENTRY
),
172 if (!pGraphicsDevice
->pDevModeList
)
174 DPRINT1("No devmode list\n");
175 ExFreePool(pGraphicsDevice
);
179 /* Loop through all DEVMODEINFOs */
180 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
182 pdminfo
= pdminfo
->pdmiNext
)
184 /* Calculate End of the DEVMODEs */
185 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
187 /* Loop through the DEVMODEs */
188 for (pdm
= pdminfo
->adevmode
;
190 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
192 /* Compare with the default entry */
193 if (pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
194 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
195 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
&&
196 pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
198 pGraphicsDevice
->iDefaultMode
= i
;
199 pGraphicsDevice
->iCurrentMode
= i
;
200 DPRINT1("Found default entry: %ld '%ls'\n", i
, pdm
->dmDeviceName
);
203 /* Initialize the entry */
204 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
205 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
211 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
213 /* Insert the device into the global list */
214 pGraphicsDevice
->pNextGraphicsDevice
= gpGraphicsDeviceLast
;
215 gpGraphicsDeviceLast
= pGraphicsDevice
;
216 if (!gpGraphicsDeviceFirst
)
217 gpGraphicsDeviceFirst
= pGraphicsDevice
;
219 /* Increment device number */
223 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
224 DPRINT1("Prepared %ld modes for %ls\n", cModes
, pGraphicsDevice
->pwszDescription
);
226 return pGraphicsDevice
;
232 EngpFindGraphicsDevice(
233 PUNICODE_STRING pustrDevice
,
237 UNICODE_STRING ustrCurrent
;
238 PGRAPHICS_DEVICE pGraphicsDevice
;
242 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
246 /* Loop through the list of devices */
247 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
249 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
251 /* Compare the device name */
252 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
253 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
261 /* Loop through the list of devices */
262 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
263 pGraphicsDevice
&& i
< iDevNum
;
264 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
268 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
270 return pGraphicsDevice
;
277 PFILE_OBJECT pFileObject
,
278 ULONG ulMajorFunction
,
281 ULONGLONG ullStartOffset
,
282 OUT LPDWORD lpInformation
)
284 PDEVICE_OBJECT pDeviceObject
;
287 IO_STATUS_BLOCK Iosb
;
289 LARGE_INTEGER liStartOffset
;
291 /* Get corresponding device object */
292 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
295 return STATUS_INVALID_PARAMETER
;
298 /* Initialize an event */
299 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
302 liStartOffset
.QuadPart
= ullStartOffset
;
303 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
312 return STATUS_INSUFFICIENT_RESOURCES
;
315 /* Call the driver */
316 Status
= IoCallDriver(pDeviceObject
, pIrp
);
318 /* Wait if neccessary */
319 if (STATUS_PENDING
== Status
)
321 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
322 Status
= Iosb
.Status
;
325 /* Return information to the caller about the operation. */
326 *lpInformation
= Iosb
.Information
;
328 /* Return NTSTATUS */
335 IN PFILE_OBJECT pFileObject
,
338 IN PSIZE_T lpBytesWritten
)
340 EngpFileIoRequest(pFileObject
,
351 IN PFILE_OBJECT pFileObject
,
352 IN DWORD dwIoControlCode
,
354 IN SIZE_T nInBufferSize
,
355 OUT PVOID lpOutBuffer
,
356 IN SIZE_T nOutBufferSize
,
357 OUT LPDWORD lpInformation
)
359 PDEVICE_OBJECT pDeviceObject
;
362 IO_STATUS_BLOCK Iosb
;
365 /* Get corresponding device object */
366 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
369 return STATUS_INVALID_PARAMETER
;
372 /* Initialize an event */
373 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
375 /* Build IO control IRP */
376 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
387 return STATUS_INSUFFICIENT_RESOURCES
;
390 /* Call the driver */
391 Status
= IoCallDriver(pDeviceObject
, pIrp
);
393 /* Wait if neccessary */
394 if (Status
== STATUS_PENDING
)
396 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
397 Status
= Iosb
.Status
;
400 /* Return information to the caller about the operation. */
401 *lpInformation
= Iosb
.Information
;
403 /* This function returns NTSTATUS */
413 DWORD dwIoControlCode
,
417 DWORD nOutBufferSize
,
418 DWORD
*lpBytesReturned
)
423 IO_STATUS_BLOCK Iosb
;
424 PDEVICE_OBJECT DeviceObject
;
426 DPRINT("EngDeviceIoControl() called\n");
428 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
430 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
432 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
437 nOutBufferSize
, FALSE
, &Event
, &Iosb
);
438 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
440 Status
= IoCallDriver(DeviceObject
, Irp
);
442 if (Status
== STATUS_PENDING
)
444 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
445 Status
= Iosb
.Status
;
448 DPRINT("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
451 /* Return information to the caller about the operation. */
452 *lpBytesReturned
= Iosb
.Information
;
454 /* Convert NT status values to win32 error codes. */
457 case STATUS_INSUFFICIENT_RESOURCES
:
458 return ERROR_NOT_ENOUGH_MEMORY
;
460 case STATUS_BUFFER_OVERFLOW
:
461 return ERROR_MORE_DATA
;
463 case STATUS_NOT_IMPLEMENTED
:
464 return ERROR_INVALID_FUNCTION
;
466 case STATUS_INVALID_PARAMETER
:
467 return ERROR_INVALID_PARAMETER
;
469 case STATUS_BUFFER_TOO_SMALL
:
470 return ERROR_INSUFFICIENT_BUFFER
;
472 case STATUS_DEVICE_DOES_NOT_EXIST
:
473 return ERROR_DEV_NOT_EXIST
;
476 return ERROR_IO_PENDING
;