1 #include "precomp.h" 2 3 #define NDEBUG 4 #include <debug.h> 5 6 #define LCDTIMING0_PPL(x) ((((x) / 16 - 1) & 0x3f) << 2) 7 #define LCDTIMING1_LPP(x) (((x) & 0x3ff) - 1) 8 #define LCDCONTROL_LCDPWR (1 << 11) 9 #define LCDCONTROL_LCDEN (1) 10 #define LCDCONTROL_LCDBPP(x) (((x) & 7) << 1) 11 #define LCDCONTROL_LCDTFT (1 << 5) 12 13 #define PL110_LCDTIMING0 (PVOID)0xE0020000 14 #define PL110_LCDTIMING1 (PVOID)0xE0020004 15 #define PL110_LCDTIMING2 (PVOID)0xE0020008 16 #define PL110_LCDUPBASE (PVOID)0xE0020010 17 #define PL110_LCDLPBASE (PVOID)0xE0020014 18 #define PL110_LCDCONTROL (PVOID)0xE0020018 19 20 #define READ_REGISTER_ULONG(r) (*(volatile ULONG * const)(r)) 21 #define WRITE_REGISTER_ULONG(r, v) (*(volatile ULONG *)(r) = (v)) 22 23 #define READ_REGISTER_USHORT(r) (*(volatile USHORT * const)(r)) 24 #define WRITE_REGISTER_USHORT(r, v) (*(volatile USHORT *)(r) = (v)) 25 26 PUSHORT VgaArmBase; 27 PHYSICAL_ADDRESS VgaPhysical; 28 BOOLEAN ClearRow = FALSE; 29 UCHAR VidpTextColor = 0xF; 30 ULONG VidpCurrentX = 0; 31 ULONG VidpCurrentY = 0; 32 ULONG VidpScrollRegion[4] = 33 { 34 0, 35 0, 36 SCREEN_WIDTH - 1, 37 SCREEN_HEIGHT - 1 38 }; 39 40 typedef struct _VGA_COLOR 41 { 42 UCHAR Red; 43 UCHAR Green; 44 UCHAR Blue; 45 } VGA_COLOR; 46 47 VGA_COLOR VidpVga8To16BitTransform[16] = 48 { 49 {0x00, 0x00, 0x00}, // Black 50 {0x00, 0x00, 0x08}, // Blue 51 {0x00, 0x08, 0x00}, // Green 52 {0x00, 0x08, 0x08}, // Cyan 53 {0x08, 0x00, 0x00}, // Red 54 {0x08, 0x00, 0x08}, // Magenta 55 {0x0B, 0x0D, 0x0F}, // Brown 56 {0x10, 0x10, 0x10}, // Light Gray 57 {0x08, 0x08, 0x08}, // Dark Gray 58 {0x00, 0x00, 0x1F}, // Light Blue 59 {0x00, 0x1F, 0x00}, // Light Green 60 {0x00, 0x1F, 0x1F}, // Light Cyan 61 {0x1F, 0x00, 0x00}, // Light Red 62 {0x1F, 0x00, 0x1F}, // Light Magenta 63 {0x1F, 0x1F, 0x00}, // Yellow 64 {0x1F, 0x1F, 0x1F}, // White 65 }; 66 67 /* PRIVATE FUNCTIONS *********************************************************/ 68 69 FORCEINLINE 70 USHORT 71 VidpBuildColor(IN UCHAR Color) 72 { 73 UCHAR Red, Green, Blue; 74 75 /* Extract color components */ 76 Red = VidpVga8To16BitTransform[Color].Red; 77 Green = VidpVga8To16BitTransform[Color].Green; 78 Blue = VidpVga8To16BitTransform[Color].Blue; 79 80 /* Build the 16-bit color mask */ 81 return ((Red & 0x1F) << 11) | ((Green & 0x1F) << 6) | ((Blue & 0x1F)); 82 } 83 84 FORCEINLINE 85 VOID 86 VidpSetPixel(IN ULONG Left, 87 IN ULONG Top, 88 IN UCHAR Color) 89 { 90 PUSHORT PixelPosition; 91 92 /* Calculate the pixel position */ 93 PixelPosition = &VgaArmBase[Left + (Top * SCREEN_WIDTH)]; 94 95 /* Set our color */ 96 WRITE_REGISTER_USHORT(PixelPosition, VidpBuildColor(Color)); 97 } 98 99 VOID 100 NTAPI 101 DisplayCharacter(IN CHAR Character, 102 IN ULONG Left, 103 IN ULONG Top, 104 IN ULONG TextColor, 105 IN ULONG BackColor) 106 { 107 PUCHAR FontChar; 108 ULONG i, j, XOffset; 109 110 /* Get the font line for this character */ 111 FontChar = &FontData[Character * BOOTCHAR_HEIGHT - Top]; 112 113 /* Loop each pixel height */ 114 for (i = BOOTCHAR_HEIGHT; i > 0; --i) 115 { 116 /* Loop each pixel width */ 117 XOffset = Left; 118 for (j = (1 << 7); j > 0; j >>= 1) 119 { 120 /* Check if we should draw this pixel */ 121 if (FontChar[Top] & (UCHAR)j) 122 { 123 /* We do, use the given Text Color */ 124 VidpSetPixel(XOffset, Top, (UCHAR)TextColor); 125 } 126 else if (BackColor < 16) 127 { 128 /* 129 * This is a background pixel. We're drawing it 130 * unless it's transparent. 131 */ 132 VidpSetPixel(XOffset, Top, (UCHAR)BackColor); 133 } 134 135 /* Increase X Offset */ 136 XOffset++; 137 } 138 139 /* Move to the next Y ordinate */ 140 Top++; 141 } 142 } 143 144 VOID 145 NTAPI 146 VgaScroll(IN ULONG Scroll) 147 { 148 ULONG Top, Offset; 149 PUSHORT SourceOffset, DestOffset; 150 PUSHORT i, j; 151 152 /* Set memory positions of the scroll */ 153 SourceOffset = &VgaArmBase[(VidpScrollRegion[1] * (SCREEN_WIDTH / 8)) + (VidpScrollRegion[0] >> 3)]; 154 DestOffset = &SourceOffset[Scroll * (SCREEN_WIDTH / 8)]; 155 156 /* Start loop */ 157 for (Top = VidpScrollRegion[1]; Top <= VidpScrollRegion[3]; ++Top) 158 { 159 /* Set number of bytes to loop and start offset */ 160 Offset = VidpScrollRegion[0] >> 3; 161 j = SourceOffset; 162 163 /* Check if this is part of the scroll region */ 164 if (Offset <= (VidpScrollRegion[2] >> 3)) 165 { 166 /* Update position */ 167 i = (PUSHORT)(DestOffset - SourceOffset); 168 169 /* Loop the X axis */ 170 do 171 { 172 /* Write value in the new position so that we can do the scroll */ 173 WRITE_REGISTER_USHORT(j, READ_REGISTER_USHORT(j + (ULONG_PTR)i)); 174 175 /* Move to the next memory location to write to */ 176 j++; 177 178 /* Move to the next byte in the region */ 179 Offset++; 180 181 /* Make sure we don't go past the scroll region */ 182 } while (Offset <= (VidpScrollRegion[2] >> 3)); 183 } 184 185 /* Move to the next line */ 186 SourceOffset += (SCREEN_WIDTH / 8); 187 DestOffset += (SCREEN_WIDTH / 8); 188 } 189 } 190 191 VOID 192 NTAPI 193 PreserveRow(IN ULONG CurrentTop, 194 IN ULONG TopDelta, 195 IN BOOLEAN Restore) 196 { 197 PUSHORT Position1, Position2; 198 ULONG Count; 199 200 /* Calculate the position in memory for the row */ 201 if (Restore) 202 { 203 /* Restore the row by copying back the contents saved off-screen */ 204 Position1 = &VgaArmBase[CurrentTop * (SCREEN_WIDTH / 8)]; 205 Position2 = &VgaArmBase[SCREEN_HEIGHT * (SCREEN_WIDTH / 8)]; 206 } 207 else 208 { 209 /* Preserve the row by saving its contents off-screen */ 210 Position1 = &VgaArmBase[SCREEN_HEIGHT * (SCREEN_WIDTH / 8)]; 211 Position2 = &VgaArmBase[CurrentTop * (SCREEN_WIDTH / 8)]; 212 } 213 214 /* Set the count and loop every pixel */ 215 Count = TopDelta * (SCREEN_WIDTH / 8); 216 while (Count--) 217 { 218 /* Write the data back on the other position */ 219 WRITE_REGISTER_USHORT(Position1, READ_REGISTER_USHORT(Position2)); 220 221 /* Increase both positions */ 222 Position1++; 223 Position2++; 224 } 225 } 226 227 VOID 228 NTAPI 229 VidpInitializeDisplay(VOID) 230 { 231 // 232 // Set framebuffer address 233 // 234 WRITE_REGISTER_ULONG(PL110_LCDUPBASE, VgaPhysical.LowPart); 235 WRITE_REGISTER_ULONG(PL110_LCDLPBASE, VgaPhysical.LowPart); 236 237 // 238 // Initialize timings to 640x480 239 // 240 WRITE_REGISTER_ULONG(PL110_LCDTIMING0, LCDTIMING0_PPL(SCREEN_WIDTH)); 241 WRITE_REGISTER_ULONG(PL110_LCDTIMING1, LCDTIMING1_LPP(SCREEN_HEIGHT)); 242 243 // 244 // Enable the LCD Display 245 // 246 WRITE_REGISTER_ULONG(PL110_LCDCONTROL, 247 LCDCONTROL_LCDEN | 248 LCDCONTROL_LCDTFT | 249 LCDCONTROL_LCDPWR | 250 LCDCONTROL_LCDBPP(4)); 251 } 252 253 /* PUBLIC FUNCTIONS **********************************************************/ 254 255 /* 256 * @implemented 257 */ 258 BOOLEAN 259 NTAPI 260 VidInitialize(IN BOOLEAN SetMode) 261 { 262 DPRINT1("bv-arm v0.1\n"); 263 264 // 265 // Allocate framebuffer 266 // 600kb works out to 640x480@16bpp 267 // 268 VgaPhysical.QuadPart = -1; 269 VgaArmBase = MmAllocateContiguousMemory(600 * 1024, VgaPhysical); 270 if (!VgaArmBase) return FALSE; 271 272 // 273 // Get physical address 274 // 275 VgaPhysical = MmGetPhysicalAddress(VgaArmBase); 276 if (!VgaPhysical.QuadPart) return FALSE; 277 DPRINT1("[BV-ARM] Frame Buffer @ 0x%p 0p%p\n", VgaArmBase, VgaPhysical.LowPart); 278 279 // 280 // Setup the display 281 // 282 VidpInitializeDisplay(); 283 284 // 285 // We are done! 286 // 287 return TRUE; 288 } 289 290 /* 291 * @implemented 292 */ 293 VOID 294 NTAPI 295 VidResetDisplay(IN BOOLEAN HalReset) 296 { 297 // 298 // Clear the current position 299 // 300 VidpCurrentX = 0; 301 VidpCurrentY = 0; 302 303 // 304 // Re-initialize the VGA Display 305 // 306 VidpInitializeDisplay(); 307 308 // 309 // Re-initialize the palette and fill the screen black 310 // 311 //InitializePalette(); 312 VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); 313 } 314 315 /* 316 * @implemented 317 */ 318 ULONG 319 NTAPI 320 VidSetTextColor(IN ULONG Color) 321 { 322 UCHAR OldColor; 323 324 // 325 // Save the old, set the new 326 // 327 OldColor = VidpTextColor; 328 VidpTextColor = Color; 329 330 // 331 // Return the old text color 332 // 333 return OldColor; 334 } 335 336 /* 337 * @implemented 338 */ 339 VOID 340 NTAPI 341 VidDisplayStringXY(IN PUCHAR String, 342 IN ULONG Left, 343 IN ULONG Top, 344 IN BOOLEAN Transparent) 345 { 346 UNIMPLEMENTED; 347 while (TRUE); 348 } 349 350 /* 351 * @implemented 352 */ 353 VOID 354 NTAPI 355 VidSetScrollRegion(IN ULONG Left, 356 IN ULONG Top, 357 IN ULONG Right, 358 IN ULONG Bottom) 359 { 360 /* Assert alignment */ 361 ASSERT((Left & 0x7) == 0); 362 ASSERT((Right & 0x7) == 7); 363 364 /* Set Scroll Region */ 365 VidpScrollRegion[0] = Left; 366 VidpScrollRegion[1] = Top; 367 VidpScrollRegion[2] = Right; 368 VidpScrollRegion[3] = Bottom; 369 370 /* Set current X and Y */ 371 VidpCurrentX = Left; 372 VidpCurrentY = Top; 373 } 374 375 /* 376 * @implemented 377 */ 378 VOID 379 NTAPI 380 VidCleanUp(VOID) 381 { 382 UNIMPLEMENTED; 383 while (TRUE); 384 } 385 386 /* 387 * @implemented 388 */ 389 VOID 390 NTAPI 391 VidBufferToScreenBlt(IN PUCHAR Buffer, 392 IN ULONG Left, 393 IN ULONG Top, 394 IN ULONG Width, 395 IN ULONG Height, 396 IN ULONG Delta) 397 { 398 UNIMPLEMENTED; 399 while (TRUE); 400 } 401 402 /* 403 * @implemented 404 */ 405 VOID 406 NTAPI 407 VidDisplayString(IN PUCHAR String) 408 { 409 ULONG TopDelta = BOOTCHAR_HEIGHT + 1; 410 411 /* Start looping the string */ 412 for (; *String; ++String) 413 { 414 /* Treat new-line separately */ 415 if (*String == '\n') 416 { 417 /* Modify Y position */ 418 VidpCurrentY += TopDelta; 419 if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3]) 420 { 421 /* Scroll the view and clear the current row */ 422 VgaScroll(TopDelta); 423 VidpCurrentY -= TopDelta; 424 PreserveRow(VidpCurrentY, TopDelta, TRUE); 425 } 426 else 427 { 428 /* Preserve the current row */ 429 PreserveRow(VidpCurrentY, TopDelta, FALSE); 430 } 431 432 /* Update current X */ 433 VidpCurrentX = VidpScrollRegion[0]; 434 435 /* No need to clear this row */ 436 ClearRow = FALSE; 437 } 438 else if (*String == '\r') 439 { 440 /* Update current X */ 441 VidpCurrentX = VidpScrollRegion[0]; 442 443 /* If a new-line does not follow we will clear the current row */ 444 if (String[1] != '\n') ClearRow = TRUE; 445 } 446 else 447 { 448 /* Clear the current row if we had a return-carriage without a new-line */ 449 if (ClearRow) 450 { 451 PreserveRow(VidpCurrentY, TopDelta, TRUE); 452 ClearRow = FALSE; 453 } 454 455 /* Display this character */ 456 DisplayCharacter(*String, 457 VidpCurrentX, 458 VidpCurrentY, 459 VidpTextColor, 460 16); 461 VidpCurrentX += 8; 462 463 /* Check if we should scroll */ 464 if (VidpCurrentX + 7 > VidpScrollRegion[2]) 465 { 466 /* Update Y position and check if we should scroll it */ 467 VidpCurrentY += TopDelta; 468 if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3]) 469 { 470 /* Scroll the view and clear the current row */ 471 VgaScroll(TopDelta); 472 VidpCurrentY -= TopDelta; 473 PreserveRow(VidpCurrentY, TopDelta, TRUE); 474 } 475 else 476 { 477 /* Preserve the current row */ 478 PreserveRow(VidpCurrentY, TopDelta, FALSE); 479 } 480 481 /* Update current X */ 482 VidpCurrentX = VidpScrollRegion[0]; 483 } 484 } 485 } 486 } 487 488 /* 489 * @implemented 490 */ 491 VOID 492 NTAPI 493 VidBitBlt(IN PUCHAR Buffer, 494 IN ULONG Left, 495 IN ULONG Top) 496 { 497 UNIMPLEMENTED; 498 //while (TRUE); 499 } 500 501 /* 502 * @implemented 503 */ 504 VOID 505 NTAPI 506 VidScreenToBufferBlt(IN PUCHAR Buffer, 507 IN ULONG Left, 508 IN ULONG Top, 509 IN ULONG Width, 510 IN ULONG Height, 511 IN ULONG Delta) 512 { 513 UNIMPLEMENTED; 514 while (TRUE); 515 } 516 517 /* 518 * @implemented 519 */ 520 VOID 521 NTAPI 522 VidSolidColorFill(IN ULONG Left, 523 IN ULONG Top, 524 IN ULONG Right, 525 IN ULONG Bottom, 526 IN UCHAR Color) 527 { 528 int y, x; 529 530 // 531 // Loop along the Y-axis 532 // 533 for (y = Top; y <= Bottom; y++) 534 { 535 // 536 // Loop along the X-axis 537 // 538 for (x = Left; x <= Right; x++) 539 { 540 // 541 // Draw the pixel 542 // 543 VidpSetPixel(x, y, Color); 544 } 545 } 546 } 547