Orion
Barry Keyboard/Mouse drivers + POSIX names for structs 1628fcf (2 years, 4 months ago)/* * This file contains the implementation of the TTY Device, generates a device * /dev/tty, which displays to the default text video output. This file handles * all the formatting required for a TTY. */ #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/fb.h> #include <termios.h> #include "../drivers.h" #include "../../task/task.h" #include "../../proc/proc.h" #include "../../mem/heap.h" #include "../../io.h" size_t tty_read(File *file, char *buf, size_t size, off_t offset); size_t tty_write(File *file, char *buf, size_t size, off_t offset); int tty_ioctl(File *file, unsigned long request, uintptr_t argp); int tty_open(File *file); FileOps ttyFileOps = { .read = tty_read, .write = tty_write, .ioctl = tty_ioctl, .open = tty_open, }; Driver ttyDriver = { .major = 5, .ops = &ttyFileOps, .next = NULL, }; extern uint8_t font[]; Termios tty; uintptr_t vgaLfb; int vgaWidth, vgaHeight, vgaBpp; int ttyMode; int ttyX, ttyY; int ttyW = 80, ttyH = 25; char ttyAttr = 0x07; char *lineBuf, *line; int lineBufLen = 0, lineLen = 0; unsigned char shift = 0, ctrl = 0; uint32_t colours[] = { 0x000000, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0x884422, 0xCCCCCC, 0x666666, 0x6666FF, 0x66FF66, 0x66FFFF, 0xFF6666, 0xFF66FF, 0xFFFF66, 0xFFFFFF, }; TaskQueue ttyWait; /* Map of keys on the keyboard */ char kbmap[128] = { 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '#', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0 }; char skbmap[128] = { 0, 27, '!', '"', '$', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '@', '|', 0, '~', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, '|', 0, 0, 0 }; /* Convert a string to a number */ static int number(char *str) { int num = 0, col = 1, len; for (len = 0; str[len] >= '0' && str[len] <= '9'; len++); while (len--) { num += (str[len] - '0') * col; col *= 10; } return num; } /* Put a pixel on the screen */ static void putpixel(int x, int y, uint32_t colour) { /* This splits the framebuffer into bytes to be BPP agnostic */ uint8_t *screen = (uint8_t *) vgaLfb; unsigned where = x*(vgaBpp/8) + y*vgaWidth*(vgaBpp/8); screen[where + 0] = (colour >> 0) & 0xFF; /* BLUE */ screen[where + 1] = (colour >> 8) & 0xFF; /* GREEN */ screen[where + 2] = (colour >> 16) & 0xFF; /* RED */ } /* Draw a character to the framebuffer using the font */ static void draw_char(unsigned char c, int x, int y, uint32_t fgcolour, uint32_t bgcolour) { int cx, cy; unsigned char *glyph = font + ((int) c * 16); for (cy = 0; cy < 16; cy++) { for (cx = 0; cx < 8; cx++) { putpixel(x + 7 - cx, y + cy, (glyph[cy] & (1 << cx)) ? fgcolour : bgcolour); } } } /* Set the ANSI attribute */ static void set_ansi_attribute(int mode, int foreground, int background) { char bold; switch (mode) { case 0: /* RESET */ ttyAttr = 0x07; return; case 1: bold = 1; break; } switch (foreground) { case 0: /* DEFAULT */ ttyAttr = (ttyAttr & 0xF0) + 7 + (bold ? 8 : 0); break; case 30: /* BLACK */ ttyAttr = (ttyAttr & 0xF0) + 0; break; case 31: /* RED */ ttyAttr = (ttyAttr & 0xF0) + 4 + (bold ? 8 : 0); break; case 32: /* GREEN */ ttyAttr = (ttyAttr & 0xF0) + 2 + (bold ? 8 : 0); break; case 33: /* YELLOW */ ttyAttr = (ttyAttr & 0xF0) + 14; break; case 34: /* BLUE */ ttyAttr = (ttyAttr & 0xF0) + 1 + (bold ? 8 : 0); break; case 35: /* MAGENTA */ ttyAttr = (ttyAttr & 0xF0) + 5 + (bold ? 8 : 0); break; case 36: /* CYAN */ ttyAttr = (ttyAttr & 0xF0) + 3 + (bold ? 8 : 0); break; } } /* Parse ANSI escape codes */ static size_t ansi_escape(char *buf) { int len; char *end; for (len = 0; buf[len] < 'A' || buf[len] > 'z'; len++); end = buf + len + 1; switch (buf[len]) { case 'H': /* Set the cursor position */ ttyX = 0; ttyY = 0; break; case 'J': /* 2J clears screen */ int jmode = 0; jmode = number(buf); if (jmode == 2) { if (ttyMode == 0) memset((void *) 0xB8000, '\0', ttyW * ttyH * 2); else memset((void *) vgaLfb, '\0', vgaWidth * vgaHeight * (vgaBpp / 8)); } break; case 'm': /* Set attribute */ int mode = 0, foreground = 0, background = 0; mode = number(buf); while (*buf >= '0' && *buf <= '9') buf++; buf++; if (buf == end) goto set; foreground = number(buf); while (*buf >= '0' && *buf <= '9') buf++; buf++; if (buf == end) goto set; background = number(buf); set: set_ansi_attribute(mode, foreground, background); break; } return len + 1; } /* Print a character to the screen */ void print_char(char c) { char *screen = (char *) 0xB8000; if (ttyMode == 0) screen[(((ttyY * ttyW) + ttyX) * 2) + 1] = ttyAttr; else draw_char(' ', ttyX*8, ttyY*16, 0xFFFFFF, 0x000000); /* Characters */ if (!(tty.c_lflag & ECHO) && c != '\n') goto curctl; switch (c) { case '\r': ttyX = 0; break; case '\n': ttyX = 0; ttyY++; break; case '\b': ttyX--; if (ttyMode == 0) screen[((ttyY * ttyW) + ttyX) * 2] = ' '; else draw_char(' ', ttyX*8, ttyY*16, colours[ttyAttr & 0xF], colours[ttyAttr >> 4]); break; case '\t': ttyX += 8 - (ttyX % 8); break; default: if (ttyMode == 0) screen[((ttyY * ttyW) + ttyX) * 2] = c; else draw_char(c, ttyX*8, ttyY*16, colours[ttyAttr & 0xF], colours[ttyAttr >> 4]); ttyX++; } /* Control cursor */ curctl: if (ttyX >= ttyW) { ttyX = 0; ttyY++; } if (ttyX < 0) { ttyX = ttyW - 1; ttyY--; } if (ttyY >= ttyH) { if (ttyMode == 0) { memcpy(screen, screen + (ttyW*2), ttyW * (ttyH-1) * 2); memset(screen + (ttyW * 2 * (ttyH-1)), 0, ttyW * 2); } else { memcpy((void *) vgaLfb, (void *) vgaLfb + (vgaWidth*(vgaBpp/8)*16), vgaWidth*(vgaBpp/8)*(vgaHeight-16)); memset((void *) vgaLfb + (vgaWidth*(vgaBpp/8)*(vgaHeight-16)), '\0', vgaWidth*(vgaBpp/8)*16); } ttyY--; } if (ttyY < 0) ttyY++; if (ttyMode == 0) screen[(((ttyY * ttyW) + ttyX) * 2) + 1] = ((ttyAttr & 0x0F) << 4) + ((ttyAttr >> 4) & 0x0F); else draw_char(' ', ttyX*8, ttyY*16, 0x000000, 0x888888); } /* Handle the keyboard interrupt */ void tty_keypress(unsigned char key) { char c; if (key == 0x1D) ctrl = 128; if (key == 0x9D) ctrl = 0; if (key == 0x2A || key == 0x36) shift = 128; if (key == 0xAA || key == 0xB6) shift = 0; if (key >= 128) return; if (shift) c = skbmap[key]; else c = kbmap[key]; if (!c) return; if (ctrl && c == 'c') { kprintf("Killing foreground process"); return; } if (c == '\b' && lineBufLen == 0) return; if (c == '\b') lineBuf[lineBufLen--] = '\0'; else lineBuf[lineBufLen++] = c; print_char(c); if (c == '\n') { memcpy(line, lineBuf, lineBufLen); memset(lineBuf, 0, lineBufLen); lineLen = lineBufLen; lineBufLen = 0; for (Task *tmp = ttyWait.start; tmp; tmp = tmp->next) unblock_task(pop_from_queue(&ttyWait)); } } /* Initialise the TTY */ void init_tty(void) { register_driver(&ttyDriver); mknod("/dev/tty", S_IFCHR | 0666, MKDEV(ttyDriver.major, 0)); tty.c_lflag = ICANON | ECHO; int fd = open("/dev/fb", O_RDWR); if (fd < 0) { ttyMode = 0; int x, y; uint16_t *screen = (uint16_t *) 0xB8000; for (y = 0; y < 25; y++) for (x = 0; x < 80; x++) screen[(y * 80) + x] = 0x0000; } else { FBVarInfo vinfo; FBFixInfo finfo; ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); ioctl(fd, FBIOGET_FSCREENINFO, &finfo); close(fd); vgaWidth = vinfo.xres; vgaHeight = vinfo.yres; vgaBpp = vinfo.bpp; vgaLfb = finfo.fbmem; ttyMode = 1; ttyW = vgaWidth/8; ttyH = vgaHeight/16; } lineBuf = kmalloc(4096); line = kmalloc(4096); } /* Read from the TTY */ size_t tty_read(File *file, char *buf, size_t size, off_t offset) { if (!lineLen) { add_to_queue(&ttyWait, current); block_task(WAITING_FOR_IO); } size_t count = (size < lineLen) ? size : lineLen; memcpy(buf, line, count); if (size < lineLen) { memcpy(line, line + size, lineLen - size); lineLen -= size; } else { memset(line, 0, lineLen); lineLen = 0; } return count; } /* Write to the TTY */ size_t tty_write(File *file, char *buf, size_t size, off_t offset) { size_t skip, count = 0; while (size--) { if (buf[0] == '\033' && buf[1] == '[') { skip = ansi_escape(buf + 2); buf += skip + 2; size -= skip + 1; continue; } print_char(*buf++); count++; } return count; } /* Open the TTY */ int tty_open(File *file) { return 0; }