mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 03:27:31 +00:00
27cd9eaf1a
This adds generic graphics support on PC-9821.
379 lines
13 KiB
C
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;
|
|
}
|