diff --git a/sdk/include/psdk/ntddvdeo.h b/sdk/include/psdk/ntddvdeo.h index 8fcd361f502..5e2b63b7214 100644 --- a/sdk/include/psdk/ntddvdeo.h +++ b/sdk/include/psdk/ntddvdeo.h @@ -75,7 +75,7 @@ extern "C" { CTL_CODE(FILE_DEVICE_VIDEO, 0x0b, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_VIDEO_DISABLE_CURSOR \ - CTL_CODE (FILE_DEVICE_VIDEO, 0x109, METHOD_BUFFERED, FILE_ANY_ACCESS) + CTL_CODE(FILE_DEVICE_VIDEO, 0x109, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_VIDEO_DISABLE_POINTER \ CTL_CODE(FILE_DEVICE_VIDEO, 0x10f, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -254,7 +254,7 @@ typedef struct _VIDEO_WIN32K_CALLBACKS_PARAMS { typedef VOID -(*PVIDEO_WIN32K_CALLOUT)( +(NTAPI *PVIDEO_WIN32K_CALLOUT)( _In_ PVOID Params); typedef struct _VIDEO_WIN32K_CALLBACKS { diff --git a/win32ss/drivers/videoprt/CMakeLists.txt b/win32ss/drivers/videoprt/CMakeLists.txt index 664f8cb7c62..be116547d59 100644 --- a/win32ss/drivers/videoprt/CMakeLists.txt +++ b/win32ss/drivers/videoprt/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(videoprt MODULE ${CMAKE_CURRENT_BINARY_DIR}/videoprt.def) set_module_type(videoprt kernelmodedriver) +target_link_libraries(videoprt ${PSEH_LIB}) add_importlibs(videoprt ntoskrnl hal) add_pch(videoprt videoprt.h SOURCE) add_cd_file(TARGET videoprt DESTINATION reactos/system32/drivers FOR all) diff --git a/win32ss/drivers/videoprt/dispatch.c b/win32ss/drivers/videoprt/dispatch.c index d1682549185..42f7023b0b1 100644 --- a/win32ss/drivers/videoprt/dispatch.c +++ b/win32ss/drivers/videoprt/dispatch.c @@ -22,6 +22,7 @@ #include "videoprt.h" #include +#include #include #define NDEBUG @@ -29,40 +30,280 @@ /* GLOBAL VARIABLES ***********************************************************/ -PVIDEO_PORT_DEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL; -PVIDEO_WIN32K_CALLOUT Win32kCallout; +static PVIDEO_WIN32K_CALLOUT Win32kCallout = NULL; +static HANDLE InbvThreadHandle = NULL; +static BOOLEAN InbvMonitoring = FALSE; /* PRIVATE FUNCTIONS **********************************************************/ +static VOID +VideoPortWin32kCallout( + _In_ PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams) +{ + if (!Win32kCallout) + return; + + /* Perform the call in the context of CSRSS */ + if (!CsrProcess) + return; + + KeAttachProcess(CsrProcess); + Win32kCallout(CallbackParams); + KeDetachProcess(); +} + /* - * Reset display to blue screen + * Reinitialize the display to base VGA mode. + * + * Returns TRUE if it completely resets the adapter to the given character mode. + * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode + * reset itself after HwVidResetHw() returns control. + * + * This callback has been registered with InbvNotifyDisplayOwnershipLost() + * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck + * code regains display access. Therefore this routine can be called at any + * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside + * completely in non-paged pool, and cannot perform the following actions: + * Allocate memory, access pageable memory, use any synchronization mechanisms + * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below. */ -BOOLEAN +static BOOLEAN +NTAPI +IntVideoPortResetDisplayParametersEx( + _In_ ULONG Columns, + _In_ ULONG Rows, + _In_ BOOLEAN CalledByInbv) +{ + BOOLEAN Success = TRUE; + PLIST_ENTRY PrevEntry, Entry; + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; + + if (IsListEmpty(&HwResetAdaptersList)) + return FALSE; + + if (CalledByInbv) + { + /* + * We have been unexpectedly called via a callback from + * InbvAcquireDisplayOwnership(): start monitoring INBV. + */ + InbvMonitoring = TRUE; + } + + for (PrevEntry = &HwResetAdaptersList, Entry = PrevEntry->Flink; + Entry != &HwResetAdaptersList; + PrevEntry = Entry, Entry = Entry->Flink) + { + /* + * Check whether the entry address is properly aligned, + * the device and driver extensions must be readable and + * the device extension properly back-linked to the last entry. + */ +// #define IS_ALIGNED(addr, align) (((ULONG64)(addr) & (align - 1)) == 0) + if (((ULONG_PTR)Entry & (sizeof(ULONG_PTR) - 1)) != 0) + return FALSE; + + DeviceExtension = CONTAINING_RECORD(Entry, + VIDEO_PORT_DEVICE_EXTENSION, + HwResetListEntry); + /* + * As this function can be called as part of the INBV initialization + * by the bugcheck code, avoid any problems and protect all accesses + * within SEH. + */ + _SEH2_TRY + { + DriverExtension = DeviceExtension->DriverExtension; + ASSERT(DriverExtension); + + if (DeviceExtension->HwResetListEntry.Blink != PrevEntry) + _SEH2_YIELD(return FALSE); + + if ((DeviceExtension->DeviceOpened >= 1) && + (DriverExtension->InitializationData.HwResetHw != NULL)) + { + Success &= DriverExtension->InitializationData.HwResetHw( + &DeviceExtension->MiniPortDeviceExtension, + Columns, Rows); + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + } + + return Success; +} + +/* This callback is registered with InbvNotifyDisplayOwnershipLost() */ +static BOOLEAN NTAPI IntVideoPortResetDisplayParameters(ULONG Columns, ULONG Rows) { - PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; + /* Call the extended function, specifying we were called by INBV */ + return IntVideoPortResetDisplayParametersEx(Columns, Rows, TRUE); +} - if (ResetDisplayParametersDeviceExtension == NULL) - return FALSE; +/* + * (Adapted for ReactOS/Win2k3 from an original comment + * by Gé van Geldorp, June 2003, r4937) + * + * DISPLAY OWNERSHIP + * + * So, who owns the physical display and is allowed to write to it? + * + * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless + * /NOGUIBOOT has been specified in the boot command line. Later in the boot + * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in + * VIDEOPRT.SYS. This component takes ownership of the display by calling + * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release + * ownership of the display it previously had. From that moment on, the display + * is owned by that component and can be switched to graphics mode. The display + * is not supposed to return to text mode, except in case of a bugcheck. + * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV + * re-take display ownership, and calls back the function previously registered + * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck, + * execution is halted. So, under NT, the only possible sequence of display + * modes is text mode -> graphics mode -> text mode (the latter hopefully + * happening very infrequently). + * + * In ReactOS things are a little bit different. We want to have a functional + * interactive text mode. We should be able to switch back and forth from + * text mode to graphics mode when a GUI app is started and then finished. + * Also, when the system bugchecks in graphics mode we want to switch back to + * text mode and show the bugcheck information. Last but not least, when using + * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a + * switch to text mode, and the user would expect that by continuing execution + * a switch back to graphics mode is done. + */ +static VOID +NTAPI +InbvMonitorThread( + _In_ PVOID Context) +{ + VIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams; + LARGE_INTEGER Delay; + USHORT i; - DriverExtension = ResetDisplayParametersDeviceExtension->DriverExtension; + KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); - if (DriverExtension->InitializationData.HwResetHw != NULL) + while (TRUE) { - if (DriverExtension->InitializationData.HwResetHw( - &ResetDisplayParametersDeviceExtension->MiniPortDeviceExtension, - Columns, Rows)) + /* + * During one second, check the INBV status each 100 milliseconds, + * then revert to 1 second delay. + */ + i = 10; + Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay + while (!InbvMonitoring) { - ResetDisplayParametersDeviceExtension = NULL; - return TRUE; + KeDelayExecutionThread(KernelMode, FALSE, &Delay); + + if ((i > 0) && (--i == 0)) + Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay } + + /* + * Loop while the display is owned by INBV. We cannot do anything else + * than polling since INBV does not offer a proper notification system. + * + * During one second, check the INBV status each 100 milliseconds, + * then revert to 1 second delay. + */ + i = 10; + Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay + while (InbvCheckDisplayOwnership()) + { + KeDelayExecutionThread(KernelMode, FALSE, &Delay); + + if ((i > 0) && (--i == 0)) + Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay + } + + /* Reset the monitoring */ + InbvMonitoring = FALSE; + + /* + * Somebody released INBV display ownership, usually by invoking + * InbvNotifyDisplayOwnershipLost(). However the caller of this + * function certainly specified a different callback than ours. + * As we are going to be the only owner of the active display, + * we need to re-register our own display reset callback. + */ + InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters); + + /* Tell Win32k to reset the display */ + CallbackParams.CalloutType = VideoFindAdapterCallout; + // CallbackParams.PhysDisp = NULL; + CallbackParams.Param = (ULONG_PTR)TRUE; // TRUE: Re-enable display; FALSE: Disable display. + VideoPortWin32kCallout(&CallbackParams); } - ResetDisplayParametersDeviceExtension = NULL; - return FALSE; + // FIXME: See IntVideoPortInbvCleanup(). + // PsTerminateSystemThread(STATUS_SUCCESS); } +static NTSTATUS +IntVideoPortInbvInitialize(VOID) +{ + /* Create the INBV monitoring thread if needed */ + if (!InbvThreadHandle) + { + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE); + + Status = PsCreateSystemThread(&InbvThreadHandle, + 0, + &ObjectAttributes, + NULL, + NULL, + InbvMonitorThread, + NULL); + if (!NT_SUCCESS(Status)) + InbvThreadHandle = NULL; + } + + /* Re-register the display reset callback with INBV */ + InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters); + + return STATUS_SUCCESS; +} + +static NTSTATUS +IntVideoPortInbvCleanup( + IN PDEVICE_OBJECT DeviceObject) +{ + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + // HANDLE ThreadHandle; + + DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + if ((DeviceExtension->DeviceOpened >= 1) && + (InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0)) + { + // RemoveEntryList(&DeviceExtension->HwResetListEntry); + InbvNotifyDisplayOwnershipLost(NULL); + IntVideoPortResetDisplayParametersEx(80, 50, FALSE); + // or InbvAcquireDisplayOwnership(); ? + } + +#if 0 + // TODO: Find the best way to communicate the request. + /* Signal the INBV monitoring thread and wait for it to terminate */ + ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL); + if (ThreadHandle) + { + KeWaitForSingleObject(&ThreadHandle, Executive, KernelMode, FALSE, NULL); + /* Close its handle */ + ObCloseHandle(ThreadHandle, KernelMode); + } +#endif + + return STATUS_SUCCESS; +} + + NTSTATUS NTAPI IntVideoPortAddDevice( @@ -101,36 +342,39 @@ IntVideoPortDispatchOpen( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { + NTSTATUS Status; PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; PVIDEO_PORT_DRIVER_EXTENSION DriverExtension; - NTSTATUS Status; TRACE_(VIDEOPRT, "IntVideoPortDispatchOpen\n"); - if (CsrssInitialized == FALSE) + if (!CsrProcess) { /* * We know the first open call will be from the CSRSS process * to let us know its handle. */ - INFO_(VIDEOPRT, "Referencing CSRSS\n"); - Csrss = (PKPROCESS)PsGetCurrentProcess(); - INFO_(VIDEOPRT, "Csrss %p\n", Csrss); + CsrProcess = (PKPROCESS)PsGetCurrentProcess(); + ObReferenceObject(CsrProcess); + INFO_(VIDEOPRT, "CsrProcess 0x%p\n", CsrProcess); Status = IntInitializeVideoAddressSpace(); if (!NT_SUCCESS(Status)) { ERR_(VIDEOPRT, "IntInitializeVideoAddressSpace() failed: 0x%lx\n", Status); + ObDereferenceObject(CsrProcess); + CsrProcess = NULL; return Status; } - - CsrssInitialized = TRUE; } DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; DriverExtension = DeviceExtension->DriverExtension; + // FIXME: (Re-)initialize INBV only if DeviceObject doesn't belong to a mirror driver. + IntVideoPortInbvInitialize(); + if (DriverExtension->InitializationData.HwInitialize(&DeviceExtension->MiniPortDeviceExtension)) { Irp->IoStatus.Status = STATUS_SUCCESS; @@ -161,30 +405,19 @@ IntVideoPortDispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - TRACE_(VIDEOPRT, "IntVideoPortDispatchClose\n"); - DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - if ((DeviceExtension->DeviceOpened >= 1) && - (InterlockedDecrement((PLONG)&DeviceExtension->DeviceOpened) == 0)) - { - ResetDisplayParametersDeviceExtension = NULL; - InbvNotifyDisplayOwnershipLost(NULL); - ResetDisplayParametersDeviceExtension = DeviceExtension; - IntVideoPortResetDisplayParameters(80, 50); - } + IntVideoPortInbvCleanup(DeviceObject); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; } PSTR IoctlName(ULONG Ioctl) { - switch(Ioctl) + switch (Ioctl) { case IOCTL_VIDEO_ENABLE_VDM: return "IOCTL_VIDEO_ENABLE_VDM"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -296,7 +529,7 @@ IoctlName(ULONG Ioctl) return "IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS"; // CTL_CODE(FILE_DEVICE_VIDEO, 0x127, METHOD_BUFFERED, FILE_ANY_ACCESS) } - return ""; } static @@ -376,7 +609,7 @@ VideoPortInitWin32kCallbacks( /* Save the callout function globally */ Win32kCallout = Win32kCallbacks->Callout; - /* Return reasonable values to win32k */ + /* Return reasonable values to Win32k */ Win32kCallbacks->bACPI = FALSE; Win32kCallbacks->pPhysDeviceObject = DeviceObject; Win32kCallbacks->DualviewFlags = 0; @@ -465,12 +698,64 @@ IntVideoPortDispatchDeviceControl( IrpStack = IoGetCurrentIrpStackLocation(Irp); + switch (IrpStack->MajorFunction) + { + case IRP_MJ_DEVICE_CONTROL: + /* This is the main part of this function and is handled below */ + break; + + case IRP_MJ_SHUTDOWN: + { + /* Dereference CSRSS */ + PKPROCESS OldCsrProcess; + OldCsrProcess = InterlockedExchangePointer((PVOID*)&CsrProcess, NULL); + if (OldCsrProcess) + ObDereferenceObject(OldCsrProcess); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + + default: + ERR_(VIDEOPRT, "- Unknown MajorFunction 0x%x\n", IrpStack->MajorFunction); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; - INFO_(VIDEOPRT, "- IoControlCode: %x: %s\n", IoControlCode, IoctlName(IoControlCode)); + INFO_(VIDEOPRT, "- IoControlCode: 0x%x: %s\n", IoControlCode, IoctlName(IoControlCode)); - switch(IoControlCode) + switch (IoControlCode) { + case IOCTL_VIDEO_ENABLE_VDM: + case IOCTL_VIDEO_DISABLE_VDM: + case IOCTL_VIDEO_REGISTER_VDM: + WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_VDM are UNIMPLEMENTED!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + + case IOCTL_VIDEO_SET_OUTPUT_DEVICE_POWER_STATE: + case IOCTL_VIDEO_GET_OUTPUT_DEVICE_POWER_STATE: + WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_OUTPUT_DEVICE_POWER_STATE are UNIMPLEMENTED!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + + case IOCTL_VIDEO_SET_POWER_MANAGEMENT: + case IOCTL_VIDEO_GET_POWER_MANAGEMENT: + WARN_(VIDEOPRT, "- IOCTL_VIDEO_GET/SET_POWER_MANAGEMENT are UNIMPLEMENTED!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + + case IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS: + case IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS: + case IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS: + WARN_(VIDEOPRT, "- IOCTL_VIDEO_*_BRIGHTNESS are UNIMPLEMENTED!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + case IOCTL_VIDEO_INIT_WIN32K_CALLBACKS: INFO_(VIDEOPRT, "- IOCTL_VIDEO_INIT_WIN32K_CALLBACKS\n"); Status = VideoPortInitWin32kCallbacks(DeviceObject, @@ -479,6 +764,11 @@ IntVideoPortDispatchDeviceControl( &Irp->IoStatus.Information); break; + case IOCTL_VIDEO_IS_VGA_DEVICE: + WARN_(VIDEOPRT, "- IOCTL_VIDEO_IS_VGA_DEVICE is UNIMPLEMENTED!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + case IOCTL_VIDEO_USE_DEVICE_IN_SESSION: INFO_(VIDEOPRT, "- IOCTL_VIDEO_USE_DEVICE_IN_SESSION\n"); Status = VideoPortUseDeviceInSession(DeviceObject, @@ -487,71 +777,35 @@ IntVideoPortDispatchDeviceControl( &Irp->IoStatus.Information); break; + case IOCTL_VIDEO_PREPARE_FOR_EARECOVERY: + INFO_(VIDEOPRT, "- IOCTL_VIDEO_PREPARE_FOR_EARECOVERY\n"); + /* + * The Win32k Watchdog Timer detected that a thread spent more time + * in a display driver than the allotted time its threshold specified, + * and thus is going to attempt to recover by switching to VGA mode. + * If this attempt fails, the watchdog generates bugcheck 0xEA + * "THREAD_STUCK_IN_DEVICE_DRIVER". + * + * Prepare the recovery by resetting the display adapters to + * standard VGA 80x25 text mode. + */ + IntVideoPortResetDisplayParametersEx(80, 25, FALSE); + Status = STATUS_SUCCESS; + break; + default: /* Forward to the Miniport Driver */ Status = VideoPortForwardDeviceControl(DeviceObject, Irp); break; } - INFO_(VIDEOPRT, "- Returned status: %x\n", Irp->IoStatus.Status); + INFO_(VIDEOPRT, "- Returned status: 0x%x\n", Status); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; } -/* - * IntVideoPortWrite - * - * This is a bit of a hack. We want to take ownership of the display as late - * as possible, just before the switch to graphics mode. Win32k knows when - * this happens, we don't. So we need Win32k to inform us. This could be done - * using an IOCTL, but there's no way of knowing which IOCTL codes are unused - * in the communication between GDI driver and miniport driver. So we use - * IRP_MJ_WRITE as the signal that win32k is ready to switch to graphics mode, - * since we know for certain that there is no read/write activity going on - * between GDI and miniport drivers. - * We don't actually need the data that is passed, we just trigger on the fact - * that an IRP_MJ_WRITE was sent. - * - * Run Level - * PASSIVE_LEVEL - */ -NTSTATUS -NTAPI -IntVideoPortDispatchWrite( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - PIO_STACK_LOCATION piosStack = IoGetCurrentIrpStackLocation(Irp); - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - NTSTATUS nErrCode; - - DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - /* - * Storing the device extension pointer in a static variable is an - * ugly hack. Unfortunately, we need it in IntVideoPortResetDisplayParameters - * and InbvNotifyDisplayOwnershipLost doesn't allow us to pass a userdata - * parameter. On the bright side, the DISPLAY device is opened - * exclusively, so there can be only one device extension active at - * any point in time. - * - * FIXME: We should process all opened display devices in - * IntVideoPortResetDisplayParameters. - */ - ResetDisplayParametersDeviceExtension = DeviceExtension; - InbvNotifyDisplayOwnershipLost(IntVideoPortResetDisplayParameters); - - nErrCode = STATUS_SUCCESS; - Irp->IoStatus.Information = piosStack->Parameters.Write.Length; - Irp->IoStatus.Status = nErrCode; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return nErrCode; -} - NTSTATUS NTAPI IntVideoPortPnPStartDevice( diff --git a/win32ss/drivers/videoprt/int10.c b/win32ss/drivers/videoprt/int10.c index f83ed0f3dd2..caa50ddfc35 100644 --- a/win32ss/drivers/videoprt/int10.c +++ b/win32ss/drivers/videoprt/int10.c @@ -393,7 +393,7 @@ VideoPortInt10( INT10_BIOS_ARGUMENTS Int10BiosArguments; VP_STATUS Status; - if (!CsrssInitialized) + if (!CsrProcess) { return ERROR_INVALID_PARAMETER; } diff --git a/win32ss/drivers/videoprt/videoprt.c b/win32ss/drivers/videoprt/videoprt.c index 812f55ad6af..6e75d563ea9 100644 --- a/win32ss/drivers/videoprt/videoprt.c +++ b/win32ss/drivers/videoprt/videoprt.c @@ -30,10 +30,10 @@ /* GLOBAL VARIABLES ***********************************************************/ -ULONG CsrssInitialized = FALSE; -PKPROCESS Csrss = NULL; +PKPROCESS CsrProcess = NULL; ULONG VideoPortDeviceNumber = 0; KMUTEX VideoPortInt10Mutex; +RTL_STATIC_LIST_HEAD(HwResetAdaptersList); /* PRIVATE FUNCTIONS **********************************************************/ @@ -406,6 +406,14 @@ IntVideoPortFindAdapter( goto Failure; } + /* If the device can be reset, insert it in the list of resettable adapters */ + InitializeListHead(&DeviceExtension->HwResetListEntry); + if (DriverExtension->InitializationData.HwResetHw != NULL) + { + InsertTailList(&HwResetAdaptersList, + &DeviceExtension->HwResetListEntry); + } + /* Query children of the device. */ VideoPortEnumerateChildren(&DeviceExtension->MiniPortDeviceExtension, NULL); @@ -427,9 +435,9 @@ IntAttachToCSRSS( PKAPC_STATE ApcState) { *CallingProcess = (PKPROCESS)PsGetCurrentProcess(); - if (*CallingProcess != Csrss) + if (*CallingProcess != CsrProcess) { - KeStackAttachProcess(Csrss, ApcState); + KeStackAttachProcess(CsrProcess, ApcState); } } @@ -439,7 +447,7 @@ IntDetachFromCSRSS( PKPROCESS *CallingProcess, PKAPC_STATE ApcState) { - if (*CallingProcess != Csrss) + if (*CallingProcess != CsrProcess) { KeUnstackDetachProcess(ApcState); } @@ -516,10 +524,8 @@ VideoPortInitialize( DriverObject->MajorFunction[IRP_MJ_CLOSE] = IntVideoPortDispatchClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IntVideoPortDispatchDeviceControl; - DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = IntVideoPortDispatchDeviceControl; - DriverObject->MajorFunction[IRP_MJ_WRITE] = - IntVideoPortDispatchWrite; // ReactOS-specific hack DriverObject->DriverUnload = IntVideoPortUnload; /* Determine type of the miniport driver */ @@ -608,8 +614,8 @@ VideoPortInitialize( DriverExtension->HwContext = HwContext; /* - * Plug & Play drivers registers the device in AddDevice routine. For - * legacy drivers we must do it now. + * Plug & Play drivers registers the device in AddDevice routine. + * For legacy drivers we must do it now. */ if (LegacyDetection) { @@ -617,7 +623,7 @@ VideoPortInitialize( if (HwInitializationData->HwInitDataSize != SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA) { - /* power management */ + /* Power management */ DriverObject->MajorFunction[IRP_MJ_POWER] = IntVideoPortDispatchPower; } diff --git a/win32ss/drivers/videoprt/videoprt.h b/win32ss/drivers/videoprt/videoprt.h index 3490e5625ba..94289dc031a 100644 --- a/win32ss/drivers/videoprt/videoprt.h +++ b/win32ss/drivers/videoprt/videoprt.h @@ -32,11 +32,14 @@ #include #include -#define TAG_VIDEO_PORT 'PDIV' -#define TAG_VIDEO_PORT_BUFFER '\0mpV' -#define TAG_REQUEST_PACKET 'qRpV' +/* PSEH for SEH Support */ +#include -#define GUID_STRING_LENGTH 38 * sizeof(WCHAR) +#define TAG_VIDEO_PORT 'PDIV' +#define TAG_VIDEO_PORT_BUFFER '\0mpV' +#define TAG_REQUEST_PACKET 'qRpV' + +#define GUID_STRING_LENGTH (38 * sizeof(WCHAR)) typedef struct _VIDEO_PORT_ADDRESS_MAPPING { @@ -102,6 +105,7 @@ typedef struct _VIDEO_PORT_DEVICE_EXTENSTION AGP_BUS_INTERFACE_STANDARD AgpInterface; KMUTEX DeviceLock; LIST_ENTRY DmaAdapterList, ChildDeviceList; + LIST_ENTRY HwResetListEntry; ULONG SessionId; CHAR MiniPortDeviceExtension[1]; } VIDEO_PORT_DEVICE_EXTENSION, *PVIDEO_PORT_DEVICE_EXTENSION; @@ -204,11 +208,6 @@ IntVideoPortDispatchSystemControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); -NTSTATUS NTAPI -IntVideoPortDispatchWrite( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp); - VOID NTAPI IntVideoPortUnload(PDRIVER_OBJECT DriverObject); @@ -244,10 +243,10 @@ IntVideoPortMapPhysicalMemory( /* videoprt.c */ -extern ULONG CsrssInitialized; -extern PKPROCESS Csrss; +extern PKPROCESS CsrProcess; extern ULONG VideoPortDeviceNumber; extern KMUTEX VideoPortInt10Mutex; +extern LIST_ENTRY HwResetAdaptersList; VOID FASTCALL IntAttachToCSRSS(PKPROCESS *CallingProcess, PKAPC_STATE ApcState); diff --git a/win32ss/gdi/eng/device.c b/win32ss/gdi/eng/device.c index 7691aad92f5..21f63f86a7c 100644 --- a/win32ss/gdi/eng/device.c +++ b/win32ss/gdi/eng/device.c @@ -8,7 +8,9 @@ */ #include -DBG_DEFAULT_CHANNEL(EngDev) +#include + +DBG_DEFAULT_CHANNEL(EngDev); PGRAPHICS_DEVICE gpPrimaryGraphicsDevice; PGRAPHICS_DEVICE gpVgaGraphicsDevice; @@ -156,6 +158,70 @@ EngpPopulateDeviceModeList( return TRUE; } +extern VOID +UserRefreshDisplay(IN PPDEVOBJ ppdev); + +// PVIDEO_WIN32K_CALLOUT +VOID +NTAPI +VideoPortCallout( + _In_ PVOID Params) +{ +/* + * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of + * a specific VideoPortCalloutThread() system thread using the same mechanism + * as the RIT/desktop/Ghost system threads. + */ + + PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params; + + TRACE("VideoPortCallout(0x%p, 0x%x)\n", + CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1); + + if (!CallbackParams) + return; + + switch (CallbackParams->CalloutType) + { + case VideoFindAdapterCallout: + { + TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n", + CallbackParams->Param ? "TRUE" : "FALSE"); + if (CallbackParams->Param == TRUE) + { + /* Re-enable the display */ + UserRefreshDisplay(gppdevPrimary); + } + else + { + /* Disable the display */ + NOTHING; // Nothing to do for the moment... + } + + CallbackParams->Status = STATUS_SUCCESS; + break; + } + + case VideoPowerNotifyCallout: + case VideoDisplaySwitchCallout: + case VideoEnumChildPdoNotifyCallout: + case VideoWakeupCallout: + case VideoChangeDisplaySettingsCallout: + case VideoPnpNotifyCallout: + case VideoDxgkDisplaySwitchCallout: + case VideoDxgkMonitorEventCallout: + case VideoDxgkFindAdapterTdrCallout: + ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType); + CallbackParams->Status = STATUS_NOT_IMPLEMENTED; + break; + + default: + ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType); + CallbackParams->Status = STATUS_UNSUCCESSFUL; + break; + } +} + PGRAPHICS_DEVICE NTAPI EngpRegisterGraphicsDevice( @@ -168,10 +234,10 @@ EngpRegisterGraphicsDevice( PDEVICE_OBJECT pDeviceObject; PFILE_OBJECT pFileObject; NTSTATUS Status; + VIDEO_WIN32K_CALLBACKS Win32kCallbacks; + ULONG ulReturn; PWSTR pwsz; ULONG cj; - SIZE_T cjWritten; - BOOL bEnable = TRUE; TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName); @@ -197,13 +263,34 @@ EngpRegisterGraphicsDevice( return NULL; } - /* Enable the device */ - EngFileWrite(pFileObject, &bEnable, sizeof(BOOL), &cjWritten); - /* Copy the device and file object pointers */ pGraphicsDevice->DeviceObject = pDeviceObject; pGraphicsDevice->FileObject = pFileObject; + /* Initialize and register the device with videoprt for Win32k callbacks */ + Win32kCallbacks.PhysDisp = pGraphicsDevice; + Win32kCallbacks.Callout = VideoPortCallout; + // Reset the data being returned prior to the call. + Win32kCallbacks.bACPI = FALSE; + Win32kCallbacks.pPhysDeviceObject = NULL; + Win32kCallbacks.DualviewFlags = 0; + Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject, + IOCTL_VIDEO_INIT_WIN32K_CALLBACKS, + &Win32kCallbacks, + sizeof(Win32kCallbacks), + &Win32kCallbacks, + sizeof(Win32kCallbacks), + &ulReturn); + if (Status != ERROR_SUCCESS) + { + ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n", + pDeviceObject, Status); + } + // TODO: Set flags according to the results. + // if (Win32kCallbacks.bACPI) + // if (Win32kCallbacks.DualviewFlags & ???) + // Win32kCallbacks.pPhysDeviceObject; + /* Copy the device name */ RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName, sizeof(pGraphicsDevice->szNtDeviceName), diff --git a/win32ss/user/ntuser/display.c b/win32ss/user/ntuser/display.c index cebaf8c1148..be0335c52da 100644 --- a/win32ss/user/ntuser/display.c +++ b/win32ss/user/ntuser/display.c @@ -285,6 +285,45 @@ InitVideo(VOID) return STATUS_SUCCESS; } +VOID +UserRefreshDisplay(IN PPDEVOBJ ppdev) +{ + ULONG_PTR ulResult; + // PVOID pvOldCursor; + + // TODO: Re-enable the cursor reset code once this function becomes called + // from within a Win32 thread... Indeed UserSetCursor() requires this, but + // at the moment this function is directly called from a separate thread + // from within videoprt, instead of by a separate win32k system thread. + + if (!ppdev) + return; + + PDEVOBJ_vReference(ppdev); + + /* Remove mouse pointer */ + // pvOldCursor = UserSetCursor(NULL, TRUE); + + /* Do the mode switch -- Use the actual same current mode */ + ulResult = PDEVOBJ_bSwitchMode(ppdev, ppdev->pdmwDev); + ASSERT(ulResult); + + /* Restore mouse pointer, no hooks called */ + // pvOldCursor = UserSetCursor(pvOldCursor, TRUE); + // ASSERT(pvOldCursor == NULL); + + /* Update the system metrics */ + InitMetrics(); + + /* Set new size of the monitor */ + // UserUpdateMonitorSize((HDEV)ppdev); + + //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes); + UserRedrawDesktop(); + + PDEVOBJ_vRelease(ppdev); +} + NTSTATUS NTAPI UserEnumDisplayDevices(