libpayload: Support curses for serial
authorJordan Crouse <jordan.crouse@amd.com>
Fri, 20 Jun 2008 00:01:42 +0000 (00:01 +0000)
committerJordan Crouse <jordan.crouse@amd.com>
Fri, 20 Jun 2008 00:01:42 +0000 (00:01 +0000)
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

payloads/libpayload/curses/keyboard.c
payloads/libpayload/curses/tinycurses.c
payloads/libpayload/drivers/serial.c
payloads/libpayload/include/libpayload.h

index 0f55614f396c3c4e4448d215c70023c0dbdf87a9..facf2ace1985bb5f3f5b1bfde506f1b5d0a8159f 100644 (file)
@@ -43,11 +43,89 @@ static int _halfdelay = 0;
 
 /* ============== 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 ================ */
index a51efb29746f1d8d4aaa79b503484399ad6726cd..9e9b3cdec00796bd2b949762c1d4056f9868a794 100644 (file)
@@ -218,6 +218,10 @@ WINDOW *initscr(void)
        // 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 @@ int whline(WINDOW *win, chtype ch, int n)
        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)
index a97e7dd8087677dd29a2f18f75acbdfe7b7e04f5..f7b12eb561c15b84ea220b1c6fab6c99eb63fd40 100644 (file)
 #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_init(void)
 
 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 @@ int serial_getchar(void)
        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);
+}
index dc2f5eec1b561b00bd76374f1e05874e1ab57203..03dc07177817cdc254e17f461f6c289c1cf7bff5 100644 (file)
@@ -107,6 +107,11 @@ void serial_putchar(unsigned char c);
 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);