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