2 * PROJECT: ReactOS Boot Video Driver for NEC PC-98 series
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
8 /* INCLUDES *******************************************************************/
12 /* GLOBALS ********************************************************************/
14 static ULONG_PTR PegcControl
= 0;
15 ULONG_PTR FrameBuffer
= 0;
17 #define PEGC_MAX_COLORS 256
19 /* PRIVATE FUNCTIONS **********************************************************/
27 WRITE_PORT_UCHAR((PUCHAR
)GRAPH_IO_o_STATUS_SELECT
, Status
);
28 Result
= READ_PORT_UCHAR((PUCHAR
)GRAPH_IO_i_STATUS
);
30 return (Result
& GRAPH_STATUS_SET
) && (Result
!= 0xFF);
36 USHORT OldValue
, NewValue
;
38 OldValue
= READ_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_MODE
));
40 /* Bits [15:1] are not writable */
41 WRITE_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_MODE
), 0x80);
42 NewValue
= READ_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_MODE
));
44 WRITE_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_MODE
), OldValue
);
46 return !(NewValue
& 0x80);
50 HasPegcController(VOID
)
54 if (GraphGetStatus(GRAPH_STATUS_PEGC
))
57 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_EGC_FF_UNPROTECT
);
58 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_PEGC_ENABLE
);
59 Success
= GraphGetStatus(GRAPH_STATUS_PEGC
) ? TestMmio() : FALSE
;
60 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_PEGC_DISABLE
);
61 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_EGC_FF_PROTECT
);
69 while (READ_PORT_UCHAR((PUCHAR
)GDC1_IO_i_STATUS
) & GDC_STATUS_VSYNC
)
72 while (!(READ_PORT_UCHAR((PUCHAR
)GDC1_IO_i_STATUS
) & GDC_STATUS_VSYNC
))
77 InitializeDisplay(VOID
)
79 SYNCPARAM SyncParameters
;
80 CSRFORMPARAM CursorParameters
;
81 CSRWPARAM CursorPosition
;
82 PITCHPARAM PitchParameters
;
83 PRAMPARAM RamParameters
;
84 ZOOMPARAM ZoomParameters
;
87 /* RESET, without FIFO check */
88 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_COMMAND
, GDC_COMMAND_RESET1
);
89 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_COMMAND
, GDC_COMMAND_RESET1
);
91 /* Configure chipset */
92 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_MODE_FLIPFLOP1
, GRAPH_MODE_COLORED
);
93 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_MODE_FLIPFLOP1
, GDC2_MODE_ODD_RLINE_SHOW
);
94 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_COLORS_16
);
95 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_GRCG
);
96 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_LCD
);
97 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_LINES_400
);
98 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_CLOCK1_5MHZ
);
99 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_CLOCK2_5MHZ
);
100 WRITE_PORT_UCHAR((PUCHAR
)GRAPH_IO_o_HORIZONTAL_SCAN_RATE
, GRAPH_HF_31KHZ
);
101 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_VIDEO_PAGE
, 0);
102 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_VIDEO_PAGE_ACCESS
, 0);
104 /* =========================== MASTER ============================ */
107 WRITE_GDC1_COMMAND(GDC_COMMAND_MASTER
);
110 SyncParameters
.Flags
= SYNC_DISPLAY_MODE_GRAPHICS_AND_CHARACTERS
| SYNC_VIDEO_FRAMING_NONINTERLACED
|
111 SYNC_DRAW_ONLY_DURING_RETRACE_BLANKING
| SYNC_STATIC_RAM_NO_REFRESH
;
112 SyncParameters
.ScreenWidthChars
= 80;
113 SyncParameters
.HorizontalSyncWidth
= 12;
114 SyncParameters
.VerticalSyncWidth
= 2;
115 SyncParameters
.HorizontalFrontPorchWidth
= 4;
116 SyncParameters
.HorizontalBackPorchWidth
= 4;
117 SyncParameters
.VerticalFrontPorchWidth
= 6;
118 SyncParameters
.ScreenWidthLines
= 480;
119 SyncParameters
.VerticalBackPorchWidth
= 37;
120 WRITE_GDC1_COMMAND(GDC_COMMAND_SYNC_ON
);
121 WRITE_GDC_SYNC((PUCHAR
)GDC1_IO_o_PARAM
, &SyncParameters
);
124 CursorParameters
.Show
= FALSE
;
125 CursorParameters
.Blink
= FALSE
;
126 CursorParameters
.BlinkRate
= 12;
127 CursorParameters
.LinesPerRow
= 16;
128 CursorParameters
.StartScanLine
= 0;
129 CursorParameters
.EndScanLine
= 15;
130 WRITE_GDC1_COMMAND(GDC_COMMAND_CSRFORM
);
131 WRITE_GDC_CSRFORM((PUCHAR
)GDC1_IO_o_PARAM
, &CursorParameters
);
134 PitchParameters
.WordsPerScanline
= BYTES_PER_SCANLINE
;
135 WRITE_GDC1_COMMAND(GDC_COMMAND_PITCH
);
136 WRITE_GDC_PITCH((PUCHAR
)GDC1_IO_o_PARAM
, &PitchParameters
);
139 RamParameters
.StartingAddress
= 0;
140 RamParameters
.Length
= 1023;
141 RamParameters
.ImageBit
= FALSE
;
142 RamParameters
.WideDisplay
= FALSE
;
143 WRITE_GDC1_COMMAND(GDC_COMMAND_PRAM
);
144 WRITE_GDC_PRAM((PUCHAR
)GDC1_IO_o_PARAM
, &RamParameters
);
147 ZoomParameters
.DisplayZoomFactor
= 0;
148 ZoomParameters
.WritingZoomFactor
= 0;
149 WRITE_GDC1_COMMAND(GDC_COMMAND_ZOOM
);
150 WRITE_GDC_ZOOM((PUCHAR
)GDC1_IO_o_PARAM
, &ZoomParameters
);
153 CursorPosition
.CursorAddress
= 0;
154 CursorPosition
.DotAddress
= 0;
155 WRITE_GDC1_COMMAND(GDC_COMMAND_CSRW
);
156 WRITE_GDC_CSRW((PUCHAR
)GDC1_IO_o_PARAM
, &CursorPosition
);
159 WRITE_GDC1_COMMAND(GDC_COMMAND_BCTRL_START
);
161 /* ============================ SLAVE ============================ */
164 WRITE_GDC2_COMMAND(GDC_COMMAND_SLAVE
);
167 SyncParameters
.Flags
= SYNC_DISPLAY_MODE_GRAPHICS
| SYNC_VIDEO_FRAMING_NONINTERLACED
|
168 SYNC_DRAW_DURING_ACTIVE_DISPLAY_TIME_AND_RETRACE_BLANKING
|
169 SYNC_STATIC_RAM_NO_REFRESH
;
170 SyncParameters
.ScreenWidthChars
= 80;
171 SyncParameters
.HorizontalSyncWidth
= 12;
172 SyncParameters
.VerticalSyncWidth
= 2;
173 SyncParameters
.HorizontalFrontPorchWidth
= 4;
174 SyncParameters
.HorizontalBackPorchWidth
= 132;
175 SyncParameters
.VerticalFrontPorchWidth
= 6;
176 SyncParameters
.ScreenWidthLines
= 480;
177 SyncParameters
.VerticalBackPorchWidth
= 37;
178 WRITE_GDC2_COMMAND(GDC_COMMAND_SYNC_ON
);
179 WRITE_GDC_SYNC((PUCHAR
)GDC2_IO_o_PARAM
, &SyncParameters
);
182 CursorParameters
.Show
= FALSE
;
183 CursorParameters
.Blink
= FALSE
;
184 CursorParameters
.BlinkRate
= 0;
185 CursorParameters
.LinesPerRow
= 1;
186 CursorParameters
.StartScanLine
= 0;
187 CursorParameters
.EndScanLine
= 0;
188 WRITE_GDC2_COMMAND(GDC_COMMAND_CSRFORM
);
189 WRITE_GDC_CSRFORM((PUCHAR
)GDC2_IO_o_PARAM
, &CursorParameters
);
192 PitchParameters
.WordsPerScanline
= BYTES_PER_SCANLINE
;
193 WRITE_GDC2_COMMAND(GDC_COMMAND_PITCH
);
194 WRITE_GDC_PITCH((PUCHAR
)GDC2_IO_o_PARAM
, &PitchParameters
);
197 RamParameters
.StartingAddress
= 0;
198 RamParameters
.Length
= 1023;
199 RamParameters
.ImageBit
= TRUE
;
200 RamParameters
.WideDisplay
= FALSE
;
201 WRITE_GDC2_COMMAND(GDC_COMMAND_PRAM
);
202 WRITE_GDC_PRAM((PUCHAR
)GDC2_IO_o_PARAM
, &RamParameters
);
205 ZoomParameters
.DisplayZoomFactor
= 0;
206 ZoomParameters
.WritingZoomFactor
= 0;
207 WRITE_GDC2_COMMAND(GDC_COMMAND_ZOOM
);
208 WRITE_GDC_ZOOM((PUCHAR
)GDC2_IO_o_PARAM
, &ZoomParameters
);
211 CursorPosition
.CursorAddress
= 0;
212 CursorPosition
.DotAddress
= 0;
213 WRITE_GDC2_COMMAND(GDC_COMMAND_CSRW
);
214 WRITE_GDC_CSRW((PUCHAR
)GDC2_IO_o_PARAM
, &CursorPosition
);
216 /* Synchronize the master sync source */
223 WRITE_GDC2_COMMAND(GDC_COMMAND_BCTRL_START
);
226 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_EGC_FF_UNPROTECT
);
227 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_PEGC_ENABLE
);
228 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_MODE_LINES_800
);
229 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_MODE_FLIPFLOP2
, GDC2_EGC_FF_PROTECT
);
230 WRITE_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_MODE
), PEGC_MODE_PACKED
);
231 WRITE_REGISTER_USHORT((PUSHORT
)(PegcControl
+ PEGC_MMIO_FRAMEBUFFER
), PEGC_FB_MAP
);
233 /* Select the video source */
234 RelayState
= READ_PORT_UCHAR((PUCHAR
)GRAPH_IO_i_RELAY
) & ~(GRAPH_RELAY_0
| GRAPH_RELAY_1
);
235 RelayState
|= GRAPH_VID_SRC_INTERNAL
| GRAPH_SRC_GDC
;
236 WRITE_PORT_UCHAR((PUCHAR
)GRAPH_IO_o_RELAY
, RelayState
);
244 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_PALETTE_INDEX
, Id
);
245 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_RED
, GetRValue(Rgb
));
246 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_GREEN
, GetGValue(Rgb
));
247 WRITE_PORT_UCHAR((PUCHAR
)GDC2_IO_o_BLUE
, GetBValue(Rgb
));
252 InitPaletteWithTable(
257 PULONG Entry
= Table
;
259 for (i
= 0; i
< Count
; i
++)
260 SetPaletteEntryRGB(i
, *Entry
++);
262 for (i
= Count
; i
< PEGC_MAX_COLORS
; i
++)
263 SetPaletteEntryRGB(i
, VidpDefaultPalette
[BV_COLOR_BLACK
]);
272 _In_ ULONG TextColor
,
273 _In_ ULONG BackColor
)
275 ULONG X
, Y
, PixelMask
;
276 PUCHAR FontChar
= GetFontPtr(Character
);
279 Y
< Top
+ BOOTCHAR_HEIGHT
;
280 ++Y
, FontChar
+= FONT_PTR_DELTA
)
282 for (X
= Left
, PixelMask
= 1 << (BOOTCHAR_WIDTH
- 1);
283 X
< Left
+ BOOTCHAR_WIDTH
;
284 ++X
, PixelMask
>>= 1)
286 if (*FontChar
& PixelMask
)
287 SetPixel(X
, Y
, (UCHAR
)TextColor
);
288 else if (BackColor
< BV_COLOR_NONE
)
289 SetPixel(X
, Y
, (UCHAR
)BackColor
);
297 _In_ ULONG CurrentTop
,
299 _In_ BOOLEAN Restore
)
301 PULONG OldPosition
, NewPosition
;
302 ULONG PixelCount
= TopDelta
* (SCREEN_WIDTH
/ sizeof(ULONG
));
306 /* Restore the row by copying back the contents saved off-screen */
307 OldPosition
= (PULONG
)(FrameBuffer
+ FB_OFFSET(0, SCREEN_HEIGHT
));
308 NewPosition
= (PULONG
)(FrameBuffer
+ FB_OFFSET(0, CurrentTop
));
312 /* Preserve the row by saving its contents off-screen */
313 OldPosition
= (PULONG
)(FrameBuffer
+ FB_OFFSET(0, CurrentTop
));
314 NewPosition
= (PULONG
)(FrameBuffer
+ FB_OFFSET(0, SCREEN_HEIGHT
));
318 WRITE_REGISTER_ULONG(NewPosition
++, READ_REGISTER_ULONG(OldPosition
++));
322 PrepareForSetPixel(VOID
)
334 PULONG SrcWide
, DstWide
;
335 USHORT PixelCount
= (VidpScrollRegion
[2] - VidpScrollRegion
[0]) + 1;
336 ULONG_PTR SourceOffset
= FrameBuffer
+ FB_OFFSET(VidpScrollRegion
[0], VidpScrollRegion
[1] + Scroll
);
337 ULONG_PTR DestinationOffset
= FrameBuffer
+ FB_OFFSET(VidpScrollRegion
[0], VidpScrollRegion
[1]);
339 for (Line
= VidpScrollRegion
[1]; Line
<= VidpScrollRegion
[3]; Line
++)
341 SrcWide
= (PULONG
)SourceOffset
;
342 DstWide
= (PULONG
)DestinationOffset
;
343 for (i
= 0; i
< PixelCount
/ sizeof(ULONG
); i
++)
344 WRITE_REGISTER_ULONG(DstWide
++, READ_REGISTER_ULONG(SrcWide
++));
346 Src
= (PUCHAR
)SrcWide
;
347 Dst
= (PUCHAR
)DstWide
;
348 for (i
= 0; i
< PixelCount
% sizeof(ULONG
); i
++)
349 WRITE_REGISTER_UCHAR(Dst
++, READ_REGISTER_UCHAR(Src
++));
351 SourceOffset
+= SCREEN_WIDTH
;
352 DestinationOffset
+= SCREEN_WIDTH
;
356 /* PUBLIC FUNCTIONS ***********************************************************/
361 _In_ BOOLEAN SetMode
)
363 PHYSICAL_ADDRESS BaseAddress
;
365 BaseAddress
.QuadPart
= VRAM_NORMAL_PLANE_I
;
366 PegcControl
= (ULONG_PTR
)MmMapIoSpace(BaseAddress
, PEGC_CONTROL_SIZE
, MmNonCached
);
370 if (!HasPegcController())
373 BaseAddress
.QuadPart
= PEGC_FRAMEBUFFER_PACKED
;
374 FrameBuffer
= (ULONG_PTR
)MmMapIoSpace(BaseAddress
, PEGC_FRAMEBUFFER_SIZE
, MmNonCached
);
379 VidResetDisplay(TRUE
);
385 MmUnmapIoSpace((PVOID
)PegcControl
, PEGC_CONTROL_SIZE
);
394 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_MODE_FLIPFLOP1
, GRAPH_MODE_DISPLAY_DISABLE
);
400 _In_ BOOLEAN HalReset
)
402 PULONG PixelsPosition
= (PULONG
)(FrameBuffer
+ FB_OFFSET(0, 0));
403 ULONG PixelCount
= ((SCREEN_WIDTH
* SCREEN_HEIGHT
) / sizeof(ULONG
)) + 1;
405 /* Clear the current position */
409 /* Clear the screen with HAL if we were asked to */
413 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_MODE_FLIPFLOP1
, GRAPH_MODE_DISPLAY_DISABLE
);
415 /* 640x480 256-color 31 kHz mode */
418 /* Re-initialize the palette and fill the screen black */
421 WRITE_REGISTER_ULONG(PixelsPosition
++, 0);
423 WRITE_PORT_UCHAR((PUCHAR
)GDC1_IO_o_MODE_FLIPFLOP1
, GRAPH_MODE_DISPLAY_ENABLE
);
428 VidScreenToBufferBlt(
429 _Out_writes_bytes_(Delta
* Height
) PUCHAR Buffer
,
439 PUSHORT PixelsPosition
;
441 /* Clear the destination buffer */
442 RtlZeroMemory(Buffer
, Delta
* Height
);
444 for (Y
= 0; Y
< Height
; Y
++)
446 OutputBuffer
= Buffer
+ Y
* Delta
;
447 PixelsPosition
= (PUSHORT
)(FrameBuffer
+ FB_OFFSET(Left
, Top
+ Y
));
449 for (X
= 0; X
< Width
; X
+= sizeof(USHORT
))
451 Px
= READ_REGISTER_USHORT(PixelsPosition
++);
452 *OutputBuffer
++ = (FIRSTBYTE(Px
) << 4) | (SECONDBYTE(Px
) & 0x0F);
469 ULONG WideColor
= (Color
<< 24) | (Color
<< 16) | (Color
<< 8) | Color
;
470 USHORT PixelCount
= (Right
- Left
) + 1;
471 ULONG_PTR StartOffset
= FrameBuffer
+ FB_OFFSET(Left
, Top
);
473 for (Line
= Top
; Line
<= Bottom
; Line
++)
475 PixelsPtr
= (PULONG
)StartOffset
;
476 for (i
= 0; i
< PixelCount
/ sizeof(ULONG
); i
++)
477 WRITE_REGISTER_ULONG(PixelsPtr
++, WideColor
);
479 PixelPtr
= (PUCHAR
)PixelsPtr
;
480 for (i
= 0; i
< PixelCount
% sizeof(ULONG
); i
++)
481 WRITE_REGISTER_UCHAR(PixelPtr
++, Color
);
483 StartOffset
+= SCREEN_WIDTH
;