Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/clock.c | 1 + src/serial.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 1 + 3 files changed, 257 insertions(+)
diff --git a/src/clock.c b/src/clock.c index e83e0f3..e44e112 100644 --- a/src/clock.c +++ b/src/clock.c @@ -295,6 +295,7 @@ clock_update(void) floppy_tick(); usb_check_event(); ps2_check_event(); + sercon_check_event(); }
// INT 08h System Timer ISR Entry Point diff --git a/src/serial.c b/src/serial.c index 74b91bb..d72dd01 100644 --- a/src/serial.c +++ b/src/serial.c @@ -655,3 +655,258 @@ void sercon_enable(void) outb(0x01, addr + 0x02); // enable fifo enable_vga_console(); } + +/**************************************************************** + * serial input + ****************************************************************/ + +VARLOW u8 rx_buf[16]; +VARLOW u8 rx_bytes; + +VARLOW struct { + char seq[4]; + u8 len; + u8 scancode; +} termseq[] = { + { .seq = "OP", .len = 2, .scancode = 0x3b }, // F1 + { .seq = "OQ", .len = 2, .scancode = 0x3c }, // F2 + { .seq = "OR", .len = 2, .scancode = 0x3d }, // F3 + { .seq = "OS", .len = 2, .scancode = 0x3e }, // F4 + { .seq = "[A", .len = 2, .scancode = 0xc8 }, // up + { .seq = "[B", .len = 2, .scancode = 0xd0 }, // down + { .seq = "[C", .len = 2, .scancode = 0xcd }, // right + { .seq = "[D", .len = 2, .scancode = 0xcb }, // left +}; + +#define FLAG_CTRL (1<<0) +#define FLAG_SHIFT (1<<1) + +VARLOW struct { + u8 flags; + u8 scancode; +} termchr[256] = { + [ '1' ] = { .scancode = 0x02, }, + [ '!' ] = { .scancode = 0x02, .flags = FLAG_SHIFT }, + [ '2' ] = { .scancode = 0x03, }, + [ '@' ] = { .scancode = 0x03, .flags = FLAG_SHIFT }, + [ '3' ] = { .scancode = 0x04, }, + [ '#' ] = { .scancode = 0x04, .flags = FLAG_SHIFT }, + [ '4' ] = { .scancode = 0x05, }, + [ '$' ] = { .scancode = 0x05, .flags = FLAG_SHIFT }, + [ '5' ] = { .scancode = 0x06, }, + [ '%' ] = { .scancode = 0x06, .flags = FLAG_SHIFT }, + [ '6' ] = { .scancode = 0x07, }, + [ '^' ] = { .scancode = 0x07, .flags = FLAG_SHIFT }, + [ '7' ] = { .scancode = 0x08, }, + [ '&' ] = { .scancode = 0x08, .flags = FLAG_SHIFT }, + [ '8' ] = { .scancode = 0x09, }, + [ '*' ] = { .scancode = 0x09, .flags = FLAG_SHIFT }, + [ '9' ] = { .scancode = 0x0a, }, + [ '(' ] = { .scancode = 0x0a, .flags = FLAG_SHIFT }, + [ '0' ] = { .scancode = 0x0b, }, + [ ')' ] = { .scancode = 0x0b, .flags = FLAG_SHIFT }, + [ '-' ] = { .scancode = 0x0c, }, + [ '=' ] = { .scancode = 0x0d, }, + [ '+' ] = { .scancode = 0x0d, .flags = FLAG_SHIFT }, + + [ 'q' ] = { .scancode = 0x10, }, + [ 'Q' ] = { .scancode = 0x10, .flags = FLAG_SHIFT }, + [ 'Q' & 0x1f ] = { .scancode = 0x10, .flags = FLAG_CTRL }, + [ 'w' ] = { .scancode = 0x11, }, + [ 'W' ] = { .scancode = 0x11, .flags = FLAG_SHIFT }, + [ 'W' & 0x1f ] = { .scancode = 0x11, .flags = FLAG_CTRL }, + [ 'e' ] = { .scancode = 0x12, }, + [ 'E' ] = { .scancode = 0x12, .flags = FLAG_SHIFT }, + [ 'E' & 0x1f ] = { .scancode = 0x12, .flags = FLAG_CTRL }, + [ 'r' ] = { .scancode = 0x13, }, + [ 'R' ] = { .scancode = 0x13, .flags = FLAG_SHIFT }, + [ 'R' & 0x1f ] = { .scancode = 0x13, .flags = FLAG_CTRL }, + [ 't' ] = { .scancode = 0x14, }, + [ 'T' ] = { .scancode = 0x14, .flags = FLAG_SHIFT }, + [ 'T' & 0x1f ] = { .scancode = 0x14, .flags = FLAG_CTRL }, + [ 'y' ] = { .scancode = 0x15, }, + [ 'Y' ] = { .scancode = 0x15, .flags = FLAG_SHIFT }, + [ 'Y' & 0x1f ] = { .scancode = 0x15, .flags = FLAG_CTRL }, + [ 'u' ] = { .scancode = 0x16, }, + [ 'U' ] = { .scancode = 0x16, .flags = FLAG_SHIFT }, + [ 'U' & 0x1f ] = { .scancode = 0x16, .flags = FLAG_CTRL }, + [ 'i' ] = { .scancode = 0x17, }, + [ 'I' ] = { .scancode = 0x17, .flags = FLAG_SHIFT }, + [ 'I' & 0x1f ] = { .scancode = 0x17, .flags = FLAG_CTRL }, + [ 'o' ] = { .scancode = 0x18, }, + [ 'O' ] = { .scancode = 0x18, .flags = FLAG_SHIFT }, + [ 'O' & 0x1f ] = { .scancode = 0x18, .flags = FLAG_CTRL }, + [ 'p' ] = { .scancode = 0x19, }, + [ 'P' ] = { .scancode = 0x19, .flags = FLAG_SHIFT }, + [ 'P' & 0x1f ] = { .scancode = 0x19, .flags = FLAG_CTRL }, + [ '[' ] = { .scancode = 0x1a, }, + [ '{' ] = { .scancode = 0x1a, .flags = FLAG_SHIFT }, + [ ']' ] = { .scancode = 0x1b, }, + [ '}' ] = { .scancode = 0x1b, .flags = FLAG_SHIFT }, + + [ 'a' ] = { .scancode = 0x1e, }, + [ 'A' ] = { .scancode = 0x1e, .flags = FLAG_SHIFT }, + [ 'A' & 0x1f ] = { .scancode = 0x1e, .flags = FLAG_CTRL }, + [ 's' ] = { .scancode = 0x1f, }, + [ 'S' ] = { .scancode = 0x1f, .flags = FLAG_SHIFT }, + [ 'S' & 0x1f ] = { .scancode = 0x1f, .flags = FLAG_CTRL }, + [ 'd' ] = { .scancode = 0x20, }, + [ 'D' ] = { .scancode = 0x20, .flags = FLAG_SHIFT }, + [ 'D' & 0x1f ] = { .scancode = 0x20, .flags = FLAG_CTRL }, + [ 'f' ] = { .scancode = 0x21, }, + [ 'F' ] = { .scancode = 0x21, .flags = FLAG_SHIFT }, + [ 'F' & 0x1f ] = { .scancode = 0x21, .flags = FLAG_CTRL }, + [ 'g' ] = { .scancode = 0x22, }, + [ 'G' ] = { .scancode = 0x22, .flags = FLAG_SHIFT }, + [ 'G' & 0x1f ] = { .scancode = 0x22, .flags = FLAG_CTRL }, + [ 'h' ] = { .scancode = 0x23, }, + [ 'H' ] = { .scancode = 0x23, .flags = FLAG_SHIFT }, + [ 'H' & 0x1f ] = { .scancode = 0x23, .flags = FLAG_CTRL }, + [ 'j' ] = { .scancode = 0x24, }, + [ 'J' ] = { .scancode = 0x24, .flags = FLAG_SHIFT }, + [ 'J' & 0x1f ] = { .scancode = 0x24, .flags = FLAG_CTRL }, + [ 'k' ] = { .scancode = 0x25, }, + [ 'K' ] = { .scancode = 0x25, .flags = FLAG_SHIFT }, + [ 'K' & 0x1f ] = { .scancode = 0x25, .flags = FLAG_CTRL }, + [ 'l' ] = { .scancode = 0x26, }, + [ 'L' ] = { .scancode = 0x26, .flags = FLAG_SHIFT }, + [ 'L' & 0x1f ] = { .scancode = 0x26, .flags = FLAG_CTRL }, + [ ';' ] = { .scancode = 0x27, }, + [ ':' ] = { .scancode = 0x27, .flags = FLAG_SHIFT }, + [ ''' ] = { .scancode = 0x28, }, + [ '"' ] = { .scancode = 0x28, .flags = FLAG_SHIFT }, + + [ '\' ] = { .scancode = 0x2b, }, + [ '|' ] = { .scancode = 0x2b, .flags = FLAG_SHIFT }, + [ 'z' ] = { .scancode = 0x2c, }, + [ 'Z' ] = { .scancode = 0x2c, .flags = FLAG_SHIFT }, + [ 'Z' & 0x1f ] = { .scancode = 0x2c, .flags = FLAG_CTRL }, + [ 'x' ] = { .scancode = 0x2d, }, + [ 'X' ] = { .scancode = 0x2d, .flags = FLAG_SHIFT }, + [ 'X' & 0x1f ] = { .scancode = 0x2d, .flags = FLAG_CTRL }, + [ 'c' ] = { .scancode = 0x2e, }, + [ 'C' ] = { .scancode = 0x2e, .flags = FLAG_SHIFT }, + [ 'C' & 0x1f ] = { .scancode = 0x2e, .flags = FLAG_CTRL }, + [ 'v' ] = { .scancode = 0x2f, }, + [ 'V' ] = { .scancode = 0x2f, .flags = FLAG_SHIFT }, + [ 'V' & 0x1f ] = { .scancode = 0x2f, .flags = FLAG_CTRL }, + [ 'b' ] = { .scancode = 0x30, }, + [ 'B' ] = { .scancode = 0x30, .flags = FLAG_SHIFT }, + [ 'B' & 0x1f ] = { .scancode = 0x30, .flags = FLAG_CTRL }, + [ 'n' ] = { .scancode = 0x31, }, + [ 'N' ] = { .scancode = 0x31, .flags = FLAG_SHIFT }, + [ 'N' & 0x1f ] = { .scancode = 0x31, .flags = FLAG_CTRL }, + [ 'm' ] = { .scancode = 0x32, }, + [ 'M' ] = { .scancode = 0x32, .flags = FLAG_SHIFT }, + [ 'M' & 0x1f ] = { .scancode = 0x32, .flags = FLAG_CTRL }, + [ ',' ] = { .scancode = 0x33, }, + [ '<' ] = { .scancode = 0x33, .flags = FLAG_SHIFT }, + [ '.' ] = { .scancode = 0x34, }, + [ '>' ] = { .scancode = 0x34, .flags = FLAG_SHIFT }, + [ '?' ] = { .scancode = 0x35, }, + [ '|' ] = { .scancode = 0x35, .flags = FLAG_SHIFT }, + + [ '\x1b' ] = { .scancode = 0x01, }, + [ '\t' ] = { .scancode = 0x0f, }, + [ '\r' ] = { .scancode = 0x1c, }, + [ '\n' ] = { .scancode = 0x1c, }, + [ ' ' ] = { .scancode = 0x39, }, +}; + +static void shiftbuf(int remove) +{ + int i, remaining; + + remaining = GET_LOW(rx_bytes) - remove; + SET_LOW(rx_bytes, remaining); + for (i = 0; i < remaining; i++) + SET_LOW(rx_buf[i], GET_LOW(rx_buf[i + remove])); +} + +static void sercon_sendkey(u8 scancode, u8 flags) +{ + if (flags & FLAG_CTRL) + process_key(0x1d); + if (flags & FLAG_SHIFT) + process_key(0x2a); + + if (scancode & 0x80) { + process_key(0xe0); + process_key(scancode & ~0x80); + process_key(0xe0); + process_key(scancode); + } else { + process_key(scancode); + process_key(scancode | 0x80); + } + + if (flags & FLAG_SHIFT) + process_key(0x2a | 0x80); + if (flags & FLAG_CTRL) + process_key(0x1d | 0x80); +} + +void VISIBLE16 +sercon_check_event(void) +{ + u16 addr = GET_LOW(sercon_port); + u8 byte, scancode, flags, count = 0; + int seq, chr, len; + + // check to see if there is a active serial port + if (!addr) + return; + if (inb(addr + SEROFF_LSR) == 0xFF) + return; + + // flush pending output + sercon_flush_lazy(); + + // read all available data + while (inb(addr + SEROFF_LSR) & 0x01) { + byte = inb(addr + SEROFF_DATA); + if (GET_LOW(rx_bytes) < sizeof(rx_buf)) { + SET_LOW(rx_buf[rx_bytes], byte); + SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1); + count++; + } + } + +next_char: + // no (more) input data + if (!GET_LOW(rx_bytes)) + return; + + // lookup escape sequences + if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) { + for (seq = 0; seq < ARRAY_SIZE(termseq); seq++) { + len = GET_LOW(termseq[seq].len); + if (GET_LOW(rx_bytes) < len + 1) + continue; + for (chr = 0; chr < len; chr++) { + if (GET_LOW(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1])) + break; + } + if (chr == len) { + scancode = GET_LOW(termseq[seq].scancode); + sercon_sendkey(scancode, 0); + shiftbuf(len + 1); + goto next_char; + } + } + } + + // Seems we got a escape sequence we didn't recognise. + // -> If we received data wait for more, maybe it is just incomplete. + if (GET_LOW(rx_buf[0]) == 0x1b && count) + return; + + // Handle input as individual chars. + chr = GET_LOW(rx_buf[0]); + scancode = GET_LOW(termchr[chr].scancode); + flags = GET_LOW(termchr[chr].flags); + if (scancode) + sercon_sendkey(scancode, flags); + shiftbuf(1); + goto next_char; +} diff --git a/src/util.h b/src/util.h index 29f17be..3e7366b 100644 --- a/src/util.h +++ b/src/util.h @@ -232,6 +232,7 @@ void serial_setup(void); void lpt_setup(void); void sercon_10(struct bregs *regs); void sercon_enable(void); +void sercon_check_event(void);
// vgahooks.c void handle_155f(struct bregs *regs);