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