2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 /* PRIVATE VARIABLES **********************************************************/
18 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
19 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
21 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
22 static BYTE VgaMiscRegister
;
23 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
24 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
25 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
26 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
27 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
28 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
29 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
30 static BOOLEAN VgaAcLatch
= FALSE
;
31 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
32 static BYTE VgaDacIndex
= 0;
33 static BOOLEAN VgaDacReadWrite
= FALSE
;
34 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
35 static BOOLEAN InVerticalRetrace
= FALSE
;
36 static BOOLEAN InHorizontalRetrace
= FALSE
;
37 static HANDLE TextConsoleBuffer
= NULL
;
38 static HANDLE GraphicsConsoleBuffer
= NULL
;
39 static LPVOID ConsoleFramebuffer
= NULL
;
40 static HANDLE ConsoleMutex
= NULL
;
41 static BOOLEAN NeedsUpdate
= FALSE
;
42 static BOOLEAN ModeChanged
= TRUE
;
43 static BOOLEAN CursorMoved
= FALSE
;
44 static BOOLEAN TextMode
= TRUE
;
45 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
47 /* PRIVATE FUNCTIONS **********************************************************/
49 static inline INT
VgaGetAddressSize(VOID
)
51 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
53 /* Double-word addressing */
57 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
67 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
69 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
72 /* Check for chain-4 and odd-even mode */
73 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
75 /* The lowest two bits are the plane number */
79 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
81 /* The LSB is the plane number */
87 /* Use the read mode */
88 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
91 /* Multiply the offset by the address size */
92 Offset
*= VgaGetAddressSize();
94 return Offset
+ Plane
* VGA_BANK_SIZE
;
97 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
99 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
101 /* Check for chain-4 and odd-even mode */
102 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
104 /* Shift the offset to the right by 2 */
107 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
109 /* Shift the offset to the right by 1 */
113 /* Multiply the offset by the address size */
114 Offset
*= VgaGetAddressSize();
116 /* Return the offset on plane 0 */
120 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
122 DPRINT("VgaMarkForUpdate: Row %d, Column %d\n", Row
, Column
);
124 /* Check if this is the first time the rectangle is updated */
127 UpdateRectangle
.Left
= UpdateRectangle
.Top
= SHRT_MAX
;
128 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= SHRT_MIN
;
131 /* Expand the rectangle to include the point */
132 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
133 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
134 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
135 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
137 /* Set the update request flag */
141 static VOID
VgaWriteSequencer(BYTE Data
)
143 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
146 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
149 static VOID
VgaWriteGc(BYTE Data
)
151 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
154 VgaGcRegisters
[VgaGcIndex
] = Data
;
156 /* Check the index */
159 case VGA_GC_MISC_REG
:
161 /* The GC misc register decides if it's text or graphics mode */
169 static VOID
VgaWriteCrtc(BYTE Data
)
171 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
174 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
176 /* Check the index */
177 switch (VgaCrtcIndex
)
179 case VGA_CRTC_END_HORZ_DISP_REG
:
180 case VGA_CRTC_VERT_DISP_END_REG
:
181 case VGA_CRTC_OVERFLOW_REG
:
183 /* The video mode has changed */
189 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
190 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
191 case VGA_CRTC_CURSOR_START_REG
:
192 case VGA_CRTC_CURSOR_END_REG
:
194 /* Set the cursor moved flag */
202 static VOID
VgaWriteDac(BYTE Data
)
205 VgaDacRegisters
[VgaDacIndex
++] = Data
;
206 VgaDacIndex
%= VGA_PALETTE_SIZE
;
208 // TODO: Change the palette!
211 static VOID
VgaWriteAc(BYTE Data
)
213 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
216 VgaAcRegisters
[VgaAcIndex
] = Data
;
219 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
222 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
223 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
224 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
225 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfoBuffer
+ sizeof(BITMAPINFOHEADER
));
227 /* Fill the bitmap info header */
228 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
229 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
230 BitmapInfo
->bmiHeader
.biWidth
= Resolution
->X
;
231 BitmapInfo
->bmiHeader
.biHeight
= Resolution
->Y
;
232 BitmapInfo
->bmiHeader
.biBitCount
= 8;
233 BitmapInfo
->bmiHeader
.biPlanes
= 1;
234 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
235 BitmapInfo
->bmiHeader
.biSizeImage
= Resolution
->X
* Resolution
->Y
;
237 /* Fill the palette data */
238 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
240 /* Fill the console graphics buffer info */
241 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
242 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
243 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
245 /* Create the buffer */
246 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
247 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
249 CONSOLE_GRAPHICS_BUFFER
,
250 &GraphicsBufferInfo
);
251 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
253 /* Save the framebuffer address and mutex */
254 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
255 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
257 /* Clear the framebuffer */
258 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
260 /* Set the active buffer */
261 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
266 static VOID
VgaLeaveGraphicsMode(VOID
)
268 /* Release the console framebuffer mutex if needed */
269 ReleaseMutex(ConsoleMutex
);
271 /* Switch back to the text buffer */
272 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
274 /* Cleanup the video data */
275 CloseHandle(ConsoleMutex
);
277 CloseHandle(GraphicsConsoleBuffer
);
278 GraphicsConsoleBuffer
= NULL
;
281 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
283 /* Resize the console */
284 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
286 /* Allocate a framebuffer */
287 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
289 Resolution
->X
* Resolution
->Y
290 * sizeof(CHAR_INFO
));
291 if (ConsoleFramebuffer
== NULL
)
293 DisplayMessage(L
"An unexpected error occurred!\n");
301 static VOID
VgaLeaveTextMode(VOID
)
303 /* Free the old framebuffer */
304 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
305 ConsoleFramebuffer
= NULL
;
308 static VOID
VgaUpdateMode(VOID
)
310 COORD Resolution
= VgaGetDisplayResolution();
314 /* Leave the current graphics mode */
315 VgaLeaveGraphicsMode();
319 /* Leave the current text mode */
323 /* Check if the new mode is alphanumeric */
324 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
326 /* Enter new text mode */
327 if (!VgaEnterTextMode(&Resolution
)) return;
329 /* Set the text mode flag */
334 /* Enter 8-bit graphics mode */
335 if (!VgaEnterGraphicsMode(&Resolution
)) return;
337 /* Clear the text mode flag */
341 /* Perform a full update */
343 UpdateRectangle
.Left
= 0;
344 UpdateRectangle
.Top
= 0;
345 UpdateRectangle
.Right
= Resolution
.X
;
346 UpdateRectangle
.Bottom
= Resolution
.Y
;
349 static VOID
VgaUpdateFramebuffer(VOID
)
352 COORD Resolution
= VgaGetDisplayResolution();
353 INT AddressSize
= VgaGetAddressSize();
354 DWORD Address
= (VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
] << 8)
355 + VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
];
356 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
358 /* Check if this is text mode or graphics mode */
359 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
362 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
365 * Synchronize access to the graphics framebuffer
366 * with the console framebuffer mutex.
368 WaitForSingleObject(ConsoleMutex
, INFINITE
);
370 /* Loop through the scanlines */
371 for (i
= 0; i
< Resolution
.Y
; i
++)
373 /* Loop through the pixels */
374 for (j
= 0; j
< Resolution
.X
; j
++)
378 /* Check the shifting mode */
379 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
381 /* 4 bits shifted from each plane */
383 /* Check if this is 16 or 256 color mode */
384 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
386 /* One byte per pixel */
387 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
388 + (Address
+ (j
/ VGA_NUM_BANKS
))
393 /* 4-bits per pixel */
395 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
396 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
399 /* Check if we should use the highest 4 bits or lowest 4 */
400 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
412 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
415 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
416 * then 2 bits shifted from plane 1 and 3 for the next 4
419 // TODO: NOT IMPLEMENTED!
420 DPRINT1("Interleaved shift mode is not implemented!\n");
424 /* 1 bit shifted from each plane */
426 /* Check if this is 16 or 256 color mode */
427 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
429 /* 8 bits per pixel, 2 on each plane */
431 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
433 /* The data is on plane k, 4 pixels per byte */
434 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
435 + (Address
+ (j
/ 4)) * AddressSize
];
437 /* The mask of the first bit in the pair */
438 BYTE BitMask
= 1 << (((3 - (j
% 4)) * 2) + 1);
440 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
441 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
443 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
444 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
449 /* 4 bits per pixel, 1 on each plane */
451 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
453 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
454 + (Address
+ (j
/ 8)) * AddressSize
];
456 /* If the bit on that plane is set, set it */
457 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
462 /* Now check if the resulting pixel data has changed */
463 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
465 /* Yes, write the new value */
466 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
468 /* Mark the specified pixel as changed */
469 VgaMarkForUpdate(i
, j
);
473 /* Move to the next scanline */
474 Address
+= ScanlineSize
;
478 * Release the console framebuffer mutex
479 * so that we allow for repainting.
481 ReleaseMutex(ConsoleMutex
);
486 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
488 /* Loop through the scanlines */
489 for (i
= 0; i
< Resolution
.Y
; i
++)
491 /* Loop through the characters */
492 for (j
= 0; j
< Resolution
.X
; j
++)
494 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
497 /* Plane 0 holds the character itself */
498 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
500 /* Plane 1 holds the attribute */
501 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
503 /* Now check if the resulting character data has changed */
504 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
505 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
507 /* Yes, write the new value */
508 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
510 /* Mark the specified pixel as changed */
511 VgaMarkForUpdate(i
, j
);
515 /* Move to the next scanline */
516 Address
+= ScanlineSize
;
521 static VOID
VgaUpdateTextCursor(VOID
)
524 CONSOLE_CURSOR_INFO CursorInfo
;
525 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
526 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
527 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
528 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
529 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
530 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
532 if (CursorStart
< CursorEnd
)
535 CursorInfo
.bVisible
= TRUE
;
536 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
541 CursorInfo
.bVisible
= FALSE
;
542 CursorInfo
.dwSize
= 0;
545 /* Add the cursor skew to the location */
546 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
548 /* Find the coordinates of the new position */
549 Position
.X
= (WORD
)(Location
% ScanlineSize
);
550 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
552 /* Update the physical cursor */
553 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
554 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
557 /* PUBLIC FUNCTIONS ***********************************************************/
559 DWORD
VgaGetVideoBaseAddress(VOID
)
561 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
564 DWORD
VgaGetVideoLimitAddress(VOID
)
566 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
569 COORD
VgaGetDisplayResolution(VOID
)
572 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
574 /* The low 8 bits are in the display registers */
575 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
576 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
578 /* Set the top bits from the overflow register */
579 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
581 Resolution
.Y
|= 1 << 8;
583 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
585 Resolution
.Y
|= 1 << 9;
588 /* Increase the values by 1 */
592 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
594 /* Multiply the horizontal resolution by the 9/8 dot mode */
595 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
598 /* The horizontal resolution is halved in 8-bit mode */
599 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
601 /* Divide the vertical resolution by the maximum scan line */
602 Resolution
.Y
/= ((DWORD
)VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F) + 1;
606 /* Divide the number of scanlines by the font size */
607 Resolution
.Y
/= TextSize
;
610 /* Return the resolution */
614 VOID
VgaRefreshDisplay(VOID
)
616 COORD Resolution
= VgaGetDisplayResolution();
618 DPRINT("VgaRefreshDisplay\n");
622 /* Change the display mode */
625 /* Reset the mode change flag */
631 /* Change the text cursor location */
632 VgaUpdateTextCursor();
634 /* Reset the cursor move flag */
638 /* Update the contents of the framebuffer */
639 VgaUpdateFramebuffer();
641 /* Set the vertical retrace flag */
642 InVerticalRetrace
= TRUE
;
644 /* Ignore if there's nothing to update */
645 if (!NeedsUpdate
) return;
647 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
648 UpdateRectangle
.Left
,
650 UpdateRectangle
.Right
,
651 UpdateRectangle
.Bottom
);
653 /* Check if this is text mode or graphics mode */
654 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
658 /* Redraw the screen */
659 InvalidateConsoleDIBits(GraphicsConsoleBuffer
, &UpdateRectangle
);
664 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
666 /* Write the data to the console */
667 WriteConsoleOutputA(TextConsoleBuffer
,
668 (PCHAR_INFO
)ConsoleFramebuffer
,
675 /* Clear the update flag */
679 VOID
VgaHorizontalRetrace(VOID
)
682 InHorizontalRetrace
= TRUE
;
685 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
690 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n",
694 /* Ignore if video RAM access is disabled */
695 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
697 /* Loop through each byte */
698 for (i
= 0; i
< Size
; i
++)
700 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
702 /* Copy the value to the buffer */
703 Buffer
[i
] = VgaMemory
[VideoAddress
];
707 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
712 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n",
716 /* Ignore if video RAM access is disabled */
717 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
719 /* Also ignore if write access to all planes is disabled */
720 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
722 /* Loop through each byte */
723 for (i
= 0; i
< Size
; i
++)
725 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
727 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
729 /* Make sure the page is writeable */
730 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
732 /* Check if this is chain-4 mode */
733 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
735 if (((Address
+ i
) & 3) != j
)
737 /* This plane will not be accessed */
742 /* Check if this is odd-even mode */
743 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
745 if (((Address
+ i
) & 1) != (j
& 1))
747 /* This plane will not be accessed */
752 /* Copy the value to the VGA memory */
753 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = Buffer
[i
];
758 BYTE
VgaReadPort(WORD Port
)
760 DPRINT("VgaReadPort: Port 0x%04X\n", Port
);
771 return VgaAcRegisters
[VgaAcIndex
];
781 return VgaSeqRegisters
[VgaSeqIndex
];
784 case VGA_DAC_READ_INDEX
:
786 /* This returns the read/write state */
787 return VgaDacReadWrite
? 0 : 3;
790 case VGA_DAC_WRITE_INDEX
:
797 /* Ignore reads in write mode */
798 if (!VgaDacReadWrite
)
800 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
801 VgaDacIndex
%= VGA_PALETTE_SIZE
;
810 return VgaMiscRegister
;
820 return VgaCrtcRegisters
[VgaCrtcIndex
];
830 return VgaGcRegisters
[VgaGcIndex
];
838 /* Reset the AC latch */
841 /* Set a flag if there is a vertical or horizontal retrace */
842 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
844 /* Set an additional flag if there was a vertical retrace */
845 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
847 /* Clear the flags */
848 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
857 VOID
VgaWritePort(WORD Port
, BYTE Data
)
859 DPRINT("VgaWritePort: Port 0x%04X, Data 0x%02X\n", Port
, Data
);
867 /* Change the index */
868 if (Data
< VGA_AC_MAX_REG
) VgaAcIndex
= Data
;
876 /* Toggle the latch */
877 VgaAcLatch
= !VgaAcLatch
;
884 /* Set the sequencer index register */
885 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
892 /* Call the sequencer function */
893 VgaWriteSequencer(Data
);
898 case VGA_DAC_READ_INDEX
:
900 VgaDacReadWrite
= FALSE
;
901 VgaDacIndex
= Data
% VGA_PALETTE_SIZE
;
906 case VGA_DAC_WRITE_INDEX
:
908 VgaDacReadWrite
= TRUE
;
909 VgaDacIndex
= Data
% VGA_PALETTE_SIZE
;
916 /* Ignore writes in read mode */
917 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
924 VgaMiscRegister
= Data
;
931 /* Set the CRTC index register */
932 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
939 /* Call the CRTC function */
947 /* Set the GC index register */
948 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
954 /* Call the GC function */
962 VOID
VgaInitialize(HANDLE TextHandle
)
968 COORD Origin
= { 0, 0 };
969 SMALL_RECT ScreenRect
;
970 PCHAR_INFO CharBuffer
;
974 /* Set the global handle */
975 TextConsoleBuffer
= TextHandle
;
977 /* Clear the VGA memory */
978 ZeroMemory(VgaMemory
, VGA_NUM_BANKS
* VGA_BANK_SIZE
);
980 /* Set the default video mode */
981 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
986 Resolution
= VgaGetDisplayResolution();
987 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
988 AddressSize
= VgaGetAddressSize();
989 ScreenRect
.Left
= ScreenRect
.Top
= 0;
990 ScreenRect
.Right
= Resolution
.X
;
991 ScreenRect
.Bottom
= Resolution
.Y
;
992 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
994 /* Read the data from the console into the framebuffer */
995 ReadConsoleOutputA(TextConsoleBuffer
,
1001 /* Loop through the scanlines */
1002 for (i
= 0; i
< Resolution
.Y
; i
++)
1004 /* Loop through the characters */
1005 for (j
= 0; j
< Resolution
.X
; j
++)
1007 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1009 /* Store the character in plane 0 */
1010 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
1012 /* Store the attribute in plane 1 */
1013 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
1016 /* Move to the next scanline */
1017 Address
+= ScanlineSize
;