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;
27 ghsemGraphicsDeviceList
= EngCreateSemaphore();
28 if (!ghsemGraphicsDeviceList
)
37 EngpRegisterGraphicsDevice(
38 PUNICODE_STRING pustrDeviceName
,
39 PUNICODE_STRING pustrDiplayDrivers
,
40 PUNICODE_STRING pustrDescription
,
43 PGRAPHICS_DEVICE pGraphicsDevice
;
44 PDEVICE_OBJECT pDeviceObject
;
45 PFILE_OBJECT pFileObject
;
48 ULONG i
, cj
, cModes
= 0;
51 PDEVMODEW pdm
, pdmEnd
;
54 DPRINT1("EngpRegisterGraphicsDevice(%S)\n", pustrDeviceName
->Buffer
);
56 /* Allocate a GRAPHICS_DEVICE structure */
57 pGraphicsDevice
= ExAllocatePoolWithTag(PagedPool
,
58 sizeof(GRAPHICS_DEVICE
),
62 DPRINT1("ExAllocatePoolWithTag failed\n");
66 /* Try to open the driver */
67 Status
= IoGetDeviceObjectPointer(pustrDeviceName
,
68 FILE_READ_DATA
| FILE_WRITE_DATA
,
71 if (!NT_SUCCESS(Status
))
73 DPRINT1("Could not open driver, 0x%lx\n", Status
);
74 ExFreePoolWithTag(pGraphicsDevice
, GDITAG_GDEVICE
);
78 /* Enable the device */
79 EngFileWrite(pFileObject
, &bEnable
, sizeof(BOOL
), &cj
);
81 /* Copy the device and file object pointers */
82 pGraphicsDevice
->DeviceObject
= pDeviceObject
;
83 pGraphicsDevice
->FileObject
= pFileObject
;
85 /* Copy device name */
86 wcsncpy(pGraphicsDevice
->szNtDeviceName
,
87 pustrDeviceName
->Buffer
,
88 sizeof(pGraphicsDevice
->szNtDeviceName
) / sizeof(WCHAR
));
90 /* Create a win device name (FIXME: virtual devices!) */
91 swprintf(pGraphicsDevice
->szWinDeviceName
, L
"\\\\.\\VIDEO%d", (CHAR
)giDevNum
);
93 /* Allocate a buffer for the strings */
94 cj
= pustrDiplayDrivers
->Length
+ pustrDescription
->Length
+ sizeof(WCHAR
);
95 pwsz
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_DRVSUP
);
98 DPRINT1("Could not allocate string buffer\n");
99 ASSERT(FALSE
); // FIXME
102 /* Copy display driver names */
103 pGraphicsDevice
->pDiplayDrivers
= pwsz
;
104 RtlCopyMemory(pGraphicsDevice
->pDiplayDrivers
,
105 pustrDiplayDrivers
->Buffer
,
106 pustrDiplayDrivers
->Length
);
108 /* Copy description */
109 pGraphicsDevice
->pwszDescription
= pwsz
+ pustrDiplayDrivers
->Length
/ sizeof(WCHAR
);
110 RtlCopyMemory(pGraphicsDevice
->pwszDescription
,
111 pustrDescription
->Buffer
,
112 pustrDescription
->Length
+ sizeof(WCHAR
));
114 /* Initialize the pdevmodeInfo list and default index */
115 pGraphicsDevice
->pdevmodeInfo
= NULL
;
116 pGraphicsDevice
->iDefaultMode
= 0;
117 pGraphicsDevice
->iCurrentMode
= 0;
119 // FIXME: initialize state flags
120 pGraphicsDevice
->StateFlags
= 0;
122 /* Loop through the driver names
123 * This is a REG_MULTI_SZ string */
124 for (; *pwsz
; pwsz
+= wcslen(pwsz
) + 1)
126 DPRINT1("trying driver: %ls\n", pwsz
);
127 /* Try to load the display driver */
128 pldev
= EngLoadImageEx(pwsz
, LDEV_DEVICE_DISPLAY
);
131 DPRINT1("Could not load driver: '%ls'\n", pwsz
);
135 /* Get the mode list from the driver */
136 pdminfo
= LDEVOBJ_pdmiGetModes(pldev
, pDeviceObject
);
139 DPRINT1("Could not get mode list for '%ls'\n", pwsz
);
143 /* Attach the mode info to the device */
144 pdminfo
->pdmiNext
= pGraphicsDevice
->pdevmodeInfo
;
145 pGraphicsDevice
->pdevmodeInfo
= pdminfo
;
148 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
149 for (pdm
= pdminfo
->adevmode
;
151 pdm
= (DEVMODEW
*)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
156 // FIXME: release the driver again until it's used?
159 if (!pGraphicsDevice
->pdevmodeInfo
|| cModes
== 0)
161 DPRINT1("No devmodes\n");
162 ExFreePool(pGraphicsDevice
);
166 /* Allocate an index buffer */
167 pGraphicsDevice
->cDevModes
= cModes
;
168 pGraphicsDevice
->pDevModeList
= ExAllocatePoolWithTag(PagedPool
,
169 cModes
* sizeof(DEVMODEENTRY
),
171 if (!pGraphicsDevice
->pDevModeList
)
173 DPRINT1("No devmode list\n");
174 ExFreePool(pGraphicsDevice
);
178 /* Loop through all DEVMODEINFOs */
179 for (pdminfo
= pGraphicsDevice
->pdevmodeInfo
, i
= 0;
181 pdminfo
= pdminfo
->pdmiNext
)
183 /* Calculate End of the DEVMODEs */
184 pdmEnd
= (DEVMODEW
*)((PCHAR
)pdminfo
->adevmode
+ pdminfo
->cbdevmode
);
186 /* Loop through the DEVMODEs */
187 for (pdm
= pdminfo
->adevmode
;
189 pdm
= (PDEVMODEW
)((PCHAR
)pdm
+ pdm
->dmSize
+ pdm
->dmDriverExtra
))
191 /* Compare with the default entry */
192 if (pdm
->dmBitsPerPel
== pdmDefault
->dmBitsPerPel
&&
193 pdm
->dmPelsWidth
== pdmDefault
->dmPelsWidth
&&
194 pdm
->dmPelsHeight
== pdmDefault
->dmPelsHeight
&&
195 pdm
->dmDisplayFrequency
== pdmDefault
->dmDisplayFrequency
)
197 pGraphicsDevice
->iDefaultMode
= i
;
198 pGraphicsDevice
->iCurrentMode
= i
;
199 DPRINT1("Found default entry: %ld '%ls'\n", i
, pdm
->dmDeviceName
);
202 /* Initialize the entry */
203 pGraphicsDevice
->pDevModeList
[i
].dwFlags
= 0;
204 pGraphicsDevice
->pDevModeList
[i
].pdm
= pdm
;
210 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
212 /* Insert the device into the global list */
213 pGraphicsDevice
->pNextGraphicsDevice
= gpGraphicsDeviceLast
;
214 gpGraphicsDeviceLast
= pGraphicsDevice
;
215 if (!gpGraphicsDeviceFirst
)
216 gpGraphicsDeviceFirst
= pGraphicsDevice
;
218 /* Increment device number */
222 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
223 DPRINT1("Prepared %ld modes for %ls\n", cModes
, pGraphicsDevice
->pwszDescription
);
225 return pGraphicsDevice
;
231 EngpFindGraphicsDevice(
232 PUNICODE_STRING pustrDevice
,
236 UNICODE_STRING ustrCurrent
;
237 PGRAPHICS_DEVICE pGraphicsDevice
;
241 EngAcquireSemaphore(ghsemGraphicsDeviceList
);
245 /* Loop through the list of devices */
246 for (pGraphicsDevice
= gpGraphicsDeviceFirst
;
248 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
)
250 /* Compare the device name */
251 RtlInitUnicodeString(&ustrCurrent
, pGraphicsDevice
->szWinDeviceName
);
252 if (RtlEqualUnicodeString(&ustrCurrent
, pustrDevice
, FALSE
))
260 /* Loop through the list of devices */
261 for (pGraphicsDevice
= gpGraphicsDeviceFirst
, i
= 0;
262 pGraphicsDevice
&& i
< iDevNum
;
263 pGraphicsDevice
= pGraphicsDevice
->pNextGraphicsDevice
, i
++);
267 EngReleaseSemaphore(ghsemGraphicsDeviceList
);
269 return pGraphicsDevice
;
276 PFILE_OBJECT pFileObject
,
277 ULONG ulMajorFunction
,
280 ULONGLONG ullStartOffset
,
281 OUT LPDWORD lpInformation
)
283 PDEVICE_OBJECT pDeviceObject
;
286 IO_STATUS_BLOCK Iosb
;
288 LARGE_INTEGER liStartOffset
;
290 /* Get corresponding device object */
291 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
294 return STATUS_INVALID_PARAMETER
;
297 /* Initialize an event */
298 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
301 liStartOffset
.QuadPart
= ullStartOffset
;
302 pIrp
= IoBuildSynchronousFsdRequest(ulMajorFunction
,
311 return STATUS_INSUFFICIENT_RESOURCES
;
314 /* Call the driver */
315 Status
= IoCallDriver(pDeviceObject
, pIrp
);
317 /* Wait if neccessary */
318 if (STATUS_PENDING
== Status
)
320 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
321 Status
= Iosb
.Status
;
324 /* Return information to the caller about the operation. */
325 *lpInformation
= Iosb
.Information
;
327 /* Return NTSTATUS */
334 IN PFILE_OBJECT pFileObject
,
337 IN PSIZE_T lpBytesWritten
)
339 EngpFileIoRequest(pFileObject
,
350 IN PFILE_OBJECT pFileObject
,
351 IN DWORD dwIoControlCode
,
353 IN SIZE_T nInBufferSize
,
354 OUT PVOID lpOutBuffer
,
355 IN SIZE_T nOutBufferSize
,
356 OUT LPDWORD lpInformation
)
358 PDEVICE_OBJECT pDeviceObject
;
361 IO_STATUS_BLOCK Iosb
;
364 /* Get corresponding device object */
365 pDeviceObject
= IoGetRelatedDeviceObject(pFileObject
);
368 return STATUS_INVALID_PARAMETER
;
371 /* Initialize an event */
372 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
374 /* Build IO control IRP */
375 pIrp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
386 return STATUS_INSUFFICIENT_RESOURCES
;
389 /* Call the driver */
390 Status
= IoCallDriver(pDeviceObject
, pIrp
);
392 /* Wait if neccessary */
393 if (Status
== STATUS_PENDING
)
395 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
396 Status
= Iosb
.Status
;
399 /* Return information to the caller about the operation. */
400 *lpInformation
= Iosb
.Information
;
402 /* This function returns NTSTATUS */
412 DWORD dwIoControlCode
,
416 DWORD nOutBufferSize
,
417 DWORD
*lpBytesReturned
)
422 IO_STATUS_BLOCK Iosb
;
423 PDEVICE_OBJECT DeviceObject
;
425 DPRINT("EngDeviceIoControl() called\n");
427 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
429 DeviceObject
= (PDEVICE_OBJECT
) hDevice
;
431 Irp
= IoBuildDeviceIoControlRequest(dwIoControlCode
,
436 nOutBufferSize
, FALSE
, &Event
, &Iosb
);
437 if (!Irp
) return ERROR_NOT_ENOUGH_MEMORY
;
439 Status
= IoCallDriver(DeviceObject
, Irp
);
441 if (Status
== STATUS_PENDING
)
443 (VOID
)KeWaitForSingleObject(&Event
, Executive
, KernelMode
, TRUE
, 0);
444 Status
= Iosb
.Status
;
447 DPRINT("EngDeviceIoControl(): Returning %X/%X\n", Iosb
.Status
,
450 /* Return information to the caller about the operation. */
451 *lpBytesReturned
= Iosb
.Information
;
453 /* Convert NT status values to win32 error codes. */
456 case STATUS_INSUFFICIENT_RESOURCES
:
457 return ERROR_NOT_ENOUGH_MEMORY
;
459 case STATUS_BUFFER_OVERFLOW
:
460 return ERROR_MORE_DATA
;
462 case STATUS_NOT_IMPLEMENTED
:
463 return ERROR_INVALID_FUNCTION
;
465 case STATUS_INVALID_PARAMETER
:
466 return ERROR_INVALID_PARAMETER
;
468 case STATUS_BUFFER_TOO_SMALL
:
469 return ERROR_INSUFFICIENT_BUFFER
;
471 case STATUS_DEVICE_DOES_NOT_EXIST
:
472 return ERROR_DEV_NOT_EXIST
;
475 return ERROR_IO_PENDING
;