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