1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "videoprt.h"
23
24 #include <ndk/inbvfuncs.h>
25 #include <ndk/obfuncs.h>
26 #include <ndk/psfuncs.h>
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* GLOBAL VARIABLES ***********************************************************/
32
33 static PVIDEO_WIN32K_CALLOUT Win32kCallout = NULL;
34 static HANDLE InbvThreadHandle = NULL;
35 static BOOLEAN InbvMonitoring = FALSE;
36
37 /* PRIVATE FUNCTIONS **********************************************************/
38
39 static VOID
VideoPortWin32kCallout(_In_ PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams)40 VideoPortWin32kCallout(
41 _In_ PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams)
42 {
43 if (!Win32kCallout)
44 return;
45
46 /* Perform the call in the context of CSRSS */
47 if (!CsrProcess)
48 return;
49
50 KeAttachProcess(CsrProcess);
51 Win32kCallout(CallbackParams);
52 KeDetachProcess();
53 }
54
55 /*
56 * Reinitialize the display to base VGA mode.
57 *
58 * Returns TRUE if it completely resets the adapter to the given character mode.
59 * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode
60 * reset itself after HwVidResetHw() returns control.
61 *
62 * This callback has been registered with InbvNotifyDisplayOwnershipLost()
63 * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck
64 * code regains display access. Therefore this routine can be called at any
65 * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside
66 * completely in non-paged pool, and cannot perform the following actions:
67 * Allocate memory, access pageable memory, use any synchronization mechanisms
68 * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below.
69 */
70 static BOOLEAN
71 NTAPI
IntVideoPortResetDisplayParametersEx(_In_ ULONG Columns,_In_ ULONG Rows,_In_ BOOLEAN CalledByInbv)72 IntVideoPortResetDisplayParametersEx(
73 _In_ ULONG Columns,
74 _In_ ULONG Rows,
75 _In_ BOOLEAN CalledByInbv)
76 {
77 BOOLEAN Success = TRUE; // Suppose we don't need to perform a full reset.
78 KIRQL OldIrql;
79 PLIST_ENTRY PrevEntry, Entry;
80 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
81 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
82
83 /* Check if we are at dispatch level or lower, and acquire the lock */
84 OldIrql = KeGetCurrentIrql();
85 if (OldIrql <= DISPATCH_LEVEL)
86 {
87 /* Loop until the lock is free, then raise IRQL to dispatch level */
88 while (!KeTestSpinLock(&HwResetAdaptersLock));
89 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
90 }
91 KeAcquireSpinLockAtDpcLevel(&HwResetAdaptersLock);
92
93 /* Bail out early if we don't have any resettable adapter */
94 if (IsListEmpty(&HwResetAdaptersList))
95 {
96 Success = FALSE; // No adapter found: request HAL to perform a full reset.
97 goto Quit;
98 }
99
100 /*
101 * If we have been unexpectedly called via a callback from
102 * InbvAcquireDisplayOwnership(), start monitoring INBV.
103 */
104 if (CalledByInbv)
105 InbvMonitoring = TRUE;
106
107 for (PrevEntry = &HwResetAdaptersList, Entry = PrevEntry->Flink;
108 Entry != &HwResetAdaptersList;
109 PrevEntry = Entry, Entry = Entry->Flink)
110 {
111 /*
112 * Check whether the entry address is properly aligned,
113 * the device and driver extensions must be readable and
114 * the device extension properly back-linked to the last entry.
115 */
116 // #define IS_ALIGNED(addr, align) (((ULONG64)(addr) & (align - 1)) == 0)
117 if (((ULONG_PTR)Entry & (sizeof(ULONG_PTR) - 1)) != 0)
118 {
119 Success = FALSE; // We failed: request HAL to perform a full reset.
120 goto Quit;
121 }
122
123 DeviceExtension = CONTAINING_RECORD(Entry,
124 VIDEO_PORT_DEVICE_EXTENSION,
125 HwResetListEntry);
126 /*
127 * As this function can be called as part of the INBV initialization
128 * by the bugcheck code, avoid any problems and protect all accesses
129 * within SEH.
130 */
131 _SEH2_TRY
132 {
133 DriverExtension = DeviceExtension->DriverExtension;
134 ASSERT(DriverExtension);
135
136 if (DeviceExtension->HwResetListEntry.Blink != PrevEntry)
137 {
138 Success = FALSE; // We failed: request HAL to perform a full reset.
139 _SEH2_YIELD(goto Quit);
140 }
141
142 if ((DeviceExtension->DeviceOpened >= 1) &&
143 (DriverExtension->InitializationData.HwResetHw != NULL))
144 {
145 Success &= DriverExtension->InitializationData.HwResetHw(
146 &DeviceExtension->MiniPortDeviceExtension,
147 Columns, Rows);
148 }
149 }
150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
151 {
152 }
153 _SEH2_END;
154 }
155
156 Quit:
157 /* Release the lock and restore the old IRQL if we were at dispatch level or lower */
158 KeReleaseSpinLockFromDpcLevel(&HwResetAdaptersLock);
159 if (OldIrql <= DISPATCH_LEVEL)
160 KeLowerIrql(OldIrql);
161
162 return Success;
163 }
164
165 /* This callback is registered with InbvNotifyDisplayOwnershipLost() */
166 static BOOLEAN
167 NTAPI
IntVideoPortResetDisplayParameters(ULONG Columns,ULONG Rows)168 IntVideoPortResetDisplayParameters(ULONG Columns, ULONG Rows)
169 {
170 /* Call the extended function, specifying we were called by INBV */
171 return IntVideoPortResetDisplayParametersEx(Columns, Rows, TRUE);
172 }
173
174 /*
175 * (Adapted for ReactOS/Win2k3 from an original comment
176 * by Gé van Geldorp, June 2003, r4937)
177 *
178 * DISPLAY OWNERSHIP
179 *
180 * So, who owns the physical display and is allowed to write to it?
181 *
182 * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless
183 * /NOGUIBOOT has been specified in the boot command line. Later in the boot
184 * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in
185 * VIDEOPRT.SYS. This component takes ownership of the display by calling
186 * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release
187 * ownership of the display it previously had. From that moment on, the display
188 * is owned by that component and can be switched to graphics mode. The display
189 * is not supposed to return to text mode, except in case of a bugcheck.
190 * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV
191 * re-take display ownership, and calls back the function previously registered
192 * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck,
193 * execution is halted. So, under NT, the only possible sequence of display
194 * modes is text mode -> graphics mode -> text mode (the latter hopefully
195 * happening very infrequently).
196 *
197 * In ReactOS things are a little bit different. We want to have a functional
198 * interactive text mode. We should be able to switch back and forth from
199 * text mode to graphics mode when a GUI app is started and then finished.
200 * Also, when the system bugchecks in graphics mode we want to switch back to
201 * text mode and show the bugcheck information. Last but not least, when using
202 * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a
203 * switch to text mode, and the user would expect that by continuing execution
204 * a switch back to graphics mode is done.
205 */
206 static VOID
207 NTAPI
InbvMonitorThread(_In_ PVOID Context)208 InbvMonitorThread(
209 _In_ PVOID Context)
210 {
211 VIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams;
212 LARGE_INTEGER Delay;
213 USHORT i;
214
215 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
216
217 while (TRUE)
218 {
219 /*
220 * During one second, check the INBV status each 100 milliseconds,
221 * then revert to 1 second delay.
222 */
223 i = 10;
224 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay
225 while (!InbvMonitoring)
226 {
227 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
228
229 if ((i > 0) && (--i == 0))
230 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay
231 }
232
233 /*
234 * Loop while the display is owned by INBV. We cannot do anything else
235 * than polling since INBV does not offer a proper notification system.
236 *
237 * During one second, check the INBV status each 100 milliseconds,
238 * then revert to 1 second delay.
239 */
240 i = 10;
241 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay
242 while (InbvCheckDisplayOwnership())
243 {
244 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
245
246 if ((i > 0) && (--i == 0))
247 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay
248 }
249
250 /* Reset the monitoring */
251 InbvMonitoring = FALSE;
252
253 /*
254 * Somebody released INBV display ownership, usually by invoking
255 * InbvNotifyDisplayOwnershipLost(). However the caller of this
256 * function certainly specified a different callback than ours.
257 * As we are going to be the only owner of the active display,
258 * we need to re-register our own display reset callback.
259 */
260 InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters);
261
262 /* Tell Win32k to reset the display */
263 CallbackParams.CalloutType = VideoFindAdapterCallout;
264 // CallbackParams.PhysDisp = NULL;
265 CallbackParams.Param = (ULONG_PTR)TRUE; // TRUE: Re-enable display; FALSE: Disable display.
266 VideoPortWin32kCallout(&CallbackParams);
267 }
268
269 // FIXME: See IntVideoPortInbvCleanup().
270 // PsTerminateSystemThread(STATUS_SUCCESS);
271 }
272
273 static NTSTATUS
IntVideoPortInbvInitialize(VOID)274 IntVideoPortInbvInitialize(VOID)
275 {
276 /* Create the INBV monitoring thread if needed */
277 if (!InbvThreadHandle)
278 {
279 NTSTATUS Status;
280 OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE);
281
282 Status = PsCreateSystemThread(&InbvThreadHandle,
283 0,
284 &ObjectAttributes,
285 NULL,
286 NULL,
287 InbvMonitorThread,
288 NULL);
289 if (!NT_SUCCESS(Status))
290 InbvThreadHandle = NULL;
291 }
292
293 /* Re-register the display reset callback with INBV */
294 InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters);
295
296 return STATUS_SUCCESS;
297 }
298
299 static NTSTATUS
IntVideoPortInbvCleanup(IN PDEVICE_OBJECT DeviceObject)300 IntVideoPortInbvCleanup(
301 IN PDEVICE_OBJECT DeviceObject)
302 {
303 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
304 // HANDLE ThreadHandle;
305
306 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
307 if ((DeviceExtension->DeviceOpened >= 1) &&
308 (InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0))
309 {
310 // RemoveEntryList(&DeviceExtension->HwResetListEntry);
311 InbvNotifyDisplayOwnershipLost(NULL);
312 IntVideoPortResetDisplayParametersEx(80, 50, FALSE);
313 // or InbvAcquireDisplayOwnership(); ?
314 }
315
316 #if 0
317 // TODO: Find the best way to communicate the request.
318 /* Signal the INBV monitoring thread and wait for it to terminate */
319 ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL);
320 if (ThreadHandle)
321 {
322 KeWaitForSingleObject(&ThreadHandle, Executive, KernelMode, FALSE, NULL);
323 /* Close its handle */
324 ObCloseHandle(ThreadHandle, KernelMode);
325 }
326 #endif
327
328 return STATUS_SUCCESS;
329 }
330
331
332 NTSTATUS
333 NTAPI
IntVideoPortAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)334 IntVideoPortAddDevice(
335 IN PDRIVER_OBJECT DriverObject,
336 IN PDEVICE_OBJECT PhysicalDeviceObject)
337 {
338 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
339 PDEVICE_OBJECT DeviceObject;
340 NTSTATUS Status;
341
342 /* Get the initialization data we saved in VideoPortInitialize. */
343 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
344
345 /* Create adapter device object. */
346 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject,
347 DriverExtension,
348 PhysicalDeviceObject,
349 DriverExtension->InitializationData.StartingDeviceNumber,
350 0,
351 &DeviceObject);
352 if (!NT_SUCCESS(Status))
353 {
354 ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject() failed with status 0x%lx\n", Status);
355 }
356 return Status;
357 }
358
359 /*
360 * IntVideoPortDispatchOpen
361 *
362 * Answer requests for Open calls.
363 *
364 * Run Level
365 * PASSIVE_LEVEL
366 */
367 NTSTATUS
368 NTAPI
IntVideoPortDispatchOpen(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)369 IntVideoPortDispatchOpen(
370 IN PDEVICE_OBJECT DeviceObject,
371 IN PIRP Irp)
372 {
373 NTSTATUS Status;
374 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
375 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
376
377 TRACE_(VIDEOPRT, "IntVideoPortDispatchOpen\n");
378
379 if (!CsrProcess)
380 {
381 /*
382 * We know the first open call will be from the CSRSS process
383 * to let us know its handle.
384 */
385 INFO_(VIDEOPRT, "Referencing CSRSS\n");
386 CsrProcess = (PKPROCESS)PsGetCurrentProcess();
387 ObReferenceObject(CsrProcess);
388 INFO_(VIDEOPRT, "CsrProcess 0x%p\n", CsrProcess);
389
390 Status = IntInitializeVideoAddressSpace();
391 if (!NT_SUCCESS(Status))
392 {
393 ERR_(VIDEOPRT, "IntInitializeVideoAddressSpace() failed: 0x%lx\n", Status);
394 ObDereferenceObject(CsrProcess);
395 CsrProcess = NULL;
396 return Status;
397 }
398 }
399
400 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
401 DriverExtension = DeviceExtension->DriverExtension;
402
403 // FIXME: (Re-)initialize INBV only if DeviceObject doesn't belong to a mirror driver.
404 IntVideoPortInbvInitialize();
405
406 if (DriverExtension->InitializationData.HwInitialize(&DeviceExtension->MiniPortDeviceExtension))
407 {
408 Status = STATUS_SUCCESS;
409 InterlockedIncrement((PLONG)&DeviceExtension->DeviceOpened);
410
411 /* Query children, now that device is opened */
412 VideoPortEnumerateChildren(DeviceExtension->MiniPortDeviceExtension, NULL);
413 }
414 else
415 {
416 Status = STATUS_UNSUCCESSFUL;
417 }
418
419 Irp->IoStatus.Status = Status;
420 Irp->IoStatus.Information = FILE_OPENED;
421 IoCompleteRequest(Irp, IO_NO_INCREMENT);
422
423 return Status;
424 }
425
426 /*
427 * IntVideoPortDispatchClose
428 *
429 * Answer requests for Close calls.
430 *
431 * Run Level
432 * PASSIVE_LEVEL
433 */
434 NTSTATUS
435 NTAPI
IntVideoPortDispatchClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)436 IntVideoPortDispatchClose(
437 IN PDEVICE_OBJECT DeviceObject,
438 IN PIRP Irp)
439 {
440 TRACE_(VIDEOPRT, "IntVideoPortDispatchClose\n");
441
442 IntVideoPortInbvCleanup(DeviceObject);
443
444 Irp->IoStatus.Status = STATUS_SUCCESS;
445 IoCompleteRequest(Irp, IO_NO_INCREMENT);
446 return STATUS_SUCCESS;
447 }
448
449 PSTR
IoctlName(ULONG Ioctl)450 IoctlName(ULONG Ioctl)
451 {
452 switch (Ioctl)
453 {
454 case IOCTL_VIDEO_ENABLE_VDM:
455 return "IOCTL_VIDEO_ENABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS)
456 case IOCTL_VIDEO_DISABLE_VDM:
457 return "IOCTL_VIDEO_DISABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x01, METHOD_BUFFERED, FILE_ANY_ACCESS)
458 case IOCTL_VIDEO_REGISTER_VDM:
459 return "IOCTL_VIDEO_REGISTER_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS)
460 case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE:
461 return "IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x03, METHOD_BUFFERED, FILE_ANY_ACCESS)
462 case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE:
463 return "IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x04, METHOD_BUFFERED, FILE_ANY_ACCESS)
464 case IOCTL_VIDEO_MONITOR_DEVICE:
465 return "IOCTL_VIDEO_MONITOR_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x05, METHOD_BUFFERED, FILE_ANY_ACCESS)
466 case IOCTL_VIDEO_ENUM_MONITOR_PDO:
467 return "IOCTL_VIDEO_ENUM_MONITOR_PDO"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x06, METHOD_BUFFERED, FILE_ANY_ACCESS)
468 case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS:
469 return "IOCTL_VIDEO_INIT_WIN32K_CALLBACKS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x07, METHOD_BUFFERED, FILE_ANY_ACCESS)
470 case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS:
471 return "IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x08, METHOD_BUFFERED, FILE_ANY_ACCESS)
472 case IOCTL_VIDEO_IS_VGA_DEVICE:
473 return "IOCTL_VIDEO_IS_VGA_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x09, METHOD_BUFFERED, FILE_ANY_ACCESS)
474 case IOCTL_VIDEO_USE_DEVICE_IN_SESSION:
475 return "IOCTL_VIDEO_USE_DEVICE_IN_SESSION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0a, METHOD_BUFFERED, FILE_ANY_ACCESS)
476 case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY:
477 return "IOCTL_VIDEO_PREPARE_FOR_EARECOVERY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0b, METHOD_BUFFERED, FILE_ANY_ACCESS)
478 case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
479 return "IOCTL_VIDEO_SAVE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x80, METHOD_BUFFERED, FILE_ANY_ACCESS)
480 case IOCTL_VIDEO_RESTORE_HARDWARE_STATE:
481 return "IOCTL_VIDEO_RESTORE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x81, METHOD_BUFFERED, FILE_ANY_ACCESS)
482 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
483 return "IOCTL_VIDEO_QUERY_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x100, METHOD_BUFFERED, FILE_ANY_ACCESS)
484 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
485 return "IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x101, METHOD_BUFFERED, FILE_ANY_ACCESS)
486 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
487 return "IOCTL_VIDEO_QUERY_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x102, METHOD_BUFFERED, FILE_ANY_ACCESS)
488 case IOCTL_VIDEO_SET_CURRENT_MODE:
489 return "IOCTL_VIDEO_SET_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x103, METHOD_BUFFERED, FILE_ANY_ACCESS)
490 case IOCTL_VIDEO_RESET_DEVICE:
491 return "IOCTL_VIDEO_RESET_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x104, METHOD_BUFFERED, FILE_ANY_ACCESS)
492 case IOCTL_VIDEO_LOAD_AND_SET_FONT:
493 return "IOCTL_VIDEO_LOAD_AND_SET_FONT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x105, METHOD_BUFFERED, FILE_ANY_ACCESS)
494 case IOCTL_VIDEO_SET_PALETTE_REGISTERS:
495 return "IOCTL_VIDEO_SET_PALETTE_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x106, METHOD_BUFFERED, FILE_ANY_ACCESS)
496 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
497 return "IOCTL_VIDEO_SET_COLOR_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x107, METHOD_BUFFERED, FILE_ANY_ACCESS)
498 case IOCTL_VIDEO_ENABLE_CURSOR:
499 return "IOCTL_VIDEO_ENABLE_CURSOR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x108, METHOD_BUFFERED, FILE_ANY_ACCESS)
500 case IOCTL_VIDEO_DISABLE_CURSOR:
501 return "IOCTL_VIDEO_DISABLE_CURSOR"; // CTL_CODE (FILE_DEVICE_VIDEO, 0x109, METHOD_BUFFERED, FILE_ANY_ACCESS)
502 case IOCTL_VIDEO_SET_CURSOR_ATTR:
503 return "IOCTL_VIDEO_SET_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10a, METHOD_BUFFERED, FILE_ANY_ACCESS)
504 case IOCTL_VIDEO_QUERY_CURSOR_ATTR:
505 return "IOCTL_VIDEO_QUERY_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10b, METHOD_BUFFERED, FILE_ANY_ACCESS)
506 case IOCTL_VIDEO_SET_CURSOR_POSITION:
507 return "IOCTL_VIDEO_SET_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10c, METHOD_BUFFERED, FILE_ANY_ACCESS)
508 case IOCTL_VIDEO_QUERY_CURSOR_POSITION:
509 return "IOCTL_VIDEO_QUERY_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10d, METHOD_BUFFERED, FILE_ANY_ACCESS)
510 case IOCTL_VIDEO_ENABLE_POINTER:
511 return "IOCTL_VIDEO_ENABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10e, METHOD_BUFFERED, FILE_ANY_ACCESS)
512 case IOCTL_VIDEO_DISABLE_POINTER:
513 return "IOCTL_VIDEO_DISABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10f, METHOD_BUFFERED, FILE_ANY_ACCESS)
514 case IOCTL_VIDEO_SET_POINTER_ATTR:
515 return "IOCTL_VIDEO_SET_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x110, METHOD_BUFFERED, FILE_ANY_ACCESS)
516 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
517 return "IOCTL_VIDEO_QUERY_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x111, METHOD_BUFFERED, FILE_ANY_ACCESS)
518 case IOCTL_VIDEO_SET_POINTER_POSITION:
519 return "IOCTL_VIDEO_SET_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x112, METHOD_BUFFERED, FILE_ANY_ACCESS)
520 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
521 return "IOCTL_VIDEO_QUERY_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x113, METHOD_BUFFERED, FILE_ANY_ACCESS)
522 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
523 return "IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x114, METHOD_BUFFERED, FILE_ANY_ACCESS)
524 case IOCTL_VIDEO_GET_BANK_SELECT_CODE:
525 return "IOCTL_VIDEO_GET_BANK_SELECT_CODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x115, METHOD_BUFFERED, FILE_ANY_ACCESS)
526 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
527 return "IOCTL_VIDEO_MAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x116, METHOD_BUFFERED, FILE_ANY_ACCESS)
528 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
529 return "IOCTL_VIDEO_UNMAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x117, METHOD_BUFFERED, FILE_ANY_ACCESS)
530 case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
531 return "IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x118, METHOD_BUFFERED, FILE_ANY_ACCESS)
532 case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
533 return "IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x119, METHOD_BUFFERED, FILE_ANY_ACCESS)
534 case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES:
535 return "IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11a, METHOD_BUFFERED, FILE_ANY_ACCESS)
536 case IOCTL_VIDEO_SET_POWER_MANAGEMENT:
537 return "IOCTL_VIDEO_SET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11b, METHOD_BUFFERED, FILE_ANY_ACCESS)
538 case IOCTL_VIDEO_GET_POWER_MANAGEMENT:
539 return "IOCTL_VIDEO_GET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11c, METHOD_BUFFERED, FILE_ANY_ACCESS)
540 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
541 return "IOCTL_VIDEO_SHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11d, METHOD_BUFFERED, FILE_ANY_ACCESS)
542 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
543 return "IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11e, METHOD_BUFFERED, FILE_ANY_ACCESS)
544 case IOCTL_VIDEO_SET_COLOR_LUT_DATA:
545 return "IOCTL_VIDEO_SET_COLOR_LUT_DATA"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11f, METHOD_BUFFERED, FILE_ANY_ACCESS)
546 case IOCTL_VIDEO_GET_CHILD_STATE:
547 return "IOCTL_VIDEO_GET_CHILD_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x120, METHOD_BUFFERED, FILE_ANY_ACCESS)
548 case IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION:
549 return "IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x121, METHOD_BUFFERED, FILE_ANY_ACCESS)
550 case IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION:
551 return "IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x122, METHOD_BUFFERED, FILE_ANY_ACCESS)
552 case IOCTL_VIDEO_SWITCH_DUALVIEW:
553 return "IOCTL_VIDEO_SWITCH_DUALVIEW"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x123, METHOD_BUFFERED, FILE_ANY_ACCESS)
554 case IOCTL_VIDEO_SET_BANK_POSITION:
555 return "IOCTL_VIDEO_SET_BANK_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x124, METHOD_BUFFERED, FILE_ANY_ACCESS)
556 case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS:
557 return "IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x125, METHOD_BUFFERED, FILE_ANY_ACCESS)
558 case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS:
559 return "IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x126, METHOD_BUFFERED, FILE_ANY_ACCESS)
560 case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS:
561 return "IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x127, METHOD_BUFFERED, FILE_ANY_ACCESS)
562 }
563
564 return "<unknown ioctl code>";
565 }
566
567 static
568 NTSTATUS
VideoPortUseDeviceInSession(_Inout_ PDEVICE_OBJECT DeviceObject,_Inout_ PVIDEO_DEVICE_SESSION_STATUS SessionState,_In_ ULONG BufferLength,_Out_ PULONG_PTR Information)569 VideoPortUseDeviceInSession(
570 _Inout_ PDEVICE_OBJECT DeviceObject,
571 _Inout_ PVIDEO_DEVICE_SESSION_STATUS SessionState,
572 _In_ ULONG BufferLength,
573 _Out_ PULONG_PTR Information)
574 {
575 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
576
577 /* Check buffer size */
578 *Information = sizeof(VIDEO_DEVICE_SESSION_STATUS);
579 if (BufferLength < sizeof(VIDEO_DEVICE_SESSION_STATUS))
580 {
581 ERR_(VIDEOPRT, "Buffer too small for VIDEO_DEVICE_SESSION_STATUS: %lx\n",
582 BufferLength);
583 return STATUS_BUFFER_TOO_SMALL;
584 }
585
586 /* Get the device extension */
587 DeviceExtension = DeviceObject->DeviceExtension;
588
589 /* Shall we enable the session? */
590 if (SessionState->bEnable)
591 {
592 /* Check if we have no session yet */
593 if (DeviceExtension->SessionId == -1)
594 {
595 /* Use this session and return success */
596 DeviceExtension->SessionId = PsGetCurrentProcessSessionId();
597 SessionState->bSuccess = TRUE;
598 }
599 else
600 {
601 ERR_(VIDEOPRT, "Requested to set session, but session is already set to: 0x%lx\n",
602 DeviceExtension->SessionId);
603 SessionState->bSuccess = FALSE;
604 }
605 }
606 else
607 {
608 /* Check if we belong to the current session */
609 if (DeviceExtension->SessionId == PsGetCurrentProcessSessionId())
610 {
611 /* Reset the session and return success */
612 DeviceExtension->SessionId = -1;
613 SessionState->bSuccess = TRUE;
614 }
615 else
616 {
617 ERR_(VIDEOPRT, "Requested to reset session, but session is not set\n");
618 SessionState->bSuccess = FALSE;
619 }
620 }
621
622 return STATUS_SUCCESS;
623 }
624
625 static
626 NTSTATUS
VideoPortInitWin32kCallbacks(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PVIDEO_WIN32K_CALLBACKS Win32kCallbacks,_In_ ULONG BufferLength,_Out_ PULONG_PTR Information)627 VideoPortInitWin32kCallbacks(
628 _In_ PDEVICE_OBJECT DeviceObject,
629 _Inout_ PVIDEO_WIN32K_CALLBACKS Win32kCallbacks,
630 _In_ ULONG BufferLength,
631 _Out_ PULONG_PTR Information)
632 {
633 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
634
635 *Information = sizeof(VIDEO_WIN32K_CALLBACKS);
636 if (BufferLength < sizeof(VIDEO_WIN32K_CALLBACKS))
637 {
638 ERR_(VIDEOPRT, "Buffer too small for VIDEO_WIN32K_CALLBACKS: %lx\n",
639 BufferLength);
640 return STATUS_BUFFER_TOO_SMALL;
641 }
642
643 /* Save the callout function globally */
644 Win32kCallout = Win32kCallbacks->Callout;
645
646 /* Return reasonable values to Win32k */
647 Win32kCallbacks->bACPI = FALSE;
648 Win32kCallbacks->pPhysDeviceObject = DeviceExtension->PhysicalDeviceObject;
649 Win32kCallbacks->DualviewFlags = 0;
650
651 return STATUS_SUCCESS;
652 }
653
654 static
655 NTSTATUS
VideoPortForwardDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)656 VideoPortForwardDeviceControl(
657 IN PDEVICE_OBJECT DeviceObject,
658 IN PIRP Irp)
659 {
660 PIO_STACK_LOCATION IrpStack;
661 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
662 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
663 VIDEO_REQUEST_PACKET vrp;
664
665 TRACE_(VIDEOPRT, "VideoPortForwardDeviceControl\n");
666
667 IrpStack = IoGetCurrentIrpStackLocation(Irp);
668 DeviceExtension = DeviceObject->DeviceExtension;
669 DriverExtension = DeviceExtension->DriverExtension;
670
671 /* Translate the IRP to a VRP */
672 vrp.StatusBlock = (PSTATUS_BLOCK)&Irp->IoStatus;
673 vrp.IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
674
675 INFO_(VIDEOPRT, "- IoControlCode: %x\n", vrp.IoControlCode);
676
677 /* We're assuming METHOD_BUFFERED */
678 vrp.InputBuffer = Irp->AssociatedIrp.SystemBuffer;
679 vrp.InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
680 vrp.OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
681 vrp.OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
682
683 /* Call the Miniport Driver with the VRP */
684 DriverExtension->InitializationData.HwStartIO(&DeviceExtension->MiniPortDeviceExtension,
685 &vrp);
686
687 INFO_(VIDEOPRT, "- Returned status: %x\n", Irp->IoStatus.Status);
688
689 /* Map from win32 error codes to NT status values. */
690 switch (Irp->IoStatus.Status)
691 {
692 case NO_ERROR:
693 return STATUS_SUCCESS;
694 case ERROR_NOT_ENOUGH_MEMORY:
695 return STATUS_INSUFFICIENT_RESOURCES;
696 case ERROR_MORE_DATA:
697 return STATUS_BUFFER_OVERFLOW;
698 case ERROR_INVALID_FUNCTION:
699 return STATUS_NOT_IMPLEMENTED;
700 case ERROR_INVALID_PARAMETER:
701 return STATUS_INVALID_PARAMETER;
702 case ERROR_INSUFFICIENT_BUFFER:
703 return STATUS_BUFFER_TOO_SMALL;
704 case ERROR_DEV_NOT_EXIST:
705 return STATUS_DEVICE_DOES_NOT_EXIST;
706 case ERROR_IO_PENDING:
707 return STATUS_PENDING;
708 default:
709 return STATUS_UNSUCCESSFUL;
710 }
711 }
712
713 /*
714 * IntVideoPortDispatchDeviceControl
715 *
716 * Answer requests for device control calls.
717 *
718 * Run Level
719 * PASSIVE_LEVEL
720 */
721 NTSTATUS
722 NTAPI
IntVideoPortDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)723 IntVideoPortDispatchDeviceControl(
724 IN PDEVICE_OBJECT DeviceObject,
725 IN PIRP Irp)
726 {
727 PIO_STACK_LOCATION IrpStack;
728 NTSTATUS Status;
729 ULONG IoControlCode;
730
731 TRACE_(VIDEOPRT, "IntVideoPortDispatchDeviceControl\n");
732
733 IrpStack = IoGetCurrentIrpStackLocation(Irp);
734
735 switch (IrpStack->MajorFunction)
736 {
737 case IRP_MJ_DEVICE_CONTROL:
738 /* This is the main part of this function and is handled below */
739 break;
740
741 case IRP_MJ_SHUTDOWN:
742 {
743 /* Dereference CSRSS */
744 PKPROCESS OldCsrProcess;
745 OldCsrProcess = InterlockedExchangePointer((PVOID*)&CsrProcess, NULL);
746 if (OldCsrProcess)
747 ObDereferenceObject(OldCsrProcess);
748
749 Irp->IoStatus.Status = STATUS_SUCCESS;
750 IoCompleteRequest(Irp, IO_NO_INCREMENT);
751 return STATUS_SUCCESS;
752 }
753
754 default:
755 ERR_(VIDEOPRT, "- Unknown MajorFunction 0x%x\n", IrpStack->MajorFunction);
756 Irp->IoStatus.Status = STATUS_SUCCESS;
757 IoCompleteRequest(Irp, IO_NO_INCREMENT);
758 return STATUS_SUCCESS;
759 }
760
761 IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
762
763 INFO_(VIDEOPRT, "- IoControlCode: 0x%x: %s\n", IoControlCode, IoctlName(IoControlCode));
764
765 switch (IoControlCode)
766 {
767 case IOCTL_VIDEO_ENABLE_VDM:
768 case IOCTL_VIDEO_DISABLE_VDM:
769 case IOCTL_VIDEO_REGISTER_VDM:
770 WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_VDM are UNIMPLEMENTED!\n");
771 Status = STATUS_NOT_IMPLEMENTED;
772 break;
773
774 case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE:
775 case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE:
776 WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_OUTPUT_DEVICE_POWER_STATE are UNIMPLEMENTED!\n");
777 Status = STATUS_NOT_IMPLEMENTED;
778 break;
779
780 case IOCTL_VIDEO_SET_POWER_MANAGEMENT:
781 case IOCTL_VIDEO_GET_POWER_MANAGEMENT:
782 WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_POWER_MANAGEMENT are UNIMPLEMENTED!\n");
783 Status = STATUS_NOT_IMPLEMENTED;
784 break;
785
786 case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS:
787 case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS:
788 case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS:
789 WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_BRIGHTNESS are UNIMPLEMENTED!\n");
790 Status = STATUS_NOT_IMPLEMENTED;
791 break;
792
793 case IOCTL_VIDEO_ENUM_MONITOR_PDO:
794 WARN_(VIDEOPRT, "- IOCTL_VIDEO_ENUM_MONITOR_PDO is UNIMPLEMENTED!\n");
795 Status = STATUS_NOT_IMPLEMENTED;
796 break;
797
798 case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS:
799 INFO_(VIDEOPRT, "- IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n");
800 Status = VideoPortInitWin32kCallbacks(DeviceObject,
801 Irp->AssociatedIrp.SystemBuffer,
802 IrpStack->Parameters.DeviceIoControl.InputBufferLength,
803 &Irp->IoStatus.Information);
804 break;
805
806 case IOCTL_VIDEO_IS_VGA_DEVICE:
807 WARN_(VIDEOPRT, "- IOCTL_VIDEO_IS_VGA_DEVICE is UNIMPLEMENTED!\n");
808 Status = STATUS_NOT_IMPLEMENTED;
809 break;
810
811 case IOCTL_VIDEO_USE_DEVICE_IN_SESSION:
812 INFO_(VIDEOPRT, "- IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n");
813 Status = VideoPortUseDeviceInSession(DeviceObject,
814 Irp->AssociatedIrp.SystemBuffer,
815 IrpStack->Parameters.DeviceIoControl.InputBufferLength,
816 &Irp->IoStatus.Information);
817 break;
818
819 case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY:
820 INFO_(VIDEOPRT, "- IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n");
821 /*
822 * The Win32k Watchdog Timer detected that a thread spent more time
823 * in a display driver than the allotted time its threshold specified,
824 * and thus is going to attempt to recover by switching to VGA mode.
825 * If this attempt fails, the watchdog generates bugcheck 0xEA
826 * "THREAD_STUCK_IN_DEVICE_DRIVER".
827 *
828 * Prepare the recovery by resetting the display adapters to
829 * standard VGA 80x25 text mode.
830 */
831 IntVideoPortResetDisplayParametersEx(80, 25, FALSE);
832 Status = STATUS_SUCCESS;
833 break;
834
835 default:
836 /* Forward to the Miniport Driver */
837 Status = VideoPortForwardDeviceControl(DeviceObject, Irp);
838 break;
839 }
840
841 INFO_(VIDEOPRT, "- Returned status: 0x%x\n", Status);
842
843 Irp->IoStatus.Status = Status;
844 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
845 return Status;
846 }
847
848 NTSTATUS
849 NTAPI
IntVideoPortPnPStartDevice(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)850 IntVideoPortPnPStartDevice(
851 IN PDEVICE_OBJECT DeviceObject,
852 IN PIRP Irp)
853 {
854 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
855 PDRIVER_OBJECT DriverObject;
856 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
857 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
858 PCM_RESOURCE_LIST AllocatedResources;
859
860 /* Get the initialization data we saved in VideoPortInitialize.*/
861 DriverObject = DeviceObject->DriverObject;
862 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
863 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
864
865 /* Store some resources in the DeviceExtension. */
866 AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
867 if (AllocatedResources != NULL)
868 {
869 CM_FULL_RESOURCE_DESCRIPTOR *FullList;
870 CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
871 ULONG ResourceCount;
872 ULONG ResourceListSize;
873
874 /* Save the resource list */
875 ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
876 ResourceListSize =
877 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
878 PartialDescriptors[ResourceCount]);
879 DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
880 if (DeviceExtension->AllocatedResources == NULL)
881 {
882 return STATUS_INSUFFICIENT_RESOURCES;
883 }
884
885 RtlCopyMemory(DeviceExtension->AllocatedResources,
886 AllocatedResources,
887 ResourceListSize);
888
889 /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */
890 FullList = AllocatedResources->List;
891 ASSERT(AllocatedResources->Count == 1);
892 INFO_(VIDEOPRT, "InterfaceType %u BusNumber List %u Device BusNumber %u Version %u Revision %u\n",
893 FullList->InterfaceType, FullList->BusNumber, DeviceExtension->SystemIoBusNumber, FullList->PartialResourceList.Version, FullList->PartialResourceList.Revision);
894
895 /* FIXME: Is this ASSERT ok for resources from the PNP manager? */
896 ASSERT(FullList->InterfaceType == PCIBus);
897 ASSERT(FullList->BusNumber == DeviceExtension->SystemIoBusNumber);
898 ASSERT(1 == FullList->PartialResourceList.Version);
899 ASSERT(1 == FullList->PartialResourceList.Revision);
900 for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
901 Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
902 Descriptor++)
903 {
904 if (Descriptor->Type == CmResourceTypeInterrupt)
905 {
906 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
907 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
908 if (Descriptor->ShareDisposition == CmResourceShareShared)
909 DeviceExtension->InterruptShared = TRUE;
910 else
911 DeviceExtension->InterruptShared = FALSE;
912 }
913 }
914 }
915
916 INFO_(VIDEOPRT, "Interrupt level: 0x%x Interrupt Vector: 0x%x\n",
917 DeviceExtension->InterruptLevel,
918 DeviceExtension->InterruptVector);
919
920 /* Create adapter device object. */
921 return IntVideoPortFindAdapter(DriverObject,
922 DriverExtension,
923 DeviceObject);
924 }
925
926
927 NTSTATUS
928 NTAPI
IntVideoPortForwardIrpAndWaitCompletionRoutine(PDEVICE_OBJECT Fdo,PIRP Irp,PVOID Context)929 IntVideoPortForwardIrpAndWaitCompletionRoutine(
930 PDEVICE_OBJECT Fdo,
931 PIRP Irp,
932 PVOID Context)
933 {
934 PKEVENT Event = Context;
935
936 if (Irp->PendingReturned)
937 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
938
939 return STATUS_MORE_PROCESSING_REQUIRED;
940 }
941
942 NTSTATUS
943 NTAPI
IntVideoPortQueryBusRelations(PDEVICE_OBJECT DeviceObject,PIRP Irp)944 IntVideoPortQueryBusRelations(PDEVICE_OBJECT DeviceObject, PIRP Irp)
945 {
946 PDEVICE_RELATIONS DeviceRelations;
947 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
948 PVIDEO_PORT_CHILD_EXTENSION ChildExtension;
949 ULONG i;
950 PLIST_ENTRY CurrentEntry;
951 NTSTATUS Status;
952
953 if (InterlockedCompareExchange((PLONG)&DeviceExtension->DeviceOpened, 0, 0) == 0)
954 {
955 /* Device not opened. Don't enumerate children yet */
956 WARN_(VIDEOPRT, "Skipping child enumeration because device is not opened");
957 return STATUS_INSUFFICIENT_RESOURCES;
958 }
959 /* Query children of the device. */
960 Status = IntVideoPortEnumerateChildren(DeviceObject, Irp);
961 if (!NT_SUCCESS(Status))
962 return Status;
963
964 /* Count the children */
965 i = 0;
966 CurrentEntry = DeviceExtension->ChildDeviceList.Flink;
967 while (CurrentEntry != &DeviceExtension->ChildDeviceList)
968 {
969 i++;
970 CurrentEntry = CurrentEntry->Flink;
971 }
972
973 if (i == 0)
974 return Irp->IoStatus.Status;
975
976 DeviceRelations = ExAllocatePool(PagedPool,
977 sizeof(DEVICE_RELATIONS) + ((i - 1) * sizeof(PVOID)));
978 if (!DeviceRelations) return STATUS_NO_MEMORY;
979
980 DeviceRelations->Count = i;
981
982 /* Add the children */
983 i = 0;
984 CurrentEntry = DeviceExtension->ChildDeviceList.Flink;
985 while (CurrentEntry != &DeviceExtension->ChildDeviceList)
986 {
987 ChildExtension = CONTAINING_RECORD(CurrentEntry, VIDEO_PORT_CHILD_EXTENSION, ListEntry);
988
989 ObReferenceObject(ChildExtension->PhysicalDeviceObject);
990 DeviceRelations->Objects[i] = ChildExtension->PhysicalDeviceObject;
991
992 i++;
993 CurrentEntry = CurrentEntry->Flink;
994 }
995
996 INFO_(VIDEOPRT, "Reported %d PDOs\n", i);
997 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
998
999 return STATUS_SUCCESS;
1000 }
1001
1002 NTSTATUS
1003 NTAPI
IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject,PIRP Irp)1004 IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject, PIRP Irp)
1005 {
1006 KEVENT Event;
1007 NTSTATUS Status;
1008 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension =
1009 (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1010
1011 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1012 IoCopyCurrentIrpStackLocationToNext(Irp);
1013 IoSetCompletionRoutine(Irp,
1014 IntVideoPortForwardIrpAndWaitCompletionRoutine,
1015 &Event,
1016 TRUE,
1017 TRUE,
1018 TRUE);
1019
1020 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1021 if (Status == STATUS_PENDING)
1022 {
1023 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1024 Status = Irp->IoStatus.Status;
1025 }
1026
1027 return Status;
1028 }
1029
1030 NTSTATUS
1031 NTAPI
IntVideoPortDispatchFdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1032 IntVideoPortDispatchFdoPnp(
1033 IN PDEVICE_OBJECT DeviceObject,
1034 IN PIRP Irp)
1035 {
1036 PIO_STACK_LOCATION IrpSp;
1037 NTSTATUS Status;
1038 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1039
1040 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1041
1042 switch (IrpSp->MinorFunction)
1043 {
1044 case IRP_MN_START_DEVICE:
1045 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1046 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1047 Status = IntVideoPortPnPStartDevice(DeviceObject, Irp);
1048 Irp->IoStatus.Status = Status;
1049 Irp->IoStatus.Information = 0;
1050 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1051 break;
1052
1053 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1054 /* Call lower drivers, and ignore result (that's probably STATUS_NOT_SUPPORTED) */
1055 (VOID)IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1056 /* Now, fill resource requirements list */
1057 Status = IntVideoPortFilterResourceRequirements(DeviceObject, IrpSp, Irp);
1058 Irp->IoStatus.Status = Status;
1059 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1060 break;
1061
1062 case IRP_MN_QUERY_DEVICE_RELATIONS:
1063 if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
1064 {
1065 IoSkipCurrentIrpStackLocation(Irp);
1066 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1067 }
1068 else
1069 {
1070 Status = IntVideoPortQueryBusRelations(DeviceObject, Irp);
1071 Irp->IoStatus.Status = Status;
1072 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1073 }
1074 break;
1075
1076 case IRP_MN_REMOVE_DEVICE:
1077 case IRP_MN_QUERY_REMOVE_DEVICE:
1078 case IRP_MN_CANCEL_REMOVE_DEVICE:
1079 case IRP_MN_SURPRISE_REMOVAL:
1080
1081 case IRP_MN_STOP_DEVICE:
1082 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1083 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1084 Status = STATUS_SUCCESS;
1085 Irp->IoStatus.Status = Status;
1086 Irp->IoStatus.Information = 0;
1087 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1088 break;
1089
1090 case IRP_MN_QUERY_STOP_DEVICE:
1091 case IRP_MN_CANCEL_STOP_DEVICE:
1092 Status = STATUS_SUCCESS;
1093 Irp->IoStatus.Status = STATUS_SUCCESS;
1094 Irp->IoStatus.Information = 0;
1095 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1096 break;
1097
1098 default:
1099 Status = Irp->IoStatus.Status;
1100 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1101 break;
1102 }
1103
1104 return Status;
1105 }
1106
1107 NTSTATUS
1108 NTAPI
IntVideoPortDispatchPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1109 IntVideoPortDispatchPnp(
1110 IN PDEVICE_OBJECT DeviceObject,
1111 IN PIRP Irp)
1112 {
1113 PVIDEO_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension;
1114
1115 if (CommonExtension->Fdo)
1116 return IntVideoPortDispatchFdoPnp(DeviceObject, Irp);
1117 else
1118 return IntVideoPortDispatchPdoPnp(DeviceObject, Irp);
1119 }
1120
1121 NTSTATUS
1122 NTAPI
IntVideoPortDispatchCleanup(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1123 IntVideoPortDispatchCleanup(
1124 IN PDEVICE_OBJECT DeviceObject,
1125 IN PIRP Irp)
1126 {
1127 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1128
1129 DeviceExtension = DeviceObject->DeviceExtension;
1130 RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
1131
1132 Irp->IoStatus.Status = STATUS_SUCCESS;
1133 Irp->IoStatus.Information = 0;
1134 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1135
1136 return STATUS_SUCCESS;
1137 }
1138
1139 NTSTATUS
1140 NTAPI
IntVideoPortDispatchPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1141 IntVideoPortDispatchPower(
1142 IN PDEVICE_OBJECT DeviceObject,
1143 IN PIRP Irp)
1144 {
1145 PIO_STACK_LOCATION IrpSp;
1146 NTSTATUS Status = Irp->IoStatus.Status;
1147 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1148
1149 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1150
1151 if (DeviceExtension->Common.Fdo)
1152 {
1153 PoStartNextPowerIrp(Irp);
1154 IoSkipCurrentIrpStackLocation(Irp);
1155 return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1156 }
1157 else
1158 {
1159 switch (IrpSp->MinorFunction)
1160 {
1161 case IRP_MN_QUERY_POWER:
1162 case IRP_MN_SET_POWER:
1163 Status = STATUS_SUCCESS;
1164 break;
1165 }
1166 PoStartNextPowerIrp(Irp);
1167 Irp->IoStatus.Status = Status;
1168 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1169 return Status;
1170 }
1171 }
1172
1173 NTSTATUS
1174 NTAPI
IntVideoPortDispatchSystemControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1175 IntVideoPortDispatchSystemControl(
1176 IN PDEVICE_OBJECT DeviceObject,
1177 IN PIRP Irp)
1178 {
1179 NTSTATUS Status;
1180 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1181
1182 if (DeviceExtension->Common.Fdo)
1183 {
1184 IoSkipCurrentIrpStackLocation(Irp);
1185 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1186 }
1187 else
1188 {
1189 Status = Irp->IoStatus.Status;
1190 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1191 return Status;
1192 }
1193 }
1194
1195 VOID
1196 NTAPI
IntVideoPortUnload(PDRIVER_OBJECT DriverObject)1197 IntVideoPortUnload(PDRIVER_OBJECT DriverObject)
1198 {
1199 }
1200