3 /* GLOBALS *******************************************************************/
5 static ULONG ScrollRegion
[4] =
12 static UCHAR lMaskTable
[8] =
23 static UCHAR rMaskTable
[8] =
27 (1 << 7)+ (1 << 6) + (1 << 5),
28 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4),
29 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3),
30 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2),
31 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1),
32 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1) +
46 static ULONG lookup
[16] =
66 ULONG_PTR VgaRegisterBase
= 0;
67 ULONG_PTR VgaBase
= 0;
70 static ULONG VidTextColor
= 0xF;
71 static BOOLEAN CarriageReturn
= FALSE
;
73 #define __outpb(Port, Value) \
74 WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase + (Port)), (UCHAR)(Value))
76 #define __outpw(Port, Value) \
77 WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + (Port)), (USHORT)(Value))
79 /* PRIVATE FUNCTIONS *********************************************************/
83 ReadWriteMode(IN UCHAR Mode
)
87 /* Switch to graphics mode register */
90 /* Get the current register value, minus the current mode */
91 Value
= READ_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF) & 0xF4;
93 /* Set the new mode */
94 __outpb(0x3CF, Mode
| Value
);
99 SetPixel(IN ULONG Left
,
103 PUCHAR PixelPosition
;
105 /* Calculate the pixel position. */
106 PixelPosition
= (PUCHAR
)(VgaBase
+ (Left
>> 3) + (Top
* 80));
108 /* Select the bitmask register and write the mask */
109 __outpw(0x3CE, (PixelMask
[Left
& 7] << 8) | 8);
111 /* Read the current pixel value and add our color */
112 WRITE_REGISTER_UCHAR(PixelPosition
,
113 READ_REGISTER_UCHAR(PixelPosition
) & Color
);
116 #define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
118 /* Select the bitmask register and write the mask */ \
119 __outpw(0x3CE, ((_PixelMask) << 8) | 8); \
120 /* Set the new color */ \
121 WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \
124 #ifdef CHAR_GEN_UPSIDE_DOWN
125 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
126 # define FONT_PTR_DELTA (-1)
128 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
129 # define FONT_PTR_DELTA (1)
134 DisplayCharacter(IN CHAR Character
,
140 PUCHAR FontChar
, PixelPtr
;
144 /* Switch to mode 10 */
147 /* Clear the 4 planes (we're already in unchained mode here) */
148 __outpw(0x3C4, 0xF02);
150 /* Select the color don't care register */
153 /* Calculate shift */
156 /* Get the font and pixel pointer */
157 FontChar
= GetFontPtr(Character
);
158 PixelPtr
= (PUCHAR
)(VgaBase
+ (Left
>> 3) + (Top
* 80));
160 /* Loop all pixel rows */
161 Height
= BOOTCHAR_HEIGHT
;
164 SET_PIXELS(PixelPtr
, *FontChar
>> Shift
, TextColor
);
166 FontChar
+= FONT_PTR_DELTA
;
169 /* Check if we need to update neighbor bytes */
172 /* Calculate shift for 2nd byte */
175 /* Get the font and pixel pointer (2nd byte) */
176 FontChar
= GetFontPtr(Character
);
177 PixelPtr
= (PUCHAR
)(VgaBase
+ (Left
>> 3) + (Top
* 80) + 1);
179 /* Loop all pixel rows */
180 Height
= BOOTCHAR_HEIGHT
;
183 SET_PIXELS(PixelPtr
, *FontChar
<< Shift
, TextColor
);
185 FontChar
+= FONT_PTR_DELTA
;
189 /* Check if the background color is transparent */
196 /* Calculate shift */
199 /* Get the font and pixel pointer */
200 FontChar
= GetFontPtr(Character
);
201 PixelPtr
= (PUCHAR
)(VgaBase
+ (Left
>> 3) + (Top
* 80));
203 /* Loop all pixel rows */
204 Height
= BOOTCHAR_HEIGHT
;
207 SET_PIXELS(PixelPtr
, ~*FontChar
>> Shift
, BackColor
);
209 FontChar
+= FONT_PTR_DELTA
;
212 /* Check if we need to update neighbor bytes */
215 /* Calculate shift for 2nd byte */
218 /* Get the font and pixel pointer (2nd byte) */
219 FontChar
= GetFontPtr(Character
);
220 PixelPtr
= (PUCHAR
)(VgaBase
+ (Left
>> 3) + (Top
* 80) + 1);
222 /* Loop all pixel rows */
223 Height
= BOOTCHAR_HEIGHT
;
226 SET_PIXELS(PixelPtr
, ~*FontChar
<< Shift
, BackColor
);
228 FontChar
+= FONT_PTR_DELTA
;
235 DisplayStringXY(IN PUCHAR String
,
241 /* Loop every character */
244 /* Display a character */
245 DisplayCharacter(*String
, Left
, Top
, TextColor
, BackColor
);
247 /* Move to next character and next position */
255 SetPaletteEntryRGB(IN ULONG Id
,
258 PCHAR Colors
= (PCHAR
)&Rgb
;
260 /* Set the palette index */
261 __outpb(0x3C8, (UCHAR
)Id
);
264 __outpb(0x3C9, Colors
[2] >> 2);
265 __outpb(0x3C9, Colors
[1] >> 2);
266 __outpb(0x3C9, Colors
[0] >> 2);
271 InitPaletteWithTable(IN PULONG Table
,
275 PULONG Entry
= Table
;
277 /* Loop every entry */
278 for (i
= 0; i
< Count
; i
++, Entry
++)
281 SetPaletteEntryRGB(i
, *Entry
);
287 SetPaletteEntry(IN ULONG Id
,
288 IN ULONG PaletteEntry
)
290 /* Set the palette index */
291 __outpb(0x3C8, (UCHAR
)Id
);
294 __outpb(0x3C9, PaletteEntry
& 0xFF);
295 __outpb(0x3C9, (PaletteEntry
>>= 8) & 0xFF);
296 __outpb(0x3C9, (PaletteEntry
>> 8) & 0xFF);
301 InitializePalette(VOID
)
303 ULONG PaletteEntry
[16] = {0x000000,
321 /* Loop all the entries and set their palettes */
322 for (i
= 0; i
< 16; i
++) SetPaletteEntry(i
, PaletteEntry
[i
]);
327 VgaScroll(IN ULONG Scroll
)
330 PUCHAR OldPosition
, NewPosition
;
332 /* Clear the 4 planes */
333 __outpw(0x3C4, 0xF02);
335 /* Set the bitmask to 0xFF for all 4 planes */
336 __outpw(0x3CE, 0xFF08);
341 RowSize
= (ScrollRegion
[2] - ScrollRegion
[0] + 1) / 8;
343 /* Calculate the position in memory for the row */
344 OldPosition
= (PUCHAR
)(VgaBase
+ (ScrollRegion
[1] + Scroll
) * 80 + ScrollRegion
[0] / 8);
345 NewPosition
= (PUCHAR
)(VgaBase
+ ScrollRegion
[1] * 80 + ScrollRegion
[0] / 8);
348 for (Top
= ScrollRegion
[1]; Top
<= ScrollRegion
[3]; ++Top
)
350 #if defined(_M_IX86) || defined(_M_AMD64)
351 __movsb(NewPosition
, OldPosition
, RowSize
);
356 for (i
= 0; i
< RowSize
; ++i
)
357 WRITE_REGISTER_UCHAR(NewPosition
+ i
, READ_REGISTER_UCHAR(OldPosition
+ i
));
366 PreserveRow(IN ULONG CurrentTop
,
368 IN BOOLEAN Direction
)
370 PUCHAR Position1
, Position2
;
373 /* Clear the 4 planes */
374 __outpw(0x3C4, 0xF02);
376 /* Set the bitmask to 0xFF for all 4 planes */
377 __outpw(0x3CE, 0xFF08);
382 /* Check which way we're preserving */
385 /* Calculate the position in memory for the row */
386 Position1
= (PUCHAR
)(VgaBase
+ CurrentTop
* 80);
387 Position2
= (PUCHAR
)(VgaBase
+ 0x9600);
391 /* Calculate the position in memory for the row */
392 Position1
= (PUCHAR
)(VgaBase
+ 0x9600);
393 Position2
= (PUCHAR
)(VgaBase
+ CurrentTop
* 80);
396 /* Set the count and loop every pixel */
397 Count
= TopDelta
* 80;
399 #if defined(_M_IX86) || defined(_M_AMD64)
400 __movsb(Position1
, Position2
, Count
);
404 /* Write the data back on the other position */
405 WRITE_REGISTER_UCHAR(Position1
, READ_REGISTER_UCHAR(Position2
));
407 /* Increase both positions */
416 BitBlt(IN ULONG Left
,
421 IN ULONG BitsPerPixel
,
427 const ULONG Bottom
= Top
+ Height
;
428 const ULONG Right
= Left
+ Width
;
430 /* Check if the buffer isn't 4bpp */
431 if (BitsPerPixel
!= 4)
434 DbgPrint("Unhandled BitBlt\n"
435 "%lux%lu @ (%lu|%lu)\n"
436 "Bits Per Pixel %lu\n"
437 "Buffer: %p. Delta: %lu\n",
448 /* Switch to mode 10 */
451 /* Clear the 4 planes (we're already in unchained mode here) */
452 __outpw(0x3C4, 0xF02);
454 /* Select the color don't care register */
465 color
= Buffer
[offset
+ sx
];
467 /* Calc destination x */
468 dx
= Left
+ (sx
<< 1);
471 SetPixel(dx
, dy
, color
>> 4);
472 SetPixel(dx
+ 1, dy
, color
& 0x0F);
475 } while (dx
< Right
);
478 } while (dy
< Bottom
);
483 RleBitBlt(IN ULONG Left
,
491 ULONG RleValue
, NewRleValue
;
496 /* Switch to mode 10 */
499 /* Clear the 4 planes (we're already in unchained mode here) */
500 __outpw(0x3C4, 0xF02);
502 /* Select the color don't care register */
505 /* Set Y height and current X value and start loop */
506 YDelta
= Top
+ Height
- 1;
510 /* Get the current value and advance in the buffer */
515 /* Check if we've gone past the edge */
516 if ((x
+ RleValue
) > (Width
+ Left
))
518 /* Fixeup the pixel value */
519 RleValue
= Left
- x
+ Width
;
522 /* Get the new value */
523 NewRleValue
= *Buffer
;
525 /* Get the two colors */
526 Color
= NewRleValue
>> 4;
527 Color2
= NewRleValue
& 0xF;
529 /* Increase buffer positition */
532 /* Check if we need to do a fill */
535 /* Do a fill and continue the loop */
537 VidSolidColorFill(x
, YDelta
, RleValue
- 1, YDelta
, (UCHAR
)Color
);
542 /* Check if the pixel value is 1 or below */
545 /* Set loop variables */
546 i
= (RleValue
- 2) / 2 + 1;
550 SetPixel(x
, YDelta
, (UCHAR
)Color
);
552 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
555 /* Decrease pixel value */
560 /* Check if there is any value at all */
563 /* Set the pixel and increase posititon */
564 SetPixel(x
, YDelta
, (UCHAR
)Color
);
572 /* Get the current pixel value */
580 /* Set new x value, decrease distance and restart */
597 /* Set new x value, decrease distance and restart */
614 /* Check if we've gone past the edge */
615 if ((x
+ RleValue
) > (Width
+ Left
))
617 /* Set fixed up loop count */
618 i
= RleValue
- Left
- Width
+ x
;
620 /* Fixup pixel value */
625 /* Clear loop count */
629 /* Check the value now */
632 /* Set loop variables */
633 j
= (RleValue
- 2) / 2 + 1;
636 /* Get the new value */
637 NewRleValue
= *Buffer
;
639 /* Get the two colors */
640 Color
= NewRleValue
>> 4;
641 Color2
= NewRleValue
& 0xF;
643 /* Increase buffer position */
647 SetPixel(x
, YDelta
, (UCHAR
)Color
);
649 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
652 /* Decrease pixel value */
657 /* Check if there is any value at all */
660 /* Set the pixel and increase position */
661 Color
= *Buffer
>> 4;
663 SetPixel(x
, YDelta
, (UCHAR
)Color
);
668 /* Check loop count now */
674 /* Set new position */
675 Buffer
= Buffer
+ (i
/ 2) + 1;
678 /* Check if we need to increase the buffer */
679 if ((ULONG_PTR
)Buffer
& 1) Buffer
++;
683 /* PUBLIC FUNCTIONS **********************************************************/
690 VidSetTextColor(IN ULONG Color
)
694 /* Save the old color and set the new one */
695 OldColor
= VidTextColor
;
696 VidTextColor
= Color
;
705 VidDisplayStringXY(IN PUCHAR String
,
708 IN BOOLEAN Transparent
)
713 * If the caller wanted transparent, then send the special value (16),
714 * else use our default and call the helper routine.
716 BackColor
= Transparent
? 16 : 14;
717 DisplayStringXY(String
, Left
, Top
, 12, BackColor
);
725 VidSetScrollRegion(IN ULONG Left
,
730 /* Assert alignment */
731 ASSERT((Left
& 0x7) == 0);
732 ASSERT((Right
& 0x7) == 7);
734 /* Set Scroll Region */
735 ScrollRegion
[0] = Left
;
736 ScrollRegion
[1] = Top
;
737 ScrollRegion
[2] = Right
;
738 ScrollRegion
[3] = Bottom
;
740 /* Set current X and Y */
752 /* Select bit mask register */
753 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CE, 8);
756 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF, 255);
764 VidBufferToScreenBlt(IN PUCHAR Buffer
,
771 /* Make sure we have a width and height */
772 if (!Width
|| !Height
) return;
774 /* Call the helper function */
775 BitBlt(Left
, Top
, Width
, Height
, Buffer
, 4, Delta
);
783 VidDisplayString(IN PUCHAR String
)
785 ULONG TopDelta
= BOOTCHAR_HEIGHT
+ 1;
787 /* Start looping the string */
790 /* Treat new-line separately */
793 /* Modify Y position */
795 if (curr_y
+ TopDelta
>= ScrollRegion
[3])
797 /* Scroll the view */
804 PreserveRow(curr_y
, TopDelta
, FALSE
);
807 /* Update current X */
808 curr_x
= ScrollRegion
[0];
810 /* Do not clear line if "\r\n" is given */
811 CarriageReturn
= FALSE
;
813 else if (*String
== '\r')
815 /* Update current X */
816 curr_x
= ScrollRegion
[0];
818 /* Check if we're being followed by a new line */
819 CarriageReturn
= TRUE
;
823 /* check if we had a '\r' last time */
826 /* We did, clear the current row */
827 PreserveRow(curr_y
, TopDelta
, TRUE
);
828 CarriageReturn
= FALSE
;
831 /* Display this character */
832 DisplayCharacter(*String
, curr_x
, curr_y
, VidTextColor
, 16);
835 /* Check if we should scroll */
836 if (curr_x
+ 8 > ScrollRegion
[2])
838 /* Update Y position and check if we should scroll it */
840 if (curr_y
+ TopDelta
> ScrollRegion
[3])
848 /* Preserve the current row */
849 PreserveRow(curr_y
, TopDelta
, FALSE
);
853 curr_x
= ScrollRegion
[0];
857 /* Get the next character */
867 VidBitBlt(IN PUCHAR Buffer
,
871 PBITMAPINFOHEADER BitmapInfoHeader
;
875 /* Get the Bitmap Header */
876 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Buffer
;
878 /* Initialize the palette */
879 InitPaletteWithTable((PULONG
)(Buffer
+ BitmapInfoHeader
->biSize
),
880 (BitmapInfoHeader
->biClrUsed
) ?
881 BitmapInfoHeader
->biClrUsed
: 16);
883 /* Make sure we can support this bitmap */
884 ASSERT((BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biPlanes
) <= 4);
887 * Calculate the delta and align it on 32-bytes, then calculate
888 * the actual start of the bitmap data.
890 Delta
= (BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biWidth
) + 31;
893 BitmapOffset
= Buffer
+ sizeof(BITMAPINFOHEADER
) + 16 * sizeof(ULONG
);
895 /* Check the compression of the bitmap */
896 if (BitmapInfoHeader
->biCompression
== BI_RLE4
)
898 /* Make sure we have a width and a height */
899 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
901 /* We can use RLE Bit Blt */
904 BitmapInfoHeader
->biWidth
,
905 BitmapInfoHeader
->biHeight
,
911 /* Check if the height is negative */
912 if (BitmapInfoHeader
->biHeight
< 0)
914 /* Make it positive in the header */
915 BitmapInfoHeader
->biHeight
*= -1;
919 /* Update buffer offset */
920 BitmapOffset
+= ((BitmapInfoHeader
->biHeight
- 1) * Delta
);
924 /* Make sure we have a width and a height */
925 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
930 BitmapInfoHeader
->biWidth
,
931 BitmapInfoHeader
->biHeight
,
933 BitmapInfoHeader
->biBitCount
,
944 VidScreenToBufferBlt(IN PUCHAR Buffer
,
953 ULONG LeftDelta
, RightDelta
;
955 PUCHAR PixelPosition
;
963 /* Calculate total distance to copy on X */
964 XDistance
= Left
+ Width
- 1;
966 /* Start at plane 0 */
969 /* Calculate the 8-byte left and right deltas */
970 LeftDelta
= Left
& 7;
971 RightDelta
= 8 - LeftDelta
;
973 /* Clear the destination buffer */
974 RtlZeroMemory(Buffer
, Delta
* Height
);
976 /* Calculate the pixel offset and convert the X distance into byte form */
977 PixelOffset
= Top
* 80 + (Left
>> 3);
980 /* Loop the 4 planes */
983 /* Set the current pixel position and reset buffer loop variable */
984 PixelPosition
= (PUCHAR
)(VgaBase
+ PixelOffset
);
990 /* Set the current plane */
991 __outpw(0x3CE, (Plane
<< 8) | 4);
993 /* Make sure we have a height */
996 /* Start the outer Y loop */
1000 /* Read the current value */
1002 Value
= READ_REGISTER_UCHAR(PixelPosition
);
1004 /* Set Pixel Position loop variable */
1005 k
= PixelPosition
+ 1;
1007 /* Check if we're still within bounds */
1008 if (Left
<= XDistance
)
1010 /* Start X Inner loop */
1011 x
= (XDistance
- Left
) + 1;
1014 /* Read the current value */
1015 Value2
= READ_REGISTER_UCHAR(k
);
1017 /* Increase pixel position */
1021 a
= Value2
>> (UCHAR
)RightDelta
;
1022 a
|= Value
<< (UCHAR
)LeftDelta
;
1023 b
= lookup
[a
& 0xF];
1028 /* Save new value to buffer */
1031 /* Move to next destination location */
1034 /* Write new value */
1039 /* Update pixel position */
1040 PixelPosition
+= 80;
1044 } while (++Plane
< 4);
1052 VidSolidColorFill(IN ULONG Left
,
1059 ULONG LeftOffset
, RightOffset
, Distance
;
1063 /* Get the left and right masks, shifts, and delta */
1064 LeftOffset
= Left
>> 3;
1065 lMask
= (lMaskTable
[Left
& 0x7] << 8) | 8;
1066 RightOffset
= Right
>> 3;
1067 rMask
= (rMaskTable
[Right
& 0x7] << 8) | 8;
1068 Distance
= RightOffset
- LeftOffset
;
1070 /* If there is no distance, then combine the right and left masks */
1071 if (!Distance
) lMask
&= rMask
;
1073 /* Switch to mode 10 */
1076 /* Clear the 4 planes (we're already in unchained mode here) */
1077 __outpw(0x3C4, 0xF02);
1079 /* Select the color don't care register */
1082 /* Calculate pixel position for the read */
1083 Offset
= (PUCHAR
)(VgaBase
+ (Top
* 80) + LeftOffset
);
1085 /* Select the bitmask register and write the mask */
1086 __outpw(0x3CE, (USHORT
)lMask
);
1088 /* Check if the top coord is below the bottom one */
1091 /* Start looping each line */
1092 i
= (Bottom
- Top
) + 1;
1095 /* Read the previous value and add our color */
1096 WRITE_REGISTER_UCHAR(Offset
, READ_REGISTER_UCHAR(Offset
) & Color
);
1098 /* Move to the next line */
1103 /* Check if we have a delta */
1106 /* Calculate new pixel position */
1107 Offset
= (PUCHAR
)(VgaBase
+ (Top
* 80) + RightOffset
);
1110 /* Select the bitmask register and write the mask */
1111 __outpw(0x3CE, (USHORT
)rMask
);
1113 /* Check if the top coord is below the bottom one */
1116 /* Start looping each line */
1117 i
= (Bottom
- Top
) + 1;
1120 /* Read the previous value and add our color */
1121 WRITE_REGISTER_UCHAR(Offset
,
1122 READ_REGISTER_UCHAR(Offset
) & Color
);
1124 /* Move to the next line */
1129 /* Check if we still have a delta */
1132 /* Calculate new pixel position */
1133 Offset
= (PUCHAR
)(VgaBase
+ (Top
* 80) + LeftOffset
+ 1);
1135 /* Set the bitmask to 0xFF for all 4 planes */
1136 __outpw(0x3CE, 0xFF08);
1138 /* Check if the top coord is below the bottom one */
1141 /* Start looping each line */
1142 i
= (Bottom
- Top
) + 1;
1145 /* Loop the shift delta */
1148 for (j
= Distance
; j
; Offset
++, j
--)
1150 /* Write the color */
1151 WRITE_REGISTER_UCHAR(Offset
, Color
);
1155 /* Update position in memory */
1156 Offset
+= (80 - Distance
);