reactos/win32ss/drivers/miniport/pc98vid/hardware.c
Dmitry Borisov 27cd9eaf1a
[PC98VID] Add framebuffer video miniport driver for NEC PC-98 series (#3040)
This adds generic graphics support on PC-9821.
2020-08-19 00:50:08 +03:00

379 lines
13 KiB
C

/*
* PROJECT: ReactOS framebuffer driver for NEC PC-98 series
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Hardware support code
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
*/
/* INCLUDES *******************************************************************/
#include "pc98vid.h"
/* GLOBALS ********************************************************************/
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Pc98VidSetCurrentMode)
#pragma alloc_text(PAGE, Pc98VidSetColorRegisters)
#pragma alloc_text(PAGE, Pc98VidGetPowerState)
#pragma alloc_text(PAGE, Pc98VidSetPowerState)
#endif
#define PEGC_MAX_COLORS 256
/* FUNCTIONS ******************************************************************/
static BOOLEAN
GraphGetStatus(
_In_ UCHAR Status)
{
UCHAR Result;
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_STATUS_SELECT, Status);
Result = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_STATUS);
return (Result & GRAPH_STATUS_SET) && (Result != 0xFF);
}
static BOOLEAN
TestMmio(
_In_ PHW_DEVICE_EXTENSION DeviceExtension)
{
USHORT OldValue, NewValue;
OldValue = VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_MODE));
/* Bits [15:1] are not writable */
VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_MODE), 0x80);
NewValue = VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_MODE));
VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_MODE), OldValue);
return !(NewValue & 0x80);
}
static VOID
TextSync(VOID)
{
while (VideoPortReadPortUchar((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC)
NOTHING;
while (!(VideoPortReadPortUchar((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC))
NOTHING;
}
BOOLEAN
NTAPI
HasPegcController(
_In_ PHW_DEVICE_EXTENSION DeviceExtension)
{
BOOLEAN Success;
if (GraphGetStatus(GRAPH_STATUS_PEGC))
return TestMmio(DeviceExtension);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE);
Success = GraphGetStatus(GRAPH_STATUS_PEGC) ? TestMmio(DeviceExtension) : FALSE;
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_DISABLE);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT);
return Success;
}
VP_STATUS
FASTCALL
Pc98VidSetCurrentMode(
_In_ PHW_DEVICE_EXTENSION DeviceExtension,
_In_ PVIDEO_MODE RequestedMode)
{
SYNCPARAM SyncParameters;
CSRFORMPARAM CursorParameters;
CSRWPARAM CursorPosition;
PITCHPARAM PitchParameters;
PRAMPARAM RamParameters;
ZOOMPARAM ZoomParameters;
UCHAR RelayState;
PAGED_CODE();
VideoDebugPrint((Trace, "%s() Mode %d\n",
__FUNCTION__, RequestedMode->RequestedMode));
if (RequestedMode->RequestedMode > DeviceExtension->ModeCount)
return ERROR_INVALID_PARAMETER;
/* Blank screen */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_DISABLE);
/* RESET, without FIFO check */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_COMMAND, GDC_COMMAND_RESET1);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_COMMAND, GDC_COMMAND_RESET1);
/* Configure chipset */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_COLORED);
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GDC2_MODE_ODD_RLINE_SHOW);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_COLORS_16);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_GRCG);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LCD);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LINES_400);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2,
VideoModes[RequestedMode->RequestedMode].Clock1);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2,
VideoModes[RequestedMode->RequestedMode].Clock2);
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_HORIZONTAL_SCAN_RATE,
VideoModes[RequestedMode->RequestedMode].HorizontalScanRate);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_VIDEO_PAGE, 0);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_VIDEO_PAGE_ACCESS, 0);
/* =========================== MASTER ============================ */
/* MASTER */
WRITE_GDC1_COMMAND(GDC_COMMAND_MASTER);
/* SYNC */
SyncParameters = VideoModes[RequestedMode->RequestedMode].TextSyncParameters;
SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS_AND_CHARACTERS | SYNC_VIDEO_FRAMING_NONINTERLACED |
SYNC_DRAW_ONLY_DURING_RETRACE_BLANKING | SYNC_STATIC_RAM_NO_REFRESH;
WRITE_GDC1_COMMAND(GDC_COMMAND_SYNC_ON);
WRITE_GDC_SYNC((PUCHAR)GDC1_IO_o_PARAM, &SyncParameters);
/* CSRFORM */
CursorParameters.Show = FALSE;
CursorParameters.Blink = FALSE;
CursorParameters.BlinkRate = 12;
CursorParameters.LinesPerRow = 16;
CursorParameters.StartScanLine = 0;
CursorParameters.EndScanLine = 15;
WRITE_GDC1_COMMAND(GDC_COMMAND_CSRFORM);
WRITE_GDC_CSRFORM((PUCHAR)GDC1_IO_o_PARAM, &CursorParameters);
/* PITCH */
PitchParameters.WordsPerScanline = 80;
WRITE_GDC1_COMMAND(GDC_COMMAND_PITCH);
WRITE_GDC_PITCH((PUCHAR)GDC1_IO_o_PARAM, &PitchParameters);
/* PRAM */
RamParameters.StartingAddress = 0;
RamParameters.Length = 1023;
RamParameters.ImageBit = FALSE;
RamParameters.WideDisplay = FALSE;
WRITE_GDC1_COMMAND(GDC_COMMAND_PRAM);
WRITE_GDC_PRAM((PUCHAR)GDC1_IO_o_PARAM, &RamParameters);
/* ZOOM */
ZoomParameters.DisplayZoomFactor = 0;
ZoomParameters.WritingZoomFactor = 0;
WRITE_GDC1_COMMAND(GDC_COMMAND_ZOOM);
WRITE_GDC_ZOOM((PUCHAR)GDC1_IO_o_PARAM, &ZoomParameters);
/* CSRW */
CursorPosition.CursorAddress = 0;
CursorPosition.DotAddress = 0;
WRITE_GDC1_COMMAND(GDC_COMMAND_CSRW);
WRITE_GDC_CSRW((PUCHAR)GDC1_IO_o_PARAM, &CursorPosition);
/* START */
WRITE_GDC1_COMMAND(GDC_COMMAND_BCTRL_START);
/* ============================ SLAVE ============================ */
/* SLAVE */
WRITE_GDC2_COMMAND(GDC_COMMAND_SLAVE);
/* SYNC */
SyncParameters = VideoModes[RequestedMode->RequestedMode].VideoSyncParameters;
SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS | SYNC_VIDEO_FRAMING_NONINTERLACED |
SYNC_DRAW_DURING_ACTIVE_DISPLAY_TIME_AND_RETRACE_BLANKING |
SYNC_STATIC_RAM_NO_REFRESH;
WRITE_GDC2_COMMAND(GDC_COMMAND_SYNC_ON);
WRITE_GDC_SYNC((PUCHAR)GDC2_IO_o_PARAM, &SyncParameters);
/* CSRFORM */
CursorParameters.Show = FALSE;
CursorParameters.Blink = FALSE;
CursorParameters.BlinkRate = 0;
CursorParameters.LinesPerRow = 1;
CursorParameters.StartScanLine = 0;
CursorParameters.EndScanLine = 0;
WRITE_GDC2_COMMAND(GDC_COMMAND_CSRFORM);
WRITE_GDC_CSRFORM((PUCHAR)GDC2_IO_o_PARAM, &CursorParameters);
/* PITCH */
PitchParameters.WordsPerScanline = 80;
WRITE_GDC2_COMMAND(GDC_COMMAND_PITCH);
WRITE_GDC_PITCH((PUCHAR)GDC2_IO_o_PARAM, &PitchParameters);
/* PRAM */
RamParameters.StartingAddress = 0;
RamParameters.Length = 1023;
RamParameters.ImageBit = TRUE;
RamParameters.WideDisplay = FALSE;
WRITE_GDC2_COMMAND(GDC_COMMAND_PRAM);
WRITE_GDC_PRAM((PUCHAR)GDC2_IO_o_PARAM, &RamParameters);
/* ZOOM */
ZoomParameters.DisplayZoomFactor = 0;
ZoomParameters.WritingZoomFactor = 0;
WRITE_GDC2_COMMAND(GDC_COMMAND_ZOOM);
WRITE_GDC_ZOOM((PUCHAR)GDC2_IO_o_PARAM, &ZoomParameters);
/* CSRW */
CursorPosition.CursorAddress = 0;
CursorPosition.DotAddress = 0;
WRITE_GDC2_COMMAND(GDC_COMMAND_CSRW);
WRITE_GDC_CSRW((PUCHAR)GDC2_IO_o_PARAM, &CursorPosition);
/* Synchronize the master sync source */
TextSync();
TextSync();
TextSync();
TextSync();
/* START */
WRITE_GDC2_COMMAND(GDC_COMMAND_BCTRL_START);
/* 256 colors, packed pixel */
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2,
VideoModes[RequestedMode->RequestedMode].Mem);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT);
VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_MODE), PEGC_MODE_PACKED);
VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa +
PEGC_MMIO_FRAMEBUFFER), PEGC_FB_MAP);
/* Select the video source */
RelayState = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_RELAY) &
~(GRAPH_RELAY_0 | GRAPH_RELAY_1);
RelayState |= GRAPH_VID_SRC_INTERNAL | GRAPH_SRC_GDC;
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_RELAY, RelayState);
/* Unblank screen */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_ENABLE);
DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
return NO_ERROR;
}
VP_STATUS
FASTCALL
Pc98VidSetColorRegisters(
_In_ PVIDEO_CLUT ColorLookUpTable)
{
USHORT Entry;
PAGED_CODE();
VideoDebugPrint((Trace, "%s()\n", __FUNCTION__));
if (ColorLookUpTable->NumEntries > PEGC_MAX_COLORS)
return ERROR_INVALID_PARAMETER;
for (Entry = ColorLookUpTable->FirstEntry;
Entry < ColorLookUpTable->FirstEntry + ColorLookUpTable->NumEntries;
++Entry)
{
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_PALETTE_INDEX, Entry);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_RED,
ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_GREEN,
ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_BLUE,
ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
}
return NO_ERROR;
}
VP_STATUS
NTAPI
Pc98VidGetPowerState(
_In_ PVOID HwDeviceExtension,
_In_ ULONG HwId,
_In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{
PAGED_CODE();
VideoDebugPrint((Trace, "%s() Id %lX, State %x\n",
__FUNCTION__, HwId, VideoPowerControl->PowerState));
if (HwId == MONITOR_HW_ID || HwId == DISPLAY_ADAPTER_HW_ID)
{
switch (VideoPowerControl->PowerState)
{
case VideoPowerOn:
case VideoPowerStandBy:
case VideoPowerSuspend:
case VideoPowerOff:
case VideoPowerShutdown:
return NO_ERROR;
}
}
return ERROR_DEVICE_REINITIALIZATION_NEEDED;
}
VP_STATUS
NTAPI
Pc98VidSetPowerState(
_In_ PVOID HwDeviceExtension,
_In_ ULONG HwId,
_In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{
UCHAR Dpms;
PAGED_CODE();
VideoDebugPrint((Trace, "%s() Id %lX, State %x\n",
__FUNCTION__, HwId, VideoPowerControl->PowerState));
if (HwId == MONITOR_HW_ID)
{
Dpms = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_DPMS);
switch (VideoPowerControl->PowerState)
{
case VideoPowerOn:
/* Turn on HS/VS signals */
Dpms &= ~(GRAPH_DPMS_HSYNC_MASK | GRAPH_DPMS_VSYNC_MASK);
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms);
/* Unblank screen */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1,
GRAPH_MODE_DISPLAY_ENABLE);
break;
case VideoPowerStandBy:
/* Disable HS signal */
Dpms = (Dpms | GRAPH_DPMS_HSYNC_MASK) & ~GRAPH_DPMS_VSYNC_MASK;
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms);
break;
case VideoPowerSuspend:
/* Disable VS signal */
Dpms = (Dpms | GRAPH_DPMS_VSYNC_MASK) & ~GRAPH_DPMS_HSYNC_MASK;
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms);
break;
case VideoPowerOff:
case VideoPowerShutdown:
/* Turn off HS/VS signals */
Dpms |= GRAPH_DPMS_HSYNC_MASK | GRAPH_DPMS_VSYNC_MASK;
VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms);
/* Blank screen */
VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1,
GRAPH_MODE_DISPLAY_DISABLE);
break;
}
}
return NO_ERROR;
}