[WIN32K] Code formatting.
[reactos.git] / win32ss / gdi / eng / device.c
1 /*
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
7 * Timo Kreuzer
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(EngDev)
12
13 PGRAPHICS_DEVICE gpPrimaryGraphicsDevice;
14 PGRAPHICS_DEVICE gpVgaGraphicsDevice;
15
16 static PGRAPHICS_DEVICE gpGraphicsDeviceFirst = NULL;
17 static PGRAPHICS_DEVICE gpGraphicsDeviceLast = NULL;
18 static HSEMAPHORE ghsemGraphicsDeviceList;
19 static ULONG giDevNum = 1;
20
21 INIT_FUNCTION
22 NTSTATUS
23 NTAPI
24 InitDeviceImpl(VOID)
25 {
26 ghsemGraphicsDeviceList = EngCreateSemaphore();
27 if (!ghsemGraphicsDeviceList)
28 return STATUS_INSUFFICIENT_RESOURCES;
29
30 return STATUS_SUCCESS;
31 }
32
33 BOOLEAN
34 EngpPopulateDeviceModeList(
35 _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
36 _In_ PDEVMODEW pdmDefault)
37 {
38 PWSTR pwsz;
39 PLDEVOBJ pldev;
40 PDEVMODEINFO pdminfo;
41 PDEVMODEW pdm, pdmEnd;
42 ULONG i, cModes = 0;
43 BOOLEAN bModeMatch = FALSE;
44
45 ASSERT(pGraphicsDevice->pdevmodeInfo == NULL);
46 ASSERT(pGraphicsDevice->pDevModeList == NULL);
47
48 pwsz = pGraphicsDevice->pDiplayDrivers;
49
50 /* Loop through the driver names
51 * This is a REG_MULTI_SZ string */
52 for (; *pwsz; pwsz += wcslen(pwsz) + 1)
53 {
54 /* Try to load the display driver */
55 TRACE("Trying driver: %ls\n", pwsz);
56 pldev = EngLoadImageEx(pwsz, LDEV_DEVICE_DISPLAY);
57 if (!pldev)
58 {
59 ERR("Could not load driver: '%ls'\n", pwsz);
60 continue;
61 }
62
63 /* Get the mode list from the driver */
64 pdminfo = LDEVOBJ_pdmiGetModes(pldev, pGraphicsDevice->DeviceObject);
65 if (!pdminfo)
66 {
67 ERR("Could not get mode list for '%ls'\n", pwsz);
68 continue;
69 }
70
71 /* Attach the mode info to the device */
72 pdminfo->pdmiNext = pGraphicsDevice->pdevmodeInfo;
73 pGraphicsDevice->pdevmodeInfo = pdminfo;
74
75 /* Loop all DEVMODEs */
76 pdmEnd = (DEVMODEW*)((PCHAR)pdminfo->adevmode + pdminfo->cbdevmode);
77 for (pdm = pdminfo->adevmode;
78 (pdm + 1 <= pdmEnd) && (pdm->dmSize != 0);
79 pdm = (DEVMODEW*)((PCHAR)pdm + pdm->dmSize + pdm->dmDriverExtra))
80 {
81 /* Count this DEVMODE */
82 cModes++;
83
84 /* Some drivers like the VBox driver don't fill the dmDeviceName
85 with the name of the display driver. So fix that here. */
86 wcsncpy(pdm->dmDeviceName, pwsz, CCHDEVICENAME);
87 pdm->dmDeviceName[CCHDEVICENAME - 1] = 0;
88 }
89
90 // FIXME: release the driver again until it's used?
91 }
92
93 if (!pGraphicsDevice->pdevmodeInfo || cModes == 0)
94 {
95 ERR("No devmodes\n");
96 return FALSE;
97 }
98
99 /* Allocate an index buffer */
100 pGraphicsDevice->cDevModes = cModes;
101 pGraphicsDevice->pDevModeList = ExAllocatePoolWithTag(PagedPool,
102 cModes * sizeof(DEVMODEENTRY),
103 GDITAG_GDEVICE);
104 if (!pGraphicsDevice->pDevModeList)
105 {
106 ERR("No devmode list\n");
107 return FALSE;
108 }
109
110 TRACE("Looking for mode %lux%lux%lu(%lu Hz)\n",
111 pdmDefault->dmPelsWidth,
112 pdmDefault->dmPelsHeight,
113 pdmDefault->dmBitsPerPel,
114 pdmDefault->dmDisplayFrequency);
115
116 /* Loop through all DEVMODEINFOs */
117 for (pdminfo = pGraphicsDevice->pdevmodeInfo, i = 0;
118 pdminfo;
119 pdminfo = pdminfo->pdmiNext)
120 {
121 /* Calculate End of the DEVMODEs */
122 pdmEnd = (DEVMODEW*)((PCHAR)pdminfo->adevmode + pdminfo->cbdevmode);
123
124 /* Loop through the DEVMODEs */
125 for (pdm = pdminfo->adevmode;
126 (pdm + 1 <= pdmEnd) && (pdm->dmSize != 0);
127 pdm = (PDEVMODEW)((PCHAR)pdm + pdm->dmSize + pdm->dmDriverExtra))
128 {
129 TRACE(" %S has mode %lux%lux%lu(%lu Hz)\n",
130 pdm->dmDeviceName,
131 pdm->dmPelsWidth,
132 pdm->dmPelsHeight,
133 pdm->dmBitsPerPel,
134 pdm->dmDisplayFrequency);
135 /* Compare with the default entry */
136 if (!bModeMatch &&
137 pdm->dmBitsPerPel == pdmDefault->dmBitsPerPel &&
138 pdm->dmPelsWidth == pdmDefault->dmPelsWidth &&
139 pdm->dmPelsHeight == pdmDefault->dmPelsHeight)
140 {
141 pGraphicsDevice->iDefaultMode = i;
142 pGraphicsDevice->iCurrentMode = i;
143 TRACE("Found default entry: %lu '%ls'\n", i, pdm->dmDeviceName);
144 if (pdm->dmDisplayFrequency == pdmDefault->dmDisplayFrequency)
145 {
146 /* Uh oh, even the display frequency matches. */
147 bModeMatch = TRUE;
148 }
149 }
150
151 /* Initialize the entry */
152 pGraphicsDevice->pDevModeList[i].dwFlags = 0;
153 pGraphicsDevice->pDevModeList[i].pdm = pdm;
154 i++;
155 }
156 }
157 return TRUE;
158 }
159
160 PGRAPHICS_DEVICE
161 NTAPI
162 EngpRegisterGraphicsDevice(
163 _In_ PUNICODE_STRING pustrDeviceName,
164 _In_ PUNICODE_STRING pustrDiplayDrivers,
165 _In_ PUNICODE_STRING pustrDescription,
166 _In_ PDEVMODEW pdmDefault)
167 {
168 PGRAPHICS_DEVICE pGraphicsDevice;
169 PDEVICE_OBJECT pDeviceObject;
170 PFILE_OBJECT pFileObject;
171 NTSTATUS Status;
172 PWSTR pwsz;
173 ULONG cj;
174 SIZE_T cjWritten;
175 BOOL bEnable = TRUE;
176
177 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName);
178
179 /* Allocate a GRAPHICS_DEVICE structure */
180 pGraphicsDevice = ExAllocatePoolWithTag(PagedPool,
181 sizeof(GRAPHICS_DEVICE),
182 GDITAG_GDEVICE);
183 if (!pGraphicsDevice)
184 {
185 ERR("ExAllocatePoolWithTag failed\n");
186 return NULL;
187 }
188
189 /* Try to open and enable the device */
190 Status = IoGetDeviceObjectPointer(pustrDeviceName,
191 FILE_READ_DATA | FILE_WRITE_DATA,
192 &pFileObject,
193 &pDeviceObject);
194 if (!NT_SUCCESS(Status))
195 {
196 ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status);
197 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
198 return NULL;
199 }
200
201 /* Enable the device */
202 EngFileWrite(pFileObject, &bEnable, sizeof(BOOL), &cjWritten);
203
204 /* Copy the device and file object pointers */
205 pGraphicsDevice->DeviceObject = pDeviceObject;
206 pGraphicsDevice->FileObject = pFileObject;
207
208 /* Copy device name */
209 RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName,
210 sizeof(pGraphicsDevice->szNtDeviceName),
211 pustrDeviceName->Buffer,
212 pustrDeviceName->Length);
213
214 /* Create a win device name (FIXME: virtual devices!) */
215 swprintf(pGraphicsDevice->szWinDeviceName, L"\\\\.\\DISPLAY%d", (int)giDevNum);
216
217 /* Allocate a buffer for the strings */
218 cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR);
219 pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP);
220 if (!pwsz)
221 {
222 ERR("Could not allocate string buffer\n");
223 ASSERT(FALSE); // FIXME
224 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
225 return NULL;
226 }
227
228 /* Copy the display driver names */
229 pGraphicsDevice->pDiplayDrivers = pwsz;
230 RtlCopyMemory(pGraphicsDevice->pDiplayDrivers,
231 pustrDiplayDrivers->Buffer,
232 pustrDiplayDrivers->Length);
233
234 /* Copy the description */
235 pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR);
236 RtlCopyMemory(pGraphicsDevice->pwszDescription,
237 pustrDescription->Buffer,
238 pustrDescription->Length);
239 pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0;
240
241 /* Initialize the pdevmodeInfo list and default index */
242 pGraphicsDevice->pdevmodeInfo = NULL;
243 pGraphicsDevice->iDefaultMode = 0;
244 pGraphicsDevice->iCurrentMode = 0;
245
246 // FIXME: initialize state flags
247 pGraphicsDevice->StateFlags = 0;
248
249 /* Create the mode list */
250 pGraphicsDevice->pDevModeList = NULL;
251 if (!EngpPopulateDeviceModeList(pGraphicsDevice, pdmDefault))
252 {
253 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE);
254 return NULL;
255 }
256
257 /* Lock loader */
258 EngAcquireSemaphore(ghsemGraphicsDeviceList);
259
260 /* Insert the device into the global list */
261 pGraphicsDevice->pNextGraphicsDevice = NULL;
262 if (gpGraphicsDeviceLast)
263 gpGraphicsDeviceLast->pNextGraphicsDevice = pGraphicsDevice;
264 gpGraphicsDeviceLast = pGraphicsDevice;
265 if (!gpGraphicsDeviceFirst)
266 gpGraphicsDeviceFirst = pGraphicsDevice;
267
268 /* Increment the device number */
269 giDevNum++;
270
271 /* Unlock loader */
272 EngReleaseSemaphore(ghsemGraphicsDeviceList);
273 TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription);
274
275 return pGraphicsDevice;
276 }
277
278 PGRAPHICS_DEVICE
279 NTAPI
280 EngpFindGraphicsDevice(
281 _In_opt_ PUNICODE_STRING pustrDevice,
282 _In_ ULONG iDevNum,
283 _In_ DWORD dwFlags)
284 {
285 UNICODE_STRING ustrCurrent;
286 PGRAPHICS_DEVICE pGraphicsDevice;
287 ULONG i;
288 TRACE("EngpFindGraphicsDevice('%wZ', %lu, 0x%lx)\n",
289 pustrDevice, iDevNum, dwFlags);
290
291 /* Lock list */
292 EngAcquireSemaphore(ghsemGraphicsDeviceList);
293
294 if (pustrDevice && pustrDevice->Buffer)
295 {
296 /* Loop through the list of devices */
297 for (pGraphicsDevice = gpGraphicsDeviceFirst;
298 pGraphicsDevice;
299 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice)
300 {
301 /* Compare the device name */
302 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
303 if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE))
304 {
305 break;
306 }
307 }
308 }
309 else
310 {
311 /* Loop through the list of devices */
312 for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0;
313 pGraphicsDevice && i < iDevNum;
314 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++);
315 }
316
317 /* Unlock list */
318 EngReleaseSemaphore(ghsemGraphicsDeviceList);
319
320 return pGraphicsDevice;
321 }
322
323 static
324 NTSTATUS
325 EngpFileIoRequest(
326 _In_ PFILE_OBJECT pFileObject,
327 _In_ ULONG ulMajorFunction,
328 _In_reads_(nBufferSize) PVOID lpBuffer,
329 _In_ SIZE_T nBufferSize,
330 _In_ ULONGLONG ullStartOffset,
331 _Out_ PULONG_PTR lpInformation)
332 {
333 PDEVICE_OBJECT pDeviceObject;
334 KEVENT Event;
335 PIRP pIrp;
336 IO_STATUS_BLOCK Iosb;
337 NTSTATUS Status;
338 LARGE_INTEGER liStartOffset;
339
340 /* Get corresponding device object */
341 pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
342 if (!pDeviceObject)
343 {
344 return STATUS_INVALID_PARAMETER;
345 }
346
347 /* Initialize an event */
348 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
349
350 /* Build IRP */
351 liStartOffset.QuadPart = ullStartOffset;
352 pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction,
353 pDeviceObject,
354 lpBuffer,
355 (ULONG)nBufferSize,
356 &liStartOffset,
357 &Event,
358 &Iosb);
359 if (!pIrp)
360 {
361 return STATUS_INSUFFICIENT_RESOURCES;
362 }
363
364 /* Call the driver */
365 Status = IoCallDriver(pDeviceObject, pIrp);
366
367 /* Wait if neccessary */
368 if (STATUS_PENDING == Status)
369 {
370 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
371 Status = Iosb.Status;
372 }
373
374 /* Return information to the caller about the operation. */
375 *lpInformation = Iosb.Information;
376
377 /* Return NTSTATUS */
378 return Status;
379 }
380
381 VOID
382 APIENTRY
383 EngFileWrite(
384 _In_ PFILE_OBJECT pFileObject,
385 _In_reads_(nLength) PVOID lpBuffer,
386 _In_ SIZE_T nLength,
387 _Out_ PSIZE_T lpBytesWritten)
388 {
389 NTSTATUS status;
390
391 status = EngpFileIoRequest(pFileObject,
392 IRP_MJ_WRITE,
393 lpBuffer,
394 nLength,
395 0,
396 lpBytesWritten);
397 if (!NT_SUCCESS(status))
398 {
399 *lpBytesWritten = 0;
400 }
401 }
402
403 _Success_(return>=0)
404 NTSTATUS
405 APIENTRY
406 EngFileIoControl(
407 _In_ PFILE_OBJECT pFileObject,
408 _In_ DWORD dwIoControlCode,
409 _In_reads_(nInBufferSize) PVOID lpInBuffer,
410 _In_ SIZE_T nInBufferSize,
411 _Out_writes_(nOutBufferSize) PVOID lpOutBuffer,
412 _In_ SIZE_T nOutBufferSize,
413 _Out_ PULONG_PTR lpInformation)
414 {
415 PDEVICE_OBJECT pDeviceObject;
416 KEVENT Event;
417 PIRP pIrp;
418 IO_STATUS_BLOCK Iosb;
419 NTSTATUS Status;
420
421 /* Get corresponding device object */
422 pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
423 if (!pDeviceObject)
424 {
425 return STATUS_INVALID_PARAMETER;
426 }
427
428 /* Initialize an event */
429 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
430
431 /* Build IO control IRP */
432 pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode,
433 pDeviceObject,
434 lpInBuffer,
435 (ULONG)nInBufferSize,
436 lpOutBuffer,
437 (ULONG)nOutBufferSize,
438 FALSE,
439 &Event,
440 &Iosb);
441 if (!pIrp)
442 {
443 return STATUS_INSUFFICIENT_RESOURCES;
444 }
445
446 /* Call the driver */
447 Status = IoCallDriver(pDeviceObject, pIrp);
448
449 /* Wait if neccessary */
450 if (Status == STATUS_PENDING)
451 {
452 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
453 Status = Iosb.Status;
454 }
455
456 /* Return information to the caller about the operation. */
457 *lpInformation = Iosb.Information;
458
459 /* This function returns NTSTATUS */
460 return Status;
461 }
462
463 /*
464 * @implemented
465 */
466 _Success_(return==0)
467 DWORD
468 APIENTRY
469 EngDeviceIoControl(
470 _In_ HANDLE hDevice,
471 _In_ DWORD dwIoControlCode,
472 _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer,
473 _In_ DWORD cjInBufferSize,
474 _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer,
475 _In_ DWORD cjOutBufferSize,
476 _Out_ LPDWORD lpBytesReturned)
477 {
478 PIRP Irp;
479 NTSTATUS Status;
480 KEVENT Event;
481 IO_STATUS_BLOCK Iosb;
482 PDEVICE_OBJECT DeviceObject;
483
484 TRACE("EngDeviceIoControl() called\n");
485
486 if (!hDevice)
487 {
488 return ERROR_INVALID_HANDLE;
489 }
490
491 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
492
493 DeviceObject = (PDEVICE_OBJECT) hDevice;
494
495 Irp = IoBuildDeviceIoControlRequest(dwIoControlCode,
496 DeviceObject,
497 lpInBuffer,
498 cjInBufferSize,
499 lpOutBuffer,
500 cjOutBufferSize,
501 FALSE,
502 &Event,
503 &Iosb);
504 if (!Irp) return ERROR_NOT_ENOUGH_MEMORY;
505
506 Status = IoCallDriver(DeviceObject, Irp);
507
508 if (Status == STATUS_PENDING)
509 {
510 (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
511 Status = Iosb.Status;
512 }
513
514 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status,
515 Iosb.Information);
516
517 /* Return information to the caller about the operation. */
518 *lpBytesReturned = (DWORD)Iosb.Information;
519
520 /* Convert NT status values to win32 error codes. */
521 switch (Status)
522 {
523 case STATUS_INSUFFICIENT_RESOURCES:
524 return ERROR_NOT_ENOUGH_MEMORY;
525
526 case STATUS_BUFFER_OVERFLOW:
527 return ERROR_MORE_DATA;
528
529 case STATUS_NOT_IMPLEMENTED:
530 return ERROR_INVALID_FUNCTION;
531
532 case STATUS_INVALID_PARAMETER:
533 return ERROR_INVALID_PARAMETER;
534
535 case STATUS_BUFFER_TOO_SMALL:
536 return ERROR_INSUFFICIENT_BUFFER;
537
538 case STATUS_DEVICE_DOES_NOT_EXIST:
539 return ERROR_DEV_NOT_EXIST;
540
541 case STATUS_PENDING:
542 return ERROR_IO_PENDING;
543 }
544
545 return Status;
546 }
547
548 /* EOF */