3 /* GLOBALS *******************************************************************/
5 ULONG ScrollRegion
[4] =
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) +
66 ULONG VidTextColor
= 0xF;
69 BOOLEAN CarriageReturn
= FALSE
;
70 ULONG_PTR VgaRegisterBase
= 0;
71 ULONG_PTR VgaBase
= 0;
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(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
);
100 SetPixel(IN ULONG Left
,
104 PUCHAR PixelPosition
;
106 /* Calculate the pixel position. */
107 PixelPosition
= (PUCHAR
)VgaBase
+ (Left
>> 3) + (Top
* 80);
109 /* Select the bitmask register and write the mask */
110 __outpw(0x3CE, (PixelMask
[Left
& 7] << 8) | 8);
112 /* Read the current pixel value and add our color */
113 WRITE_REGISTER_UCHAR(PixelPosition
,
114 READ_REGISTER_UCHAR(PixelPosition
) & Color
);
117 #ifdef CHAR_GEN_UPSIDE_DOWN
118 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
119 # define FONT_PTR_DELTA (-1)
121 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
122 # define FONT_PTR_DELTA (1)
125 #define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
126 /* Select the bitmask register and write the mask */ \
127 __outpw(0x3CE, (_PixelMask << 8) | 8); \
129 /* Set the new color */ \
130 WRITE_REGISTER_UCHAR(_PixelPtr, (UCHAR)_TextColor);\
134 DisplayCharacter(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(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] = {0,
321 /* Loop all the entries and set their palettes */
322 for (i
= 0; i
< 16; i
++) SetPaletteEntry(i
, PaletteEntry
[i
]);
327 VgaScroll(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 make sure it's above 0 */
397 Count
= TopDelta
* 80;
399 #if defined(_M_IX86) || defined(_M_AMD64)
400 __movsb(Position1
, Position2
, Count
);
402 /* Loop every pixel */
405 /* Write the data back on the other position */
406 WRITE_REGISTER_UCHAR(Position1
, READ_REGISTER_UCHAR(Position2
));
408 /* Increase both positions */
417 BitBlt(IN ULONG Left
,
422 IN ULONG BitsPerPixel
,
428 const ULONG Bottom
= Top
+ Height
;
429 const ULONG Right
= Left
+ Width
;
431 /* Check if the buffer isn't 4bpp */
432 if (BitsPerPixel
!= 4)
435 DbgPrint("Unhandled BitBlt\n"
436 "%lux%lu @ (%lu|%lu)\n"
437 "Bits Per Pixel %lu\n"
438 "Buffer: %p. Delta: %lu\n",
449 /* Switch to mode 10 */
452 /* Clear the 4 planes (we're already in unchained mode here) */
453 __outpw(0x3C4, 0xF02);
455 /* Select the color don't care register */
466 color
= Buffer
[offset
+ sx
];
468 /* Calc destination x */
469 dx
= Left
+ (sx
<< 1);
472 SetPixel(dx
, dy
, color
>> 4);
473 SetPixel(dx
+ 1, dy
, color
& 0x0F);
476 } while (dx
< Right
);
479 } while (dy
< Bottom
);
484 RleBitBlt(IN ULONG Left
,
492 ULONG RleValue
, NewRleValue
;
497 /* Switch to mode 10 */
500 /* Clear the 4 planes (we're already in unchained mode here) */
501 __outpw(0x3C4, 0xF02);
503 /* Select the color don't care register */
506 /* Set Y height and current X value and start loop */
507 YDelta
= Top
+ Height
- 1;
511 /* Get the current value and advance in the buffer */
516 /* Check if we've gone past the edge */
517 if ((x
+ RleValue
) > (Width
+ Left
))
519 /* Fixeup the pixel value */
520 RleValue
= Left
- x
+ Width
;
523 /* Get the new value */
524 NewRleValue
= *Buffer
;
526 /* Get the two colors */
527 Color
= NewRleValue
>> 4;
528 Color2
= NewRleValue
& 0xF;
530 /* Increase buffer positition */
533 /* Check if we need to do a fill */
536 /* Do a fill and continue the loop */
538 VidSolidColorFill(x
, YDelta
, RleValue
- 1, YDelta
, (UCHAR
)Color
);
543 /* Check if the pixel value is 1 or below */
546 /* Set loop variables */
547 i
= (RleValue
- 2) / 2 + 1;
551 SetPixel(x
, YDelta
, (UCHAR
)Color
);
553 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
556 /* Decrease pixel value */
561 /* Check if there is any value at all */
564 /* Set the pixel and increase posititon */
565 SetPixel(x
, YDelta
, (UCHAR
)Color
);
573 /* Get the current pixel value */
581 /* Set new x value, decrease distance and restart */
596 /* Set new x value, decrease distance and restart */
611 /* Check if we've gone past the edge */
612 if ((x
+ RleValue
) > (Width
+ Left
))
614 /* Set fixed up loop count */
615 i
= RleValue
- Left
- Width
+ x
;
617 /* Fixup pixel value */
622 /* Clear loop count */
626 /* Check the value now */
629 /* Set loop variables */
630 j
= (RleValue
- 2) / 2 + 1;
633 /* Get the new value */
634 NewRleValue
= *Buffer
;
636 /* Get the two colors */
637 Color
= NewRleValue
>> 4;
638 Color2
= NewRleValue
& 0xF;
640 /* Increase buffer position */
644 SetPixel(x
, YDelta
, (UCHAR
)Color
);
646 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
649 /* Decrease pixel value */
654 /* Check if there is any value at all */
657 /* Set the pixel and increase position */
658 Color
= *Buffer
>> 4;
660 SetPixel(x
, YDelta
, (UCHAR
)Color
);
665 /* Check loop count now */
671 /* Set new position */
672 Buffer
= Buffer
+ (i
/ 2) + 1;
675 /* Check if we need to increase the buffer */
676 if ((ULONG_PTR
)Buffer
& 1) Buffer
++;
680 /* PUBLIC FUNCTIONS **********************************************************/
687 VidSetTextColor(ULONG Color
)
691 /* Save the old color and set the new one */
692 OldColor
= VidTextColor
;
693 VidTextColor
= Color
;
702 VidDisplayStringXY(PUCHAR String
,
709 /* If the caller wanted transparent, then send the special value (16), else */
710 /* use our default and call the helper routine. */
711 BackColor
= (Transparent
) ? 16 : 14;
712 DisplayStringXY(String
, Left
, Top
, 12, BackColor
);
720 VidSetScrollRegion(ULONG x1
,
725 /* Assert alignment */
726 ASSERT((x1
& 0x7) == 0);
727 ASSERT((x2
& 0x7) == 7);
729 /* Set Scroll Region */
730 ScrollRegion
[0] = x1
;
731 ScrollRegion
[1] = y1
;
732 ScrollRegion
[2] = x2
;
733 ScrollRegion
[3] = y2
;
735 /* Set current X and Y */
747 /* Select bit mask register */
748 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CE, 8);
751 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF, 255);
759 VidBufferToScreenBlt(IN PUCHAR Buffer
,
766 /* Make sure we have a width and height */
767 if (!(Width
) || !(Height
)) return;
769 /* Call the helper function */
770 BitBlt(Left
, Top
, Width
, Height
, Buffer
, 4, Delta
);
778 VidDisplayString(PUCHAR String
)
780 ULONG TopDelta
= BOOTCHAR_HEIGHT
+ 1;
782 /* Start looping the string */
785 /* Treat new-line separately */
788 /* Modify Y position */
790 if (curr_y
+ TopDelta
>= ScrollRegion
[3])
792 /* Scroll the view */
799 PreserveRow(curr_y
, TopDelta
, FALSE
);
802 /* Update current X */
803 curr_x
= ScrollRegion
[0];
805 /* Do not clear line if "\r\n" is given */
806 CarriageReturn
= FALSE
;
808 else if (*String
== '\r')
810 /* Update current X */
811 curr_x
= ScrollRegion
[0];
813 /* Check if we're being followed by a new line */
814 CarriageReturn
= TRUE
;
818 /* check if we had a '\r' last time */
821 /* We did, clear the current row */
822 PreserveRow(curr_y
, TopDelta
, TRUE
);
823 CarriageReturn
= FALSE
;
826 /* Display this character */
827 DisplayCharacter(*String
, curr_x
, curr_y
, VidTextColor
, 16);
830 /* Check if we should scroll */
831 if (curr_x
+ 8 > ScrollRegion
[2])
833 /* Update Y position and check if we should scroll it */
835 if (curr_y
+ TopDelta
> ScrollRegion
[3])
843 /* Preserve the current row */
844 PreserveRow(curr_y
, TopDelta
, FALSE
);
848 curr_x
= ScrollRegion
[0];
852 /* Get the next character */
862 VidBitBlt(PUCHAR Buffer
,
866 PBITMAPINFOHEADER BitmapInfoHeader
;
870 /* Get the Bitmap Header */
871 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Buffer
;
873 /* Initialize the palette */
874 InitPaletteWithTable((PULONG
)(Buffer
+ BitmapInfoHeader
->biSize
),
875 (BitmapInfoHeader
->biClrUsed
) ?
876 BitmapInfoHeader
->biClrUsed
: 16);
878 /* Make sure we can support this bitmap */
879 ASSERT((BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biPlanes
) <= 4);
881 /* Calculate the delta and align it on 32-bytes, then calculate the actual */
882 /* start of the bitmap data. */
883 Delta
= (BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biWidth
) + 31;
886 BitmapOffset
= Buffer
+ sizeof(BITMAPINFOHEADER
) + 16 * sizeof(ULONG
);
888 /* Check the compression of the bitmap */
889 if (BitmapInfoHeader
->biCompression
== 2)
891 /* Make sure we have a width and a height */
892 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
894 /* We can use RLE Bit Blt */
897 BitmapInfoHeader
->biWidth
,
898 BitmapInfoHeader
->biHeight
,
904 /* Check if the height is negative */
905 if (BitmapInfoHeader
->biHeight
< 0)
907 /* Make it positive in the header */
908 BitmapInfoHeader
->biHeight
*= -1;
912 /* Update buffer offset */
913 BitmapOffset
+= ((BitmapInfoHeader
->biHeight
-1) * Delta
);
917 /* Make sure we have a width and a height */
918 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
923 BitmapInfoHeader
->biWidth
,
924 BitmapInfoHeader
->biHeight
,
926 BitmapInfoHeader
->biBitCount
,
937 VidScreenToBufferBlt(PUCHAR Buffer
,
946 ULONG LeftDelta
, RightDelta
;
948 PUCHAR PixelPosition
;
956 /* Calculate total distance to copy on X */
957 XDistance
= Left
+ Width
- 1;
959 /* Start at plane 0 */
962 /* Calculate the 8-byte left and right deltas */
963 LeftDelta
= Left
& 7;
964 RightDelta
= 8 - LeftDelta
;
966 /* Clear the destination buffer */
967 RtlZeroMemory(Buffer
, Delta
* Height
);
969 /* Calculate the pixel offset and convert the X distance into byte form */
970 PixelOffset
= Top
* 80 + (Left
>> 3);
973 /* Loop the 4 planes */
976 /* Set the current pixel position and reset buffer loop variable */
977 PixelPosition
= (PUCHAR
)VgaBase
+ PixelOffset
;
983 /* Set the current plane */
984 __outpw(0x3CE, (Plane
<< 8) | 4);
986 /* Make sure we have a height */
989 /* Start the outer Y loop */
993 /* Read the current value */
995 Value
= READ_REGISTER_UCHAR(PixelPosition
);
997 /* Set Pixel Position loop variable */
998 k
= PixelPosition
+ 1;
1000 /* Check if we're still within bounds */
1001 if (Left
<= XDistance
)
1003 /* Start X Inner loop */
1004 x
= (XDistance
- Left
) + 1;
1007 /* Read the current value */
1008 Value2
= READ_REGISTER_UCHAR(k
);
1010 /* Increase pixel position */
1014 a
= Value2
>> (UCHAR
)RightDelta
;
1015 a
|= Value
<< (UCHAR
)LeftDelta
;
1016 b
= lookup
[a
& 0xF];
1021 /* Save new value to buffer */
1024 /* Move to next destination location */
1027 /* Write new value */
1032 /* Update pixel position */
1033 PixelPosition
+= 80;
1037 } while (++Plane
< 4);
1045 VidSolidColorFill(IN ULONG Left
,
1052 ULONG LeftOffset
, RightOffset
, Distance
;
1056 /* Get the left and right masks, shifts, and delta */
1057 LeftOffset
= Left
>> 3;
1058 lMask
= (lMaskTable
[Left
& 0x7] << 8) | 8;
1059 RightOffset
= Right
>> 3;
1060 rMask
= (rMaskTable
[Right
& 0x7] << 8) | 8;
1061 Distance
= RightOffset
- LeftOffset
;
1063 /* If there is no distance, then combine the right and left masks */
1064 if (!Distance
) lMask
&= rMask
;
1066 /* Switch to mode 10 */
1069 /* Clear the 4 planes (we're already in unchained mode here) */
1070 __outpw(0x3C4, 0xF02);
1072 /* Select the color don't care register */
1075 /* Calculate pixel position for the read */
1076 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)LeftOffset
;
1078 /* Select the bitmask register and write the mask */
1079 __outpw(0x3CE, (USHORT
)lMask
);
1081 /* Check if the top coord is below the bottom one */
1084 /* Start looping each line */
1085 i
= (Bottom
- Top
) + 1;
1088 /* Read the previous value and add our color */
1089 WRITE_REGISTER_UCHAR(Offset
, READ_REGISTER_UCHAR(Offset
) & Color
);
1091 /* Move to the next line */
1096 /* Check if we have a delta */
1099 /* Calculate new pixel position */
1100 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)RightOffset
;
1103 /* Select the bitmask register and write the mask */
1104 __outpw(0x3CE, (USHORT
)rMask
);
1106 /* Check if the top coord is below the bottom one */
1109 /* Start looping each line */
1110 i
= (Bottom
- Top
) + 1;
1113 /* Read the previous value and add our color */
1114 WRITE_REGISTER_UCHAR(Offset
,
1115 READ_REGISTER_UCHAR(Offset
) & Color
);
1117 /* Move to the next line */
1122 /* Check if we still have a delta */
1125 /* Calculate new pixel position */
1126 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)(LeftOffset
+ 1);
1128 /* Set the bitmask to 0xFF for all 4 planes */
1129 __outpw(0x3CE, 0xFF08);
1131 /* Check if the top coord is below the bottom one */
1134 /* Start looping each line */
1135 i
= (Bottom
- Top
) + 1;
1138 /* Loop the shift delta */
1141 for (j
= Distance
; j
; Offset
++, j
--)
1143 /* Write the color */
1144 WRITE_REGISTER_UCHAR(Offset
, Color
);
1148 /* Update position in memory */
1149 Offset
+= (80 - Distance
);