Fork me on GitHub

root/drivers/video/fbcon.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_fg_color
  2. get_bg_color
  3. set_color
  4. draw_glyph
  5. remove_cursor
  6. draw_cursor
  7. fbcon_put_char
  8. fbcon_insert_char
  9. fbcon_delete_char
  10. fbcon_update_curpos
  11. fbcon_show_cursor
  12. fbcon_get_curpos
  13. fbcon_write_screen
  14. fbcon_blank_screen
  15. fbcon_scroll_screen
  16. fbcon_restore_screen
  17. fbcon_screen_on
  18. fbcon_screen_off
  19. fbcon_buf_scroll
  20. fbcon_cursor_blink
  21. fbcon_init

   1 /*
   2  * fiwix/drivers/char/fbcon.c
   3  *
   4  * Copyright 2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/fb.h>
  10 #include <fiwix/fbcon.h>
  11 #include <fiwix/font.h>
  12 #include <fiwix/console.h>
  13 #include <fiwix/tty.h>
  14 #include <fiwix/timer.h>
  15 #include <fiwix/stdio.h>
  16 #include <fiwix/string.h>
  17 
  18 #define SPACE_CHAR      32
  19 
  20 unsigned char *font_data;
  21 unsigned char *cursor_shape;
  22 struct video_parms video;
  23 static unsigned char screen_is_off = 0;
  24 
  25 /* RGB colors */
  26 static int color_table[] = {
  27         0x000000,       /* black */
  28         0x0000AA,       /* blue */
  29         0x00AA00,       /* green */
  30         0x00AAAA,       /* cyan */
  31         0xAA0000,       /* red */
  32         0xAA00AA,       /* magenta */
  33         0xAA5000,       /* brown */
  34         0xAAAAAA,       /* gray */
  35 
  36         0x555555,       /* dark gray */
  37         0x5555FF,       /* light blue */
  38         0x55FF55,       /* light green */
  39         0x55FFFF,       /* light cyan */
  40         0xFF5555,       /* light red */
  41         0xFF55FF,       /* light magenta */
  42         0xFFFF55,       /* yellow */
  43         0xFFFFFF,       /* white */
  44 };
  45 
  46 static int get_fg_color(unsigned char color)
  47 {
  48         int fg, bright;
  49 
  50         fg = color & 7;
  51         bright = (color & 0xF) & 8;
  52         return color_table[bright + fg];
  53 }
  54 
  55 static int get_bg_color(unsigned char color)
  56 {
  57         int bg;
  58 
  59         bg = (color >> 4) & 7;
  60         return color_table[bg];
  61 }
  62 
  63 static void set_color(void *addr, int color)
  64 {
  65         unsigned int *addr32;
  66         unsigned short int *addr16;
  67         unsigned char *addr8;
  68         short int r, g, b;
  69 
  70         switch(video.fb_bpp) {
  71                 case 32:
  72                         addr32 = (unsigned int *)addr;
  73                         *addr32 = color;
  74                         break;
  75                 case 24:
  76                         addr8 = (unsigned char *)addr;
  77                         *(addr8++) = color & 0xFF;
  78                         *(addr8++) = (color >> 8) & 0xFF;
  79                         *(addr8++) = (color >> 16) & 0xFF;
  80                         break;
  81                 case 16:
  82                         /* 0:5:6:5 */
  83                         r = ((color >> 16) & 0xFF) << 8;
  84                         g = ((color >> 8) & 0xFF) << 8;
  85                         b = (color & 0xFF) << 8;
  86                         addr16 = (unsigned short int *)addr;
  87                         *addr16 = (r & 0xf800) | ((g & 0xfc00) >> 5) | ((b & 0xf800) >> 11);
  88                 case 15:
  89                         /* 1:5:5:5 */
  90                         r = ((color >> 16) & 0xFF) << 8;
  91                         g = ((color >> 8) & 0xFF) << 8;
  92                         b = (color & 0xFF) << 8;
  93                         addr16 = (unsigned short int *)addr;
  94                         *addr16 = ((r & 0xf800) >> 1) | ((g & 0xf800) >> 6) | ((b & 0xf800) >> 11);
  95                         break;
  96         }
  97 }
  98 
  99 static void draw_glyph(unsigned char *addr, int x, int y, unsigned char *ch, int color)
 100 {
 101         int n, b, offset;
 102 
 103         if(screen_is_off) {
 104                 return;
 105         }
 106 
 107         offset = (y * video.fb_linesize) + (x * video.fb_bpp);
 108         addr += offset;
 109 
 110         for(n = 0; n < video.fb_char_height; n++) {
 111                 if(*(ch + n) == 0) {
 112                         if(ch == cursor_shape) {
 113                                 addr += video.fb_pitch;
 114                                 continue;
 115                         }
 116                         b = video.fb_char_width - 1;
 117                         do {
 118                                 set_color(addr, get_bg_color(color));
 119                                 addr += video.fb_pixelwidth;
 120                                 b--;
 121                         } while(b >= 0);
 122                 } else {
 123                         b = video.fb_char_width - 1;
 124                         do {
 125                                 if(*(ch + n) & (1 << b)) {
 126                                         set_color(addr, get_fg_color(color));
 127                                 } else {
 128                                         set_color(addr, get_bg_color(color));
 129                                 }
 130                                 addr += video.fb_pixelwidth;
 131                                 b--;
 132                         } while(b >= 0);
 133                 }
 134                 addr += (video.fb_width - video.fb_char_width) * video.fb_pixelwidth;
 135         }
 136 }
 137 
 138 static void remove_cursor(struct vconsole *vc)
 139 {
 140         int soffset;
 141         unsigned char *vidmem, *ch;
 142         short int *screen, sch;
 143 
 144         vidmem = vc->vidmem;
 145         screen = vc->screen;
 146         soffset = (vc->cursor_y * vc->columns) + vc->cursor_x;
 147 
 148         sch = screen[soffset];
 149         if(sch & 0xFF) {
 150                 ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 151         } else {
 152                 ch = &font_data[SPACE_CHAR * video.fb_char_height];
 153         }
 154         draw_glyph(vidmem, vc->cursor_x, vc->cursor_y, ch, sch >> 8);
 155 }
 156 
 157 static void draw_cursor(struct vconsole *vc)
 158 {
 159         unsigned char *vidmem;
 160 
 161         vidmem = vc->vidmem;
 162         draw_glyph(vidmem, vc->x, vc->y, cursor_shape, DEF_MODE >> 8);
 163 }
 164 
 165 void fbcon_put_char(struct vconsole *vc, unsigned char ch)
 166 {
 167         short int *screen;
 168         unsigned char *vidmem;
 169 
 170         screen = vc->screen;
 171 
 172         if(!(vc->flags & CONSOLE_HAS_FOCUS)) {
 173                 screen[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;
 174                 return;
 175         }
 176 
 177         vidmem = vc->vidmem;
 178         draw_glyph(vidmem, vc->x, vc->y, &font_data[ch * video.fb_char_height], vc->color_attr >> 8);
 179         screen[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;
 180         vcbuf[(video.buf_y * vc->columns) + vc->x] = vc->color_attr | ch;
 181 }
 182 
 183 void fbcon_insert_char(struct vconsole *vc)
 184 {
 185         int n, soffset;
 186         short int tmp, slast_ch;
 187         unsigned char *vidmem, *last_ch;
 188         short int *screen;
 189 
 190         vidmem = vc->vidmem;
 191         screen = vc->screen;
 192         soffset = (vc->y * vc->columns) + vc->x;
 193         n = vc->x;
 194         last_ch = &font_data[SPACE_CHAR * video.fb_char_height];
 195         slast_ch = BLANK_MEM;
 196 
 197         while(n < vc->columns) {
 198                 tmp = screen[soffset];
 199                 if(vc->flags & CONSOLE_HAS_FOCUS) {
 200                         draw_glyph(vidmem, n, vc->y, last_ch, vc->color_attr >> 8);
 201                         last_ch = &font_data[(tmp & 0xFF) * video.fb_char_height];
 202                 }
 203                 memset_w(screen + soffset, slast_ch, 1);
 204                 slast_ch = tmp;
 205                 soffset++;
 206                 n++;
 207         }
 208 }
 209 
 210 void fbcon_delete_char(struct vconsole *vc)
 211 {
 212         int n, soffset;
 213         short int sch;
 214         unsigned char *vidmem, *ch;
 215         short int *screen;
 216 
 217         vidmem = vc->vidmem;
 218         screen = vc->screen;
 219         soffset = (vc->y * vc->columns) + vc->x;
 220         n = vc->x;
 221 
 222         while(n < vc->columns) {
 223                 sch = screen[soffset + 1];
 224                 if(vc->flags & CONSOLE_HAS_FOCUS) {
 225                         if(sch & 0xFF) {
 226                                 ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 227                         } else {
 228                                 ch = &font_data[SPACE_CHAR * video.fb_char_height];
 229                         }
 230                         draw_glyph(vidmem, n, vc->y, ch, vc->color_attr >> 8);
 231                 }
 232                 memset_w(screen + soffset, sch, 1);
 233                 soffset++;
 234                 n++;
 235         }
 236         memset_w(screen + soffset, BLANK_MEM, 1);
 237 }
 238 
 239 void fbcon_update_curpos(struct vconsole *vc)
 240 {
 241         if(!(vc->flags & CONSOLE_HAS_FOCUS)) {
 242                 return;
 243         }
 244 
 245         /* remove old cursor */
 246         if(vc->x != vc->cursor_x || vc->y != vc->cursor_y) {
 247                 remove_cursor(vc);
 248         }
 249 
 250         if(video.flags & VPF_CURSOR_ON) {
 251                 draw_cursor(vc);
 252         }
 253         vc->cursor_x = vc->x;
 254         vc->cursor_y = vc->y;
 255 }
 256 
 257 void fbcon_show_cursor(struct vconsole *vc, int mode)
 258 {
 259         switch(mode) {
 260                 case COND:
 261                         if(!(video.flags & VPF_CURSOR_ON)) {
 262                                 break;
 263                         }
 264                         /* fall through */
 265                 case ON:
 266                         video.flags |= VPF_CURSOR_ON;
 267                         fbcon_update_curpos(vc);
 268                         break;
 269                 case OFF:
 270                         video.flags &= ~VPF_CURSOR_ON;
 271                         fbcon_update_curpos(vc);
 272                         break;
 273         }
 274 }
 275 
 276 void fbcon_get_curpos(struct vconsole *vc)
 277 {
 278         /* not used */
 279 }       
 280 
 281 void fbcon_write_screen(struct vconsole *vc, int from, int count, short int color)
 282 {
 283         int n, n2, lines, columns, x, y;
 284         unsigned char *vidmem, *ch;
 285         short int *screen;
 286 
 287         screen = vc->screen;
 288         if(!(vc->flags & CONSOLE_HAS_FOCUS)) {
 289                 memset_w(screen + from, color, count);
 290                 return;
 291         }
 292 
 293         vidmem = vc->vidmem;
 294         ch = &font_data[SPACE_CHAR * video.fb_char_height];
 295         x = from % vc->columns;
 296         y = from / vc->columns;
 297         lines = count / vc->columns;
 298         columns = x + count;
 299         if(!lines) {
 300                 lines = 1;
 301         }
 302         if(!columns) {
 303                 columns = vc->columns;
 304         }
 305         for(n = 0; n < lines; n++) {
 306                 for(n2 = x; n2 < columns; n2++) {
 307                         draw_glyph(vidmem, n2, y + n, ch, color >> 8);
 308                 }
 309                 x = 0;
 310                 columns = vc->columns;
 311         }
 312         memset_w(screen + from, color, count);
 313 }
 314 
 315 void fbcon_blank_screen(struct vconsole *vc)
 316 {
 317         unsigned char *vidmem;
 318 
 319         if(vc->flags & CONSOLE_BLANKED) {
 320                 return;
 321         }
 322 
 323         vidmem = vc->vidmem;
 324         if(!(int)vidmem) {
 325                 return;
 326         }
 327 
 328         memset_b(vidmem, 0, video.fb_size);
 329         vc->flags |= CONSOLE_BLANKED;
 330 }
 331 
 332 void fbcon_scroll_screen(struct vconsole *vc, int top, int mode)
 333 {
 334         int soffset, poffset, count;
 335         int x, y;
 336         short int *screen, sch, pch;
 337         unsigned char *vidmem, *ch;
 338 
 339         vidmem = vc->vidmem;
 340         screen = vc->screen;
 341 
 342         if(!top) {
 343                 top = vc->top;
 344         }
 345         switch(mode) {
 346                 case SCROLL_UP:
 347                         if(vc->flags & CONSOLE_HAS_FOCUS) {
 348                                 for(y = top + 1; y < vc->lines; y++) {
 349                                         for(x = 0; x < vc->columns; x++) {
 350                                                 soffset = (y * vc->columns) + x;
 351                                                 poffset = ((y - 1) * vc->columns) + x;
 352                                                 sch = screen[soffset];
 353                                                 pch = screen[poffset];
 354                                                 if(sch == pch) {
 355                                                         continue;
 356                                                 }
 357                                                 if(sch & 0xFF) {
 358                                                         ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 359                                                 } else {
 360                                                         ch = &font_data[SPACE_CHAR * video.fb_char_height];
 361                                                 }
 362                                                 draw_glyph(vidmem, x, y - 1, ch, sch >> 8);
 363                                         }
 364                                 }
 365                                 if(!screen_is_off) {
 366                                         count = video.fb_pitch * video.fb_char_height;
 367                                         memset_l(vidmem + video.fb_vsize - count, 0, count / sizeof(unsigned int));
 368                                 }
 369                         }
 370                         count = vc->columns * (vc->lines - top - 1);
 371                         soffset = top * vc->columns;
 372                         top = (top + 1) * vc->columns;
 373                         if(vc->cursor_y) {
 374                                 vc->cursor_y--;
 375                         }
 376                         memcpy_w(screen + soffset, screen + top, count);
 377                         memset_w(screen + soffset + count, BLANK_MEM, top);
 378                         break;
 379                 case SCROLL_DOWN:
 380                         for(y = vc->lines - 2; y >= top; y--) {
 381                                 for(x = 0; x < vc->columns; x++) {
 382                                         if(vc->flags & CONSOLE_HAS_FOCUS) {
 383                                                 soffset = (y * vc->columns) + x;
 384                                                 poffset = ((y + 1) * vc->columns) + x;
 385                                                 sch = screen[soffset];
 386                                                 pch = screen[poffset];
 387                                                 if(sch == pch) {
 388                                                         continue;
 389                                                 }
 390                                                 if(sch & 0xFF) {
 391                                                         ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 392                                                 } else {
 393                                                         ch = &font_data[SPACE_CHAR * video.fb_char_height];
 394                                                 }
 395                                                 draw_glyph(vidmem, x, y + 1, ch, sch >> 8);
 396                                         }
 397                                 }
 398                                 memcpy_w(screen + (vc->columns * (y + 1)), screen + (vc->columns * y), vc->columns);
 399                         }
 400                         if((vc->flags & CONSOLE_HAS_FOCUS) && !screen_is_off) {
 401                                 count = video.fb_pitch * video.fb_char_height;
 402                                 memset_l(vidmem + (top * count), 0, count / sizeof(unsigned int));
 403                         }
 404                         memset_w(screen + (top * vc->columns), BLANK_MEM, vc->columns);
 405                         break;
 406         }
 407         return;
 408 }
 409 
 410 void fbcon_restore_screen(struct vconsole *vc)
 411 {
 412         int x, y;
 413         short int *screen, sch;
 414         unsigned char *vidmem, *ch, c;
 415 
 416         vidmem = vc->vidmem;
 417         screen = vc->screen;
 418 
 419         if(!screen_is_off && !video.buf_top) {
 420                 memset_b(vidmem, 0, video.fb_size);
 421         }
 422         for(y = 0; y < video.lines; y++) {
 423                 for(x = 0; x < vc->columns; x++) {
 424                         sch = screen[(y * vc->columns) + x];
 425                         c = sch & 0xFF;
 426                         if(!c || (c == SPACE_CHAR && !(sch >> 8))) {
 427                                 continue;
 428                         }
 429                         ch = &font_data[c * video.fb_char_height];
 430                         draw_glyph(vidmem, x, y, ch, sch >> 8);
 431                 }
 432         }
 433         vc->flags &= ~CONSOLE_BLANKED;
 434 }
 435 
 436 void fbcon_screen_on(struct vconsole *vc)
 437 {
 438         unsigned long int flags;
 439         struct callout_req creq;
 440 
 441         if(screen_is_off) {
 442                 screen_is_off = 0;
 443                 SAVE_FLAGS(flags); CLI();
 444                 fbcon_restore_screen(vc);
 445                 fbcon_update_curpos(vc);
 446                 RESTORE_FLAGS(flags);
 447                 vc->flags &= ~CONSOLE_BLANKED;
 448         }
 449 
 450         if(BLANK_INTERVAL) {
 451                 creq.fn = fbcon_screen_off;
 452                 creq.arg = (unsigned int)vc;
 453                 add_callout(&creq, BLANK_INTERVAL);
 454         }
 455 }
 456 
 457 void fbcon_screen_off(unsigned int arg)
 458 {
 459         struct vconsole *vc;
 460         unsigned long int flags;
 461 
 462         vc = (struct vconsole *)arg;
 463         screen_is_off = 1;
 464         SAVE_FLAGS(flags); CLI();
 465         fbcon_blank_screen(vc);
 466         RESTORE_FLAGS(flags);
 467 }
 468 
 469 void fbcon_buf_scroll(struct vconsole *vc, int mode)
 470 {
 471         short int sch;
 472         int y, x, offset;
 473         unsigned char *vidmem, *ch;
 474 
 475         if(video.buf_y <= SCREEN_LINES) {
 476                 return;
 477         }
 478 
 479         vidmem = vc->vidmem;
 480 
 481         if(mode == SCROLL_UP) {
 482                 if(video.buf_top < 0) {
 483                         return;
 484                 }
 485                 if(!video.buf_top) {
 486                         video.buf_top = (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS;
 487                 }
 488                 video.buf_top -= (SCREEN_LINES / 2) * SCREEN_COLS;
 489                 if(video.buf_top < 0) {
 490                         video.buf_top = 0;
 491                 }
 492                 for(offset = 0, y = 0; y < video.lines; y++) {
 493                         for(x = 0; x < vc->columns; x++, offset++) {
 494                                 sch = vcbuf[video.buf_top + offset];
 495                                 if(sch & 0xFF) {
 496                                         ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 497                                 } else {
 498                                         ch = &font_data[SPACE_CHAR * video.fb_char_height];
 499                                 }
 500                                 draw_glyph(vidmem, x, y, ch, sch >> 8);
 501                         }
 502                 }
 503                 if(!video.buf_top) {
 504                         video.buf_top = -1;
 505                 }
 506                 fbcon_show_cursor(vc, OFF);
 507                 return;
 508         }
 509         if(mode == SCROLL_DOWN) {
 510                 if(!video.buf_top) {
 511                         return;
 512                 }
 513                 if(video.buf_top == video.buf_y * SCREEN_COLS) {
 514                         return;
 515                 }
 516                 if(video.buf_top < 0) {
 517                         video.buf_top = 0;
 518                 }
 519                 video.buf_top += (SCREEN_LINES / 2) * SCREEN_COLS;
 520                 if(video.buf_top >= (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS) {
 521                         video.buf_top = (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS;
 522                 }
 523                 for(offset = 0, y = 0; y < video.lines; y++) {
 524                         for(x = 0; x < vc->columns; x++, offset++) {
 525                                 sch = vcbuf[video.buf_top + offset];
 526                                 if(sch & 0xFF) {
 527                                         ch = &font_data[(sch & 0xFF) * video.fb_char_height];
 528                                 } else {
 529                                         ch = &font_data[SPACE_CHAR * video.fb_char_height];
 530                                 }
 531                                 draw_glyph(vidmem, x, y, ch, sch >> 8);
 532                         }
 533                 }
 534                 if(video.buf_top >= (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS) {
 535                         fbcon_show_cursor(vc, ON);
 536                         fbcon_update_curpos(vc);
 537                 }
 538                 return;
 539         }
 540 }
 541 
 542 void fbcon_cursor_blink(unsigned int arg)
 543 {
 544         struct vconsole *vc;
 545         struct callout_req creq;
 546         static int blink_on = 0;
 547 
 548         vc = (struct vconsole *)arg;
 549         if(!(vc->flags & CONSOLE_HAS_FOCUS)) {
 550                 return;
 551         }
 552 
 553         if(video.flags & VPF_CURSOR_ON && !screen_is_off) {
 554                 if(blink_on) {
 555                         draw_cursor(vc);
 556                 } else {
 557                         remove_cursor(vc);
 558                 }
 559         }
 560         blink_on = !blink_on;
 561         creq.fn = fbcon_cursor_blink;
 562         creq.arg = arg;
 563         add_callout(&creq, 25);         /* 250ms */
 564 }
 565 
 566 void fbcon_init(void)
 567 {
 568         struct fbcon_font_desc *font_desc;
 569 
 570         video.put_char = fbcon_put_char;
 571         video.insert_char = fbcon_insert_char;
 572         video.delete_char = fbcon_delete_char;
 573         video.update_curpos = fbcon_update_curpos;
 574         video.show_cursor = fbcon_show_cursor;
 575         video.get_curpos = fbcon_get_curpos;
 576         video.write_screen = fbcon_write_screen;
 577         video.blank_screen = fbcon_blank_screen;
 578         video.scroll_screen = fbcon_scroll_screen;
 579         video.restore_screen = fbcon_restore_screen;
 580         video.screen_on = fbcon_screen_on;
 581         video.buf_scroll = fbcon_buf_scroll;
 582         video.cursor_blink = fbcon_cursor_blink;
 583 
 584         if(!(font_desc = fbcon_find_font(video.fb_char_height))) {
 585                 font_desc = fbcon_find_font(16);
 586         }
 587         font_data = font_desc->data;
 588         cursor_shape = font_desc->cursorshape;
 589 }

/* [previous][next][first][last][top][bottom][index][help] */