quinn-os/console.c

789 lines
15 KiB
C

#include <stdarg.h>
#include "io.h"
#include "multiboot.h"
#include "font.h"
#include "console.h"
#include "quinn.xbm"
#include "gui.h"
#include "vfs.h"
#include "tty_fs.h"
#include "string.h"
#include "memory.h"
#define KEYBOARD_KEY_LSHIFT 0x2A
#define KEYBOARD_KEY_RSHIFT 0x36
#define KEYBOARD_KEY_ENTER 0x1C
#define KEYBOARD_KEY_BSPACE 0x66
#define KEYBOARD_KEY_LCTRL 0x14
#define KEYBOARD_KEY_CAPS 0x58
#define KEYBOARD_KEY_F9 0x01
#define KEYBOARD_KEY_F5 0x03
#define KEYBOARD_KEY_F3 0x04
#define KEYBOARD_KEY_F1 0x05
#define KEYBOARD_KEY_F2 0x06
#define KEYBOARD_KEY_F12 0x07
#define KEYBOARD_KEY_F10 0x09
#define KEYBOARD_KEY_F8 0x0A
#define KEYBOARD_KEY_F6 0x0B
#define KEYBOARD_KEY_F4 0x0C
#define KEYBOARD_KEY_TAB 0x0D
#define KEYBOARD_KEY_LALT 0x11
#define BochsConsolePrintChar(c) outportb(0xe9, c)
extern const struct bitmap_font font;
extern unsigned short depth;
int x;
int y;
unsigned char attrib;
unsigned char initialized = 0;
unsigned int char_width, char_height;
extern unsigned char vidmode;
void putpixel_24bpp(int x, int y, unsigned int color);
void console_display_quinn();
static unsigned int console_col_map[16] = {
0x000000, 0x0000AA, 0x00AA00, 0x00AAAA,
0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA,
0x555555, 0x5555FF, 0x55FF55, 0x55FFFF,
0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF
};
extern void mem_reserve(char *blk, int pages);
struct vfs_device_t *consoletty = (void *)0;
unsigned char *consolebuffer;
unsigned int cons_w;
unsigned int cons_h;
unsigned char capslock;
unsigned char lshift;
unsigned char rshift;
static const char keyChars_set1[] = {
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, 0, 0
};
static const char keyChars_set1_s[] = {
0, 27, '!', '@',
'#', '$', '%', '^',
'&', '*', '(', ')',
'_', '+', '\b', '\t',
'Q', 'W', 'E', 'R',
'T', 'Y', 'U', 'I',
'O', 'P', '{', '}',
0, 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, 0, 0
};
static const char keyChars_set2[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, '\t', '`', 0,
0, 0, 0, 0,
0, 'q', '1', 0,
0, 0, 'z', 0,
'a', 'w', '2', 0,
0, 'c', 'x', 'd',
'e', '4', '3', 0,
0, ' ', 'v', 'f',
't', 'r', '5', 0,
0, 'n', 'b', 'h',
'g', 'y', '6', 0,
0, 0, 'm', 'j',
'u', '7', '8', 0,
0, ',', 'k', 'i',
'o', '0', '9', 0,
0, '.', '/', 'l',
';', 'p', '-', 0,
0, 0, '\'', 0,
'[', '=', 0, 0,
0, 0, 0, ']',
0, '\\', 0, 0};
void console_input(unsigned char scancode, unsigned char state) {
if (state == 0) {
if (scancode == KEYBOARD_KEY_LSHIFT) {
lshift = 0;
}
if (scancode == KEYBOARD_KEY_RSHIFT) {
rshift = 0;
}
} else {
if (scancode == KEYBOARD_KEY_LSHIFT) {
lshift = 1;
}
if (scancode == KEYBOARD_KEY_RSHIFT) {
rshift = 1;
}
if (scancode > 0x00 && scancode < 0x57) {
if (lshift || rshift) {
if (keyChars_set1_s[scancode] != 0) {
tty_input(consoletty, keyChars_set1_s[scancode]);
}
} else {
if (keyChars_set1[scancode] != 0) {
tty_input(consoletty, keyChars_set1[scancode]);
}
}
} else {
kprintf("scancode %x\n", scancode);
}
}
}
void init_console() {
if (vidmode == 1) {
cons_w = 80 * font.Width;
cons_h = 25 * font.Height;
consolebuffer = (char *)malloc((cons_w * cons_h) * depth);
char_height = 25;//height / font.Height;
char_width = 80;//width / font.Width;
memset(consolebuffer, 0, cons_w * cons_h * depth);
gui_add_window(consolebuffer, "System Console", 10, 35, cons_w, cons_h, (void *)0, console_input);
console_display_quinn();
x = 0;
y = 7;
} else {
char_width = 80;
char_height = 25;
x = 0;
y = 0;
clear_screen();
}
attrib = 0x07;
capslock = 0;
lshift = 0;
rshift = 0;
initialized = 1;
}
void console_display_quinn() {
int x;
int y;
for (y=0;y<quinn_height;y++) {
for (x=0;x<quinn_width;x++) {
unsigned long mask, offset, index, i;
mask = 1;
index = (y * quinn_width + x) / 8;
offset = (y * quinn_width + x) % 8;
if (!(quinn_bits[index] & (mask << offset))) {
putpixel_24bpp(x, y, console_col_map[7]);
}
}
}
//flip();
}
void putpixel_24bpp(int x, int y, unsigned int color) {
if (x < 0 || x >= cons_w || y < 0 || y >= cons_h) {
return;
}
int where = (x * depth) + (y * cons_w * depth);
consolebuffer[where] = color & 255; // BLUE
consolebuffer[where + 1] = (color >> 8) & 255; // GREEN
consolebuffer[where + 2] = (color >> 16) & 255; // RED
}
void clear_screen(void) {
unsigned char *videoram = (char *)0xB8000;
if (vidmode == 0) {
int i;
int j;
for (i=0;i<25;i++) {
for (j=0;j<80;j++) {
videoram[(i * 80 + j) * 2] = ' ';
videoram[(i * 80 + j) * 2 + 1] = attrib;
}
}
} else {
int j;
int k;
unsigned char *where = consolebuffer;
unsigned int colour = console_col_map[(attrib & 0xf0) >> 4];
for (k=0;k<cons_w;k++) {
for (j=0;j<cons_h;j++) {
where[j*4] = colour & 255;
where[j*4 + 1] = (colour >> 8) & 255;
where[j*4 + 2] = (colour >> 16) & 255;
}
where += cons_w * depth;
}
//flip();
}
}
void scroll_up(void) {
unsigned char *videoram = (char *)0xB8000;
int i;
int j;
if (vidmode == 0) {
for (i=0;i<24;i++) {
for (j=0;j<80;j++) {
videoram[(i * 80 + j) * 2] = videoram[((i + 1) * 80 + j) * 2];
videoram[(i * 80 + j) * 2 + 1] = videoram[((i + 1) * 80 + j) * 2 + 1];
}
}
for (j=0;j<80;j++) {
videoram[(i * 80 + j) * 2] = ' ';
videoram[(i * 80 + j) * 2 + 1] = 0x07;
}
} else {
unsigned char *read_ptr = consolebuffer + (font.Height * (80 * font.Width * depth));
unsigned char *write_ptr = consolebuffer;
unsigned int num_bytes = ((80 * font.Width * depth) * cons_h) - ((80 * font.Width * depth) * font.Height);
memcpy(write_ptr, read_ptr, num_bytes);
read_ptr = (unsigned char *) consolebuffer + ((80 * font.Width * depth) * cons_h) - ((80 * font.Width * depth) * font.Height);
memset(read_ptr, 0, (80 * font.Width * depth) * font.Height);
//flip();
}
}
void draw_char(unsigned int x, unsigned int y, char c) {
int i;
for (i=0;i<font.Chars;i++) {
if (font.Index[i] == c) break;
}
const char *font_char = &font.Bitmap[i * font.Height];
int cx,cy;
//int mask[8]={1,2,4,8,16,32,64,128};
int mask[8]={128,64,32,16,8,4,2,1};
unsigned int fgcolor = console_col_map[attrib & 0x0F];
unsigned int bgcolor = console_col_map[(attrib & 0xF0) >> 4];
for(cy=0;cy<16;cy++){
for(cx=0;cx<8;cx++){
if (initialized == 1) {
putpixel_24bpp(x+cx,y+cy,font_char[cy]&mask[cx]?fgcolor:bgcolor);
}
}
}
}
void console_backspace() {
unsigned char *videoram = (char *)0xB8000;
if (x == 0) {
y--;
x = char_width - 1;
} else {
x--;
}
if (vidmode == 0) {
videoram[(y * 80 + x)* 2] = ' ';
videoram[(y * 80 + x)* 2 + 1] = attrib;
} else {
draw_char(x * font.Width, y * font.Height, ' ');
}
}
void putchar(char c) {
unsigned char *videoram = (char *)0xB8000;
switch (c) {
case '\n':
x = 0;
y++;
BochsConsolePrintChar('\n');
if (y == char_height) {
scroll_up();
y = char_height - 1;
}
break;
default:
if (vidmode == 0) {
videoram[(y * 80 + x)* 2] = c;
videoram[(y * 80 + x)* 2 + 1] = attrib;
} else {
BochsConsolePrintChar(c);
draw_char(x * font.Width, y * font.Height, c);
}
x++;
if (x==char_width) {
x = 0;
y++;
}
if (y == char_height) {
scroll_up();
y = char_height - 1;
}
break;
}
}
void putstr(char *str) {
char *ptr = str;
while (*ptr != '\0') {
putchar(*ptr);
ptr++;
}
}
void goto_xy(int newx, int newy) {
if (newx > char_width || newy > char_height || newx < 0 || newy < 0) {
return;
}
x = newx;
y = newy;
}
static int state = 0;
static int params[16];
static int param_count = 0;
static int saved_x = 0;
static int saved_y = 0;
static int bold = 0;
static unsigned char saved_attr = 0x07;
void putdata(char *str, int len) {
int i;
int j;
int k;
for (i=0;i<len;i++) {
if (state == 0) {
if (str[i] == 27) {
state = 1;
continue;
} if ((str[i] > 31 && str[i] < 127) || str[i] == '\n') {
putchar(str[i]);
}
} else if (state == 1) {
if (str[i] == '[') {
state = 2;
continue;
}
} else if (state == 2) {
param_count = 0;
for (j=0;j<16;j++) {
params[j] = 0;
}
state = 3;
}
if (state == 3) {
if (str[i] == ';') {
if (param_count < 15) {
param_count++;
}
continue;
} else if (str[i] >= '0' && str[i] <= '9') {
if (!param_count) param_count = 1;
params[param_count-1] = params[param_count-1] * 10 + (str[i] - '0');
continue;
} else {
state = 4;
}
}
if (state == 4) {
switch (str[i]) {
case 'H':
case 'f':
if (params[0]) params[0]--;
if (params[1]) params[1]--;
goto_xy(params[0], params[1]);
state = 0;
break;
case 'A':
if (param_count > 0) {
goto_xy(x, y - params[0]);
} else {
goto_xy(x, y - 1);
}
state = 0;
break;
case 'B':
if (param_count > 0) {
goto_xy(x, y + params[0]);
} else {
goto_xy(x, y + 1);
}
state = 0;
break;
case 'C':
if (param_count > 0) {
goto_xy(x + params[0], y);
} else {
goto_xy(x + 1, y);
}
state = 0;
break;
case 'D':
if (param_count > 0) {
goto_xy(x - params[0], y);
} else {
goto_xy(x - 1, y);
}
state = 0;
break;
case 's':
saved_x = x;
saved_y = y;
state = 0;
break;
case 'u':
goto_xy(saved_x, saved_y);
break;
case '7':
saved_x = x;
saved_y = y;
saved_attr = attrib;
state = 0;
break;
case '8':
goto_xy(saved_x, saved_y);
attrib = saved_attr;
break;
case 'm':
for (j=0;j<param_count;j++) {
switch (params[j]) {
case 0:
attrib = 0x07;
break;
case 1:
bold = 1;
break;
case 2:
bold = 0;
break;
case 30:
attrib &= 0xF0;
if (bold) {
attrib |= 0x08;
} else {
attrib |= 0x00;
}
break;
case 31:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0C;
} else {
attrib |= 0x04;
}
break;
case 32:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0A;
} else {
attrib |= 0x02;
}
break;
case 33:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0E;
} else {
attrib |= 0x06;
}
break;
case 34:
attrib &= 0xF0;
if (bold) {
attrib |= 0x09;
} else {
attrib |= 0x01;
}
break;
case 35:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0D;
} else {
attrib |= 0x05;
}
break;
case 36:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0B;
} else {
attrib |= 0x03;
}
break;
case 37:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0F;
} else {
attrib |= 0x07;
}
break;
case 40:
attrib &= 0x0F;
attrib |= 0x00;
break;
case 41:
attrib &= 0x0F;
attrib |= 0x40;
break;
case 42:
attrib &= 0x0F;
attrib |= 0x20;
break;
case 43:
attrib &= 0x0F;
attrib |= 0x60;
break;
case 44:
attrib &= 0x0F;
attrib |= 0x10;
break;
case 45:
attrib &= 0x0F;
attrib |= 0x50;
break;
case 46:
attrib &= 0x0F;
attrib |= 0x30;
break;
case 47:
attrib &= 0x0F;
attrib |= 0x70;
break;
}
}
state = 0;
break;
case 'K':
if (params[0] == 0) {
j = x;
for (k=j;k<char_width;k++) {
putchar(' ');
}
x = j;
} else if (params[0] == 1) {
j = x;
x = 0;
for (k=0;k<j;j++) {
putchar(' ');
}
x = j;
} else if (params[0] == 2) {
j = x;
for (k=0;k<char_width;k++) {
putchar(' ');
}
x = j;
}
state = 0;
break;
case 'J':
if (params[0] == 0) {
fill_rect(consolebuffer, cons_w, cons_h, 0, y * font.Height, cons_w, (char_height - y) * font.Height, attrib & 0xF0 >> 4);
} else if (params[0] == 1) {
fill_rect(consolebuffer, cons_w, cons_h, 0, 0, cons_w, y * font.Height, attrib & 0xF0 >> 4);
} else if (params[0] == 2) {
clear_screen();
x = 0;
y = 0;
}
state = 0;
break;
}
}
}
//flip();
}
void putunumber(unsigned int number, int base) {
char buffer[256];
char *ptr;
int i;
buffer[255] = '\0';
ptr = &buffer[255];
if (number < 0) {
putchar('-');
}
if (number == 0) {
putchar('0');
return;
}
while (number > 0 && ptr != buffer) {
ptr--;
i = number % base;
*ptr = "fedcba9876543210123456789abcdef"[15 + i];
number /= base;
}
putstr(ptr);
}
void putnumber(int number, int base) {
char buffer[256];
char *ptr;
int i;
buffer[255] = '\0';
ptr = &buffer[255];
if (number < 0) {
putchar('-');
}
if (number == 0) {
putchar('0');
return;
}
while (number > 0 && ptr != buffer) {
ptr--;
i = number % base;
*ptr = "fedcba9876543210123456789abcdef"[15 + i];
number /= base;
}
putstr(ptr);
}
void do_printf(char *fmt, va_list args) {
int state = 0;
char *ptr = fmt;
int number;
char *str;
char c;
while (*ptr != '\0') {
if (state == 0) {
if (*ptr == '%') {
state = 1;
} else {
putchar(*ptr);
}
} else {
switch (*ptr) {
case '%':
putchar(*ptr);
break;
case 'd':
number = va_arg(args, int);
putnumber(number, 10);
break;
case 's':
str = va_arg(args, char *);
putstr(str);
break;
case 'x':
number = va_arg(args, int);
putnumber(number, 16);
break;
case 'p':
number = va_arg(args, unsigned int);
putunumber(number, 16);
break;
case 'c':
c = va_arg(args, int);
putchar(c);
break;
}
state = 0;
}
ptr++;
}
}
void kprintf(char *fmt, ...) {
if (initialized == 1) {
va_list args;
va_start(args, fmt);
do_printf(fmt, args);
va_end(args);
}
}
void update_cursor(void) {
if (vidmode == 0) {
unsigned short position = y * 80 + x;
outportb(0x3d4, 0x0f);
outportb(0x3d5, (unsigned char)(position & 0xFF));
outportb(0x3d4, 0x0e);
outportb(0x3d5, (unsigned char)((position >> 8) & 0xFF));
}
}