libpayload: Support curses for serial
Support the curses interface over serial by supporting a minimal vt100
terminal.
Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3370 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/payloads/libpayload/curses/keyboard.c b/payloads/libpayload/curses/keyboard.c
index 0f55614..facf2ac 100644
--- a/payloads/libpayload/curses/keyboard.c
+++ b/payloads/libpayload/curses/keyboard.c
@@ -43,11 +43,89 @@
/* ============== Serial ==================== */
-/* FIXME: Cook the serial correctly */
+/* We treat serial like a vt100 terminal. For now we
+ do the cooking in here, but we should probably eventually
+ pass it to dedicated vt100 code */
+
+static int getkeyseq(char *buffer, int len)
+{
+ int i;
+
+ for(i = 0; i < 75; i++) {
+ if (serial_havechar())
+ break;
+ mdelay(1);
+ }
+
+ if (i == 75)
+ return len;
+
+ buffer[len++] = serial_getchar();
+ return getkeyseq(buffer, len);
+}
+
+static struct {
+ char *seq;
+ int key;
+} escape_codes[] = {
+ { "[A", KEY_UP },
+ { "[B", KEY_DOWN },
+ { "[C", KEY_RIGHT },
+ { "[D", KEY_LEFT },
+ { "OP", KEY_F(1) },
+ { "OQ", KEY_F(2) },
+ { "OR", KEY_F(3) },
+ { "OS", KEY_F(4) },
+ { "[15~", KEY_F(5) },
+ { "[17~", KEY_F(6) },
+ { "[18~", KEY_F(7) },
+ { "[19~", KEY_F(8) },
+ { "[20~", KEY_F(9) },
+ { "[21~", KEY_F(10) },
+ { "[24~", KEY_F(12) },
+ { NULL },
+};
+
+static int handle_escape(void)
+{
+ char buffer[5];
+ int len = getkeyseq(buffer, 0);
+ int i, t;
+
+ if (len == 0)
+ return 27;
+
+ for(i = 0; escape_codes[i].seq != NULL; i++) {
+ char *p = escape_codes[i].seq;
+
+ for(t = 0; t < len; t++) {
+ if (!*p || *p != buffer[t])
+ break;
+ p++;
+ }
+
+ if (t == len)
+ return escape_codes[i].key;
+ }
+
+ return 0;
+}
static int cook_serial(unsigned char ch)
{
- return (int) ch;
+ switch(ch) {
+ case 8:
+ return KEY_BACKSPACE;
+
+ case 13:
+ return KEY_ENTER;
+
+ case 27:
+ return handle_escape();
+
+ default:
+ return ch;
+ }
}
/* ================ Keyboard ================ */
diff --git a/payloads/libpayload/curses/tinycurses.c b/payloads/libpayload/curses/tinycurses.c
index a51efb2..9e9b3cd 100644
--- a/payloads/libpayload/curses/tinycurses.c
+++ b/payloads/libpayload/curses/tinycurses.c
@@ -218,6 +218,10 @@
// newterm(name, stdout, stdin);
// def_prog_mode();
+ if (curses_flags & F_ENABLE_SERIAL) {
+ serial_clear();
+ }
+
if (curses_flags & F_ENABLE_CONSOLE) {
/* Clear the screen and kill the cursor */
@@ -586,20 +590,48 @@
win->_flags |= _HASMOVED;
return OK;
}
+
int wnoutrefresh(WINDOW *win)
{
// FIXME.
+ int serial_is_bold = 0;
+
int x, y;
+ serial_end_bold();
+
for (y = 0; y <= win->_maxy; y++) {
+
+ /* Position the serial cursor */
+
+ if (curses_flags & F_ENABLE_SERIAL)
+ serial_set_cursor(win->_begy + y, win->_begx);
+
for (x = 0; x <= win->_maxx; x++) {
- if (curses_flags & F_ENABLE_SERIAL)
+ attr_t attr = win->_line[y].text[x].attr;
+
+ unsigned int c =
+ ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
+
+ if (curses_flags & F_ENABLE_SERIAL) {
+
+ if (attr & A_BOLD) {
+ if (!serial_is_bold) {
+ serial_start_bold();
+ serial_is_bold = 1;
+ }
+ }
+ else {
+ if (serial_is_bold) {
+ serial_end_bold();
+ serial_is_bold = 0;
+ }
+ }
+
serial_putchar(win->_line[y].text[x].chars[0]);
+ }
if (curses_flags & F_ENABLE_CONSOLE) {
- attr_t attr = win->_line[y].text[x].attr;
- unsigned int c =
- ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
/* Handle some of the attributes. */
if (attr & A_BOLD)
diff --git a/payloads/libpayload/drivers/serial.c b/payloads/libpayload/drivers/serial.c
index a97e7dd..f7b12eb 100644
--- a/payloads/libpayload/drivers/serial.c
+++ b/payloads/libpayload/drivers/serial.c
@@ -35,6 +35,25 @@
#define DIVISOR (115200 / CONFIG_SERIAL_BAUD_RATE)
#endif
+/* This is a hack - we convert the drawing characters to ASCII */
+
+static unsigned char translate_special_chars(unsigned char c)
+{
+ switch(c) {
+ case 196:
+ return '-';
+ case 179:
+ return '|';
+ case 218:
+ case 191:
+ case 192:
+ case 217:
+ return '+';
+ default:
+ return ' ';
+ }
+}
+
void serial_init(void)
{
#ifdef CONFIG_SERIAL_SET_SPEED
@@ -61,6 +80,9 @@
void serial_putchar(unsigned char c)
{
+ if (c > 127)
+ c = translate_special_chars(c);
+
while ((inb(IOBASE + 0x05) & 0x20) == 0) ;
outb(c, IOBASE);
}
@@ -75,3 +97,38 @@
while (!serial_havechar()) ;
return (int)inb(IOBASE);
}
+
+/* These are thinly veiled vt100 functions used by curses */
+
+#define VT100_CLEAR "\e[H\e[J"
+#define VT100_SBOLD "\e[7m"
+#define VT100_EBOLD "\e[m"
+#define VT100_CURSOR_ADDR "\e[%d;%dH"
+
+static void serial_putcmd(char *str)
+{
+ while(*str)
+ serial_putchar(*(str++));
+}
+
+void serial_clear(void)
+{
+ serial_putcmd(VT100_CLEAR);
+}
+
+void serial_start_bold(void)
+{
+ serial_putcmd(VT100_SBOLD);
+}
+
+void serial_end_bold(void)
+{
+ serial_putcmd(VT100_EBOLD);
+}
+
+void serial_set_cursor(int y, int x)
+{
+ char buffer[32];
+ snprintf(buffer, sizeof(buffer), VT100_CURSOR_ADDR, y, x);
+ serial_putcmd(buffer);
+}
diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h
index dc2f5ee..03dc071 100644
--- a/payloads/libpayload/include/libpayload.h
+++ b/payloads/libpayload/include/libpayload.h
@@ -107,6 +107,11 @@
int serial_havechar(void);
int serial_getchar(void);
+void serial_clear(void);
+void serial_start_bold(void);
+void serial_end_bold(void);
+void serial_set_cursor(int y, int x);
+
/* drivers/speaker.c */
void speaker_enable(u16 freq);
void speaker_disable(void);