/* * con.c * * Basic VGA text console. Implements printk(). */ #include #include #include #include #include #define COLS 80 #define ROWS 25 /* internal function prototypes */ static void con_write(void); struct tty_struct tty_con = { .init = NULL, .write = &con_write }; static uint8_t *vram = (uint8_t*) 0xB8000; static int pos; static inline void cursorpos(int pos) { outb(0x3D4, 0x0E); outb(0x3D5, (uint8_t) ((pos >> 9) & 0xFF)); outb(0x3D4, 0x0F); outb(0x3D5, (uint8_t) ((pos >> 1) & 0xFF)); } /* scrolls the console up one line */ static void scroll_up(void) { int n = (COLS * (ROWS - 1)) << 1; uint8_t *p = vram; while(n--) { *p = p[COLS << 1]; p++; } p = (uint8_t*) (vram + (COLS * (ROWS - 1) << 1)); n = COLS; while(n--) { *p = ' '; p += 2; } pos -= COLS << 1; cursorpos(pos); } /* clear the console and reset the cursor to the starting position */ void con_clear(void) { int n = COLS * ROWS; uint8_t *p = vram; while(n--) { *(p++) = 0x20; *(p++) = 0x07; } pos = 0; cursorpos(0); } /* must be called before any console output */ void con_init(void) { /* clear the console */ con_clear(); } /* write a zero-terminated string to console */ static int con_puts(char *s) { uint8_t *p = &vram[pos]; while(*s) { if(*s == '\n') { pos = (int) (p - vram); pos = ((pos / (COLS << 1)) + 1) * (COLS << 1); p = &vram[pos]; s++; } else { *p = *(s++); p += 2; } pos = (int) (p - vram); if(pos >= (COLS * ROWS) << 1) scroll_up(); } /* update the cursor position */ cursorpos(pos); /* this always succeeds */ return 0; } /* same as con_puts() but deals with bytes rather than strings */ static void con_write(void) { char c; int copied = 0; uint8_t *p = &vram[pos]; struct tty_queue *q = &tty_con.wqueue; while(q->pread != q->pwrite) { c = q->buf[q->pread]; if(c == '\n') { pos = (int) (p - vram); pos = ((pos / (COLS << 1)) + 1) * (COLS << 1); p = &vram[pos]; } else { *p = c; p += 2; } q->pread = (q->pread + 1) % TTY_BUF_SIZE; copied = 1; pos = (int) (p - vram); if(pos >= (COLS * ROWS) << 1) scroll_up(); } /* update the cursor position */ cursorpos(pos); if(copied) wake_up(&q->waiting); } int printk(char *fmt, ...) { int ret; char buf[1024]; va_list ap; va_start(ap, fmt); ret = vsprintf(buf, fmt, ap); va_end(ap); con_puts(buf); return ret; }