Maps characters received from serial port as INT16h keypresses.
This enables making choice of boot media over serial port.
Source extracted from SageBIOS release for PC Engines apu1.
af6c8ab3b85d1a5a9fbeb41efa30a1ef pcengines.apu_139_osp.tar.gz
Signed-off-by: Kyösti Mälkki <kyosti.malkki(a)gmail.com>
---
src/Kconfig | 6 +++
src/clock.c | 4 ++
src/kbd.c | 2 +-
src/serial.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util.h | 2 +
5 files changed, 168 insertions(+), 1 deletion(-)
diff --git a/src/Kconfig b/src/Kconfig
index e767be1..dedce08 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -411,6 +411,12 @@ menu "BIOS interfaces"
default y
help
Support int 16 keyboard calls.
+ config INT16_SERIAL_KEYBOARD
+ bool "Keyboard on serial port"
+ depends on SERIAL && KEYBOARD
+ default n
+ help
+ Translate serial port input to keyboard scancodes.
config KBD_CALL_INT15_4F
depends on KEYBOARD
bool "Keyboard hook interface"
diff --git a/src/clock.c b/src/clock.c
index e83e0f3..b69a139 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -295,6 +295,10 @@ clock_update(void)
floppy_tick();
usb_check_event();
ps2_check_event();
+
+#if CONFIG_INT16_SERIAL_KEYBOARD
+ uart_check_keystrokes();
+#endif
}
// INT 08h System Timer ISR Entry Point
diff --git a/src/kbd.c b/src/kbd.c
index 61d9df0..48c7d06 100644
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -51,7 +51,7 @@ kbd_init(void)
, x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
}
-static u8
+u8
enqueue_key(u16 keycode)
{
u16 buffer_start = GET_BDA(kbd_buf_start_offset);
diff --git a/src/serial.c b/src/serial.c
index 88349c8..8c93411 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -315,3 +315,158 @@ handle_17(struct bregs *regs)
default: handle_17XX(regs); break;
}
}
+
+#if CONFIG_INT16_SERIAL_KEYBOARD
+static u8 UartToScanCode[] VAR16 = {
+// x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf
+// =====================================================================================================
+ 0x0f, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, // 0x
+ 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, // 1x
+ 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d, 0x33, 0x0c, 0x34, 0x35, // 2x
+ 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, // 3x
+ 0x03, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, // 4x
+ 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x07, 0x0c, // 5x
+ 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, // 6x
+ 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x29, 0x00, // 7x
+};
+
+static u8
+inject_key(u8 scan_code, u8 ascii_code)
+{
+ return enqueue_key((u16) scan_code << 8 | ascii_code);
+}
+
+void
+uart_check_keystrokes(void)
+{
+ u8 rx_buf[5], rx_bytes = 0, ascii_code = 0, scan_code = 0;
+
+ // check to see if there is a active serial port
+ if (inb(CONFIG_DEBUG_SERIAL_PORT + SEROFF_LSR) == 0xFF)
+ return;
+
+ while (inb(CONFIG_DEBUG_SERIAL_PORT + SEROFF_LSR) & 0x01) {
+ if (rx_bytes > sizeof(rx_buf)) {
+ dprintf(1, "uart_check_keystrokes: error too many bytes are available\n");
+ while (inb(CONFIG_DEBUG_SERIAL_PORT + SEROFF_LSR) & 0x01)
+ inb(CONFIG_DEBUG_SERIAL_PORT + SEROFF_DATA);
+ return;
+ }
+ else
+ rx_buf[rx_bytes++] = inb(CONFIG_DEBUG_SERIAL_PORT + SEROFF_DATA);
+ }
+
+ if (!rx_bytes)
+ return;
+
+ if (rx_bytes == 1) {
+ ascii_code = rx_buf[0];
+ if (ascii_code >= ARRAY_SIZE(UartToScanCode)) {
+ dprintf(3, "uart_check_keystrokes: error UartToScanCode out of bounds index\n");
+ return;
+ }
+ scan_code = GET_GLOBAL(UartToScanCode[ascii_code]);
+ inject_key(scan_code, ascii_code);
+ }
+ else if (rx_bytes == 2) { // assume it's actually 2 single-byte keystrokes
+ ascii_code = rx_buf[0];
+ if (ascii_code >= ARRAY_SIZE(UartToScanCode)) {
+ dprintf(3, "uart_check_keystrokes: error in 1/2 byte UartToScanCode out of bounds index\n");
+ return;
+ }
+ scan_code = GET_GLOBAL(UartToScanCode[ascii_code]);
+ inject_key(scan_code, ascii_code);
+
+ ascii_code = rx_buf[1];
+ if (ascii_code >= ARRAY_SIZE(UartToScanCode)) {
+ dprintf(3, "uart_check_keystrokes: error in 2/2 UartToScanCode out of bounds index\n");
+ return;
+ }
+ scan_code = GET_GLOBAL(UartToScanCode[ascii_code]);
+ inject_key(scan_code, ascii_code);
+ }
+ else if (rx_bytes == 3) {
+ if ((rx_buf[0] == 0x1b) && (rx_buf[1] == 0x4f)) { // F1-F12
+ ascii_code = 0;
+ if ((rx_buf[2] >= 0x50) && (rx_buf[2] <= 0x59))
+ scan_code = (rx_buf[2] - 0x50) +0x3b;
+ else if ((rx_buf[2] >= 0x5a) && (rx_buf[2] <= 0x5b))
+ scan_code = (rx_buf[2] - 0x5a) + 0x85;
+ else {
+ dprintf(3, "uart_check_keystrokes: error in Fkey handling %x\n",rx_buf[2]);
+ return;
+ }
+ }
+ else if ((rx_buf[0] == 0x1b) && (rx_buf[1] == 0x5b)) { // cursor keys
+ ascii_code = 0xe0;
+ if (rx_buf[2] == 0x41) scan_code = 0x48; // UP
+ else if (rx_buf[2] == 0x42) scan_code = 0x50; // DOWN
+ else if (rx_buf[2] == 0x43) scan_code = 0x4d; // LEFT
+ else if (rx_buf[2] == 0x44) scan_code = 0x4b; // RIGHT
+ else {
+ dprintf(3, "uart_check_keystrokes: error in cursor handling %x\n",rx_buf[2]);
+ return;
+ }
+ }
+ else {
+ dprintf(3, "uart_check_keystrokes: error in 3 byte key sequence\n");
+ return;
+ }
+ inject_key(scan_code, ascii_code);
+ }
+ else if (rx_bytes == 4) {
+ if ((rx_buf[0] == 0x1b) && (rx_buf[1] == 0x5b) && (rx_buf[2] == 0x33) && (rx_buf[3] == 0x7e)) { // DEL
+ ascii_code = 0xe0;
+ scan_code = 0x53;
+ inject_key(scan_code, ascii_code);
+ }
+ else {
+ dprintf(3, "uart_check_keystrokes: unhandled 4 byte keystroke ");
+ dprintf(3, "%x %x %x %x\n",rx_buf[0],rx_buf[1],rx_buf[2],rx_buf[3]);
+ return;
+ }
+ }
+ /* these 5 byte scan codes are used by some terminal emulators */
+ else if (rx_bytes == 5) {
+ if ((rx_buf[0] == 0x1b) && (rx_buf[1] == 0x5b) && (rx_buf[2] == 0x32) && (rx_buf[4] == 0x7e)) { // F9-F12
+ ascii_code = 0x00;
+ if (rx_buf[3] == 0x30) scan_code = 0x43; // F9
+ else if (rx_buf[3] == 0x31) scan_code = 0x44; // F10
+ else if (rx_buf[3] == 0x33) scan_code = 0x85; // F11
+ else if (rx_buf[3] == 0x34) scan_code = 0x86; // F12
+ else {
+ dprintf(3, "uart_check_keystrokes: unhandled 5 byte keystroke F9-F12 ");
+ dprintf(3, "%x %x %x %x %x\n",rx_buf[0],rx_buf[1],rx_buf[2],rx_buf[3],rx_buf[4]);
+ return;
+ }
+ }
+ else if ((rx_buf[0] == 0x1b) && (rx_buf[1] == 0x5b) && (rx_buf[2] == 0x31) && (rx_buf[4] == 0x7e)) { // F1-F8
+ ascii_code = 0x00;
+ if (rx_buf[3] == 0x31) scan_code = 0x3B; // F1
+ else if (rx_buf[3] == 0x32) scan_code = 0x3C; // F2
+ else if (rx_buf[3] == 0x33) scan_code = 0x3D; // F3
+ else if (rx_buf[3] == 0x34) scan_code = 0x3E; // F4
+ else if (rx_buf[3] == 0x35) scan_code = 0x3F; // F5
+ else if (rx_buf[3] == 0x37) scan_code = 0x40; // F6
+ else if (rx_buf[3] == 0x38) scan_code = 0x41; // F7
+ else if (rx_buf[3] == 0x39) scan_code = 0x42; // F8
+ else {
+ dprintf(3, "uart_check_keystrokes: unhandled 5 byte keystroke F1-F8 ");
+ dprintf(3, "%x %x %x %x %x\n",rx_buf[0],rx_buf[1],rx_buf[2],rx_buf[3],rx_buf[4]);
+ return;
+ }
+ }
+ else {
+ dprintf(3, "uart_check_keystrokes: unhandled 5 byte keystroke ");
+ dprintf(3, "%x %x %x %x %x\n",rx_buf[0],rx_buf[1],rx_buf[2],rx_buf[3],rx_buf[4]);
+ return;
+ }
+ inject_key(scan_code, ascii_code);
+ }
+ else {
+ dprintf(3, "uart_check_keystrokes: unhandled rx_bytes = %x\n",rx_bytes);
+ dprintf(3, "%x %x %x %x %x\n",rx_buf[0],rx_buf[1],rx_buf[2],rx_buf[3],rx_buf[4]);
+ return;
+ }
+}
+#endif /* CONFIG_INT16_SERIAL_KEYBOARD */
diff --git a/src/util.h b/src/util.h
index 7b41207..9be308a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -184,6 +184,7 @@ int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
void kbd_init(void);
void handle_15c2(struct bregs *regs);
void process_key(u8 key);
+u8 enqueue_key(u16 keycode);
// misc.c
extern int HaveRunPost;
@@ -230,6 +231,7 @@ void code_mutable_preinit(void);
// serial.c
void serial_setup(void);
void lpt_setup(void);
+void uart_check_keystrokes(void);
// vgahooks.c
void handle_155f(struct bregs *regs);
--
1.9.1