/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: GDI Driver Device Functions * FILE: win32ss/gdi/eng/device.c * PROGRAMER: Jason Filby * Timo Kreuzer */ #include #include DBG_DEFAULT_CHANNEL(EngDev); PGRAPHICS_DEVICE gpPrimaryGraphicsDevice; PGRAPHICS_DEVICE gpVgaGraphicsDevice; static PGRAPHICS_DEVICE gpGraphicsDeviceFirst = NULL; static PGRAPHICS_DEVICE gpGraphicsDeviceLast = NULL; static HSEMAPHORE ghsemGraphicsDeviceList; static ULONG giDevNum = 1; CODE_SEG("INIT") NTSTATUS NTAPI InitDeviceImpl(VOID) { ghsemGraphicsDeviceList = EngCreateSemaphore(); if (!ghsemGraphicsDeviceList) return STATUS_INSUFFICIENT_RESOURCES; return STATUS_SUCCESS; } static BOOLEAN EngpHasVgaDriver( _In_ PGRAPHICS_DEVICE pGraphicsDevice) { WCHAR awcDeviceKey[256], awcServiceName[100]; PWSTR lastBkSlash; NTSTATUS Status; ULONG cbValue; HKEY hkey; /* Open the key for the adapters */ Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); if (!NT_SUCCESS(Status)) { ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: 0x%08lx\n", Status); return FALSE; } /* Read the name of the device key */ cbValue = sizeof(awcDeviceKey); Status = RegQueryValue(hkey, pGraphicsDevice->szNtDeviceName, REG_SZ, awcDeviceKey, &cbValue); ZwClose(hkey); if (!NT_SUCCESS(Status)) { ERR("Could not read '%S' registry value: 0x%08lx\n", Status); return FALSE; } /* Replace 'DeviceN' by 'Video' */ lastBkSlash = wcsrchr(awcDeviceKey, L'\\'); if (!lastBkSlash) { ERR("Invalid registry key '%S'\n", lastBkSlash); return FALSE; } if (!NT_SUCCESS(RtlStringCchCopyW(lastBkSlash + 1, ARRAYSIZE(awcDeviceKey) - (lastBkSlash + 1 - awcDeviceKey), L"Video"))) { ERR("Failed to add 'Video' to registry key '%S'\n", awcDeviceKey); return FALSE; } /* Open device key */ Status = RegOpenKey(awcDeviceKey, &hkey); if (!NT_SUCCESS(Status)) { ERR("Could not open %S registry key: 0x%08lx\n", awcDeviceKey, Status); return FALSE; } /* Read service name */ cbValue = sizeof(awcServiceName); Status = RegQueryValue(hkey, L"Service", REG_SZ, awcServiceName, &cbValue); ZwClose(hkey); if (!NT_SUCCESS(Status)) { ERR("Could not read Service registry value in %S: 0x%08lx\n", awcDeviceKey, Status); return FALSE; } /* Device is using VGA driver if service name starts with 'VGA' (case insensitive) */ return (_wcsnicmp(awcServiceName, L"VGA", 3) == 0); } static BOOLEAN EngpIsVgaDevice( _In_ PGRAPHICS_DEVICE pGraphicsDevice) { BOOLEAN IsVgaDevice; ULONG ulReturn; NTSTATUS Status; Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pGraphicsDevice->DeviceObject, IOCTL_VIDEO_IS_VGA_DEVICE, NULL, 0, &IsVgaDevice, sizeof(IsVgaDevice), &ulReturn); if (Status != ERROR_SUCCESS) { ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_IS_VGA_DEVICE) failed, Status 0x%lx\n", pGraphicsDevice->DeviceObject, Status); return FALSE; } TRACE("'%S' is%s VGA device\n", pGraphicsDevice->szNtDeviceName, IsVgaDevice ? "" : " NOT"); return IsVgaDevice; } /* * Add a device to gpGraphicsDeviceFirst/gpGraphicsDeviceLast list (if not already present). */ _Requires_lock_held_(ghsemGraphicsDeviceList) static VOID EngpLinkGraphicsDevice( _In_ PGRAPHICS_DEVICE pToAdd) { PGRAPHICS_DEVICE pGraphicsDevice; TRACE("EngLinkGraphicsDevice(%p)\n", pToAdd); /* Search if device is not already linked */ for (pGraphicsDevice = gpGraphicsDeviceFirst; pGraphicsDevice; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) { if (pGraphicsDevice == pToAdd) return; } pToAdd->pNextGraphicsDevice = NULL; if (gpGraphicsDeviceLast) gpGraphicsDeviceLast->pNextGraphicsDevice = pToAdd; gpGraphicsDeviceLast = pToAdd; if (!gpGraphicsDeviceFirst) gpGraphicsDeviceFirst = pToAdd; } /* * Remove a device from gpGraphicsDeviceFirst/gpGraphicsDeviceLast list. */ _Requires_lock_held_(ghsemGraphicsDeviceList) static VOID EngpUnlinkGraphicsDevice( _In_ PGRAPHICS_DEVICE pToDelete) { PGRAPHICS_DEVICE pPrevGraphicsDevice = NULL; PGRAPHICS_DEVICE pGraphicsDevice = gpGraphicsDeviceFirst; TRACE("EngpUnlinkGraphicsDevice('%S')\n", pToDelete->szNtDeviceName); while (pGraphicsDevice) { if (pGraphicsDevice != pToDelete) { /* Keep current device */ pPrevGraphicsDevice = pGraphicsDevice; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; } else { /* At first, link again associated VGA Device */ if (pGraphicsDevice->pVgaDevice) EngpLinkGraphicsDevice(pGraphicsDevice->pVgaDevice); /* We need to remove current device */ pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; /* Unlink chain */ if (!pPrevGraphicsDevice) gpGraphicsDeviceFirst = pToDelete->pNextGraphicsDevice; else pPrevGraphicsDevice->pNextGraphicsDevice = pToDelete->pNextGraphicsDevice; if (gpGraphicsDeviceLast == pToDelete) gpGraphicsDeviceLast = pPrevGraphicsDevice; } } } /* Goal of this function is to: * - detect new graphic devices (from registry) and initialize them * - set DISPLAY_DEVICE_VGA_COMPATIBLE flag on compatible devices * - set gpVgaGraphicsDevice * - handle gbBaseVideo global flag * - set DISPLAY_DEVICE_PRIMARY_DEVICE on at least one device * - set gpPrimaryGraphicsDevice * - link primary device and VGA device (if available) using pVgaDevice field */ NTSTATUS EngpUpdateGraphicsDeviceList(VOID) { ULONG iDevNum, ulMaxObjectNumber = 0; WCHAR awcDeviceName[20], awcWinDeviceName[20]; UNICODE_STRING ustrDeviceName; WCHAR awcBuffer[256]; NTSTATUS Status; PGRAPHICS_DEVICE pGraphicsDevice, pNewPrimaryGraphicsDevice = NULL; ULONG cbValue; HKEY hkey; /* Open the key for the adapters */ Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); if (!NT_SUCCESS(Status)) { ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status); return Status; } /* Get the maximum number of adapters */ if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber)) { ERR("Could not read MaxObjectNumber, defaulting to 0.\n"); } TRACE("Found %lu devices\n", ulMaxObjectNumber + 1); /* Loop through all adapters, to detect new ones */ for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++) { /* Create the adapter's key name */ swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum); /* Create the display device name */ swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1); RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName); /* Check if the device exists already */ pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum); if (pGraphicsDevice != NULL) { continue; } /* Read the reg key name */ cbValue = sizeof(awcBuffer); Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue); if (!NT_SUCCESS(Status)) { ERR("failed to query the registry path:0x%lx\n", Status); continue; } /* Initialize the driver for this device */ pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer); if (!pGraphicsDevice) continue; } /* Close the device map registry key */ ZwClose(hkey); /* Choose a VGA device */ /* Try a device with DISPLAY_DEVICE_VGA_COMPATIBLE flag. If not found, * fall back to current VGA device */ for (pGraphicsDevice = gpGraphicsDeviceFirst; pGraphicsDevice; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) { if (pGraphicsDevice == gpVgaGraphicsDevice) continue; if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE && EngpIsVgaDevice(pGraphicsDevice)) { gpVgaGraphicsDevice = pGraphicsDevice; break; } } /* Handle gbBaseVideo */ if (gbBaseVideo) { PGRAPHICS_DEVICE pToDelete; /* Lock list */ EngAcquireSemaphore(ghsemGraphicsDeviceList); /* Remove every device from linked list, except base-video one */ pGraphicsDevice = gpGraphicsDeviceFirst; while (pGraphicsDevice) { if (!EngpHasVgaDriver(pGraphicsDevice)) { /* Not base-video device. Remove it */ pToDelete = pGraphicsDevice; TRACE("Removing non-base-video device %S (%S)\n", pToDelete->szWinDeviceName, pToDelete->szNtDeviceName); EngpUnlinkGraphicsDevice(pGraphicsDevice); pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; /* Free memory */ ExFreePoolWithTag(pToDelete->pDiplayDrivers, GDITAG_DRVSUP); ExFreePoolWithTag(pToDelete, GDITAG_GDEVICE); } else { pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; } } /* Unlock list */ EngReleaseSemaphore(ghsemGraphicsDeviceList); } /* Choose a primary device (if none already exists) */ if (!gpPrimaryGraphicsDevice) { for (pGraphicsDevice = gpGraphicsDeviceFirst; pGraphicsDevice; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) { if (EngpHasVgaDriver(pGraphicsDevice)) { pNewPrimaryGraphicsDevice = pGraphicsDevice; break; } } if (!pNewPrimaryGraphicsDevice) pNewPrimaryGraphicsDevice = gpGraphicsDeviceFirst; if (pNewPrimaryGraphicsDevice) { pNewPrimaryGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; gpPrimaryGraphicsDevice = pNewPrimaryGraphicsDevice; } } /* Can we link VGA device to primary device? */ if (gpPrimaryGraphicsDevice && gpVgaGraphicsDevice && gpPrimaryGraphicsDevice != gpVgaGraphicsDevice && !gpPrimaryGraphicsDevice->pVgaDevice) { /* Yes. Remove VGA device from global list, and attach it to primary device */ TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName); EngAcquireSemaphore(ghsemGraphicsDeviceList); EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice); gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice; EngReleaseSemaphore(ghsemGraphicsDeviceList); } return STATUS_SUCCESS; } /* Open display settings registry key * Returns NULL in case of error. */ static HKEY EngpGetRegistryHandleFromDeviceMap( _In_ PGRAPHICS_DEVICE pGraphicsDevice) { static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO"; HKEY hKey; WCHAR szDeviceKey[256]; ULONG cbSize; NTSTATUS Status; /* Open the device map registry key */ Status = RegOpenKey(KEY_VIDEO, &hKey); if (!NT_SUCCESS(Status)) { ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: status 0x%08x\n", Status); return NULL; } /* Query the registry path */ cbSize = sizeof(szDeviceKey); RegQueryValue(hKey, pGraphicsDevice->szNtDeviceName, REG_SZ, szDeviceKey, &cbSize); ZwClose(hKey); /* Open the registry key */ Status = RegOpenKey(szDeviceKey, &hKey); if (!NT_SUCCESS(Status)) { ERR("Could not open registry key '%S': status 0x%08x\n", szDeviceKey, Status); return NULL; } return hKey; } NTSTATUS EngpGetDisplayDriverParameters( _In_ PGRAPHICS_DEVICE pGraphicsDevice, _Out_ PDEVMODEW pdm) { HKEY hKey; NTSTATUS Status; RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = { #define READ(field, str) \ { \ NULL, \ RTL_QUERY_REGISTRY_DIRECT, \ L ##str, \ &pdm->field, \ REG_NONE, NULL, 0 \ }, READ(dmBitsPerPel, "DefaultSettings.BitsPerPel") READ(dmPelsWidth, "DefaultSettings.XResolution") READ(dmPelsHeight, "DefaultSettings.YResolution") READ(dmDisplayFlags, "DefaultSettings.Flags") READ(dmDisplayFrequency, "DefaultSettings.VRefresh") READ(dmPanningWidth, "DefaultSettings.XPanning") READ(dmPanningHeight, "DefaultSettings.YPanning") READ(dmDisplayOrientation, "DefaultSettings.Orientation") READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput") READ(dmPosition.x, "Attach.RelativeX") READ(dmPosition.y, "Attach.RelativeY") #undef READ {0} }; hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); if (!hKey) return STATUS_UNSUCCESSFUL; Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hKey, DisplaySettingsTable, NULL, NULL); ZwClose(hKey); return Status; } DWORD EngpGetDisplayDriverAccelerationLevel( _In_ PGRAPHICS_DEVICE pGraphicsDevice) { HKEY hKey; DWORD dwAccelerationLevel = 0; RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = { { NULL, RTL_QUERY_REGISTRY_DIRECT, L"Acceleration.Level", &dwAccelerationLevel, REG_NONE, NULL, 0 }, {0} }; hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); if (!hKey) return 0; RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hKey, DisplaySettingsTable, NULL, NULL); ZwClose(hKey); return dwAccelerationLevel; } 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(gpmdev->ppdevGlobal); } 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( _In_ PUNICODE_STRING pustrDeviceName, _In_ PUNICODE_STRING pustrDiplayDrivers, _In_ PUNICODE_STRING pustrDescription) { PGRAPHICS_DEVICE pGraphicsDevice; PDEVICE_OBJECT pDeviceObject; PFILE_OBJECT pFileObject; NTSTATUS Status; VIDEO_WIN32K_CALLBACKS Win32kCallbacks; ULONG ulReturn; PWSTR pwsz; ULONG cj; TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName); /* Allocate a GRAPHICS_DEVICE structure */ pGraphicsDevice = ExAllocatePoolZero(PagedPool, sizeof(GRAPHICS_DEVICE), GDITAG_GDEVICE); if (!pGraphicsDevice) { ERR("ExAllocatePoolWithTag failed\n"); return NULL; } /* Try to open and enable the device */ Status = IoGetDeviceObjectPointer(pustrDeviceName, FILE_READ_DATA | FILE_WRITE_DATA, &pFileObject, &pDeviceObject); if (!NT_SUCCESS(Status)) { ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status); ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); return NULL; } /* 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 & ???) pGraphicsDevice->PhysDeviceHandle = Win32kCallbacks.pPhysDeviceObject; /* FIXME: Enumerate children monitor devices for this video adapter * * - Force the adapter to re-enumerate its monitors: * IoSynchronousInvalidateDeviceRelations(pdo, BusRelations) * * - Retrieve all monitor PDOs from VideoPrt: * EngDeviceIoControl(0x%p, IOCTL_VIDEO_ENUM_MONITOR_PDO) * * - Initialize these fields and structures accordingly: * pGraphicsDevice->dwMonCnt * pGraphicsDevice->pvMonDev[0..dwMonCnt-1] */ /* Copy the device name */ RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName, sizeof(pGraphicsDevice->szNtDeviceName), pustrDeviceName->Buffer, pustrDeviceName->Length); /* Create a Win32 device name (FIXME: virtual devices!) */ RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName, sizeof(pGraphicsDevice->szWinDeviceName), L"\\\\.\\DISPLAY%d", (int)giDevNum); /* Allocate a buffer for the strings */ cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR); pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP); if (!pwsz) { ERR("Could not allocate string buffer\n"); ASSERT(FALSE); // FIXME ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); return NULL; } /* Copy the display driver names */ pGraphicsDevice->pDiplayDrivers = pwsz; RtlCopyMemory(pGraphicsDevice->pDiplayDrivers, pustrDiplayDrivers->Buffer, pustrDiplayDrivers->Length); /* Copy the description */ pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR); RtlCopyMemory(pGraphicsDevice->pwszDescription, pustrDescription->Buffer, pustrDescription->Length); pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0; /* Lock loader */ EngAcquireSemaphore(ghsemGraphicsDeviceList); /* Insert the device into the global list */ EngpLinkGraphicsDevice(pGraphicsDevice); /* Increment the device number */ giDevNum++; /* Unlock loader */ EngReleaseSemaphore(ghsemGraphicsDeviceList); TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription); /* HACK: already in graphic mode; display wallpaper on this new display */ if (ScreenDeviceContext) { UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY"); UNICODE_STRING DisplayName; HDC hdc; RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName); hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE); IntPaintDesktop(hdc); } return pGraphicsDevice; } PGRAPHICS_DEVICE NTAPI EngpFindGraphicsDevice( _In_opt_ PUNICODE_STRING pustrDevice, _In_ ULONG iDevNum) { UNICODE_STRING ustrCurrent; PGRAPHICS_DEVICE pGraphicsDevice; ULONG i; TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n", pustrDevice, iDevNum); /* Lock list */ EngAcquireSemaphore(ghsemGraphicsDeviceList); if (pustrDevice && pustrDevice->Buffer) { /* Find specified video adapter by name */ for (pGraphicsDevice = gpGraphicsDeviceFirst; pGraphicsDevice; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) { /* Compare the device name */ RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE)) { break; } } if (pGraphicsDevice) { /* Validate selected monitor number */ #if 0 if (iDevNum >= pGraphicsDevice->dwMonCnt) pGraphicsDevice = NULL; #else /* FIXME: dwMonCnt not initialized, see EngpRegisterGraphicsDevice */ #endif } } else { /* Select video adapter by device number */ for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0; pGraphicsDevice && i < iDevNum; pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++); } /* Unlock list */ EngReleaseSemaphore(ghsemGraphicsDeviceList); return pGraphicsDevice; } static NTSTATUS EngpFileIoRequest( _In_ PFILE_OBJECT pFileObject, _In_ ULONG ulMajorFunction, _In_reads_(nBufferSize) PVOID lpBuffer, _In_ SIZE_T nBufferSize, _In_ ULONGLONG ullStartOffset, _Out_ PULONG_PTR lpInformation) { PDEVICE_OBJECT pDeviceObject; KEVENT Event; PIRP pIrp; IO_STATUS_BLOCK Iosb; NTSTATUS Status; LARGE_INTEGER liStartOffset; /* Get corresponding device object */ pDeviceObject = IoGetRelatedDeviceObject(pFileObject); if (!pDeviceObject) { return STATUS_INVALID_PARAMETER; } /* Initialize an event */ KeInitializeEvent(&Event, SynchronizationEvent, FALSE); /* Build IRP */ liStartOffset.QuadPart = ullStartOffset; pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction, pDeviceObject, lpBuffer, (ULONG)nBufferSize, &liStartOffset, &Event, &Iosb); if (!pIrp) { return STATUS_INSUFFICIENT_RESOURCES; } /* Call the driver */ Status = IoCallDriver(pDeviceObject, pIrp); /* Wait if neccessary */ if (STATUS_PENDING == Status) { KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); Status = Iosb.Status; } /* Return information to the caller about the operation. */ *lpInformation = Iosb.Information; /* Return NTSTATUS */ return Status; } VOID APIENTRY EngFileWrite( _In_ PFILE_OBJECT pFileObject, _In_reads_(nLength) PVOID lpBuffer, _In_ SIZE_T nLength, _Out_ PSIZE_T lpBytesWritten) { NTSTATUS status; status = EngpFileIoRequest(pFileObject, IRP_MJ_WRITE, lpBuffer, nLength, 0, lpBytesWritten); if (!NT_SUCCESS(status)) { *lpBytesWritten = 0; } } _Success_(return>=0) NTSTATUS APIENTRY EngFileIoControl( _In_ PFILE_OBJECT pFileObject, _In_ DWORD dwIoControlCode, _In_reads_(nInBufferSize) PVOID lpInBuffer, _In_ SIZE_T nInBufferSize, _Out_writes_(nOutBufferSize) PVOID lpOutBuffer, _In_ SIZE_T nOutBufferSize, _Out_ PULONG_PTR lpInformation) { PDEVICE_OBJECT pDeviceObject; KEVENT Event; PIRP pIrp; IO_STATUS_BLOCK Iosb; NTSTATUS Status; /* Get corresponding device object */ pDeviceObject = IoGetRelatedDeviceObject(pFileObject); if (!pDeviceObject) { return STATUS_INVALID_PARAMETER; } /* Initialize an event */ KeInitializeEvent(&Event, SynchronizationEvent, FALSE); /* Build IO control IRP */ pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode, pDeviceObject, lpInBuffer, (ULONG)nInBufferSize, lpOutBuffer, (ULONG)nOutBufferSize, FALSE, &Event, &Iosb); if (!pIrp) { return STATUS_INSUFFICIENT_RESOURCES; } /* Call the driver */ Status = IoCallDriver(pDeviceObject, pIrp); /* Wait if neccessary */ if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); Status = Iosb.Status; } /* Return information to the caller about the operation. */ *lpInformation = Iosb.Information; /* This function returns NTSTATUS */ return Status; } /* * @implemented */ _Success_(return==0) DWORD APIENTRY EngDeviceIoControl( _In_ HANDLE hDevice, _In_ DWORD dwIoControlCode, _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer, _In_ DWORD cjInBufferSize, _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer, _In_ DWORD cjOutBufferSize, _Out_ LPDWORD lpBytesReturned) { PIRP Irp; NTSTATUS Status; KEVENT Event; IO_STATUS_BLOCK Iosb; PDEVICE_OBJECT DeviceObject; TRACE("EngDeviceIoControl() called\n"); if (!hDevice) { return ERROR_INVALID_HANDLE; } KeInitializeEvent(&Event, SynchronizationEvent, FALSE); DeviceObject = (PDEVICE_OBJECT) hDevice; Irp = IoBuildDeviceIoControlRequest(dwIoControlCode, DeviceObject, lpInBuffer, cjInBufferSize, lpOutBuffer, cjOutBufferSize, FALSE, &Event, &Iosb); if (!Irp) return ERROR_NOT_ENOUGH_MEMORY; Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); Status = Iosb.Status; } TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status, Iosb.Information); /* Return information to the caller about the operation. */ *lpBytesReturned = (DWORD)Iosb.Information; /* Convert NT status values to win32 error codes. */ switch (Status) { case STATUS_INSUFFICIENT_RESOURCES: return ERROR_NOT_ENOUGH_MEMORY; case STATUS_BUFFER_OVERFLOW: return ERROR_MORE_DATA; case STATUS_NOT_IMPLEMENTED: return ERROR_INVALID_FUNCTION; case STATUS_INVALID_PARAMETER: return ERROR_INVALID_PARAMETER; case STATUS_BUFFER_TOO_SMALL: return ERROR_INSUFFICIENT_BUFFER; case STATUS_DEVICE_DOES_NOT_EXIST: return ERROR_DEV_NOT_EXIST; case STATUS_PENDING: return ERROR_IO_PENDING; } return Status; } /* EOF */