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 TextColor
= 0xF;
69 BOOLEAN NextLine
= FALSE
;
70 ULONG_PTR VgaRegisterBase
= 0;
71 ULONG_PTR VgaBase
= 0;
73 /* PRIVATE FUNCTIONS *********************************************************/
77 ReadWriteMode(UCHAR Mode
)
81 /* Switch to graphics mode register */
82 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CE, 5);
84 /* Get the current register value, minus the current mode */
85 Value
= READ_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF) & 0xF4;
87 /* Set the new mode */
88 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF, Mode
| Value
);
93 __outpb(IN ULONG Port
,
96 /* Write to the VGA Register */
97 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ Port
, (UCHAR
)Value
);
102 __outpw(IN ULONG Port
,
105 /* Write to the VGA Register */
106 WRITE_PORT_USHORT((PUSHORT
)(VgaRegisterBase
+ Port
), (USHORT
)Value
);
111 SetPixel(IN ULONG Left
,
115 PUCHAR PixelPosition
;
117 /* Calculate the pixel position. */
118 PixelPosition
= (PUCHAR
)VgaBase
+ (Left
>> 3) + (Top
* 80);
120 /* Switch to mode 10 */
123 /* Clear the 4 planes (we're already in unchained mode here) */
124 __outpw(0x3C4, 0xF02);
126 /* Select the color don't care register */
129 /* Select the bitmask register and write the mask */
130 __outpw(0x3CE, (PixelMask
[Left
& 7] << 8) | 8);
132 /* Read the current pixel value and add our color */
133 WRITE_REGISTER_UCHAR(PixelPosition
,
134 READ_REGISTER_UCHAR(PixelPosition
) & Color
);
139 DisplayCharacter(CHAR Character
,
148 /* Get the font line for this character */
149 FontChar
= &FontData
[Character
* BOOTCHAR_HEIGHT
];
151 /* Loop each pixel height */
155 /* Loop each pixel width */
160 /* Check if we should draw this pixel */
161 #ifdef CHAR_GEN_UPSIDE_DOWN
162 if (FontChar
[i
] & (UCHAR
)j
)
164 /* Normal character generator (top of char is first element) */
165 if (FontChar
[BOOTCHAR_HEIGHT
- i
] & (UCHAR
)j
)
168 /* We do, use the given Text Color */
169 SetPixel(XOffset
, Top
, (UCHAR
)TextColor
);
171 else if (BackTextColor
< 16)
173 /* This is a background pixel. */
174 /* We're drawing it unless it's transparent. */
175 SetPixel(XOffset
, Top
, (UCHAR
)BackTextColor
);
178 /* Increase X Offset */
182 /* Move to the next Y ordinate */
189 DisplayStringXY(PUCHAR String
,
195 /* Loop every character */
198 /* Display a character */
199 DisplayCharacter(*String
, Left
, Top
, TextColor
, BackColor
);
201 /* Move to next character and next position */
209 SetPaletteEntryRGB(IN ULONG Id
,
212 PCHAR Colors
= (PCHAR
)&Rgb
;
214 /* Set the palette index */
215 __outpb(0x3C8, (UCHAR
)Id
);
218 __outpb(0x3C9, Colors
[2] >> 2);
219 __outpb(0x3C9, Colors
[1] >> 2);
220 __outpb(0x3C9, Colors
[0] >> 2);
225 InitPaletteWithTable(IN PULONG Table
,
229 PULONG Entry
= Table
;
231 /* Loop every entry */
232 for (i
= 0; i
< Count
; i
++, Entry
++)
235 SetPaletteEntryRGB(i
, *Entry
);
241 SetPaletteEntry(IN ULONG Id
,
242 IN ULONG PaletteEntry
)
244 /* Set the palette index */
245 __outpb(0x3C8, (UCHAR
)Id
);
248 __outpb(0x3C9, PaletteEntry
& 0xFF);
249 __outpb(0x3C9, (PaletteEntry
>>= 8) & 0xFF);
250 __outpb(0x3C9, (PaletteEntry
>> 8) & 0xFF);
255 InitializePalette(VOID
)
257 ULONG PaletteEntry
[16] = {0,
275 /* Loop all the entries and set their palettes */
276 for (i
= 0; i
< 16; i
++) SetPaletteEntry(i
, PaletteEntry
[i
]);
281 VgaScroll(ULONG Scroll
)
284 ULONG SourceOffset
, DestOffset
;
288 /* Set memory positions of the scroll */
289 SourceOffset
= VgaBase
+ (ScrollRegion
[1] * 80) + (ScrollRegion
[0] >> 3);
290 DestOffset
= SourceOffset
+ (Scroll
* 80);
292 /* Clear the 4 planes */
293 __outpw(0x3C4, 0xF02);
295 /* Set the bitmask to 0xFF for all 4 planes */
296 __outpw(0x3CE, 0xFF08);
301 /* Save top and check if it's above the bottom */
302 Top
= ScrollRegion
[1];
303 if (Top
> ScrollRegion
[3]) return;
308 /* Set number of bytes to loop and start offset */
309 Offset
= ScrollRegion
[0] >> 3;
312 /* Check if this is part of the scroll region */
313 if (Offset
<= (ScrollRegion
[2] >> 3))
315 /* Update position */
316 i
= DestOffset
- SourceOffset
;
318 /* Loop the X axis */
321 /* Write value in the new position so that we can do the scroll */
322 WRITE_REGISTER_UCHAR(UlongToPtr(j
),
323 READ_REGISTER_UCHAR(UlongToPtr(j
+ i
)));
325 /* Move to the next memory location to write to */
328 /* Move to the next byte in the region */
331 /* Make sure we don't go past the scroll region */
332 } while (Offset
<= (ScrollRegion
[2] >> 3));
335 /* Move to the next line */
342 /* Make sure we don't go past the scroll region */
343 } while (Top
<= ScrollRegion
[3]);
348 PreserveRow(IN ULONG CurrentTop
,
350 IN BOOLEAN Direction
)
352 PUCHAR Position1
, Position2
;
355 /* Clear the 4 planes */
356 __outpw(0x3C4, 0xF02);
358 /* Set the bitmask to 0xFF for all 4 planes */
359 __outpw(0x3CE, 0xFF08);
364 /* Check which way we're preserving */
367 /* Calculate the position in memory for the row */
368 Position1
= (PUCHAR
)VgaBase
+ CurrentTop
* 80;
369 Position2
= (PUCHAR
)VgaBase
+ 0x9600;
373 /* Calculate the position in memory for the row */
374 Position1
= (PUCHAR
)VgaBase
+ 0x9600;
375 Position2
= (PUCHAR
)VgaBase
+ CurrentTop
* 80;
378 /* Set the count and make sure it's above 0 */
379 Count
= TopDelta
* 80;
382 /* Loop every pixel */
385 /* Write the data back on the other position */
386 WRITE_REGISTER_UCHAR(Position1
, READ_REGISTER_UCHAR(Position2
));
388 /* Increase both positions */
397 BitBlt(IN ULONG Left
,
402 IN ULONG BitsPerPixel
,
408 const ULONG Bottom
= Top
+ Height
;
409 const ULONG Right
= Left
+ Width
;
411 /* Check if the buffer isn't 4bpp */
412 if (BitsPerPixel
!= 4)
415 DbgPrint("Unhandled BitBlt\n"
416 "%lux%lu @ (%lu|%lu)\n"
417 "Bits Per Pixel %lu\n"
418 "Buffer: %p. Delta: %lu\n",
437 color
= Buffer
[offset
+ sx
];
439 /* Calc destination x */
440 dx
= Left
+ (sx
<< 1);
443 SetPixel(dx
, dy
, color
>> 4);
444 SetPixel(dx
+ 1, dy
, color
& 0x0F);
447 } while (dx
< Right
);
450 } while (dy
< Bottom
);
455 RleBitBlt(IN ULONG Left
,
463 ULONG RleValue
, NewRleValue
;
468 /* Set Y height and current X value and start loop */
469 YDelta
= Top
+ Height
- 1;
473 /* Get the current value and advance in the buffer */
478 /* Check if we've gone past the edge */
479 if ((x
+ RleValue
) > (Width
+ Left
))
481 /* Fixeup the pixel value */
482 RleValue
= Left
- x
+ Width
;
485 /* Get the new value */
486 NewRleValue
= *Buffer
;
488 /* Get the two colors */
489 Color
= NewRleValue
>> 4;
490 Color2
= NewRleValue
& 0xF;
492 /* Increase buffer positition */
495 /* Check if we need to do a fill */
498 /* Do a fill and continue the loop */
500 VidSolidColorFill(x
, YDelta
, RleValue
- 1, YDelta
, (UCHAR
)Color
);
505 /* Check if the pixel value is 1 or below */
508 /* Set loop variables */
509 i
= (RleValue
- 2) / 2 + 1;
513 SetPixel(x
, YDelta
, (UCHAR
)Color
);
515 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
518 /* Decrease pixel value */
523 /* Check if there is any value at all */
526 /* Set the pixel and increase posititon */
527 SetPixel(x
, YDelta
, (UCHAR
)Color
);
535 /* Get the current pixel value */
543 /* Set new x value, decrease distance and restart */
558 /* Set new x value, decrease distance and restart */
573 /* Check if we've gone past the edge */
574 if ((x
+ RleValue
) > (Width
+ Left
))
576 /* Set fixed up loop count */
577 i
= RleValue
- Left
- Width
+ x
;
579 /* Fixup pixel value */
584 /* Clear loop count */
588 /* Check the value now */
591 /* Set loop variables */
592 j
= (RleValue
- 2) / 2 + 1;
595 /* Get the new value */
596 NewRleValue
= *Buffer
;
598 /* Get the two colors */
599 Color
= NewRleValue
>> 4;
600 Color2
= NewRleValue
& 0xF;
602 /* Increase buffer position */
606 SetPixel(x
, YDelta
, (UCHAR
)Color
);
608 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
611 /* Decrease pixel value */
616 /* Check if there is any value at all */
619 /* Set the pixel and increase position */
620 Color
= *Buffer
>> 4;
622 SetPixel(x
, YDelta
, (UCHAR
)Color
);
627 /* Check loop count now */
633 /* Set new position */
634 Buffer
= Buffer
+ (i
/ 2) + 1;
637 /* Check if we need to increase the buffer */
638 if ((ULONG_PTR
)Buffer
& 1) Buffer
++;
642 /* PUBLIC FUNCTIONS **********************************************************/
649 VidSetTextColor(ULONG Color
)
653 /* Save the old color and set the new one */
654 OldColor
= TextColor
;
664 VidDisplayStringXY(PUCHAR String
,
671 /* If the caller wanted transparent, then send the special value (16), else */
672 /* use our default and call the helper routine. */
673 BackColor
= (Transparent
) ? 16 : 14;
674 DisplayStringXY(String
, Left
, Top
, 12, BackColor
);
682 VidSetScrollRegion(ULONG x1
,
687 /* Assert alignment */
688 ASSERT((x1
& 0x7) == 0);
689 ASSERT((x2
& 0x7) == 7);
691 /* Set Scroll Region */
692 ScrollRegion
[0] = x1
;
693 ScrollRegion
[1] = y1
;
694 ScrollRegion
[2] = x2
;
695 ScrollRegion
[3] = y2
;
697 /* Set current X and Y */
709 /* Select bit mask register */
710 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CE, 8);
713 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF, 255);
721 VidBufferToScreenBlt(IN PUCHAR Buffer
,
728 /* Make sure we have a width and height */
729 if (!(Width
) || !(Height
)) return;
731 /* Call the helper function */
732 BitBlt(Left
, Top
, Width
, Height
, Buffer
, 4, Delta
);
740 VidDisplayString(PUCHAR String
)
744 /* Start looping the string */
747 /* Treat new-line separately */
750 /* Modify Y position */
752 if (curr_y
>= ScrollRegion
[3])
754 /* Scroll the view */
759 PreserveRow(curr_y
, TopDelta
, TRUE
);
762 /* Update current X */
763 curr_x
= ScrollRegion
[0];
765 /* Preseve the current row */
766 PreserveRow(curr_y
, TopDelta
, FALSE
);
768 else if (*String
== '\r')
770 /* Update current X */
771 curr_x
= ScrollRegion
[0];
773 /* Check if we're being followed by a new line */
774 if (String
[1] != '\n') NextLine
= TRUE
;
778 /* Check if we had a \n\r last time */
781 /* We did, preserve the current row */
782 PreserveRow(curr_y
, TopDelta
, TRUE
);
786 /* Display this character */
787 DisplayCharacter(*String
, curr_x
, curr_y
, TextColor
, 16);
790 /* Check if we should scroll */
791 if (curr_x
> ScrollRegion
[2])
793 /* Update Y position and check if we should scroll it */
795 if (curr_y
> ScrollRegion
[3])
802 PreserveRow(curr_y
, TopDelta
, TRUE
);
806 curr_x
= ScrollRegion
[0];
810 /* Get the next character */
820 VidBitBlt(PUCHAR Buffer
,
824 PBITMAPINFOHEADER BitmapInfoHeader
;
828 /* Get the Bitmap Header */
829 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Buffer
;
831 /* Initialize the palette */
832 InitPaletteWithTable((PULONG
)(Buffer
+ BitmapInfoHeader
->biSize
),
833 (BitmapInfoHeader
->biClrUsed
) ?
834 BitmapInfoHeader
->biClrUsed
: 16);
836 /* Make sure we can support this bitmap */
837 ASSERT((BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biPlanes
) <= 4);
839 /* Calculate the delta and align it on 32-bytes, then calculate the actual */
840 /* start of the bitmap data. */
841 Delta
= (BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biWidth
) + 31;
844 BitmapOffset
= Buffer
+ sizeof(BITMAPINFOHEADER
) + 16 * sizeof(ULONG
);
846 /* Check the compression of the bitmap */
847 if (BitmapInfoHeader
->biCompression
== 2)
849 /* Make sure we have a width and a height */
850 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
852 /* We can use RLE Bit Blt */
855 BitmapInfoHeader
->biWidth
,
856 BitmapInfoHeader
->biHeight
,
862 /* Check if the height is negative */
863 if (BitmapInfoHeader
->biHeight
< 0)
865 /* Make it positive in the header */
866 BitmapInfoHeader
->biHeight
*= -1;
870 /* Update buffer offset */
871 BitmapOffset
+= ((BitmapInfoHeader
->biHeight
-1) * Delta
);
875 /* Make sure we have a width and a height */
876 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
881 BitmapInfoHeader
->biWidth
,
882 BitmapInfoHeader
->biHeight
,
884 BitmapInfoHeader
->biBitCount
,
895 VidScreenToBufferBlt(PUCHAR Buffer
,
904 ULONG LeftDelta
, RightDelta
;
906 PUCHAR PixelPosition
;
914 /* Calculate total distance to copy on X */
915 XDistance
= Left
+ Width
- 1;
917 /* Start at plane 0 */
920 /* Calculate the 8-byte left and right deltas */
921 LeftDelta
= Left
& 7;
922 RightDelta
= 8 - LeftDelta
;
924 /* Clear the destination buffer */
925 RtlZeroMemory(Buffer
, Delta
* Height
);
927 /* Calculate the pixel offset and convert the X distance into byte form */
928 PixelOffset
= Top
* 80 + (Left
>> 3);
931 /* Loop the 4 planes */
934 /* Set the current pixel position and reset buffer loop variable */
935 PixelPosition
= (PUCHAR
)VgaBase
+ PixelOffset
;
941 /* Set the current plane */
942 __outpw(0x3CE, (Plane
<< 8) | 4);
944 /* Make sure we have a height */
947 /* Start the outer Y loop */
951 /* Read the current value */
953 Value
= READ_REGISTER_UCHAR(PixelPosition
);
955 /* Set Pixel Position loop variable */
956 k
= PixelPosition
+ 1;
958 /* Check if we're still within bounds */
959 if (Left
<= XDistance
)
961 /* Start X Inner loop */
962 x
= (XDistance
- Left
) + 1;
965 /* Read the current value */
966 Value2
= READ_REGISTER_UCHAR(k
);
968 /* Increase pixel position */
972 a
= Value2
>> (UCHAR
)RightDelta
;
973 a
|= Value
<< (UCHAR
)LeftDelta
;
979 /* Save new value to buffer */
982 /* Move to next destination location */
985 /* Write new value */
990 /* Update pixel position */
995 } while (++Plane
< 4);
1003 VidSolidColorFill(IN ULONG Left
,
1010 ULONG LeftOffset
, RightOffset
, Distance
;
1014 /* Get the left and right masks, shifts, and delta */
1015 LeftOffset
= Left
>> 3;
1016 lMask
= (lMaskTable
[Left
& 0x7] << 8) | 8;
1017 RightOffset
= Right
>> 3;
1018 rMask
= (rMaskTable
[Right
& 0x7] << 8) | 8;
1019 Distance
= RightOffset
- LeftOffset
;
1021 /* If there is no distance, then combine the right and left masks */
1022 if (!Distance
) lMask
&= rMask
;
1024 /* Switch to mode 10 */
1027 /* Clear the 4 planes (we're already in unchained mode here) */
1028 __outpw(0x3C4, 0xF02);
1030 /* Select the color don't care register */
1033 /* Calculate pixel position for the read */
1034 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)LeftOffset
;
1036 /* Select the bitmask register and write the mask */
1037 __outpw(0x3CE, (USHORT
)lMask
);
1039 /* Check if the top coord is below the bottom one */
1042 /* Start looping each line */
1043 i
= (Bottom
- Top
) + 1;
1046 /* Read the previous value and add our color */
1047 WRITE_REGISTER_UCHAR(Offset
, READ_REGISTER_UCHAR(Offset
) & Color
);
1049 /* Move to the next line */
1054 /* Check if we have a delta */
1057 /* Calculate new pixel position */
1058 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)RightOffset
;
1061 /* Select the bitmask register and write the mask */
1062 __outpw(0x3CE, (USHORT
)rMask
);
1064 /* Check if the top coord is below the bottom one */
1067 /* Start looping each line */
1068 i
= (Bottom
- Top
) + 1;
1071 /* Read the previous value and add our color */
1072 WRITE_REGISTER_UCHAR(Offset
,
1073 READ_REGISTER_UCHAR(Offset
) & Color
);
1075 /* Move to the next line */
1080 /* Check if we still have a delta */
1083 /* Calculate new pixel position */
1084 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(ULONG_PTR
)(LeftOffset
+ 1);
1086 /* Set the bitmask to 0xFF for all 4 planes */
1087 __outpw(0x3CE, 0xFF08);
1089 /* Check if the top coord is below the bottom one */
1092 /* Start looping each line */
1093 i
= (Bottom
- Top
) + 1;
1096 /* Loop the shift delta */
1099 for (j
= Distance
; j
; Offset
++, j
--)
1101 /* Write the color */
1102 WRITE_REGISTER_UCHAR(Offset
, Color
);
1106 /* Update position in memory */
1107 Offset
+= (80 - Distance
);