1 /* 2 * VideoPort driver 3 * 4 * Copyright (C) 2002, 2003, 2004 ReactOS Team 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 22 #include "videoprt.h" 23 24 #include <ndk/inbvfuncs.h> 25 #include <ndk/obfuncs.h> 26 #include <ndk/psfuncs.h> 27 28 #define NDEBUG 29 #include <debug.h> 30 31 /* GLOBAL VARIABLES ***********************************************************/ 32 33 static PVIDEO_WIN32K_CALLOUT Win32kCallout = NULL; 34 static HANDLE InbvThreadHandle = NULL; 35 static BOOLEAN InbvMonitoring = FALSE; 36 37 /* PRIVATE FUNCTIONS **********************************************************/ 38 39 static VOID 40 VideoPortWin32kCallout( 41 _In_ PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams) 42 { 43 if (!Win32kCallout) 44 return; 45 46 /* Perform the call in the context of CSRSS */ 47 if (!CsrProcess) 48 return; 49 50 KeAttachProcess(CsrProcess); 51 Win32kCallout(CallbackParams); 52 KeDetachProcess(); 53 } 54 55 /* 56 * Reinitialize the display to base VGA mode. 57 * 58 * Returns TRUE if it completely resets the adapter to the given character mode. 59 * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode 60 * reset itself after HwVidResetHw() returns control. 61 * 62 * This callback has been registered with InbvNotifyDisplayOwnershipLost() 63 * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck 64 * code regains display access. Therefore this routine can be called at any 65 * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside 66 * completely in non-paged pool, and cannot perform the following actions: 67 * Allocate memory, access pageable memory, use any synchronization mechanisms 68 * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below. 69 */ 70 static BOOLEAN 71 NTAPI 72 IntVideoPortResetDisplayParametersEx( 73 _In_ ULONG Columns, 74 _In_ ULONG Rows, 75 _In_ BOOLEAN CalledByInbv) 76 { 77 BOOLEAN Success = TRUE; // Suppose we don't need to perform a full reset. 78 KIRQL OldIrql; 79 PLIST_ENTRY PrevEntry, Entry; 80 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 81 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 82 83 /* Check if we are at dispatch level or lower, and acquire the lock */ 84 OldIrql = KeGetCurrentIrql(); 85 if (OldIrql <= DISPATCH_LEVEL) 86 { 87 /* Loop until the lock is free, then raise IRQL to dispatch level */ 88 while (!KeTestSpinLock(&HwResetAdaptersLock)); 89 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 90 } 91 KeAcquireSpinLockAtDpcLevel(&HwResetAdaptersLock); 92 93 /* Bail out early if we don't have any resettable adapter */ 94 if (IsListEmpty(&HwResetAdaptersList)) 95 { 96 Success = FALSE; // No adapter found: request HAL to perform a full reset. 97 goto Quit; 98 } 99 100 /* 101 * If we have been unexpectedly called via a callback from 102 * InbvAcquireDisplayOwnership(), start monitoring INBV. 103 */ 104 if (CalledByInbv) 105 InbvMonitoring = TRUE; 106 107 for (PrevEntry = &HwResetAdaptersList, Entry = PrevEntry->Flink; 108 Entry != &HwResetAdaptersList; 109 PrevEntry = Entry, Entry = Entry->Flink) 110 { 111 /* 112 * Check whether the entry address is properly aligned, 113 * the device and driver extensions must be readable and 114 * the device extension properly back-linked to the last entry. 115 */ 116 // #define IS_ALIGNED(addr, align) (((ULONG64)(addr) & (align - 1)) == 0) 117 if (((ULONG_PTR)Entry & (sizeof(ULONG_PTR) - 1)) != 0) 118 { 119 Success = FALSE; // We failed: request HAL to perform a full reset. 120 goto Quit; 121 } 122 123 DeviceExtension = CONTAINING_RECORD(Entry, 124 VIDEO_PORT_DEVICE_EXTENSION, 125 HwResetListEntry); 126 /* 127 * As this function can be called as part of the INBV initialization 128 * by the bugcheck code, avoid any problems and protect all accesses 129 * within SEH. 130 */ 131 _SEH2_TRY 132 { 133 DriverExtension = DeviceExtension->DriverExtension; 134 ASSERT(DriverExtension); 135 136 if (DeviceExtension->HwResetListEntry.Blink != PrevEntry) 137 { 138 Success = FALSE; // We failed: request HAL to perform a full reset. 139 _SEH2_YIELD(goto Quit); 140 } 141 142 if ((DeviceExtension->DeviceOpened >= 1) && 143 (DriverExtension->InitializationData.HwResetHw != NULL)) 144 { 145 Success &= DriverExtension->InitializationData.HwResetHw( 146 &DeviceExtension->MiniPortDeviceExtension, 147 Columns, Rows); 148 } 149 } 150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 151 { 152 } 153 _SEH2_END; 154 } 155 156 Quit: 157 /* Release the lock and restore the old IRQL if we were at dispatch level or lower */ 158 KeReleaseSpinLockFromDpcLevel(&HwResetAdaptersLock); 159 if (OldIrql <= DISPATCH_LEVEL) 160 KeLowerIrql(OldIrql); 161 162 return Success; 163 } 164 165 /* This callback is registered with InbvNotifyDisplayOwnershipLost() */ 166 static BOOLEAN 167 NTAPI 168 IntVideoPortResetDisplayParameters(ULONG Columns, ULONG Rows) 169 { 170 /* Call the extended function, specifying we were called by INBV */ 171 return IntVideoPortResetDisplayParametersEx(Columns, Rows, TRUE); 172 } 173 174 /* 175 * (Adapted for ReactOS/Win2k3 from an original comment 176 * by Gé van Geldorp, June 2003, r4937) 177 * 178 * DISPLAY OWNERSHIP 179 * 180 * So, who owns the physical display and is allowed to write to it? 181 * 182 * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless 183 * /NOGUIBOOT has been specified in the boot command line. Later in the boot 184 * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in 185 * VIDEOPRT.SYS. This component takes ownership of the display by calling 186 * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release 187 * ownership of the display it previously had. From that moment on, the display 188 * is owned by that component and can be switched to graphics mode. The display 189 * is not supposed to return to text mode, except in case of a bugcheck. 190 * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV 191 * re-take display ownership, and calls back the function previously registered 192 * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck, 193 * execution is halted. So, under NT, the only possible sequence of display 194 * modes is text mode -> graphics mode -> text mode (the latter hopefully 195 * happening very infrequently). 196 * 197 * In ReactOS things are a little bit different. We want to have a functional 198 * interactive text mode. We should be able to switch back and forth from 199 * text mode to graphics mode when a GUI app is started and then finished. 200 * Also, when the system bugchecks in graphics mode we want to switch back to 201 * text mode and show the bugcheck information. Last but not least, when using 202 * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a 203 * switch to text mode, and the user would expect that by continuing execution 204 * a switch back to graphics mode is done. 205 */ 206 static VOID 207 NTAPI 208 InbvMonitorThread( 209 _In_ PVOID Context) 210 { 211 VIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams; 212 LARGE_INTEGER Delay; 213 USHORT i; 214 215 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); 216 217 while (TRUE) 218 { 219 /* 220 * During one second, check the INBV status each 100 milliseconds, 221 * then revert to 1 second delay. 222 */ 223 i = 10; 224 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay 225 while (!InbvMonitoring) 226 { 227 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 228 229 if ((i > 0) && (--i == 0)) 230 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay 231 } 232 233 /* 234 * Loop while the display is owned by INBV. We cannot do anything else 235 * than polling since INBV does not offer a proper notification system. 236 * 237 * During one second, check the INBV status each 100 milliseconds, 238 * then revert to 1 second delay. 239 */ 240 i = 10; 241 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay 242 while (InbvCheckDisplayOwnership()) 243 { 244 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 245 246 if ((i > 0) && (--i == 0)) 247 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay 248 } 249 250 /* Reset the monitoring */ 251 InbvMonitoring = FALSE; 252 253 /* 254 * Somebody released INBV display ownership, usually by invoking 255 * InbvNotifyDisplayOwnershipLost(). However the caller of this 256 * function certainly specified a different callback than ours. 257 * As we are going to be the only owner of the active display, 258 * we need to re-register our own display reset callback. 259 */ 260 InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters); 261 262 /* Tell Win32k to reset the display */ 263 CallbackParams.CalloutType = VideoFindAdapterCallout; 264 // CallbackParams.PhysDisp = NULL; 265 CallbackParams.Param = (ULONG_PTR)TRUE; // TRUE: Re-enable display; FALSE: Disable display. 266 VideoPortWin32kCallout(&CallbackParams); 267 } 268 269 // FIXME: See IntVideoPortInbvCleanup(). 270 // PsTerminateSystemThread(STATUS_SUCCESS); 271 } 272 273 static NTSTATUS 274 IntVideoPortInbvInitialize(VOID) 275 { 276 /* Create the INBV monitoring thread if needed */ 277 if (!InbvThreadHandle) 278 { 279 NTSTATUS Status; 280 OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE); 281 282 Status = PsCreateSystemThread(&InbvThreadHandle, 283 0, 284 &ObjectAttributes, 285 NULL, 286 NULL, 287 InbvMonitorThread, 288 NULL); 289 if (!NT_SUCCESS(Status)) 290 InbvThreadHandle = NULL; 291 } 292 293 /* Re-register the display reset callback with INBV */ 294 InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters); 295 296 return STATUS_SUCCESS; 297 } 298 299 static NTSTATUS 300 IntVideoPortInbvCleanup( 301 IN PDEVICE_OBJECT DeviceObject) 302 { 303 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 304 // HANDLE ThreadHandle; 305 306 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 307 if ((DeviceExtension->DeviceOpened >= 1) && 308 (InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0)) 309 { 310 // RemoveEntryList(&DeviceExtension->HwResetListEntry); 311 InbvNotifyDisplayOwnershipLost(NULL); 312 IntVideoPortResetDisplayParametersEx(80, 50, FALSE); 313 // or InbvAcquireDisplayOwnership(); ? 314 } 315 316 #if 0 317 // TODO: Find the best way to communicate the request. 318 /* Signal the INBV monitoring thread and wait for it to terminate */ 319 ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL); 320 if (ThreadHandle) 321 { 322 KeWaitForSingleObject(&ThreadHandle, Executive, KernelMode, FALSE, NULL); 323 /* Close its handle */ 324 ObCloseHandle(ThreadHandle, KernelMode); 325 } 326 #endif 327 328 return STATUS_SUCCESS; 329 } 330 331 332 NTSTATUS 333 NTAPI 334 IntVideoPortAddDevice( 335 IN PDRIVER_OBJECT DriverObject, 336 IN PDEVICE_OBJECT PhysicalDeviceObject) 337 { 338 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 339 PDEVICE_OBJECT DeviceObject; 340 NTSTATUS Status; 341 342 /* Get the initialization data we saved in VideoPortInitialize. */ 343 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 344 345 /* Create adapter device object. */ 346 Status = IntVideoPortCreateAdapterDeviceObject(DriverObject, 347 DriverExtension, 348 PhysicalDeviceObject, 349 DriverExtension->InitializationData.StartingDeviceNumber, 350 0, 351 &DeviceObject); 352 if (!NT_SUCCESS(Status)) 353 { 354 ERR_(VIDEOPRT, "IntVideoPortCreateAdapterDeviceObject() failed with status 0x%lx\n", Status); 355 } 356 return Status; 357 } 358 359 /* 360 * IntVideoPortDispatchOpen 361 * 362 * Answer requests for Open calls. 363 * 364 * Run Level 365 * PASSIVE_LEVEL 366 */ 367 NTSTATUS 368 NTAPI 369 IntVideoPortDispatchOpen( 370 IN PDEVICE_OBJECT DeviceObject, 371 IN PIRP Irp) 372 { 373 NTSTATUS Status; 374 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 375 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 376 377 TRACE_(VIDEOPRT, "IntVideoPortDispatchOpen\n"); 378 379 if (!CsrProcess) 380 { 381 /* 382 * We know the first open call will be from the CSRSS process 383 * to let us know its handle. 384 */ 385 INFO_(VIDEOPRT, "Referencing CSRSS\n"); 386 CsrProcess = (PKPROCESS)PsGetCurrentProcess(); 387 ObReferenceObject(CsrProcess); 388 INFO_(VIDEOPRT, "CsrProcess 0x%p\n", CsrProcess); 389 390 Status = IntInitializeVideoAddressSpace(); 391 if (!NT_SUCCESS(Status)) 392 { 393 ERR_(VIDEOPRT, "IntInitializeVideoAddressSpace() failed: 0x%lx\n", Status); 394 ObDereferenceObject(CsrProcess); 395 CsrProcess = NULL; 396 return Status; 397 } 398 } 399 400 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 401 DriverExtension = DeviceExtension->DriverExtension; 402 403 // FIXME: (Re-)initialize INBV only if DeviceObject doesn't belong to a mirror driver. 404 IntVideoPortInbvInitialize(); 405 406 if (DriverExtension->InitializationData.HwInitialize(&DeviceExtension->MiniPortDeviceExtension)) 407 { 408 Irp->IoStatus.Status = STATUS_SUCCESS; 409 InterlockedIncrement((PLONG)&DeviceExtension->DeviceOpened); 410 } 411 else 412 { 413 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 414 } 415 416 Irp->IoStatus.Information = FILE_OPENED; 417 IoCompleteRequest(Irp, IO_NO_INCREMENT); 418 419 return STATUS_SUCCESS; 420 } 421 422 /* 423 * IntVideoPortDispatchClose 424 * 425 * Answer requests for Close calls. 426 * 427 * Run Level 428 * PASSIVE_LEVEL 429 */ 430 NTSTATUS 431 NTAPI 432 IntVideoPortDispatchClose( 433 IN PDEVICE_OBJECT DeviceObject, 434 IN PIRP Irp) 435 { 436 TRACE_(VIDEOPRT, "IntVideoPortDispatchClose\n"); 437 438 IntVideoPortInbvCleanup(DeviceObject); 439 440 Irp->IoStatus.Status = STATUS_SUCCESS; 441 IoCompleteRequest(Irp, IO_NO_INCREMENT); 442 return STATUS_SUCCESS; 443 } 444 445 PSTR 446 IoctlName(ULONG Ioctl) 447 { 448 switch (Ioctl) 449 { 450 case IOCTL_VIDEO_ENABLE_VDM: 451 return "IOCTL_VIDEO_ENABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS) 452 case IOCTL_VIDEO_DISABLE_VDM: 453 return "IOCTL_VIDEO_DISABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x01, METHOD_BUFFERED, FILE_ANY_ACCESS) 454 case IOCTL_VIDEO_REGISTER_VDM: 455 return "IOCTL_VIDEO_REGISTER_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS) 456 case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE: 457 return "IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x03, METHOD_BUFFERED, FILE_ANY_ACCESS) 458 case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE: 459 return "IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x04, METHOD_BUFFERED, FILE_ANY_ACCESS) 460 case IOCTL_VIDEO_MONITOR_DEVICE: 461 return "IOCTL_VIDEO_MONITOR_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x05, METHOD_BUFFERED, FILE_ANY_ACCESS) 462 case IOCTL_VIDEO_ENUM_MONITOR_PDO: 463 return "IOCTL_VIDEO_ENUM_MONITOR_PDO"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x06, METHOD_BUFFERED, FILE_ANY_ACCESS) 464 case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS: 465 return "IOCTL_VIDEO_INIT_WIN32K_CALLBACKS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x07, METHOD_BUFFERED, FILE_ANY_ACCESS) 466 case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS: 467 return "IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x08, METHOD_BUFFERED, FILE_ANY_ACCESS) 468 case IOCTL_VIDEO_IS_VGA_DEVICE: 469 return "IOCTL_VIDEO_IS_VGA_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x09, METHOD_BUFFERED, FILE_ANY_ACCESS) 470 case IOCTL_VIDEO_USE_DEVICE_IN_SESSION: 471 return "IOCTL_VIDEO_USE_DEVICE_IN_SESSION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0a, METHOD_BUFFERED, FILE_ANY_ACCESS) 472 case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY: 473 return "IOCTL_VIDEO_PREPARE_FOR_EARECOVERY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x0b, METHOD_BUFFERED, FILE_ANY_ACCESS) 474 case IOCTL_VIDEO_SAVE_HARDWARE_STATE: 475 return "IOCTL_VIDEO_SAVE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x80, METHOD_BUFFERED, FILE_ANY_ACCESS) 476 case IOCTL_VIDEO_RESTORE_HARDWARE_STATE: 477 return "IOCTL_VIDEO_RESTORE_HARDWARE_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x81, METHOD_BUFFERED, FILE_ANY_ACCESS) 478 case IOCTL_VIDEO_QUERY_AVAIL_MODES: 479 return "IOCTL_VIDEO_QUERY_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x100, METHOD_BUFFERED, FILE_ANY_ACCESS) 480 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: 481 return "IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x101, METHOD_BUFFERED, FILE_ANY_ACCESS) 482 case IOCTL_VIDEO_QUERY_CURRENT_MODE: 483 return "IOCTL_VIDEO_QUERY_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x102, METHOD_BUFFERED, FILE_ANY_ACCESS) 484 case IOCTL_VIDEO_SET_CURRENT_MODE: 485 return "IOCTL_VIDEO_SET_CURRENT_MODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x103, METHOD_BUFFERED, FILE_ANY_ACCESS) 486 case IOCTL_VIDEO_RESET_DEVICE: 487 return "IOCTL_VIDEO_RESET_DEVICE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x104, METHOD_BUFFERED, FILE_ANY_ACCESS) 488 case IOCTL_VIDEO_LOAD_AND_SET_FONT: 489 return "IOCTL_VIDEO_LOAD_AND_SET_FONT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x105, METHOD_BUFFERED, FILE_ANY_ACCESS) 490 case IOCTL_VIDEO_SET_PALETTE_REGISTERS: 491 return "IOCTL_VIDEO_SET_PALETTE_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x106, METHOD_BUFFERED, FILE_ANY_ACCESS) 492 case IOCTL_VIDEO_SET_COLOR_REGISTERS: 493 return "IOCTL_VIDEO_SET_COLOR_REGISTERS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x107, METHOD_BUFFERED, FILE_ANY_ACCESS) 494 case IOCTL_VIDEO_ENABLE_CURSOR: 495 return "IOCTL_VIDEO_ENABLE_CURSOR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x108, METHOD_BUFFERED, FILE_ANY_ACCESS) 496 case IOCTL_VIDEO_DISABLE_CURSOR: 497 return "IOCTL_VIDEO_DISABLE_CURSOR"; // CTL_CODE (FILE_DEVICE_VIDEO, 0x109, METHOD_BUFFERED, FILE_ANY_ACCESS) 498 case IOCTL_VIDEO_SET_CURSOR_ATTR: 499 return "IOCTL_VIDEO_SET_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10a, METHOD_BUFFERED, FILE_ANY_ACCESS) 500 case IOCTL_VIDEO_QUERY_CURSOR_ATTR: 501 return "IOCTL_VIDEO_QUERY_CURSOR_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10b, METHOD_BUFFERED, FILE_ANY_ACCESS) 502 case IOCTL_VIDEO_SET_CURSOR_POSITION: 503 return "IOCTL_VIDEO_SET_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10c, METHOD_BUFFERED, FILE_ANY_ACCESS) 504 case IOCTL_VIDEO_QUERY_CURSOR_POSITION: 505 return "IOCTL_VIDEO_QUERY_CURSOR_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10d, METHOD_BUFFERED, FILE_ANY_ACCESS) 506 case IOCTL_VIDEO_ENABLE_POINTER: 507 return "IOCTL_VIDEO_ENABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10e, METHOD_BUFFERED, FILE_ANY_ACCESS) 508 case IOCTL_VIDEO_DISABLE_POINTER: 509 return "IOCTL_VIDEO_DISABLE_POINTER"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x10f, METHOD_BUFFERED, FILE_ANY_ACCESS) 510 case IOCTL_VIDEO_SET_POINTER_ATTR: 511 return "IOCTL_VIDEO_SET_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x110, METHOD_BUFFERED, FILE_ANY_ACCESS) 512 case IOCTL_VIDEO_QUERY_POINTER_ATTR: 513 return "IOCTL_VIDEO_QUERY_POINTER_ATTR"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x111, METHOD_BUFFERED, FILE_ANY_ACCESS) 514 case IOCTL_VIDEO_SET_POINTER_POSITION: 515 return "IOCTL_VIDEO_SET_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x112, METHOD_BUFFERED, FILE_ANY_ACCESS) 516 case IOCTL_VIDEO_QUERY_POINTER_POSITION: 517 return "IOCTL_VIDEO_QUERY_POINTER_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x113, METHOD_BUFFERED, FILE_ANY_ACCESS) 518 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES: 519 return "IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x114, METHOD_BUFFERED, FILE_ANY_ACCESS) 520 case IOCTL_VIDEO_GET_BANK_SELECT_CODE: 521 return "IOCTL_VIDEO_GET_BANK_SELECT_CODE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x115, METHOD_BUFFERED, FILE_ANY_ACCESS) 522 case IOCTL_VIDEO_MAP_VIDEO_MEMORY: 523 return "IOCTL_VIDEO_MAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x116, METHOD_BUFFERED, FILE_ANY_ACCESS) 524 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: 525 return "IOCTL_VIDEO_UNMAP_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x117, METHOD_BUFFERED, FILE_ANY_ACCESS) 526 case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES: 527 return "IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x118, METHOD_BUFFERED, FILE_ANY_ACCESS) 528 case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES: 529 return "IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x119, METHOD_BUFFERED, FILE_ANY_ACCESS) 530 case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES: 531 return "IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11a, METHOD_BUFFERED, FILE_ANY_ACCESS) 532 case IOCTL_VIDEO_SET_POWER_MANAGEMENT: 533 return "IOCTL_VIDEO_SET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11b, METHOD_BUFFERED, FILE_ANY_ACCESS) 534 case IOCTL_VIDEO_GET_POWER_MANAGEMENT: 535 return "IOCTL_VIDEO_GET_POWER_MANAGEMENT"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11c, METHOD_BUFFERED, FILE_ANY_ACCESS) 536 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY: 537 return "IOCTL_VIDEO_SHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11d, METHOD_BUFFERED, FILE_ANY_ACCESS) 538 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: 539 return "IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11e, METHOD_BUFFERED, FILE_ANY_ACCESS) 540 case IOCTL_VIDEO_SET_COLOR_LUT_DATA: 541 return "IOCTL_VIDEO_SET_COLOR_LUT_DATA"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x11f, METHOD_BUFFERED, FILE_ANY_ACCESS) 542 case IOCTL_VIDEO_GET_CHILD_STATE: 543 return "IOCTL_VIDEO_GET_CHILD_STATE"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x120, METHOD_BUFFERED, FILE_ANY_ACCESS) 544 case IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION: 545 return "IOCTL_VIDEO_VALIDATE_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x121, METHOD_BUFFERED, FILE_ANY_ACCESS) 546 case IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION: 547 return "IOCTL_VIDEO_SET_CHILD_STATE_CONFIGURATION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x122, METHOD_BUFFERED, FILE_ANY_ACCESS) 548 case IOCTL_VIDEO_SWITCH_DUALVIEW: 549 return "IOCTL_VIDEO_SWITCH_DUALVIEW"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x123, METHOD_BUFFERED, FILE_ANY_ACCESS) 550 case IOCTL_VIDEO_SET_BANK_POSITION: 551 return "IOCTL_VIDEO_SET_BANK_POSITION"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x124, METHOD_BUFFERED, FILE_ANY_ACCESS) 552 case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS: 553 return "IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x125, METHOD_BUFFERED, FILE_ANY_ACCESS) 554 case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS: 555 return "IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x126, METHOD_BUFFERED, FILE_ANY_ACCESS) 556 case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS: 557 return "IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x127, METHOD_BUFFERED, FILE_ANY_ACCESS) 558 } 559 560 return "<unknown ioctl code>"; 561 } 562 563 static 564 NTSTATUS 565 VideoPortUseDeviceInSession( 566 _Inout_ PDEVICE_OBJECT DeviceObject, 567 _Inout_ PVIDEO_DEVICE_SESSION_STATUS SessionState, 568 _In_ ULONG BufferLength, 569 _Out_ PULONG_PTR Information) 570 { 571 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 572 573 /* Check buffer size */ 574 *Information = sizeof(VIDEO_DEVICE_SESSION_STATUS); 575 if (BufferLength < sizeof(VIDEO_DEVICE_SESSION_STATUS)) 576 { 577 ERR_(VIDEOPRT, "Buffer too small for VIDEO_DEVICE_SESSION_STATUS: %lx\n", 578 BufferLength); 579 return STATUS_BUFFER_TOO_SMALL; 580 } 581 582 /* Get the device extension */ 583 DeviceExtension = DeviceObject->DeviceExtension; 584 585 /* Shall we enable the session? */ 586 if (SessionState->bEnable) 587 { 588 /* Check if we have no session yet */ 589 if (DeviceExtension->SessionId == -1) 590 { 591 /* Use this session and return success */ 592 DeviceExtension->SessionId = PsGetCurrentProcessSessionId(); 593 SessionState->bSuccess = TRUE; 594 } 595 else 596 { 597 ERR_(VIDEOPRT, "Requested to set session, but session is already set to: 0x%lx\n", 598 DeviceExtension->SessionId); 599 SessionState->bSuccess = FALSE; 600 } 601 } 602 else 603 { 604 /* Check if we belong to the current session */ 605 if (DeviceExtension->SessionId == PsGetCurrentProcessSessionId()) 606 { 607 /* Reset the session and return success */ 608 DeviceExtension->SessionId = -1; 609 SessionState->bSuccess = TRUE; 610 } 611 else 612 { 613 ERR_(VIDEOPRT, "Requested to reset session, but session is not set\n"); 614 SessionState->bSuccess = FALSE; 615 } 616 } 617 618 return STATUS_SUCCESS; 619 } 620 621 static 622 NTSTATUS 623 VideoPortInitWin32kCallbacks( 624 _In_ PDEVICE_OBJECT DeviceObject, 625 _Inout_ PVIDEO_WIN32K_CALLBACKS Win32kCallbacks, 626 _In_ ULONG BufferLength, 627 _Out_ PULONG_PTR Information) 628 { 629 *Information = sizeof(VIDEO_WIN32K_CALLBACKS); 630 if (BufferLength < sizeof(VIDEO_WIN32K_CALLBACKS)) 631 { 632 ERR_(VIDEOPRT, "Buffer too small for VIDEO_WIN32K_CALLBACKS: %lx\n", 633 BufferLength); 634 return STATUS_BUFFER_TOO_SMALL; 635 } 636 637 /* Save the callout function globally */ 638 Win32kCallout = Win32kCallbacks->Callout; 639 640 /* Return reasonable values to Win32k */ 641 Win32kCallbacks->bACPI = FALSE; 642 Win32kCallbacks->pPhysDeviceObject = DeviceObject; 643 Win32kCallbacks->DualviewFlags = 0; 644 645 return STATUS_SUCCESS; 646 } 647 648 static 649 NTSTATUS 650 VideoPortForwardDeviceControl( 651 IN PDEVICE_OBJECT DeviceObject, 652 IN PIRP Irp) 653 { 654 PIO_STACK_LOCATION IrpStack; 655 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 656 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 657 VIDEO_REQUEST_PACKET vrp; 658 659 TRACE_(VIDEOPRT, "VideoPortForwardDeviceControl\n"); 660 661 IrpStack = IoGetCurrentIrpStackLocation(Irp); 662 DeviceExtension = DeviceObject->DeviceExtension; 663 DriverExtension = DeviceExtension->DriverExtension; 664 665 /* Translate the IRP to a VRP */ 666 vrp.StatusBlock = (PSTATUS_BLOCK)&Irp->IoStatus; 667 vrp.IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; 668 669 INFO_(VIDEOPRT, "- IoControlCode: %x\n", vrp.IoControlCode); 670 671 /* We're assuming METHOD_BUFFERED */ 672 vrp.InputBuffer = Irp->AssociatedIrp.SystemBuffer; 673 vrp.InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; 674 vrp.OutputBuffer = Irp->AssociatedIrp.SystemBuffer; 675 vrp.OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; 676 677 /* Call the Miniport Driver with the VRP */ 678 DriverExtension->InitializationData.HwStartIO(&DeviceExtension->MiniPortDeviceExtension, 679 &vrp); 680 681 INFO_(VIDEOPRT, "- Returned status: %x\n", Irp->IoStatus.Status); 682 683 /* Map from win32 error codes to NT status values. */ 684 switch (Irp->IoStatus.Status) 685 { 686 case NO_ERROR: 687 return STATUS_SUCCESS; 688 case ERROR_NOT_ENOUGH_MEMORY: 689 return STATUS_INSUFFICIENT_RESOURCES; 690 case ERROR_MORE_DATA: 691 return STATUS_BUFFER_OVERFLOW; 692 case ERROR_INVALID_FUNCTION: 693 return STATUS_NOT_IMPLEMENTED; 694 case ERROR_INVALID_PARAMETER: 695 return STATUS_INVALID_PARAMETER; 696 case ERROR_INSUFFICIENT_BUFFER: 697 return STATUS_BUFFER_TOO_SMALL; 698 case ERROR_DEV_NOT_EXIST: 699 return STATUS_DEVICE_DOES_NOT_EXIST; 700 case ERROR_IO_PENDING: 701 return STATUS_PENDING; 702 default: 703 return STATUS_UNSUCCESSFUL; 704 } 705 } 706 707 /* 708 * IntVideoPortDispatchDeviceControl 709 * 710 * Answer requests for device control calls. 711 * 712 * Run Level 713 * PASSIVE_LEVEL 714 */ 715 NTSTATUS 716 NTAPI 717 IntVideoPortDispatchDeviceControl( 718 IN PDEVICE_OBJECT DeviceObject, 719 IN PIRP Irp) 720 { 721 PIO_STACK_LOCATION IrpStack; 722 NTSTATUS Status; 723 ULONG IoControlCode; 724 725 TRACE_(VIDEOPRT, "IntVideoPortDispatchDeviceControl\n"); 726 727 IrpStack = IoGetCurrentIrpStackLocation(Irp); 728 729 switch (IrpStack->MajorFunction) 730 { 731 case IRP_MJ_DEVICE_CONTROL: 732 /* This is the main part of this function and is handled below */ 733 break; 734 735 case IRP_MJ_SHUTDOWN: 736 { 737 /* Dereference CSRSS */ 738 PKPROCESS OldCsrProcess; 739 OldCsrProcess = InterlockedExchangePointer((PVOID*)&CsrProcess, NULL); 740 if (OldCsrProcess) 741 ObDereferenceObject(OldCsrProcess); 742 743 Irp->IoStatus.Status = STATUS_SUCCESS; 744 IoCompleteRequest(Irp, IO_NO_INCREMENT); 745 return STATUS_SUCCESS; 746 } 747 748 default: 749 ERR_(VIDEOPRT, "- Unknown MajorFunction 0x%x\n", IrpStack->MajorFunction); 750 Irp->IoStatus.Status = STATUS_SUCCESS; 751 IoCompleteRequest(Irp, IO_NO_INCREMENT); 752 return STATUS_SUCCESS; 753 } 754 755 IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; 756 757 INFO_(VIDEOPRT, "- IoControlCode: 0x%x: %s\n", IoControlCode, IoctlName(IoControlCode)); 758 759 switch (IoControlCode) 760 { 761 case IOCTL_VIDEO_ENABLE_VDM: 762 case IOCTL_VIDEO_DISABLE_VDM: 763 case IOCTL_VIDEO_REGISTER_VDM: 764 WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_VDM are UNIMPLEMENTED!\n"); 765 Status = STATUS_NOT_IMPLEMENTED; 766 break; 767 768 case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE: 769 case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE: 770 WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_OUTPUT_DEVICE_POWER_STATE are UNIMPLEMENTED!\n"); 771 Status = STATUS_NOT_IMPLEMENTED; 772 break; 773 774 case IOCTL_VIDEO_SET_POWER_MANAGEMENT: 775 case IOCTL_VIDEO_GET_POWER_MANAGEMENT: 776 WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_POWER_MANAGEMENT are UNIMPLEMENTED!\n"); 777 Status = STATUS_NOT_IMPLEMENTED; 778 break; 779 780 case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS: 781 case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS: 782 case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS: 783 WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_BRIGHTNESS are UNIMPLEMENTED!\n"); 784 Status = STATUS_NOT_IMPLEMENTED; 785 break; 786 787 case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS: 788 INFO_(VIDEOPRT, "- IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n"); 789 Status = VideoPortInitWin32kCallbacks(DeviceObject, 790 Irp->AssociatedIrp.SystemBuffer, 791 IrpStack->Parameters.DeviceIoControl.InputBufferLength, 792 &Irp->IoStatus.Information); 793 break; 794 795 case IOCTL_VIDEO_IS_VGA_DEVICE: 796 WARN_(VIDEOPRT, "- IOCTL_VIDEO_IS_VGA_DEVICE is UNIMPLEMENTED!\n"); 797 Status = STATUS_NOT_IMPLEMENTED; 798 break; 799 800 case IOCTL_VIDEO_USE_DEVICE_IN_SESSION: 801 INFO_(VIDEOPRT, "- IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n"); 802 Status = VideoPortUseDeviceInSession(DeviceObject, 803 Irp->AssociatedIrp.SystemBuffer, 804 IrpStack->Parameters.DeviceIoControl.InputBufferLength, 805 &Irp->IoStatus.Information); 806 break; 807 808 case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY: 809 INFO_(VIDEOPRT, "- IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n"); 810 /* 811 * The Win32k Watchdog Timer detected that a thread spent more time 812 * in a display driver than the allotted time its threshold specified, 813 * and thus is going to attempt to recover by switching to VGA mode. 814 * If this attempt fails, the watchdog generates bugcheck 0xEA 815 * "THREAD_STUCK_IN_DEVICE_DRIVER". 816 * 817 * Prepare the recovery by resetting the display adapters to 818 * standard VGA 80x25 text mode. 819 */ 820 IntVideoPortResetDisplayParametersEx(80, 25, FALSE); 821 Status = STATUS_SUCCESS; 822 break; 823 824 default: 825 /* Forward to the Miniport Driver */ 826 Status = VideoPortForwardDeviceControl(DeviceObject, Irp); 827 break; 828 } 829 830 INFO_(VIDEOPRT, "- Returned status: 0x%x\n", Status); 831 832 Irp->IoStatus.Status = Status; 833 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); 834 return Status; 835 } 836 837 NTSTATUS 838 NTAPI 839 IntVideoPortPnPStartDevice( 840 IN PDEVICE_OBJECT DeviceObject, 841 IN PIRP Irp) 842 { 843 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); 844 PDRIVER_OBJECT DriverObject; 845 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; 846 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 847 PCM_RESOURCE_LIST AllocatedResources; 848 849 /* Get the initialization data we saved in VideoPortInitialize.*/ 850 DriverObject = DeviceObject->DriverObject; 851 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 852 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 853 854 /* Store some resources in the DeviceExtension. */ 855 AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources; 856 if (AllocatedResources != NULL) 857 { 858 CM_FULL_RESOURCE_DESCRIPTOR *FullList; 859 CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor; 860 ULONG ResourceCount; 861 ULONG ResourceListSize; 862 863 /* Save the resource list */ 864 ResourceCount = AllocatedResources->List[0].PartialResourceList.Count; 865 ResourceListSize = 866 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList. 867 PartialDescriptors[ResourceCount]); 868 DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize); 869 if (DeviceExtension->AllocatedResources == NULL) 870 { 871 return STATUS_INSUFFICIENT_RESOURCES; 872 } 873 874 RtlCopyMemory(DeviceExtension->AllocatedResources, 875 AllocatedResources, 876 ResourceListSize); 877 878 /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */ 879 FullList = AllocatedResources->List; 880 ASSERT(AllocatedResources->Count == 1); 881 INFO_(VIDEOPRT, "InterfaceType %u BusNumber List %u Device BusNumber %u Version %u Revision %u\n", 882 FullList->InterfaceType, FullList->BusNumber, DeviceExtension->SystemIoBusNumber, FullList->PartialResourceList.Version, FullList->PartialResourceList.Revision); 883 884 /* FIXME: Is this ASSERT ok for resources from the PNP manager? */ 885 ASSERT(FullList->InterfaceType == PCIBus); 886 ASSERT(FullList->BusNumber == DeviceExtension->SystemIoBusNumber); 887 ASSERT(1 == FullList->PartialResourceList.Version); 888 ASSERT(1 == FullList->PartialResourceList.Revision); 889 for (Descriptor = FullList->PartialResourceList.PartialDescriptors; 890 Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count; 891 Descriptor++) 892 { 893 if (Descriptor->Type == CmResourceTypeInterrupt) 894 { 895 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level; 896 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector; 897 if (Descriptor->ShareDisposition == CmResourceShareShared) 898 DeviceExtension->InterruptShared = TRUE; 899 else 900 DeviceExtension->InterruptShared = FALSE; 901 } 902 } 903 } 904 905 INFO_(VIDEOPRT, "Interrupt level: 0x%x Interrupt Vector: 0x%x\n", 906 DeviceExtension->InterruptLevel, 907 DeviceExtension->InterruptVector); 908 909 /* Create adapter device object. */ 910 return IntVideoPortFindAdapter(DriverObject, 911 DriverExtension, 912 DeviceObject); 913 } 914 915 916 NTSTATUS 917 NTAPI 918 IntVideoPortForwardIrpAndWaitCompletionRoutine( 919 PDEVICE_OBJECT Fdo, 920 PIRP Irp, 921 PVOID Context) 922 { 923 PKEVENT Event = Context; 924 925 if (Irp->PendingReturned) 926 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 927 928 return STATUS_MORE_PROCESSING_REQUIRED; 929 } 930 931 NTSTATUS 932 NTAPI 933 IntVideoPortQueryBusRelations(PDEVICE_OBJECT DeviceObject, PIRP Irp) 934 { 935 PDEVICE_RELATIONS DeviceRelations; 936 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 937 PVIDEO_PORT_CHILD_EXTENSION ChildExtension; 938 ULONG i; 939 PLIST_ENTRY CurrentEntry; 940 941 /* Count the children */ 942 i = 0; 943 CurrentEntry = DeviceExtension->ChildDeviceList.Flink; 944 while (CurrentEntry != &DeviceExtension->ChildDeviceList) 945 { 946 i++; 947 CurrentEntry = CurrentEntry->Flink; 948 } 949 950 if (i == 0) 951 return Irp->IoStatus.Status; 952 953 DeviceRelations = ExAllocatePool(PagedPool, 954 sizeof(DEVICE_RELATIONS) + ((i - 1) * sizeof(PVOID))); 955 if (!DeviceRelations) return STATUS_NO_MEMORY; 956 957 DeviceRelations->Count = i; 958 959 /* Add the children */ 960 i = 0; 961 CurrentEntry = DeviceExtension->ChildDeviceList.Flink; 962 while (CurrentEntry != &DeviceExtension->ChildDeviceList) 963 { 964 ChildExtension = CONTAINING_RECORD(CurrentEntry, VIDEO_PORT_CHILD_EXTENSION, ListEntry); 965 966 ObReferenceObject(ChildExtension->PhysicalDeviceObject); 967 DeviceRelations->Objects[i] = ChildExtension->PhysicalDeviceObject; 968 969 i++; 970 CurrentEntry = CurrentEntry->Flink; 971 } 972 973 INFO_(VIDEOPRT, "Reported %d PDOs\n", i); 974 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 975 976 return STATUS_SUCCESS; 977 } 978 979 NTSTATUS 980 NTAPI 981 IntVideoPortForwardIrpAndWait(PDEVICE_OBJECT DeviceObject, PIRP Irp) 982 { 983 KEVENT Event; 984 NTSTATUS Status; 985 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = 986 (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 987 988 KeInitializeEvent(&Event, NotificationEvent, FALSE); 989 IoCopyCurrentIrpStackLocationToNext(Irp); 990 IoSetCompletionRoutine(Irp, 991 IntVideoPortForwardIrpAndWaitCompletionRoutine, 992 &Event, 993 TRUE, 994 TRUE, 995 TRUE); 996 997 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 998 if (Status == STATUS_PENDING) 999 { 1000 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 1001 Status = Irp->IoStatus.Status; 1002 } 1003 1004 return Status; 1005 } 1006 1007 NTSTATUS 1008 NTAPI 1009 IntVideoPortDispatchFdoPnp( 1010 IN PDEVICE_OBJECT DeviceObject, 1011 IN PIRP Irp) 1012 { 1013 PIO_STACK_LOCATION IrpSp; 1014 NTSTATUS Status; 1015 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 1016 1017 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1018 1019 switch (IrpSp->MinorFunction) 1020 { 1021 case IRP_MN_START_DEVICE: 1022 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); 1023 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) 1024 Status = IntVideoPortPnPStartDevice(DeviceObject, Irp); 1025 Irp->IoStatus.Status = Status; 1026 Irp->IoStatus.Information = 0; 1027 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1028 break; 1029 1030 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 1031 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); 1032 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) 1033 Status = IntVideoPortFilterResourceRequirements(DeviceObject, Irp); 1034 Irp->IoStatus.Status = Status; 1035 Irp->IoStatus.Information = 0; 1036 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1037 break; 1038 1039 case IRP_MN_QUERY_DEVICE_RELATIONS: 1040 if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) 1041 { 1042 IoSkipCurrentIrpStackLocation(Irp); 1043 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1044 } 1045 else 1046 { 1047 Status = IntVideoPortQueryBusRelations(DeviceObject, Irp); 1048 Irp->IoStatus.Status = Status; 1049 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1050 } 1051 break; 1052 1053 case IRP_MN_REMOVE_DEVICE: 1054 case IRP_MN_QUERY_REMOVE_DEVICE: 1055 case IRP_MN_CANCEL_REMOVE_DEVICE: 1056 case IRP_MN_SURPRISE_REMOVAL: 1057 1058 case IRP_MN_STOP_DEVICE: 1059 Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); 1060 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) 1061 Status = STATUS_SUCCESS; 1062 Irp->IoStatus.Status = Status; 1063 Irp->IoStatus.Information = 0; 1064 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1065 break; 1066 1067 case IRP_MN_QUERY_STOP_DEVICE: 1068 case IRP_MN_CANCEL_STOP_DEVICE: 1069 Status = STATUS_SUCCESS; 1070 Irp->IoStatus.Status = STATUS_SUCCESS; 1071 Irp->IoStatus.Information = 0; 1072 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1073 break; 1074 1075 default: 1076 Status = Irp->IoStatus.Status; 1077 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1078 break; 1079 } 1080 1081 return Status; 1082 } 1083 1084 NTSTATUS 1085 NTAPI 1086 IntVideoPortDispatchPnp( 1087 IN PDEVICE_OBJECT DeviceObject, 1088 IN PIRP Irp) 1089 { 1090 PVIDEO_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension; 1091 1092 if (CommonExtension->Fdo) 1093 return IntVideoPortDispatchFdoPnp(DeviceObject, Irp); 1094 else 1095 return IntVideoPortDispatchPdoPnp(DeviceObject, Irp); 1096 } 1097 1098 NTSTATUS 1099 NTAPI 1100 IntVideoPortDispatchCleanup( 1101 IN PDEVICE_OBJECT DeviceObject, 1102 IN PIRP Irp) 1103 { 1104 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; 1105 1106 DeviceExtension = DeviceObject->DeviceExtension; 1107 RtlFreeUnicodeString(&DeviceExtension->RegistryPath); 1108 1109 Irp->IoStatus.Status = STATUS_SUCCESS; 1110 Irp->IoStatus.Information = 0; 1111 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1112 1113 return STATUS_SUCCESS; 1114 } 1115 1116 NTSTATUS 1117 NTAPI 1118 IntVideoPortDispatchPower( 1119 IN PDEVICE_OBJECT DeviceObject, 1120 IN PIRP Irp) 1121 { 1122 PIO_STACK_LOCATION IrpSp; 1123 NTSTATUS Status = Irp->IoStatus.Status; 1124 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 1125 1126 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1127 1128 if (DeviceExtension->Common.Fdo) 1129 { 1130 PoStartNextPowerIrp(Irp); 1131 IoSkipCurrentIrpStackLocation(Irp); 1132 return PoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1133 } 1134 else 1135 { 1136 switch (IrpSp->MinorFunction) 1137 { 1138 case IRP_MN_QUERY_POWER: 1139 case IRP_MN_SET_POWER: 1140 Status = STATUS_SUCCESS; 1141 break; 1142 } 1143 PoStartNextPowerIrp(Irp); 1144 Irp->IoStatus.Status = Status; 1145 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1146 return Status; 1147 } 1148 } 1149 1150 NTSTATUS 1151 NTAPI 1152 IntVideoPortDispatchSystemControl( 1153 IN PDEVICE_OBJECT DeviceObject, 1154 IN PIRP Irp) 1155 { 1156 NTSTATUS Status; 1157 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 1158 1159 if (DeviceExtension->Common.Fdo) 1160 { 1161 IoSkipCurrentIrpStackLocation(Irp); 1162 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 1163 } 1164 else 1165 { 1166 Status = Irp->IoStatus.Status; 1167 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1168 return Status; 1169 } 1170 } 1171 1172 VOID 1173 NTAPI 1174 IntVideoPortUnload(PDRIVER_OBJECT DriverObject) 1175 { 1176 } 1177