tty.c (2462B)
1 #include <sys/libk.h> 2 3 #define VGA_MEM 0xb8000; 4 #define VGA_COLS 80 5 #define VGA_ROWS 25 6 #define TTY_PUTC(c) (((uint16_t)tty.color << 8) | (c)) 7 8 struct tty_info { 9 volatile uint16_t *buf; 10 size_t row; 11 size_t col; 12 uint8_t color; 13 }; 14 15 static struct tty_info tty; 16 17 void 18 tty_clear(uint8_t fg, uint8_t bg) 19 { 20 size_t y, x; 21 22 tty_curs_enable(0x0e, 0x0f); /* Low cursor shape. */ 23 tty_curs_setpos(0, 0); 24 tty.row = 0; 25 tty.col = 0; 26 tty.buf = (uint16_t *)VGA_MEM; 27 tty_set_color(fg, bg); 28 for (x = 0; x < VGA_COLS; x++) 29 for (y = 0; y < VGA_ROWS; y++) 30 tty.buf[y * VGA_COLS + x] = TTY_PUTC(' '); 31 } 32 33 void 34 tty_set_color(uint8_t fg, uint8_t bg) 35 { 36 tty.color = fg | (bg << 4); 37 } 38 39 void 40 tty_putc(char c) 41 { 42 switch (c) { 43 case '\n': 44 tty.row++; 45 tty.col = 0; 46 break; 47 case '\b': 48 tty.col--; 49 tty.buf[tty.row * VGA_COLS + tty.col] = TTY_PUTC(' '); 50 break; 51 case '\r': 52 tty.col = 0; 53 break; 54 case '\t': 55 tty.col += 8; 56 break; 57 default: 58 tty.buf[tty.row * VGA_COLS + tty.col] = TTY_PUTC(c); 59 tty.col++; 60 } 61 62 if (tty.row >= VGA_ROWS) { 63 tty.row = 0; 64 tty.col = 0; 65 } 66 if (tty.col >= VGA_COLS) { 67 tty.row++; 68 tty.col = 0; 69 } 70 tty_curs_setpos(tty.col, tty.row); 71 } 72 73 void 74 tty_write(const char *str) 75 { 76 while (*str != '\0') 77 tty_putc(*str++); 78 } 79 80 /* 81 * The arguments `start` and `end` define the shape of the cursor. 82 * The lowest scaline value is 0x00 and the highest 0x0f. A cursor shape 83 * with `start = 0x00` and `end = 0x0f` is effectively a block cursor. 84 */ 85 void 86 tty_curs_enable(uint8_t start, uint8_t end) 87 { 88 /* 0x0a: Low cursor shape */ 89 outb(IO_CURS_CMD, 0x0a); 90 outb(IO_CURS_DATA, (inb(IO_CURS_DATA) & 0xc0) | start); 91 outb(IO_CURS_CMD, 0x0b); 92 outb(IO_CURS_DATA, (inb(IO_CURS_DATA) & 0xe0) | end); 93 } 94 95 void 96 tty_curs_disable(void) 97 { 98 outb(IO_CURS_CMD, 0x0a); 99 /* 100 * Bit representation: 101 * 7 6 | 5 | 4 0 102 * Unused | Disable | Shape 103 */ 104 outb(IO_CURS_DATA, 0x20); 105 } 106 107 /* 108 * Returns the position in `y * VGA_COLS + x` format. 109 * x = pos % VGA_COLS 110 * y = pos / VGA_COLS 111 */ 112 uint16_t 113 tty_curs_getpos(void) 114 { 115 uint16_t pos = 0; 116 117 outb(IO_CURS_CMD, 0x0e); 118 pos |= (uint16_t)inb(IO_CURS_DATA) << 8; 119 outb(IO_CURS_CMD, 0x0f); 120 pos |= inb(IO_CURS_DATA); 121 122 return (pos); 123 } 124 125 void 126 tty_curs_setpos(int x, int y) 127 { 128 uint16_t pos = y * VGA_COLS + x; 129 130 /* Expect 8 highest bits */ 131 outb(IO_CURS_CMD, 0x0e); 132 outb(IO_CURS_DATA, (uint8_t)((pos >> 8) & 0xff)); 133 /* Expect 8 lowest bits */ 134 outb(IO_CURS_CMD, 0x0f); 135 outb(IO_CURS_DATA, (uint8_t)(pos & 0xff)); 136 }