xref: /reactos/win32ss/drivers/videoprt/dispatch.c (revision 84344399)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1197 IntVideoPortUnload(PDRIVER_OBJECT DriverObject)
1198 {
1199 }
1200