Changeset a71c158 in mainline for kernel/genarch/src/fb/fb.c
- Timestamp:
- 2009-08-21T14:12:45Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0e6dce8, b50b5af2, e5792d1
- Parents:
- 90c8b8d
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/genarch/src/fb/fb.c
r90c8b8d ra71c158 53 53 #include <byteorder.h> 54 54 55 SPINLOCK_INITIALIZE(fb_lock);56 57 static uint8_t *fb_addr;58 static uint16_t *backbuf;59 static uint8_t *glyphs;60 static uint8_t *bgscan;61 62 static unsigned int xres;63 static unsigned int yres;64 65 static unsigned int ylogo;66 static unsigned int ytrim;67 static unsigned int rowtrim;68 69 static unsigned int scanline;70 static unsigned int glyphscanline;71 72 static unsigned int pixelbytes;73 static unsigned int glyphbytes;74 static unsigned int bgscanbytes;75 76 static unsigned int cols;77 static unsigned int rows;78 static unsigned int position = 0;79 80 55 #define BG_COLOR 0x000080 81 56 #define FG_COLOR 0xffff00 82 57 #define INV_COLOR 0xaaaaaa 83 58 84 #define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1)) 85 #define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1)) 86 #define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1)) 87 88 #define COL2X(col) ((col) * FONT_WIDTH) 89 #define ROW2Y(row) ((row) * FONT_SCANLINES) 90 91 #define X2COL(x) ((x) / FONT_WIDTH) 92 #define Y2ROW(y) ((y) / FONT_SCANLINES) 93 94 #define FB_POS(x, y) ((y) * scanline + (x) * pixelbytes) 95 #define BB_POS(col, row) ((row) * cols + (col)) 96 #define GLYPH_POS(glyph, y) ((glyph) * glyphbytes + (y) * glyphscanline) 97 98 99 static void (*rgb_conv)(void *, uint32_t); 59 #define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1)) 60 #define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1)) 61 #define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1)) 62 63 #define COL2X(col) ((col) * FONT_WIDTH) 64 #define ROW2Y(row) ((row) * FONT_SCANLINES) 65 66 #define X2COL(x) ((x) / FONT_WIDTH) 67 #define Y2ROW(y) ((y) / FONT_SCANLINES) 68 69 #define FB_POS(instance, x, y) \ 70 ((y) * (instance)->scanline + (x) * (instance)->pixelbytes) 71 72 #define BB_POS(instance, col, row) \ 73 ((row) * (instance)->cols + (col)) 74 75 #define GLYPH_POS(instance, glyph, y) \ 76 ((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline) 77 78 typedef void (* rgb_conv_t)(void *, uint32_t); 79 80 typedef struct { 81 SPINLOCK_DECLARE(lock); 82 83 uint8_t *addr; 84 uint16_t *backbuf; 85 uint8_t *glyphs; 86 uint8_t *bgscan; 87 88 rgb_conv_t rgb_conv; 89 90 unsigned int xres; 91 unsigned int yres; 92 93 unsigned int ylogo; 94 unsigned int ytrim; 95 unsigned int rowtrim; 96 97 unsigned int scanline; 98 unsigned int glyphscanline; 99 100 unsigned int pixelbytes; 101 unsigned int glyphbytes; 102 unsigned int bgscanbytes; 103 104 unsigned int cols; 105 unsigned int rows; 106 107 unsigned int position; 108 } fb_instance_t; 109 110 static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent); 111 static void fb_redraw_internal(fb_instance_t *instance); 112 static void fb_redraw(outdev_t *dev); 113 114 static outdev_operations_t fbdev_ops = { 115 .write = fb_putchar, 116 .redraw = fb_redraw 117 }; 100 118 101 119 /* … … 169 187 GREEN(rgb, 6) << 5 | BLUE(rgb, 5)); 170 188 } 171 172 189 173 190 /** BGR 3:2:3 … … 179 196 * and setting it to simulate the 8-bit truecolor. 180 197 * 181 * Currently we set the palette on the ia32, amd64 and sparc64 port.198 * Currently we set the palette on the ia32, amd64, ppc32 and sparc64 port. 182 199 * 183 200 * Note that the byte is being inverted by this function. The reason is … … 194 211 } 195 212 196 197 213 /** Hide logo and refresh screen 198 214 * 199 215 */ 200 static void logo_hide(bool silent) 201 { 202 ylogo = 0; 203 ytrim = yres; 204 rowtrim = rows; 216 static void logo_hide(fb_instance_t *instance, bool silent) 217 { 218 instance->ylogo = 0; 219 instance->ytrim = instance->yres; 220 instance->rowtrim = instance->rows; 221 205 222 if (!silent) 206 fb_redraw(); 207 } 208 223 fb_redraw_internal(instance); 224 } 209 225 210 226 /** Draw character at given position 211 227 * 212 228 */ 213 static void glyph_draw(uint16_t glyph, unsigned int col, unsigned int row, bool silent, bool overlay) 229 static void glyph_draw(fb_instance_t *instance, uint16_t glyph, 230 unsigned int col, unsigned int row, bool silent, bool overlay) 214 231 { 215 232 unsigned int x = COL2X(col); … … 217 234 unsigned int yd; 218 235 219 if (y >= ytrim)220 logo_hide( silent);236 if (y >= instance->ytrim) 237 logo_hide(instance, silent); 221 238 222 239 if (!overlay) 223 backbuf[BB_POS(col, row)] = glyph;240 instance->backbuf[BB_POS(instance, col, row)] = glyph; 224 241 225 242 if (!silent) { 226 243 for (yd = 0; yd < FONT_SCANLINES; yd++) 227 memcpy(& fb_addr[FB_POS(x, y + yd +ylogo)],228 & glyphs[GLYPH_POS(glyph, yd)], glyphscanline);229 }230 }231 244 memcpy(&instance->addr[FB_POS(instance, x, y + yd + instance->ylogo)], 245 &instance->glyphs[GLYPH_POS(instance, glyph, yd)], 246 instance->glyphscanline); 247 } 248 } 232 249 233 250 /** Scroll screen down by one row … … 235 252 * 236 253 */ 237 static void screen_scroll( bool silent)238 { 239 if ( ylogo > 0) {240 logo_hide( silent);254 static void screen_scroll(fb_instance_t *instance, bool silent) 255 { 256 if (instance->ylogo > 0) { 257 logo_hide(instance, silent); 241 258 return; 242 259 } … … 245 262 unsigned int row; 246 263 247 for (row = 0; row < rows; row++) {264 for (row = 0; row < instance->rows; row++) { 248 265 unsigned int y = ROW2Y(row); 249 266 unsigned int yd; … … 253 270 unsigned int col; 254 271 255 for (col = 0, x = 0; col < cols; col++,256 x += FONT_WIDTH) {272 for (col = 0, x = 0; col < instance->cols; 273 col++, x += FONT_WIDTH) { 257 274 uint16_t glyph; 258 275 259 if (row < rows - 1) {260 if ( backbuf[BB_POS(col, row)] ==261 backbuf[BB_POS(col, row + 1)])276 if (row < instance->rows - 1) { 277 if (instance->backbuf[BB_POS(instance, col, row)] == 278 instance->backbuf[BB_POS(instance, col, row + 1)]) 262 279 continue; 263 280 264 glyph = backbuf[BB_POS(col, row + 1)];281 glyph = instance->backbuf[BB_POS(instance, col, row + 1)]; 265 282 } else 266 283 glyph = 0; 267 284 268 memcpy(& fb_addr[FB_POS(x, y + yd)],269 & glyphs[GLYPH_POS(glyph, yd)],270 glyphscanline);285 memcpy(&instance->addr[FB_POS(instance, x, y + yd)], 286 &instance->glyphs[GLYPH_POS(instance, glyph, yd)], 287 instance->glyphscanline); 271 288 } 272 289 } … … 274 291 } 275 292 276 memmove(backbuf, &backbuf[BB_POS(0, 1)], cols * (rows - 1) * sizeof(uint16_t)); 277 memsetw(&backbuf[BB_POS(0, rows - 1)], cols, 0); 278 } 279 280 281 static void cursor_put(bool silent) 282 { 283 unsigned int col = position % cols; 284 unsigned int row = position / cols; 285 286 glyph_draw(fb_font_glyph(U_CURSOR), col, row, silent, true); 287 } 288 289 290 static void cursor_remove(bool silent) 291 { 292 unsigned int col = position % cols; 293 unsigned int row = position / cols; 294 295 glyph_draw(backbuf[BB_POS(col, row)], col, row, silent, true); 296 } 297 298 299 /** Print character to screen 300 * 301 * Emulate basic terminal commands. 302 * 303 */ 304 static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent) 305 { 306 spinlock_lock(&fb_lock); 307 308 switch (ch) { 309 case '\n': 310 cursor_remove(silent); 311 position += cols; 312 position -= position % cols; 313 break; 314 case '\r': 315 cursor_remove(silent); 316 position -= position % cols; 317 break; 318 case '\b': 319 cursor_remove(silent); 320 if (position % cols) 321 position--; 322 break; 323 case '\t': 324 cursor_remove(silent); 325 do { 326 glyph_draw(fb_font_glyph(' '), position % cols, 327 position / cols, silent, false); 328 position++; 329 } while ((position % 8) && (position < cols * rows)); 330 break; 331 default: 332 glyph_draw(fb_font_glyph(ch), position % cols, 333 position / cols, silent, false); 334 position++; 335 } 336 337 if (position >= cols * rows) { 338 position -= cols; 339 screen_scroll(silent); 340 } 341 342 cursor_put(silent); 343 344 spinlock_unlock(&fb_lock); 345 } 346 347 static outdev_t fb_console; 348 static outdev_operations_t fb_ops = { 349 .write = fb_putchar 350 }; 351 293 memmove(instance->backbuf, &instance->backbuf[BB_POS(instance, 0, 1)], 294 instance->cols * (instance->rows - 1) * sizeof(uint16_t)); 295 memsetw(&instance->backbuf[BB_POS(instance, 0, instance->rows - 1)], 296 instance->cols, 0); 297 } 298 299 static void cursor_put(fb_instance_t *instance, bool silent) 300 { 301 unsigned int col = instance->position % instance->cols; 302 unsigned int row = instance->position / instance->cols; 303 304 glyph_draw(instance, fb_font_glyph(U_CURSOR), col, row, silent, true); 305 } 306 307 static void cursor_remove(fb_instance_t *instance, bool silent) 308 { 309 unsigned int col = instance->position % instance->cols; 310 unsigned int row = instance->position / instance->cols; 311 312 glyph_draw(instance, instance->backbuf[BB_POS(instance, col, row)], 313 col, row, silent, true); 314 } 352 315 353 316 /** Render glyphs … … 357 320 * 358 321 */ 359 static void glyphs_render( void)322 static void glyphs_render(fb_instance_t *instance) 360 323 { 361 324 /* Prerender glyphs */ … … 376 339 377 340 for (x = 0; x < FONT_WIDTH; x++) { 378 void *dst = &glyphs[GLYPH_POS(glyph, y) + 379 x * pixelbytes]; 341 void *dst = 342 &instance->glyphs[GLYPH_POS(instance, glyph, y) + 343 x * instance->pixelbytes]; 380 344 uint32_t rgb = (fb_font[glyph][y] & 381 345 (1 << (7 - x))) ? fg_color : BG_COLOR; 382 rgb_conv(dst, rgb);346 instance->rgb_conv(dst, rgb); 383 347 } 384 348 } … … 388 352 unsigned int x; 389 353 390 for (x = 0; x < xres; x++) 391 rgb_conv(&bgscan[x * pixelbytes], BG_COLOR); 392 } 393 394 395 /** Refresh the screen 396 * 397 */ 398 void fb_redraw(void) 399 { 400 if (ylogo > 0) { 354 for (x = 0; x < instance->xres; x++) 355 instance->rgb_conv(&instance->bgscan[x * instance->pixelbytes], BG_COLOR); 356 } 357 358 /** Print character to screen 359 * 360 * Emulate basic terminal commands. 361 * 362 */ 363 static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent) 364 { 365 fb_instance_t *instance = (fb_instance_t *) dev->data; 366 spinlock_lock(&instance->lock); 367 368 switch (ch) { 369 case '\n': 370 cursor_remove(instance, silent); 371 instance->position += instance->cols; 372 instance->position -= instance->position % instance->cols; 373 break; 374 case '\r': 375 cursor_remove(instance, silent); 376 instance->position -= instance->position % instance->cols; 377 break; 378 case '\b': 379 cursor_remove(instance, silent); 380 if (instance->position % instance->cols) 381 instance->position--; 382 break; 383 case '\t': 384 cursor_remove(instance, silent); 385 do { 386 glyph_draw(instance, fb_font_glyph(' '), 387 instance->position % instance->cols, 388 instance->position / instance->cols, silent, false); 389 instance->position++; 390 } while ((instance->position % 8) 391 && (instance->position < instance->cols * instance->rows)); 392 break; 393 default: 394 glyph_draw(instance, fb_font_glyph(ch), 395 instance->position % instance->cols, 396 instance->position / instance->cols, silent, false); 397 instance->position++; 398 } 399 400 if (instance->position >= instance->cols * instance->rows) { 401 instance->position -= instance->cols; 402 screen_scroll(instance, silent); 403 } 404 405 cursor_put(instance, silent); 406 407 spinlock_unlock(&instance->lock); 408 } 409 410 static void fb_redraw_internal(fb_instance_t *instance) 411 { 412 if (instance->ylogo > 0) { 401 413 unsigned int y; 402 414 … … 404 416 unsigned int x; 405 417 406 for (x = 0; x < xres; x++)407 rgb_conv(&fb_addr[FB_POS(x, y)],418 for (x = 0; x < instance->xres; x++) 419 instance->rgb_conv(&instance->addr[FB_POS(instance, x, y)], 408 420 (x < LOGO_WIDTH) ? 409 421 fb_logo[y * LOGO_WIDTH + x] : … … 414 426 unsigned int row; 415 427 416 for (row = 0; row < rowtrim; row++) {417 unsigned int y = ylogo + ROW2Y(row);428 for (row = 0; row < instance->rowtrim; row++) { 429 unsigned int y = instance->ylogo + ROW2Y(row); 418 430 unsigned int yd; 419 431 … … 422 434 unsigned int col; 423 435 424 for (col = 0, x = 0; col < cols;436 for (col = 0, x = 0; col < instance->cols; 425 437 col++, x += FONT_WIDTH) { 426 uint16_t glyph = backbuf[BB_POS(col, row)]; 427 void *dst = &fb_addr[FB_POS(x, y + yd)]; 428 void *src = &glyphs[GLYPH_POS(glyph, yd)]; 429 memcpy(dst, src, glyphscanline); 438 uint16_t glyph = 439 instance->backbuf[BB_POS(instance, col, row)]; 440 void *dst = &instance->addr[FB_POS(instance, x, y + yd)]; 441 void *src = &instance->glyphs[GLYPH_POS(instance, glyph, yd)]; 442 memcpy(dst, src, instance->glyphscanline); 430 443 } 431 444 } 432 445 } 433 446 434 if (COL2X( cols) <xres) {447 if (COL2X(instance->cols) < instance->xres) { 435 448 unsigned int y; 436 unsigned int size = (xres - COL2X(cols)) * pixelbytes; 437 438 for (y = ylogo; y < yres; y++) 439 memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size); 440 } 441 442 if (ROW2Y(rowtrim) + ylogo < yres) { 449 unsigned int size = 450 (instance->xres - COL2X(instance->cols)) * instance->pixelbytes; 451 452 for (y = instance->ylogo; y < instance->yres; y++) 453 memcpy(&instance->addr[FB_POS(instance, COL2X(instance->cols), y)], 454 instance->bgscan, size); 455 } 456 457 if (ROW2Y(instance->rowtrim) + instance->ylogo < instance->yres) { 443 458 unsigned int y; 444 459 445 for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++) 446 memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes); 447 } 448 } 449 460 for (y = ROW2Y(instance->rowtrim) + instance->ylogo; 461 y < instance->yres; y++) 462 memcpy(&instance->addr[FB_POS(instance, 0, y)], 463 instance->bgscan, instance->bgscanbytes); 464 } 465 } 466 467 /** Refresh the screen 468 * 469 */ 470 static void fb_redraw(outdev_t *dev) 471 { 472 fb_instance_t *instance = (fb_instance_t *) dev->data; 473 474 spinlock_lock(&instance->lock); 475 fb_redraw_internal(instance); 476 spinlock_unlock(&instance->lock); 477 } 450 478 451 479 /** Initialize framebuffer as a output character device 452 480 * 453 * @param addr Physical address of the framebuffer 454 * @param x Screen width in pixels 455 * @param y Screen height in pixels 456 * @param scan Bytes per one scanline 457 * @param visual Color model 458 * 459 */ 460 bool fb_init(fb_properties_t *props) 481 */ 482 outdev_t *fb_init(fb_properties_t *props) 461 483 { 462 484 ASSERT(props); … … 465 487 ASSERT(props->scan > 0); 466 488 489 rgb_conv_t rgb_conv; 490 unsigned int pixelbytes; 491 467 492 switch (props->visual) { 468 493 case VISUAL_INDIRECT_8: … … 512 537 default: 513 538 LOG("Unsupported visual."); 514 return false; 515 } 516 517 xres = props->x; 518 yres = props->y; 519 scanline = props->scan; 520 521 cols = X2COL(xres); 522 rows = Y2ROW(yres); 523 524 if (yres > ylogo) { 525 ylogo = LOGO_HEIGHT; 526 rowtrim = rows - Y2ROW(ylogo); 527 if (ylogo % FONT_SCANLINES > 0) 528 rowtrim--; 529 ytrim = ROW2Y(rowtrim); 539 return NULL; 540 } 541 542 outdev_t *fbdev = malloc(sizeof(outdev_t), FRAME_ATOMIC); 543 if (!fbdev) 544 return NULL; 545 546 fb_instance_t *instance = malloc(sizeof(fb_instance_t), FRAME_ATOMIC); 547 if (!instance) { 548 free(fbdev); 549 return NULL; 550 } 551 552 outdev_initialize("fbdev", fbdev, &fbdev_ops); 553 fbdev->data = instance; 554 555 spinlock_initialize(&instance->lock, "*fb_lock"); 556 instance->rgb_conv = rgb_conv; 557 instance->pixelbytes = pixelbytes; 558 instance->xres = props->x; 559 instance->yres = props->y; 560 instance->scanline = props->scan; 561 instance->position = 0; 562 563 instance->cols = X2COL(instance->xres); 564 instance->rows = Y2ROW(instance->yres); 565 566 if (instance->yres > LOGO_HEIGHT) { 567 instance->ylogo = LOGO_HEIGHT; 568 instance->rowtrim = instance->rows - Y2ROW(instance->ylogo); 569 if (instance->ylogo % FONT_SCANLINES > 0) 570 instance->rowtrim--; 571 instance->ytrim = ROW2Y(instance->rowtrim); 530 572 } else { 531 ylogo = 0;532 ytrim =yres;533 rowtrim =rows;534 } 535 536 glyphscanline = FONT_WIDTH *pixelbytes;537 glyphbytes = ROW2Y(glyphscanline);538 bgscanbytes = xres *pixelbytes;539 540 size_t fbsize = scanline *yres;541 size_t bbsize = cols *rows * sizeof(uint16_t);542 size_t glyphsize = FONT_GLYPHS * glyphbytes;543 544 fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);545 if (! fb_addr) {573 instance->ylogo = 0; 574 instance->ytrim = instance->yres; 575 instance->rowtrim = instance->rows; 576 } 577 578 instance->glyphscanline = FONT_WIDTH * instance->pixelbytes; 579 instance->glyphbytes = ROW2Y(instance->glyphscanline); 580 instance->bgscanbytes = instance->xres * instance->pixelbytes; 581 582 size_t fbsize = instance->scanline * instance->yres; 583 size_t bbsize = instance->cols * instance->rows * sizeof(uint16_t); 584 size_t glyphsize = FONT_GLYPHS * instance->glyphbytes; 585 586 instance->addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize); 587 if (!instance->addr) { 546 588 LOG("Unable to map framebuffer."); 547 return false; 548 } 549 550 backbuf = (uint16_t *) malloc(bbsize, 0); 551 if (!backbuf) { 589 free(instance); 590 free(fbdev); 591 return NULL; 592 } 593 594 instance->backbuf = (uint16_t *) malloc(bbsize, 0); 595 if (!instance->backbuf) { 552 596 LOG("Unable to allocate backbuffer."); 553 return false; 554 } 555 556 glyphs = (uint8_t *) malloc(glyphsize, 0); 557 if (!glyphs) { 558 free(backbuf); 597 free(instance); 598 free(fbdev); 599 return NULL; 600 } 601 602 instance->glyphs = (uint8_t *) malloc(glyphsize, 0); 603 if (!instance->glyphs) { 559 604 LOG("Unable to allocate glyphs."); 560 return false; 561 } 562 563 bgscan = malloc(bgscanbytes, 0); 564 if (!bgscan) { 565 free(glyphs); 566 free(backbuf); 605 free(instance->backbuf); 606 free(instance); 607 free(fbdev); 608 return NULL; 609 } 610 611 instance->bgscan = malloc(instance->bgscanbytes, 0); 612 if (!instance->bgscan) { 567 613 LOG("Unable to allocate background pixel."); 568 return false; 569 } 570 571 memsetw(backbuf, cols * rows, 0); 572 glyphs_render(); 573 574 sysinfo_set_item_val("fb", NULL, true); 575 sysinfo_set_item_val("fb.kind", NULL, 1); 576 sysinfo_set_item_val("fb.width", NULL, xres); 577 sysinfo_set_item_val("fb.height", NULL, yres); 578 sysinfo_set_item_val("fb.scanline", NULL, scanline); 579 sysinfo_set_item_val("fb.visual", NULL, props->visual); 580 sysinfo_set_item_val("fb.address.physical", NULL, props->addr); 581 582 fb_redraw(); 583 584 outdev_initialize("fb", &fb_console, &fb_ops); 585 stdout_wire(&fb_console); 586 587 return true; 614 free(instance->glyphs); 615 free(instance->backbuf); 616 free(instance); 617 free(fbdev); 618 return NULL; 619 } 620 621 memsetw(instance->backbuf, instance->cols * instance->rows, 0); 622 glyphs_render(instance); 623 624 if (!fb_exported) { 625 /* 626 * This is the necessary evil until the userspace driver is entirely 627 * self-sufficient. 628 */ 629 sysinfo_set_item_val("fb", NULL, true); 630 sysinfo_set_item_val("fb.kind", NULL, 1); 631 sysinfo_set_item_val("fb.width", NULL, instance->xres); 632 sysinfo_set_item_val("fb.height", NULL, instance->yres); 633 sysinfo_set_item_val("fb.scanline", NULL, instance->scanline); 634 sysinfo_set_item_val("fb.visual", NULL, props->visual); 635 sysinfo_set_item_val("fb.address.physical", NULL, props->addr); 636 637 fb_exported = true; 638 } 639 640 fb_redraw(fbdev); 641 return fbdev; 588 642 } 589 643
Note:
See TracChangeset
for help on using the changeset viewer.