os

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

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 }