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