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