xref: /reactos/win32ss/drivers/videoprt/dispatch.c (revision ea6e7740)
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         Irp->IoStatus.Status = STATUS_SUCCESS;
409         InterlockedIncrement((PLONG)&DeviceExtension->DeviceOpened);
410     }
411     else
412     {
413         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
414     }
415 
416     Irp->IoStatus.Information = FILE_OPENED;
417     IoCompleteRequest(Irp, IO_NO_INCREMENT);
418 
419     return STATUS_SUCCESS;
420 }
421 
422 /*
423  * IntVideoPortDispatchClose
424  *
425  * Answer requests for Close calls.
426  *
427  * Run Level
428  *    PASSIVE_LEVEL
429  */
430 NTSTATUS
431 NTAPI
432 IntVideoPortDispatchClose(
433     IN PDEVICE_OBJECT DeviceObject,
434     IN PIRP Irp)
435 {
436     TRACE_(VIDEOPRT, "IntVideoPortDispatchClose\n");
437 
438     IntVideoPortInbvCleanup(DeviceObject);
439 
440     Irp->IoStatus.Status = STATUS_SUCCESS;
441     IoCompleteRequest(Irp, IO_NO_INCREMENT);
442     return STATUS_SUCCESS;
443 }
444 
445 PSTR
446 IoctlName(ULONG Ioctl)
447 {
448     switch (Ioctl)
449     {
450         case IOCTL_VIDEO_ENABLE_VDM:
451             return "IOCTL_VIDEO_ENABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS)
452         case IOCTL_VIDEO_DISABLE_VDM:
453             return "IOCTL_VIDEO_DISABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x01, METHOD_BUFFERED, FILE_ANY_ACCESS)
454         case IOCTL_VIDEO_REGISTER_VDM:
455             return "IOCTL_VIDEO_REGISTER_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS)
456         case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE:
457             return "IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x03, METHOD_BUFFERED, FILE_ANY_ACCESS)
458         case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE:
459             return "IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x04, METHOD_BUFFERED, FILE_ANY_ACCESS)
460         case IOCTL_VIDEO_MONITOR_DEVICE:
461             return "IOCTL_VIDEO_MONITOR_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x05, METHOD_BUFFERED, FILE_ANY_ACCESS)
462         case IOCTL_VIDEO_ENUM_MONITOR_PDO:
463             return "IOCTL_VIDEO_ENUM_MONITOR_PDO"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x06, METHOD_BUFFERED, FILE_ANY_ACCESS)
464         case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS:
465             return "IOCTL_VIDEO_INIT_WIN32K_CALLBACKS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x07, METHOD_BUFFERED, FILE_ANY_ACCESS)
466         case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS:
467             return "IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x08, METHOD_BUFFERED, FILE_ANY_ACCESS)
468         case IOCTL_VIDEO_IS_VGA_DEVICE:
469             return "IOCTL_VIDEO_IS_VGA_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x09, METHOD_BUFFERED, FILE_ANY_ACCESS)
470         case IOCTL_VIDEO_USE_DEVICE_IN_SESSION:
471             return "IOCTL_VIDEO_USE_DEVICE_IN_SESSION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0a, METHOD_BUFFERED, FILE_ANY_ACCESS)
472         case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY:
473             return "IOCTL_VIDEO_PREPARE_FOR_EARECOVERY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0b, METHOD_BUFFERED, FILE_ANY_ACCESS)
474         case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
475             return "IOCTL_VIDEO_SAVE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x80, METHOD_BUFFERED, FILE_ANY_ACCESS)
476         case IOCTL_VIDEO_RESTORE_HARDWARE_STATE:
477             return "IOCTL_VIDEO_RESTORE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x81, METHOD_BUFFERED, FILE_ANY_ACCESS)
478         case IOCTL_VIDEO_QUERY_AVAIL_MODES:
479             return "IOCTL_VIDEO_QUERY_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x100, METHOD_BUFFERED, FILE_ANY_ACCESS)
480         case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
481             return "IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x101, METHOD_BUFFERED, FILE_ANY_ACCESS)
482         case IOCTL_VIDEO_QUERY_CURRENT_MODE:
483             return "IOCTL_VIDEO_QUERY_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x102, METHOD_BUFFERED, FILE_ANY_ACCESS)
484         case IOCTL_VIDEO_SET_CURRENT_MODE:
485             return "IOCTL_VIDEO_SET_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x103, METHOD_BUFFERED, FILE_ANY_ACCESS)
486         case IOCTL_VIDEO_RESET_DEVICE:
487             return "IOCTL_VIDEO_RESET_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x104, METHOD_BUFFERED, FILE_ANY_ACCESS)
488         case IOCTL_VIDEO_LOAD_AND_SET_FONT:
489             return "IOCTL_VIDEO_LOAD_AND_SET_FONT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x105, METHOD_BUFFERED, FILE_ANY_ACCESS)
490         case IOCTL_VIDEO_SET_PALETTE_REGISTERS:
491             return "IOCTL_VIDEO_SET_PALETTE_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x106, METHOD_BUFFERED, FILE_ANY_ACCESS)
492         case IOCTL_VIDEO_SET_COLOR_REGISTERS:
493             return "IOCTL_VIDEO_SET_COLOR_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x107, METHOD_BUFFERED, FILE_ANY_ACCESS)
494         case IOCTL_VIDEO_ENABLE_CURSOR:
495             return "IOCTL_VIDEO_ENABLE_CURSOR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x108, METHOD_BUFFERED, FILE_ANY_ACCESS)
496         case IOCTL_VIDEO_DISABLE_CURSOR:
497             return "IOCTL_VIDEO_DISABLE_CURSOR"; // CTL_CODE (FILE_DEVICE_VIDEO, 0x109, METHOD_BUFFERED, FILE_ANY_ACCESS)
498         case IOCTL_VIDEO_SET_CURSOR_ATTR:
499             return "IOCTL_VIDEO_SET_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10a, METHOD_BUFFERED, FILE_ANY_ACCESS)
500         case IOCTL_VIDEO_QUERY_CURSOR_ATTR:
501             return "IOCTL_VIDEO_QUERY_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10b, METHOD_BUFFERED, FILE_ANY_ACCESS)
502         case IOCTL_VIDEO_SET_CURSOR_POSITION:
503             return "IOCTL_VIDEO_SET_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10c, METHOD_BUFFERED, FILE_ANY_ACCESS)
504         case IOCTL_VIDEO_QUERY_CURSOR_POSITION:
505             return "IOCTL_VIDEO_QUERY_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10d, METHOD_BUFFERED, FILE_ANY_ACCESS)
506         case IOCTL_VIDEO_ENABLE_POINTER:
507             return "IOCTL_VIDEO_ENABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10e, METHOD_BUFFERED, FILE_ANY_ACCESS)
508         case IOCTL_VIDEO_DISABLE_POINTER:
509             return "IOCTL_VIDEO_DISABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10f, METHOD_BUFFERED, FILE_ANY_ACCESS)
510         case IOCTL_VIDEO_SET_POINTER_ATTR:
511             return "IOCTL_VIDEO_SET_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x110, METHOD_BUFFERED, FILE_ANY_ACCESS)
512         case IOCTL_VIDEO_QUERY_POINTER_ATTR:
513             return "IOCTL_VIDEO_QUERY_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x111, METHOD_BUFFERED, FILE_ANY_ACCESS)
514         case IOCTL_VIDEO_SET_POINTER_POSITION:
515             return "IOCTL_VIDEO_SET_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x112, METHOD_BUFFERED, FILE_ANY_ACCESS)
516         case IOCTL_VIDEO_QUERY_POINTER_POSITION:
517             return "IOCTL_VIDEO_QUERY_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x113, METHOD_BUFFERED, FILE_ANY_ACCESS)
518         case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
519             return "IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x114, METHOD_BUFFERED, FILE_ANY_ACCESS)
520         case IOCTL_VIDEO_GET_BANK_SELECT_CODE:
521             return "IOCTL_VIDEO_GET_BANK_SELECT_CODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x115, METHOD_BUFFERED, FILE_ANY_ACCESS)
522         case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
523             return "IOCTL_VIDEO_MAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x116, METHOD_BUFFERED, FILE_ANY_ACCESS)
524         case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
525             return "IOCTL_VIDEO_UNMAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x117, METHOD_BUFFERED, FILE_ANY_ACCESS)
526         case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
527             return "IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x118, METHOD_BUFFERED, FILE_ANY_ACCESS)
528         case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
529             return "IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x119, METHOD_BUFFERED, FILE_ANY_ACCESS)
530         case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES:
531             return "IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11a, METHOD_BUFFERED, FILE_ANY_ACCESS)
532         case IOCTL_VIDEO_SET_POWER_MANAGEMENT:
533             return "IOCTL_VIDEO_SET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11b, METHOD_BUFFERED, FILE_ANY_ACCESS)
534         case IOCTL_VIDEO_GET_POWER_MANAGEMENT:
535             return "IOCTL_VIDEO_GET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11c, METHOD_BUFFERED, FILE_ANY_ACCESS)
536         case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
537             return "IOCTL_VIDEO_SHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11d, METHOD_BUFFERED, FILE_ANY_ACCESS)
538         case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
539             return "IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11e, METHOD_BUFFERED, FILE_ANY_ACCESS)
540         case IOCTL_VIDEO_SET_COLOR_LUT_DATA:
541             return "IOCTL_VIDEO_SET_COLOR_LUT_DATA"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11f, METHOD_BUFFERED, FILE_ANY_ACCESS)
542         case IOCTL_VIDEO_GET_CHILD_STATE:
543             return "IOCTL_VIDEO_GET_CHILD_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x120, METHOD_BUFFERED, FILE_ANY_ACCESS)
544         case IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION:
545             return "IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x121, METHOD_BUFFERED, FILE_ANY_ACCESS)
546         case IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION:
547             return "IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x122, METHOD_BUFFERED, FILE_ANY_ACCESS)
548         case IOCTL_VIDEO_SWITCH_DUALVIEW:
549             return "IOCTL_VIDEO_SWITCH_DUALVIEW"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x123, METHOD_BUFFERED, FILE_ANY_ACCESS)
550         case IOCTL_VIDEO_SET_BANK_POSITION:
551             return "IOCTL_VIDEO_SET_BANK_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x124, METHOD_BUFFERED, FILE_ANY_ACCESS)
552         case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS:
553             return "IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x125, METHOD_BUFFERED, FILE_ANY_ACCESS)
554         case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS:
555             return "IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x126, METHOD_BUFFERED, FILE_ANY_ACCESS)
556         case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS:
557             return "IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x127, METHOD_BUFFERED, FILE_ANY_ACCESS)
558     }
559 
560     return "<unknown ioctl code>";
561 }
562 
563 static
564 NTSTATUS
565 VideoPortUseDeviceInSession(
566     _Inout_ PDEVICE_OBJECT DeviceObject,
567     _Inout_ PVIDEO_DEVICE_SESSION_STATUS SessionState,
568     _In_ ULONG BufferLength,
569     _Out_ PULONG_PTR Information)
570 {
571     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
572 
573     /* Check buffer size */
574     *Information = sizeof(VIDEO_DEVICE_SESSION_STATUS);
575     if (BufferLength < sizeof(VIDEO_DEVICE_SESSION_STATUS))
576     {
577         ERR_(VIDEOPRT, "Buffer too small for VIDEO_DEVICE_SESSION_STATUS: %lx\n",
578              BufferLength);
579         return STATUS_BUFFER_TOO_SMALL;
580     }
581 
582     /* Get the device extension */
583     DeviceExtension = DeviceObject->DeviceExtension;
584 
585     /* Shall we enable the session? */
586     if (SessionState->bEnable)
587     {
588         /* Check if we have no session yet */
589         if (DeviceExtension->SessionId == -1)
590         {
591             /* Use this session and return success */
592             DeviceExtension->SessionId = PsGetCurrentProcessSessionId();
593             SessionState->bSuccess = TRUE;
594         }
595         else
596         {
597             ERR_(VIDEOPRT, "Requested to set session, but session is already set to: 0x%lx\n",
598                  DeviceExtension->SessionId);
599             SessionState->bSuccess = FALSE;
600         }
601     }
602     else
603     {
604         /* Check if we belong to the current session */
605         if (DeviceExtension->SessionId == PsGetCurrentProcessSessionId())
606         {
607             /* Reset the session and return success */
608             DeviceExtension->SessionId = -1;
609             SessionState->bSuccess = TRUE;
610         }
611         else
612         {
613             ERR_(VIDEOPRT, "Requested to reset session, but session is not set\n");
614             SessionState->bSuccess = FALSE;
615         }
616     }
617 
618     return STATUS_SUCCESS;
619 }
620 
621 static
622 NTSTATUS
623 VideoPortInitWin32kCallbacks(
624     _In_ PDEVICE_OBJECT DeviceObject,
625     _Inout_ PVIDEO_WIN32K_CALLBACKS Win32kCallbacks,
626     _In_ ULONG BufferLength,
627     _Out_ PULONG_PTR Information)
628 {
629     *Information = sizeof(VIDEO_WIN32K_CALLBACKS);
630     if (BufferLength < sizeof(VIDEO_WIN32K_CALLBACKS))
631     {
632         ERR_(VIDEOPRT, "Buffer too small for VIDEO_WIN32K_CALLBACKS: %lx\n",
633              BufferLength);
634         return STATUS_BUFFER_TOO_SMALL;
635     }
636 
637     /* Save the callout function globally */
638     Win32kCallout = Win32kCallbacks->Callout;
639 
640     /* Return reasonable values to Win32k */
641     Win32kCallbacks->bACPI = FALSE;
642     Win32kCallbacks->pPhysDeviceObject = DeviceObject;
643     Win32kCallbacks->DualviewFlags = 0;
644 
645     return STATUS_SUCCESS;
646 }
647 
648 static
649 NTSTATUS
650 VideoPortForwardDeviceControl(
651     IN PDEVICE_OBJECT DeviceObject,
652     IN PIRP Irp)
653 {
654     PIO_STACK_LOCATION IrpStack;
655     PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
656     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
657     VIDEO_REQUEST_PACKET vrp;
658 
659     TRACE_(VIDEOPRT, "VideoPortForwardDeviceControl\n");
660 
661     IrpStack = IoGetCurrentIrpStackLocation(Irp);
662     DeviceExtension = DeviceObject->DeviceExtension;
663     DriverExtension = DeviceExtension->DriverExtension;
664 
665     /* Translate the IRP to a VRP */
666     vrp.StatusBlock = (PSTATUS_BLOCK)&Irp->IoStatus;
667     vrp.IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
668 
669     INFO_(VIDEOPRT, "- IoControlCode: %x\n", vrp.IoControlCode);
670 
671     /* We're assuming METHOD_BUFFERED */
672     vrp.InputBuffer = Irp->AssociatedIrp.SystemBuffer;
673     vrp.InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
674     vrp.OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
675     vrp.OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
676 
677     /* Call the Miniport Driver with the VRP */
678     DriverExtension->InitializationData.HwStartIO(&DeviceExtension->MiniPortDeviceExtension,
679                                                   &vrp);
680 
681     INFO_(VIDEOPRT, "- Returned status: %x\n", Irp->IoStatus.Status);
682 
683     /* Map from win32 error codes to NT status values. */
684     switch (Irp->IoStatus.Status)
685     {
686         case NO_ERROR:
687             return STATUS_SUCCESS;
688         case ERROR_NOT_ENOUGH_MEMORY:
689             return STATUS_INSUFFICIENT_RESOURCES;
690         case ERROR_MORE_DATA:
691             return STATUS_BUFFER_OVERFLOW;
692         case ERROR_INVALID_FUNCTION:
693             return STATUS_NOT_IMPLEMENTED;
694         case ERROR_INVALID_PARAMETER:
695             return STATUS_INVALID_PARAMETER;
696         case ERROR_INSUFFICIENT_BUFFER:
697             return STATUS_BUFFER_TOO_SMALL;
698         case ERROR_DEV_NOT_EXIST:
699             return STATUS_DEVICE_DOES_NOT_EXIST;
700         case ERROR_IO_PENDING:
701             return STATUS_PENDING;
702         default:
703             return STATUS_UNSUCCESSFUL;
704     }
705 }
706 
707 /*
708  * IntVideoPortDispatchDeviceControl
709  *
710  * Answer requests for device control calls.
711  *
712  * Run Level
713  *    PASSIVE_LEVEL
714  */
715 NTSTATUS
716 NTAPI
717 IntVideoPortDispatchDeviceControl(
718     IN PDEVICE_OBJECT DeviceObject,
719     IN PIRP Irp)
720 {
721     PIO_STACK_LOCATION IrpStack;
722     NTSTATUS Status;
723     ULONG IoControlCode;
724 
725     TRACE_(VIDEOPRT, "IntVideoPortDispatchDeviceControl\n");
726 
727     IrpStack = IoGetCurrentIrpStackLocation(Irp);
728 
729     switch (IrpStack->MajorFunction)
730     {
731         case IRP_MJ_DEVICE_CONTROL:
732             /* This is the main part of this function and is handled below */
733             break;
734 
735         case IRP_MJ_SHUTDOWN:
736         {
737             /* Dereference CSRSS */
738             PKPROCESS OldCsrProcess;
739             OldCsrProcess = InterlockedExchangePointer((PVOID*)&CsrProcess, NULL);
740             if (OldCsrProcess)
741                 ObDereferenceObject(OldCsrProcess);
742 
743             Irp->IoStatus.Status = STATUS_SUCCESS;
744             IoCompleteRequest(Irp, IO_NO_INCREMENT);
745             return STATUS_SUCCESS;
746         }
747 
748         default:
749             ERR_(VIDEOPRT, "- Unknown MajorFunction 0x%x\n", IrpStack->MajorFunction);
750             Irp->IoStatus.Status = STATUS_SUCCESS;
751             IoCompleteRequest(Irp, IO_NO_INCREMENT);
752             return STATUS_SUCCESS;
753     }
754 
755     IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
756 
757     INFO_(VIDEOPRT, "- IoControlCode: 0x%x: %s\n", IoControlCode, IoctlName(IoControlCode));
758 
759     switch (IoControlCode)
760     {
761         case IOCTL_VIDEO_ENABLE_VDM:
762         case IOCTL_VIDEO_DISABLE_VDM:
763         case IOCTL_VIDEO_REGISTER_VDM:
764             WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_VDM are UNIMPLEMENTED!\n");
765             Status = STATUS_NOT_IMPLEMENTED;
766             break;
767 
768         case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE:
769         case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE:
770             WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_OUTPUT_DEVICE_POWER_STATE are UNIMPLEMENTED!\n");
771             Status = STATUS_NOT_IMPLEMENTED;
772             break;
773 
774         case IOCTL_VIDEO_SET_POWER_MANAGEMENT:
775         case IOCTL_VIDEO_GET_POWER_MANAGEMENT:
776             WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_POWER_MANAGEMENT are UNIMPLEMENTED!\n");
777             Status = STATUS_NOT_IMPLEMENTED;
778             break;
779 
780         case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS:
781         case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS:
782         case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS:
783             WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_BRIGHTNESS are UNIMPLEMENTED!\n");
784             Status = STATUS_NOT_IMPLEMENTED;
785             break;
786 
787         case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS:
788             INFO_(VIDEOPRT, "- IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n");
789             Status = VideoPortInitWin32kCallbacks(DeviceObject,
790                                                   Irp->AssociatedIrp.SystemBuffer,
791                                                   IrpStack->Parameters.DeviceIoControl.InputBufferLength,
792                                                   &Irp->IoStatus.Information);
793             break;
794 
795         case IOCTL_VIDEO_IS_VGA_DEVICE:
796             WARN_(VIDEOPRT, "- IOCTL_VIDEO_IS_VGA_DEVICE is UNIMPLEMENTED!\n");
797             Status = STATUS_NOT_IMPLEMENTED;
798             break;
799 
800         case IOCTL_VIDEO_USE_DEVICE_IN_SESSION:
801             INFO_(VIDEOPRT, "- IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n");
802             Status = VideoPortUseDeviceInSession(DeviceObject,
803                                                  Irp->AssociatedIrp.SystemBuffer,
804                                                  IrpStack->Parameters.DeviceIoControl.InputBufferLength,
805                                                  &Irp->IoStatus.Information);
806             break;
807 
808         case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY:
809             INFO_(VIDEOPRT, "- IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n");
810             /*
811              * The Win32k Watchdog Timer detected that a thread spent more time
812              * in a display driver than the allotted time its threshold specified,
813              * and thus is going to attempt to recover by switching to VGA mode.
814              * If this attempt fails, the watchdog generates bugcheck 0xEA
815              * "THREAD_STUCK_IN_DEVICE_DRIVER".
816              *
817              * Prepare the recovery by resetting the display adapters to
818              * standard VGA 80x25 text mode.
819              */
820             IntVideoPortResetDisplayParametersEx(80, 25, FALSE);
821             Status = STATUS_SUCCESS;
822             break;
823 
824         default:
825             /* Forward to the Miniport Driver */
826             Status = VideoPortForwardDeviceControl(DeviceObject, Irp);
827             break;
828     }
829 
830     INFO_(VIDEOPRT, "- Returned status: 0x%x\n", Status);
831 
832     Irp->IoStatus.Status = Status;
833     IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
834     return Status;
835 }
836 
837 NTSTATUS
838 NTAPI
839 IntVideoPortPnPStartDevice(
840     IN PDEVICE_OBJECT DeviceObject,
841     IN PIRP Irp)
842 {
843     PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
844     PDRIVER_OBJECT DriverObject;
845     PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
846     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
847     PCM_RESOURCE_LIST AllocatedResources;
848 
849     /* Get the initialization data we saved in VideoPortInitialize.*/
850     DriverObject = DeviceObject->DriverObject;
851     DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
852     DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
853 
854     /* Store some resources in the DeviceExtension. */
855     AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
856     if (AllocatedResources != NULL)
857     {
858         CM_FULL_RESOURCE_DESCRIPTOR *FullList;
859         CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
860         ULONG ResourceCount;
861         ULONG ResourceListSize;
862 
863         /* Save the resource list */
864         ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
865         ResourceListSize =
866             FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
867                          PartialDescriptors[ResourceCount]);
868         DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
869         if (DeviceExtension->AllocatedResources == NULL)
870         {
871             return STATUS_INSUFFICIENT_RESOURCES;
872         }
873 
874         RtlCopyMemory(DeviceExtension->AllocatedResources,
875                       AllocatedResources,
876                       ResourceListSize);
877 
878         /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */
879         FullList = AllocatedResources->List;
880         ASSERT(AllocatedResources->Count == 1);
881         INFO_(VIDEOPRT, "InterfaceType %u BusNumber List %u Device BusNumber %u Version %u Revision %u\n",
882               FullList->InterfaceType, FullList->BusNumber, DeviceExtension->SystemIoBusNumber, FullList->PartialResourceList.Version, FullList->PartialResourceList.Revision);
883 
884         /* FIXME: Is this ASSERT ok for resources from the PNP manager? */
885         ASSERT(FullList->InterfaceType == PCIBus);
886         ASSERT(FullList->BusNumber == DeviceExtension->SystemIoBusNumber);
887         ASSERT(1 == FullList->PartialResourceList.Version);
888         ASSERT(1 == FullList->PartialResourceList.Revision);
889         for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
890              Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
891              Descriptor++)
892         {
893             if (Descriptor->Type == CmResourceTypeInterrupt)
894             {
895                 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
896                 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
897                 if (Descriptor->ShareDisposition == CmResourceShareShared)
898                     DeviceExtension->InterruptShared = TRUE;
899                 else
900                     DeviceExtension->InterruptShared = FALSE;
901             }
902         }
903     }
904 
905     INFO_(VIDEOPRT, "Interrupt level: 0x%x Interrupt Vector: 0x%x\n",
906           DeviceExtension->InterruptLevel,
907           DeviceExtension->InterruptVector);
908 
909     /* Create adapter device object. */
910     return IntVideoPortFindAdapter(DriverObject,
911                                    DriverExtension,
912                                    DeviceObject);
913 }
914 
915 
916 NTSTATUS
917 NTAPI
918 IntVideoPortForwardIrpAndWaitCompletionRoutine(
919     PDEVICE_OBJECT Fdo,
920     PIRP Irp,
921     PVOID Context)
922 {
923     PKEVENT Event = Context;
924 
925     if (Irp->PendingReturned)
926         KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
927 
928     return STATUS_MORE_PROCESSING_REQUIRED;
929 }
930 
931 NTSTATUS
932 NTAPI
933 IntVideoPortQueryBusRelations(PDEVICE_OBJECT DeviceObject, PIRP Irp)
934 {
935     PDEVICE_RELATIONS DeviceRelations;
936     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
937     PVIDEO_PORT_CHILD_EXTENSION ChildExtension;
938     ULONG i;
939     PLIST_ENTRY CurrentEntry;
940 
941     /* Count the children */
942     i = 0;
943     CurrentEntry = DeviceExtension->ChildDeviceList.Flink;
944     while (CurrentEntry != &DeviceExtension->ChildDeviceList)
945     {
946         i++;
947         CurrentEntry = CurrentEntry->Flink;
948     }
949 
950     if (i == 0)
951         return Irp->IoStatus.Status;
952 
953     DeviceRelations = ExAllocatePool(PagedPool,
954                                      sizeof(DEVICE_RELATIONS) + ((i - 1) * sizeof(PVOID)));
955     if (!DeviceRelations) return STATUS_NO_MEMORY;
956 
957     DeviceRelations->Count = i;
958 
959     /* Add the children */
960     i = 0;
961     CurrentEntry = DeviceExtension->ChildDeviceList.Flink;
962     while (CurrentEntry != &DeviceExtension->ChildDeviceList)
963     {
964         ChildExtension = CONTAINING_RECORD(CurrentEntry, VIDEO_PORT_CHILD_EXTENSION, ListEntry);
965 
966         ObReferenceObject(ChildExtension->PhysicalDeviceObject);
967         DeviceRelations->Objects[i] = ChildExtension->PhysicalDeviceObject;
968 
969         i++;
970         CurrentEntry = CurrentEntry->Flink;
971     }
972 
973     INFO_(VIDEOPRT, "Reported %d PDOs\n", i);
974     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
975 
976     return STATUS_SUCCESS;
977 }
978 
979 NTSTATUS
980 NTAPI
981 IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject, PIRP Irp)
982 {
983     KEVENT Event;
984     NTSTATUS Status;
985     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension =
986         (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
987 
988     KeInitializeEvent(&Event, NotificationEvent, FALSE);
989     IoCopyCurrentIrpStackLocationToNext(Irp);
990     IoSetCompletionRoutine(Irp,
991                            IntVideoPortForwardIrpAndWaitCompletionRoutine,
992                            &Event,
993                            TRUE,
994                            TRUE,
995                            TRUE);
996 
997     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
998     if (Status == STATUS_PENDING)
999     {
1000         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1001         Status = Irp->IoStatus.Status;
1002     }
1003 
1004     return Status;
1005 }
1006 
1007 NTSTATUS
1008 NTAPI
1009 IntVideoPortDispatchFdoPnp(
1010     IN PDEVICE_OBJECT DeviceObject,
1011     IN PIRP Irp)
1012 {
1013     PIO_STACK_LOCATION IrpSp;
1014     NTSTATUS Status;
1015     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1016 
1017     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1018 
1019     switch (IrpSp->MinorFunction)
1020     {
1021         case IRP_MN_START_DEVICE:
1022             Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1023             if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1024                 Status = IntVideoPortPnPStartDevice(DeviceObject, Irp);
1025             Irp->IoStatus.Status = Status;
1026             Irp->IoStatus.Information = 0;
1027             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1028             break;
1029 
1030         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1031             Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1032             if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1033                 Status = IntVideoPortFilterResourceRequirements(DeviceObject, Irp);
1034             Irp->IoStatus.Status = Status;
1035             Irp->IoStatus.Information = 0;
1036             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1037             break;
1038 
1039         case IRP_MN_QUERY_DEVICE_RELATIONS:
1040             if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
1041             {
1042                 IoSkipCurrentIrpStackLocation(Irp);
1043                 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1044             }
1045             else
1046             {
1047                 Status = IntVideoPortQueryBusRelations(DeviceObject, Irp);
1048                 Irp->IoStatus.Status = Status;
1049                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1050             }
1051             break;
1052 
1053         case IRP_MN_REMOVE_DEVICE:
1054         case IRP_MN_QUERY_REMOVE_DEVICE:
1055         case IRP_MN_CANCEL_REMOVE_DEVICE:
1056         case IRP_MN_SURPRISE_REMOVAL:
1057 
1058         case IRP_MN_STOP_DEVICE:
1059             Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
1060             if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1061                 Status = STATUS_SUCCESS;
1062             Irp->IoStatus.Status = Status;
1063             Irp->IoStatus.Information = 0;
1064             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1065             break;
1066 
1067         case IRP_MN_QUERY_STOP_DEVICE:
1068         case IRP_MN_CANCEL_STOP_DEVICE:
1069             Status = STATUS_SUCCESS;
1070             Irp->IoStatus.Status = STATUS_SUCCESS;
1071             Irp->IoStatus.Information = 0;
1072             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1073             break;
1074 
1075         default:
1076             Status = Irp->IoStatus.Status;
1077             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1078             break;
1079     }
1080 
1081     return Status;
1082 }
1083 
1084 NTSTATUS
1085 NTAPI
1086 IntVideoPortDispatchPnp(
1087     IN PDEVICE_OBJECT DeviceObject,
1088     IN PIRP Irp)
1089 {
1090     PVIDEO_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension;
1091 
1092     if (CommonExtension->Fdo)
1093         return IntVideoPortDispatchFdoPnp(DeviceObject, Irp);
1094     else
1095         return IntVideoPortDispatchPdoPnp(DeviceObject, Irp);
1096 }
1097 
1098 NTSTATUS
1099 NTAPI
1100 IntVideoPortDispatchCleanup(
1101     IN PDEVICE_OBJECT DeviceObject,
1102     IN PIRP Irp)
1103 {
1104     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1105 
1106     DeviceExtension = DeviceObject->DeviceExtension;
1107     RtlFreeUnicodeString(&DeviceExtension->RegistryPath);
1108 
1109     Irp->IoStatus.Status = STATUS_SUCCESS;
1110     Irp->IoStatus.Information = 0;
1111     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1112 
1113     return STATUS_SUCCESS;
1114 }
1115 
1116 NTSTATUS
1117 NTAPI
1118 IntVideoPortDispatchPower(
1119     IN PDEVICE_OBJECT DeviceObject,
1120     IN PIRP Irp)
1121 {
1122     PIO_STACK_LOCATION IrpSp;
1123     NTSTATUS Status = Irp->IoStatus.Status;
1124     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1125 
1126     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1127 
1128     if (DeviceExtension->Common.Fdo)
1129     {
1130         PoStartNextPowerIrp(Irp);
1131         IoSkipCurrentIrpStackLocation(Irp);
1132         return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1133     }
1134     else
1135     {
1136         switch (IrpSp->MinorFunction)
1137         {
1138             case IRP_MN_QUERY_POWER:
1139             case IRP_MN_SET_POWER:
1140                 Status = STATUS_SUCCESS;
1141                 break;
1142         }
1143         PoStartNextPowerIrp(Irp);
1144         Irp->IoStatus.Status = Status;
1145         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1146         return Status;
1147     }
1148 }
1149 
1150 NTSTATUS
1151 NTAPI
1152 IntVideoPortDispatchSystemControl(
1153     IN PDEVICE_OBJECT DeviceObject,
1154     IN PIRP Irp)
1155 {
1156     NTSTATUS Status;
1157     PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1158 
1159     if (DeviceExtension->Common.Fdo)
1160     {
1161         IoSkipCurrentIrpStackLocation(Irp);
1162         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1163     }
1164     else
1165     {
1166         Status = Irp->IoStatus.Status;
1167         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1168         return Status;
1169     }
1170 }
1171 
1172 VOID
1173 NTAPI
1174 IntVideoPortUnload(PDRIVER_OBJECT DriverObject)
1175 {
1176 }
1177