/** * video.c * * Text video routines * * Exports: * blink(); * select_vc() * putch_help() * putch() * init_video(); * * Imports: * main.c printf(); */ /** * TODO * * Fuck me with a blind melon...when the screen scrolls * too much, it generates a panic of type invalid opcode. */ #include <string.h> /* memcpy(), memsetw() */ #include <ctype.h> /* isdigit() */ #include <x86.h> /* outportb(), inportb() */ #include <stdint.h> #include "_krnl.h" /* MAX_VC, console_t */ /** * Imports */ void printf(const char *fmt, ...); #define VGA_MISC_READ 0x3CC console_t _vc[MAX_VC]; static unsigned _num_vcs; static console_t *_curr_vc; static unsigned short *_vga_fb_adr; static unsigned _crtc_io_adr, _vc_width, _vc_height; unsigned curr_vtty; /** * blink() * */ void blink(void) { (*(unsigned char *)_vga_fb_adr)++; } /** * get_current_vc() * */ unsigned get_current_vc() { return curr_vtty; } /** * scroll() * */ static void scroll(console_t *con) { unsigned short *fb_adr; unsigned blank, temp; blank = 0x20 | ((unsigned)con->attrib << 8); fb_adr = con->fb_adr; /** * scroll up */ if(con->csr_y >= _vc_height) { temp = con->csr_y - _vc_height + 1; memcpy(fb_adr, fb_adr + temp * _vc_width, (_vc_height - temp) * _vc_width * 2); /** * blank bottom line of screen */ memsetw(fb_adr + (_vc_height - temp) * _vc_width, blank, _vc_width); con->csr_y = _vc_height - 1; } //for(i = 0; i < 0x1000000; i++) ; } /** * set_attrib() * */ static void set_attrib(console_t *con, unsigned att) { static const unsigned ansi_to_vga[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; unsigned new_att; new_att = con->attrib; if(att == 0) new_att &= ~0x08; /* bold off */ else if(att == 1) new_att |= 0x08; /* bold on */ else if(att >= 30 && att <= 37) { att = ansi_to_vga[att - 30]; new_att = (new_att & ~0x07) | att;/* fg color */ } else if(att >= 40 && att <= 47) { att = ansi_to_vga[att - 40] << 4; new_att = (new_att & ~0x70) | att;/* bg color */ } con->attrib = new_att; } /** * move_csr() * */ static void move_csr(void) { unsigned temp; temp = (_curr_vc->csr_y * _vc_width + _curr_vc->csr_x) + (_curr_vc->fb_adr - _vga_fb_adr); outportb(_crtc_io_adr + 0, 14); outportb(_crtc_io_adr + 1, temp >> 8); outportb(_crtc_io_adr + 0, 15); outportb(_crtc_io_adr + 1, temp); } /** * select_vc() * */ void select_vc(unsigned which_vc) { unsigned i; if(which_vc >= _num_vcs) return; _curr_vc = _vc + which_vc; i = _curr_vc->fb_adr - _vga_fb_adr; outportb(_crtc_io_adr + 0, 12); outportb(_crtc_io_adr + 1, i >> 8); outportb(_crtc_io_adr + 0, 13); outportb(_crtc_io_adr + 1, i); curr_vtty = which_vc; move_csr(); } /** * putch_help() * */ void putch_help(console_t *con, unsigned c) { unsigned short *fb_adr; unsigned att; att = (unsigned)con->attrib << 8; fb_adr = con->fb_adr; /** * state machine to handle escape sequences * * ESC */ if(con->esc == 1) { if(c == '[') { con->esc++; con->esc1 = 0; return; } /* else fall-through: zero esc and print c */ } /** * ESC[ */ else if(con->esc == 2) { if(isdigit(c)) { con->esc1 = con->esc1 * 10 + c - '0'; return; } else if(c == ';') { con->esc++; con->esc2 = 0; return; } /** * ESC[2J (clear screen) */ else if(c == 'J') { if(con->esc1 == 2) { memsetw(fb_adr, ' ' | att, _vc_height * _vc_width); con->csr_x = con->csr_y = 0; } } /** * ESC[num1m (set attribute num1) */ else if(c == 'm') set_attrib(con, con->esc1); con->esc = 0; /* anything else with one numeric arg */ return; } /** * ESC[num1 */ else if(con->esc == 3) { if(isdigit(c)) { con->esc2 = con->esc2 * 10 + c - '0'; return; } else if(c == ';') { con->esc++; /* ESC[num1;num2; */ con->esc3 = 0; return; } /** * ESC[num1;num2H (move cursor to num1,num2) */ else if(c == 'H') { if(con->esc2 < _vc_width) con->csr_x = con->esc2; if(con->esc1 < _vc_height) con->csr_y = con->esc1; } /** * ESC[num1;num2m (set attributes num1,num2) */ else if(c == 'm') { set_attrib(con, con->esc1); set_attrib(con, con->esc2); } con->esc = 0; return; } /** * ESC[num1;num2;num3 */ else if(con->esc == 4) { if(isdigit(c)) { con->esc3 = con->esc3 * 10 + c - '0'; return; } /** * ESC[num1;num2;num3m (set attributes num1,num2,num3) */ else if(c == 'm') { set_attrib(con, con->esc1); set_attrib(con, con->esc2); set_attrib(con, con->esc3); } con->esc = 0; return; } con->esc = 0; /** * escape character */ if(c == 0x1B) { con->esc = 1; return; } /** * backspace */ if(c == 0x08) { if(con->csr_x != 0) con->csr_x--; } /** * tab */ else if(c == 0x09) con->csr_x = (con->csr_x + 8) & ~(8 - 1); /** * carriage return */ else if(c == '\r') /* 0x0D */ con->csr_x = 0; /** * line feed */ /* else if(c == '\n') *//* 0x0A */ /* con->csr_y++;*/ /** * CR/LF */ else if(c == '\n') /* ### - 0x0A again */ { con->csr_x = 0; con->csr_y++; } /** * printable ASCII */ else if(c >= ' ') { unsigned short *where; where = fb_adr + (con->csr_y * _vc_width + con->csr_x); *where = (c | att); con->csr_x++; } if(con->csr_x >= _vc_width) { con->csr_x = 0; con->csr_y++; } scroll(con); /** * move cursor only if the VC we're writing is the current VC */ if(_curr_vc == con) move_csr(); } /** * putch() * */ void putch(unsigned c) { /* all kernel messages to VC #0 */ // putch_help(_vc + 0, c); /* all kernel messages to current VC */ putch_help(_curr_vc, c); } /** * init_video() * */ void init_video(void) { unsigned i; /** * check for monochrome or color VGA emulation */ if((inportb(VGA_MISC_READ) & 0x01) != 0) { _vga_fb_adr = (unsigned short *)0xB8000L; _crtc_io_adr = 0x3D4; } else { _vga_fb_adr = (unsigned short *)0xB0000L; _crtc_io_adr = 0x3B4; } /** * read current screen size from BIOS data segment (addresses 400-4FF) */ _vc_width = *(unsigned short *)0x44A; _vc_height = *(unsigned char *)0x484 + 1; /** * figure out how many VCs we can have with 32K of display memory. * Use INTEGER division to round down. */ _num_vcs = 32768L / (_vc_width * _vc_height * 2); if(_num_vcs > MAX_VC) _num_vcs = MAX_VC; /** * init VCs, with a different foreground color for each */ for(i = 0; i < _num_vcs; i++) { _curr_vc = _vc + i; //_curr_vc->attrib = i + 1; /* terminal foreground color */ _curr_vc->attrib = 7; _curr_vc->fb_adr = _vga_fb_adr + _vc_width * _vc_height * i; /** * ESC[2J clears the screen */ //kprintf("\x1B[2J this is VC#%u (of 0-%u)\n", // i, _num_vcs - 1); printf("\x1B[2J"); if(i != 0) printf("$ "); } select_vc(0); curr_vtty = 0; _curr_vc->attrib = 8; printf("[ "); _curr_vc->attrib = 15; printf("init: video %5s emulation, %2ux%2u, framebuffer at 0x%1X ", (_crtc_io_adr == 0x3D4) ? "color" : "mono", _vc_width, _vc_height, _vga_fb_adr); _curr_vc->attrib = 8; printf("]................"); _curr_vc->attrib = 2; printf("Ok"); _curr_vc->attrib = 7; }