os

Toy OS
git clone git://git.margiolis.net/os.git
Log | Files | Refs | README | LICENSE

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 }