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