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
* 13 - Top
];
151 /* Loop each pixel height */
155 /* Loop each pixel width */
160 /* Check if we should draw this pixel */
161 if (FontChar
[Top
] & (UCHAR
)j
)
163 /* We do, use the given Text Color */
164 SetPixel(XOffset
, Top
, (UCHAR
)TextColor
);
166 else if (BackTextColor
< 16)
168 /* This is a background pixel. We're drawing it unless it's */
170 SetPixel(XOffset
, Top
, (UCHAR
)BackTextColor
);
173 /* Increase X Offset */
177 /* Move to the next Y ordinate */
184 DisplayStringXY(PUCHAR String
,
190 /* Loop every character */
193 /* Display a character */
194 DisplayCharacter(*String
, Left
, Top
, TextColor
, BackColor
);
196 /* Move to next character and next position */
204 SetPaletteEntryRGB(IN ULONG Id
,
207 PCHAR Colors
= (PCHAR
)&Rgb
;
209 /* Set the palette index */
210 __outpb(0x3C8, (UCHAR
)Id
);
213 __outpb(0x3C9, Colors
[2] >> 2);
214 __outpb(0x3C9, Colors
[1] >> 2);
215 __outpb(0x3C9, Colors
[0] >> 2);
220 InitPaletteWithTable(IN PULONG Table
,
224 PULONG Entry
= Table
;
226 /* Loop every entry */
227 for (i
= 0; i
< Count
; i
++, Entry
++)
230 SetPaletteEntryRGB(i
, *Entry
);
236 SetPaletteEntry(IN ULONG Id
,
237 IN ULONG PaletteEntry
)
239 /* Set the palette index */
240 __outpb(0x3C8, (UCHAR
)Id
);
243 __outpb(0x3C9, PaletteEntry
& 0xFF);
244 __outpb(0x3C9, (PaletteEntry
>>= 8) & 0xFF);
245 __outpb(0x3C9, (PaletteEntry
>> 8) & 0xFF);
250 InitializePalette(VOID
)
252 ULONG PaletteEntry
[16] = {0,
270 /* Loop all the entries and set their palettes */
271 for (i
= 0; i
< 16; i
++) SetPaletteEntry(i
, PaletteEntry
[i
]);
276 VgaScroll(ULONG Scroll
)
279 ULONG SourceOffset
, DestOffset
;
283 /* Set memory positions of the scroll */
284 SourceOffset
= VgaBase
+ (ScrollRegion
[1] * 80) + (ScrollRegion
[0] >> 3);
285 DestOffset
= SourceOffset
+ (Scroll
* 80);
287 /* Clear the 4 planes */
288 __outpw(0x3C4, 0xF02);
290 /* Set the bitmask to 0xFF for all 4 planes */
291 __outpw(0x3CE, 0xFF08);
296 /* Save top and check if it's above the bottom */
297 Top
= ScrollRegion
[1];
298 if (Top
> ScrollRegion
[3]) return;
303 /* Set number of bytes to loop and start offset */
304 Offset
= ScrollRegion
[0] >> 3;
307 /* Check if this is part of the scroll region */
308 if (Offset
<= (ScrollRegion
[2] >> 3))
310 /* Update position */
311 i
= DestOffset
- SourceOffset
;
313 /* Loop the X axis */
316 /* Write value in the new position so that we can do the scroll */
317 WRITE_REGISTER_UCHAR((PUCHAR
)j
,
318 READ_REGISTER_UCHAR((PUCHAR
)j
+ i
));
320 /* Move to the next memory location to write to */
323 /* Move to the next byte in the region */
326 /* Make sure we don't go past the scroll region */
327 } while (Offset
<= (ScrollRegion
[2] >> 3));
330 /* Move to the next line */
337 /* Make sure we don't go past the scroll region */
338 } while (Top
<= ScrollRegion
[3]);
343 PreserveRow(IN ULONG CurrentTop
,
345 IN BOOLEAN Direction
)
347 PUCHAR Position1
, Position2
;
350 /* Clear the 4 planes */
351 __outpw(0x3C4, 0xF02);
353 /* Set the bitmask to 0xFF for all 4 planes */
354 __outpw(0x3CE, 0xFF08);
359 /* Check which way we're preserving */
362 /* Calculate the position in memory for the row */
363 Position1
= (PUCHAR
)VgaBase
+ CurrentTop
* 80;
364 Position2
= (PUCHAR
)VgaBase
+ 0x9600;
368 /* Calculate the position in memory for the row */
369 Position1
= (PUCHAR
)VgaBase
+ 0x9600;
370 Position2
= (PUCHAR
)VgaBase
+ CurrentTop
* 80;
373 /* Set the count and make sure it's above 0 */
374 Count
= TopDelta
* 80;
377 /* Loop every pixel */
380 /* Write the data back on the other position */
381 WRITE_REGISTER_UCHAR(Position1
, READ_REGISTER_UCHAR(Position2
));
383 /* Increase both positions */
392 BitBlt(IN ULONG Left
,
397 IN ULONG BitsPerPixel
,
400 ULONG LeftAnd
, LeftShifted
, LeftPlusOne
, LeftPos
;
404 ULONG DistanceMinusLeftBpp
;
405 ULONG SomeYesNoFlag
, SomeYesNoFlag2
;
406 PUCHAR PixelPosition
, m
;
415 UCHAR pMask
, PlaneShift
;
419 /* Check if the buffer isn't 4bpp */
420 if (BitsPerPixel
!= 4)
423 DbgPrint("Unhandled BitBlt\n"
424 "%lxx%lx @ (%lx,%lx)\n"
425 "Bits Per Pixel %lx\n"
426 "Buffer: %p. Delta: %lx\n",
437 /* Get the masks and other values */
438 LeftAnd
= Left
& 0x7;
439 lMask
= lMaskTable
[LeftAnd
];
440 Distance
= Width
+ Left
;
441 rMask
= rMaskTable
[(Distance
- 1) & 0x7];
444 /* Set some values */
445 SomeYesNoFlag
= FALSE
;
446 SomeYesNoFlag2
= FALSE
;
447 Distance
= (Distance
- 1) >> 3;
448 DistanceMinusLeftBpp
= Distance
- Left
;
450 /* Check if the distance is equal to the left position and add the masks */
451 if (Left
== Distance
) lMask
+= rMask
;
453 /* Check if there's no distance offset */
454 if (DistanceMinusLeftBpp
)
456 /* Set the first flag on */
457 SomeYesNoFlag
= TRUE
;
459 /* Decrease offset and check if we still have one */
460 if (--DistanceMinusLeftBpp
)
462 /* Still have a distance offset */
463 SomeYesNoFlag2
= TRUE
;
467 /* Calculate initial pixel position */
468 PixelPosition
= (PUCHAR
)VgaBase
+ (Top
* 80) + Left
;
470 /* Set loop buffer variable */
473 /* Switch to mode 0 */
476 /* Leave now if the height is 0 */
477 if (Height
<= 0) return;
479 /* Set more weird values */
480 CurrentLeft
= &LeftArray
[Left
];
481 NotlMask
= ~(UCHAR
)lMask
;
482 LeftPlusOne
= Left
+ 1;
483 LeftShifted
= (lMask
<< 8) | 8;
486 /* Start the height loop */
489 /* Start the plane loop */
493 /* Clear the current value */
497 /* Set the buffer loop variable for this loop */
500 /* Calculate plane shift and pixel mask */
501 PlaneShift
= 1 << Plane
;
502 pMask
= PixelMask
[LeftAnd
];
504 /* Check if we have a width */
512 /* Check if we're odd and increase the loop count */
513 Odd
= LoopCount
& 1 ? TRUE
: FALSE
;
517 /* Check for the plane shift */
520 /* Write the pixel mask */
524 /* Increase buffer position */
529 /* Check for plane shift */
530 if ((*k
>> 4) & PlaneShift
)
532 /* Write the pixel mask */
537 /* Shift the pixel mask */
541 /* Move to the next current left position and clear it */
545 /* Set the pixel mask to 0x80 */
551 /* Set the plane value */
552 __outpw(0x3C4, (1 << (Plane
+ 8) | 2));
554 /* Select the bitmask register and write the mask */
555 __outpw(0x3CE, (USHORT
)LeftShifted
);
557 /* Read the current Pixel value */
558 Value
= READ_REGISTER_UCHAR(PixelPosition
);
561 Value
= (Value
& NotlMask
) | *CurrentLeft
;
563 /* Set current left for the loop, and write new pixel value */
564 LeftPos
= LeftPlusOne
;
565 WRITE_REGISTER_UCHAR(PixelPosition
, Value
);
567 /* Set loop pixel position and check if we should loop */
568 m
= PixelPosition
+ 1;
571 /* Set the bitmask to 0xFF for all 4 planes */
572 __outpw(0x3CE, 0xFF08);
574 /* Check if we have any distance left */
575 if (DistanceMinusLeftBpp
> 0)
577 /* Start looping it */
578 x
= DistanceMinusLeftBpp
;
581 /* Write the value */
582 WRITE_REGISTER_UCHAR(m
, LeftArray
[LeftPos
]);
584 /* Go to the next position */
591 /* Check if the first flag is on */
594 /* Set the mask value */
595 __outpw(0x3CE, (rMask
<< 8) | 8);
597 /* Read the current Pixel value */
598 Value
= READ_REGISTER_UCHAR(m
);
601 Value
= (Value
& ~(UCHAR
)rMask
) | LeftArray
[LeftPos
];
603 /* Set current left for the loop, and write new pixel value */
604 WRITE_REGISTER_UCHAR(m
, Value
);
606 } while (++Plane
< 4);
608 /* Update pixel position, buffer and height */
616 RleBitBlt(IN ULONG Left
,
624 ULONG RleValue
, NewRleValue
;
629 /* Set Y height and current X value and start loop */
630 YDelta
= Top
+ Height
- 1;
634 /* Get the current value and advance in the buffer */
639 /* Check if we've gone past the edge */
640 if ((x
+ RleValue
) > (Width
+ Left
))
642 /* Fixeup the pixel value */
643 RleValue
= Left
- x
+ Width
;
646 /* Get the new value */
647 NewRleValue
= *Buffer
;
649 /* Get the two colors */
650 Color
= NewRleValue
>> 4;
651 Color2
= NewRleValue
& 0xF;
653 /* Increase buffer positition */
656 /* Check if we need to do a fill */
659 /* Do a fill and continue the loop */
661 VidSolidColorFill(x
, YDelta
, RleValue
- 1, YDelta
, (UCHAR
)Color
);
666 /* Check if the pixel value is 1 or below */
669 /* Set loop variables */
670 i
= (RleValue
- 2) / 2 + 1;
674 SetPixel(x
, YDelta
, (UCHAR
)Color
);
676 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
679 /* Decrease pixel value */
684 /* Check if there is any value at all */
687 /* Set the pixel and increase posititon */
688 SetPixel(x
, YDelta
, (UCHAR
)Color
);
696 /* Get the current pixel value */
704 /* Set new x value, decrease distance and restart */
719 /* Set new x value, decrease distance and restart */
734 /* Check if we've gone past the edge */
735 if ((x
+ RleValue
) > (Width
+ Left
))
737 /* Set fixed up loop count */
738 i
= RleValue
- Left
- Width
+ x
;
740 /* Fixup pixel value */
745 /* Clear loop count */
749 /* Check the value now */
752 /* Set loop variables */
753 j
= (RleValue
- 2) / 2 + 1;
756 /* Get the new value */
757 NewRleValue
= *Buffer
;
759 /* Get the two colors */
760 Color
= NewRleValue
>> 4;
761 Color2
= NewRleValue
& 0xF;
763 /* Increase buffer position */
767 SetPixel(x
, YDelta
, (UCHAR
)Color
);
769 SetPixel(x
, YDelta
, (UCHAR
)Color2
);
772 /* Decrease pixel value */
777 /* Check if there is any value at all */
780 /* Set the pixel and increase position */
781 Color
= *Buffer
>> 4;
783 SetPixel(x
, YDelta
, (UCHAR
)Color
);
788 /* Check loop count now */
794 /* Set new position */
795 Buffer
= Buffer
+ (i
/ 2) + 1;
798 /* Check if we need to increase the buffer */
799 if ((ULONG_PTR
)Buffer
& 1) Buffer
++;
803 /* PUBLIC FUNCTIONS **********************************************************/
810 VidSetTextColor(ULONG Color
)
814 /* Save the old color and set the new one */
815 OldColor
= TextColor
;
825 VidDisplayStringXY(PUCHAR String
,
832 /* If the caller wanted transparent, then send the special value (16), else */
833 /* use our default and call the helper routine. */
834 BackColor
= (Transparent
) ? 16 : 14;
835 DisplayStringXY(String
, Left
, Top
, 12, BackColor
);
843 VidSetScrollRegion(ULONG x1
,
848 /* Assert alignment */
849 ASSERT((x1
& 0x7) == 0);
850 ASSERT((x2
& 0x7) == 7);
852 /* Set Scroll Region */
853 ScrollRegion
[0] = x1
;
854 ScrollRegion
[1] = y1
;
855 ScrollRegion
[2] = x2
;
856 ScrollRegion
[3] = y2
;
858 /* Set current X and Y */
870 /* Select bit mask register */
871 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CE, 8);
874 WRITE_PORT_UCHAR((PUCHAR
)VgaRegisterBase
+ 0x3CF, 255);
882 VidBufferToScreenBlt(IN PUCHAR Buffer
,
889 /* Make sure we have a width and height */
890 if (!(Width
) || !(Height
)) return;
892 /* Call the helper function */
893 BitBlt(Left
, Top
, Width
, Height
, Buffer
, 4, Delta
);
901 VidDisplayString(PUCHAR String
)
905 /* Start looping the string */
908 /* Treat new-line separately */
911 /* Modify Y position */
913 if (curr_y
>= ScrollRegion
[3])
915 /* Scroll the view */
920 PreserveRow(curr_y
, TopDelta
, TRUE
);
923 /* Update current X */
924 curr_x
= ScrollRegion
[0];
926 /* Preseve the current row */
927 PreserveRow(curr_y
, TopDelta
, FALSE
);
929 else if (*String
== '\r')
931 /* Update current X */
932 curr_x
= ScrollRegion
[0];
934 /* Check if we're being followed by a new line */
935 if (String
[1] != '\n') NextLine
= TRUE
;
939 /* Check if we had a \n\r last time */
942 /* We did, preserve the current row */
943 PreserveRow(curr_y
, TopDelta
, TRUE
);
947 /* Display this character */
948 DisplayCharacter(*String
, curr_x
, curr_y
, TextColor
, 16);
951 /* Check if we should scroll */
952 if (curr_x
> ScrollRegion
[2])
954 /* Update Y position and check if we should scroll it */
956 if (curr_y
> ScrollRegion
[3])
963 PreserveRow(curr_y
, TopDelta
, TRUE
);
967 curr_x
= ScrollRegion
[0];
971 /* Get the next character */
981 VidBitBlt(PUCHAR Buffer
,
985 PBITMAPINFOHEADER BitmapInfoHeader
;
989 /* Get the Bitmap Header */
990 BitmapInfoHeader
= (PBITMAPINFOHEADER
)Buffer
;
992 /* Initialize the palette */
993 InitPaletteWithTable((PULONG
)(Buffer
+ BitmapInfoHeader
->biSize
),
994 (BitmapInfoHeader
->biClrUsed
) ?
995 BitmapInfoHeader
->biClrUsed
: 16);
997 /* Make sure we can support this bitmap */
998 ASSERT((BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biPlanes
) <= 4);
1000 /* Calculate the delta and align it on 32-bytes, then calculate the actual */
1001 /* start of the bitmap data. */
1002 Delta
= (BitmapInfoHeader
->biBitCount
* BitmapInfoHeader
->biWidth
) + 31;
1005 BitmapOffset
= Buffer
+ sizeof(BITMAPINFOHEADER
) + 16 * sizeof(ULONG
);
1007 /* Check the compression of the bitmap */
1008 if (BitmapInfoHeader
->biCompression
== 2)
1010 /* Make sure we have a width and a height */
1011 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
1013 /* We can use RLE Bit Blt */
1016 BitmapInfoHeader
->biWidth
,
1017 BitmapInfoHeader
->biHeight
,
1023 /* Check if the height is negative */
1024 if (BitmapInfoHeader
->biHeight
< 0)
1026 /* Make it positive in the header */
1027 BitmapInfoHeader
->biHeight
*= -1;
1031 /* Update buffer offset */
1032 BitmapOffset
+= ((BitmapInfoHeader
->biHeight
-1) * Delta
);
1036 /* Make sure we have a width and a height */
1037 if ((BitmapInfoHeader
->biWidth
) && (BitmapInfoHeader
->biHeight
))
1042 BitmapInfoHeader
->biWidth
,
1043 BitmapInfoHeader
->biHeight
,
1045 BitmapInfoHeader
->biBitCount
,
1056 VidScreenToBufferBlt(PUCHAR Buffer
,
1065 ULONG LeftDelta
, RightDelta
;
1067 PUCHAR PixelPosition
;
1070 UCHAR Value
, Value2
;
1075 /* Calculate total distance to copy on X */
1076 XDistance
= Left
+ Width
- 1;
1078 /* Start at plane 0 */
1081 /* Calculate the 8-byte left and right deltas */
1082 LeftDelta
= Left
& 7;
1083 RightDelta
= 8 - LeftDelta
;
1085 /* Clear the destination buffer */
1086 RtlZeroMemory(Buffer
, Delta
* Height
);
1088 /* Calculate the pixel offset and convert the X distance into byte form */
1089 PixelOffset
= Top
* 80 + (Left
>> 3);
1092 /* Loop the 4 planes */
1095 /* Set the current pixel position and reset buffer loop variable */
1096 PixelPosition
= (PUCHAR
)VgaBase
+ PixelOffset
;
1102 /* Set the current plane */
1103 __outpw(0x3CE, (Plane
<< 8) | 4);
1105 /* Make sure we have a height */
1108 /* Start the outer Y loop */
1112 /* Read the current value */
1114 Value
= READ_REGISTER_UCHAR(PixelPosition
);
1116 /* Set Pixel Position loop variable */
1117 k
= PixelPosition
+ 1;
1119 /* Check if we're still within bounds */
1120 if (Left
<= XDistance
)
1122 /* Start X Inner loop */
1123 x
= (XDistance
- Left
) + 1;
1126 /* Read the current value */
1127 Value2
= READ_REGISTER_UCHAR(k
);
1129 /* Increase pixel position */
1133 a
= Value2
>> (UCHAR
)RightDelta
;
1134 a
|= Value
<< (UCHAR
)LeftDelta
;
1135 b
= lookup
[a
& 0xF];
1140 /* Save new value to buffer */
1143 /* Move to next destination location */
1146 /* Write new value */
1151 /* Update pixel position */
1152 PixelPosition
+= 80;
1156 } while (++Plane
< 4);
1164 VidSolidColorFill(IN ULONG Left
,
1171 ULONG LeftOffset
, RightOffset
, Distance
;
1175 /* Get the left and right masks, shifts, and delta */
1176 LeftOffset
= Left
>> 3;
1177 lMask
= (lMaskTable
[Left
& 0x7] << 8) | 8;
1178 RightOffset
= Right
>> 3;
1179 rMask
= (rMaskTable
[Right
& 0x7] << 8) | 8;
1180 Distance
= RightOffset
- LeftOffset
;
1182 /* If there is no distance, then combine the right and left masks */
1183 if (!Distance
) lMask
&= rMask
;
1185 /* Switch to mode 10 */
1188 /* Clear the 4 planes (we're already in unchained mode here) */
1189 __outpw(0x3C4, 0xF02);
1191 /* Select the color don't care register */
1194 /* Calculate pixel position for the read */
1195 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)LeftOffset
;
1197 /* Select the bitmask register and write the mask */
1198 __outpw(0x3CE, (USHORT
)lMask
);
1200 /* Check if the top coord is below the bottom one */
1203 /* Start looping each line */
1204 i
= (Bottom
- Top
) + 1;
1207 /* Read the previous value and add our color */
1208 WRITE_REGISTER_UCHAR(Offset
, READ_REGISTER_UCHAR(Offset
) & Color
);
1210 /* Move to the next line */
1215 /* Check if we have a delta */
1218 /* Calculate new pixel position */
1219 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)RightOffset
;
1222 /* Select the bitmask register and write the mask */
1223 __outpw(0x3CE, (USHORT
)rMask
);
1225 /* Check if the top coord is below the bottom one */
1228 /* Start looping each line */
1229 i
= (Bottom
- Top
) + 1;
1232 /* Read the previous value and add our color */
1233 WRITE_REGISTER_UCHAR(Offset
,
1234 READ_REGISTER_UCHAR(Offset
) & Color
);
1236 /* Move to the next line */
1241 /* Check if we still have a delta */
1244 /* Calculate new pixel position */
1245 Offset
= VgaBase
+ (Top
* 80) + (PUCHAR
)(LeftOffset
+ 1);
1247 /* Set the bitmask to 0xFF for all 4 planes */
1248 __outpw(0x3CE, 0xFF08);
1250 /* Check if the top coord is below the bottom one */
1253 /* Start looping each line */
1254 i
= (Bottom
- Top
) + 1;
1257 /* Loop the shift delta */
1260 for (j
= Distance
; j
; Offset
++, j
--)
1262 /* Write the color */
1263 WRITE_REGISTER_UCHAR(Offset
, Color
);
1267 /* Update position in memory */
1268 Offset
+= (80 - Distance
);