From bf8733749b11bacaee099c72e9a9178b29055af0 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 7 May 2010 15:44:43 +0200 Subject: [PATCH] merge common serial and ofconsole code into terminfo --- include/grub/{i386 => }/ieee1275/console.h | 3 +- include/grub/powerpc/ieee1275/console.h | 28 -- include/grub/sparc64/ieee1275/console.h | 28 -- include/grub/terminfo.h | 68 +++- kern/ieee1275/init.c | 5 +- term/ieee1275/ofconsole.c | 241 +++--------- term/serial.c | 189 ++-------- term/terminfo.c | 412 +++++++++++++++++---- term/tparm.c | 3 + 9 files changed, 483 insertions(+), 494 deletions(-) rename include/grub/{i386 => }/ieee1275/console.h (92%) delete mode 100644 include/grub/powerpc/ieee1275/console.h delete mode 100644 include/grub/sparc64/ieee1275/console.h diff --git a/include/grub/i386/ieee1275/console.h b/include/grub/ieee1275/console.h similarity index 92% rename from include/grub/i386/ieee1275/console.h rename to include/grub/ieee1275/console.h index 854724ac1..e054f54f5 100644 --- a/include/grub/i386/ieee1275/console.h +++ b/include/grub/ieee1275/console.h @@ -22,7 +22,8 @@ #include /* Initialize the console system. */ -void grub_console_init (void); +void grub_console_init_early (void); +void grub_console_init_lately (void); /* Finish the console system. */ void grub_console_fini (void); diff --git a/include/grub/powerpc/ieee1275/console.h b/include/grub/powerpc/ieee1275/console.h deleted file mode 100644 index ed2b7202a..000000000 --- a/include/grub/powerpc/ieee1275/console.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_CONSOLE_MACHINE_HEADER -#define GRUB_CONSOLE_MACHINE_HEADER 1 - -/* Initialize the console system. */ -void grub_console_init (void); - -/* Finish the console system. */ -void grub_console_fini (void); - -#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */ diff --git a/include/grub/sparc64/ieee1275/console.h b/include/grub/sparc64/ieee1275/console.h deleted file mode 100644 index ed2b7202a..000000000 --- a/include/grub/sparc64/ieee1275/console.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_CONSOLE_MACHINE_HEADER -#define GRUB_CONSOLE_MACHINE_HEADER 1 - -/* Initialize the console system. */ -void grub_console_init (void); - -/* Finish the console system. */ -void grub_console_fini (void); - -#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */ diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index f078871d0..54872caa8 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -23,18 +23,64 @@ #include #include -char *EXPORT_FUNC(grub_terminfo_get_current) (void); -grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (const char *); - -void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_uint8_t x, grub_uint8_t y, - grub_term_output_t oterm); -void EXPORT_FUNC(grub_terminfo_cls) (grub_term_output_t oterm); -void EXPORT_FUNC(grub_terminfo_reverse_video_on) (grub_term_output_t oterm); -void EXPORT_FUNC(grub_terminfo_reverse_video_off) (grub_term_output_t oterm); -void EXPORT_FUNC(grub_terminfo_cursor_on) (grub_term_output_t oterm); -void EXPORT_FUNC(grub_terminfo_cursor_off) (grub_term_output_t oterm); +char *EXPORT_FUNC(grub_terminfo_get_current) (struct grub_term_output *term); +grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (struct grub_term_output *term, + const char *); #define GRUB_TERMINFO_READKEY_MAX_LEN 4 -void EXPORT_FUNC(grub_terminfo_readkey) (int *keys, int *len, int (*readkey) (void)); +struct grub_terminfo_input_state +{ + int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN]; + int npending; + int (*readkey) (void); +}; + +struct grub_terminfo_output_state +{ + struct grub_term_output *next; + + char *name; + + char *gotoxy; + char *cls; + char *reverse_video_on; + char *reverse_video_off; + char *cursor_on; + char *cursor_off; + char *setcolor; + + grub_uint8_t normal_color; + grub_uint8_t highlight_color; + + unsigned int xpos, ypos; + + void (*put) (const int c); +}; + +void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_term_output_t term, + grub_uint8_t x, grub_uint8_t y); +void EXPORT_FUNC(grub_terminfo_cls) (grub_term_output_t term); +grub_uint16_t EXPORT_FUNC (grub_terminfo_getxy) (struct grub_term_output *term); +void EXPORT_FUNC (grub_terminfo_setcursor) (struct grub_term_output *term, + const int on); +void EXPORT_FUNC (grub_terminfo_setcolorstate) (struct grub_term_output *term, + const grub_term_color_state state); + + +int EXPORT_FUNC (grub_terminfo_checkkey) (struct grub_term_input *term); +grub_err_t EXPORT_FUNC (grub_terminfo_input_init) (struct grub_term_input *term); +int EXPORT_FUNC (grub_terminfo_getkey) (struct grub_term_input *term); +void EXPORT_FUNC (grub_terminfo_putchar) (struct grub_term_output *term, + const struct grub_unicode_glyph *c); +void EXPORT_FUNC (grub_terminfo_getcolor) (struct grub_term_output *term, + grub_uint8_t *normal_color, + grub_uint8_t *highlight_color); +void EXPORT_FUNC (grub_terminfo_setcolor) (struct grub_term_output *term, + grub_uint8_t normal_color, + grub_uint8_t highlight_color); + +grub_err_t EXPORT_FUNC (grub_terminfo_output_register) (struct grub_term_output *term, + const char *type); +grub_err_t EXPORT_FUNC (grub_terminfo_output_unregister) (struct grub_term_output *term); #endif /* ! GRUB_TERMINFO_HEADER */ diff --git a/kern/ieee1275/init.c b/kern/ieee1275/init.c index b48df37bc..1a408fb73 100644 --- a/kern/ieee1275/init.c +++ b/kern/ieee1275/init.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -225,11 +225,12 @@ grub_machine_init (void) grub_ieee1275_init (); - grub_console_init (); + grub_console_init_early (); #ifdef __i386__ grub_get_extended_memory (); #endif grub_claim_heap (); + grub_console_init_lately (); grub_ofdisk_init (); /* Process commandline. */ diff --git a/term/ieee1275/ofconsole.c b/term/ieee1275/ofconsole.c index 590fa7f53..d143a6313 100644 --- a/term/ieee1275/ofconsole.c +++ b/term/ieee1275/ofconsole.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include static grub_ieee1275_ihandle_t stdout_ihandle; @@ -32,12 +32,6 @@ static grub_ieee1275_ihandle_t stdin_ihandle; static grub_uint8_t grub_ofconsole_width; static grub_uint8_t grub_ofconsole_height; -static int grub_curr_x; -static int grub_curr_y; - -static int grub_keybuf[GRUB_TERMINFO_READKEY_MAX_LEN]; -static int grub_buflen; - struct color { int red; @@ -58,102 +52,14 @@ static struct color colors[] = {0xFE, 0xFE, 0xFE} // 7 = white }; -static grub_uint8_t grub_ofconsole_normal_color = 0x7; -static grub_uint8_t grub_ofconsole_highlight_color = 0x70; - -/* Write control characters to the console. */ static void -grub_ofconsole_writeesc (const char *str) +put (const int c) { - if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI)) - return; + char chr = c; - while (*str) - { - char chr = *(str++); - grub_ieee1275_write (stdout_ihandle, &chr, 1, 0); - } - -} - -static void -grub_ofconsole_putchar (struct grub_term_output *term __attribute__ ((unused)), - const struct grub_unicode_glyph *c) -{ - char chr; - - chr = c->base; - - if (chr == '\n') - { - grub_curr_y++; - grub_curr_x = 0; - } - else if (chr == '\r') - { - grub_curr_x = 0; - } - else - { - grub_curr_x++; - if (grub_curr_x >= grub_ofconsole_width) - { - chr = '\n'; - grub_ieee1275_write (stdout_ihandle, &chr, 1, 0); - chr = '\r'; - grub_ieee1275_write (stdout_ihandle, &chr, 1, 0); - grub_curr_y++; - grub_curr_x = 1; - } - } grub_ieee1275_write (stdout_ihandle, &chr, 1, 0); } -static void -grub_ofconsole_setcolorstate (struct grub_term_output *term __attribute__ ((unused)), - grub_term_color_state state) -{ - char setcol[256]; - int fg; - int bg; - - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - case GRUB_TERM_COLOR_NORMAL: - fg = grub_ofconsole_normal_color & 0x0f; - bg = grub_ofconsole_normal_color >> 4; - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - fg = grub_ofconsole_highlight_color & 0x0f; - bg = grub_ofconsole_highlight_color >> 4; - break; - default: - return; - } - - grub_snprintf (setcol, sizeof (setcol), "\e[3%dm\e[4%dm", fg, bg); - grub_ofconsole_writeesc (setcol); -} - -static void -grub_ofconsole_setcolor (struct grub_term_output *term __attribute__ ((unused)), - grub_uint8_t normal_color, - grub_uint8_t highlight_color) -{ - /* Discard bright bit. */ - grub_ofconsole_normal_color = normal_color & 0x77; - grub_ofconsole_highlight_color = highlight_color & 0x77; -} - -static void -grub_ofconsole_getcolor (struct grub_term_output *term __attribute__ ((unused)), - grub_uint8_t *normal_color, grub_uint8_t *highlight_color) -{ - *normal_color = grub_ofconsole_normal_color; - *highlight_color = grub_ofconsole_highlight_color; -} - static int readkey (void) { @@ -166,39 +72,6 @@ readkey (void) return -1; } -static int -grub_ofconsole_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - if (grub_buflen) - return grub_keybuf[0]; - - grub_terminfo_readkey (grub_keybuf, &grub_buflen, readkey); - - if (grub_buflen) - return grub_keybuf[0]; - - return -1; -} - -static int -grub_ofconsole_getkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int ret; - while (! grub_buflen) - grub_terminfo_readkey (grub_keybuf, &grub_buflen, readkey); - - ret = grub_keybuf[0]; - grub_buflen--; - grub_memmove (grub_keybuf, grub_keybuf + 1, grub_buflen); - return ret; -} - -static grub_uint16_t -grub_ofconsole_getxy (struct grub_term_output *term __attribute__ ((unused))) -{ - return (grub_curr_x << 8) | grub_curr_y; -} - static void grub_ofconsole_dimensions (void) { @@ -241,44 +114,6 @@ grub_ofconsole_getwh (struct grub_term_output *term __attribute__ ((unused))) return (grub_ofconsole_width << 8) | grub_ofconsole_height; } -static void -grub_ofconsole_gotoxy (struct grub_term_output *term __attribute__ ((unused)), - grub_uint8_t x, grub_uint8_t y) -{ - if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI)) - { - char s[256]; - grub_curr_x = x; - grub_curr_y = y; - - grub_snprintf (s, sizeof (s), "\e[%d;%dH", y + 1, x + 1); - grub_ofconsole_writeesc (s); - } - else - { - if ((y == grub_curr_y) && (x == grub_curr_x - 1)) - { - char chr; - - chr = '\b'; - grub_ieee1275_write (stdout_ihandle, &chr, 1, 0); - } - - grub_curr_x = x; - grub_curr_y = y; - } -} - -static void -grub_ofconsole_cls (struct grub_term_output *term) -{ - /* Clear the screen. Using serial console, screen(1) only recognizes the - * ANSI escape sequence. Using video console, Apple Open Firmware (version - * 3.1.1) only recognizes the literal ^L. So use both. */ - grub_ofconsole_writeesc (" \e[2J"); - grub_ofconsole_gotoxy (term, 0, 0); -} - static void grub_ofconsole_setcursor (struct grub_term_output *term __attribute__ ((unused)), int on) @@ -290,14 +125,8 @@ grub_ofconsole_setcursor (struct grub_term_output *term __attribute__ ((unused)) grub_ieee1275_interpret ("cursor-off", 0); } -static void -grub_ofconsole_refresh (struct grub_term_output *term __attribute__ ((unused))) -{ - /* Do nothing, the current console state is ok. */ -} - static grub_err_t -grub_ofconsole_init_input (struct grub_term_input *term __attribute__ ((unused))) +grub_ofconsole_init_input (struct grub_term_input *term) { grub_ssize_t actual; @@ -306,7 +135,7 @@ grub_ofconsole_init_input (struct grub_term_input *term __attribute__ ((unused)) || actual != sizeof stdin_ihandle) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdin"); - return 0; + return grub_terminfo_input_init (term); } static grub_err_t @@ -333,8 +162,8 @@ grub_ofconsole_init_output (struct grub_term_output *term) grub_ieee1275_set_color (stdout_ihandle, col, colors[col].red, colors[col].green, colors[col].blue); - /* Set the right fg and bg colors. */ - grub_ofconsole_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + /* Set the right fg and bg colors. */ + grub_terminfo_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); } grub_ofconsole_dimensions (); @@ -343,41 +172,73 @@ grub_ofconsole_init_output (struct grub_term_output *term) } + +struct grub_terminfo_input_state grub_ofconsole_terminfo_input = + { + .readkey = readkey + }; + +struct grub_terminfo_output_state grub_ofconsole_terminfo_output = + { + .put = put + }; + static struct grub_term_input grub_ofconsole_term_input = { .name = "ofconsole", .init = grub_ofconsole_init_input, - .checkkey = grub_ofconsole_checkkey, - .getkey = grub_ofconsole_getkey, + .checkkey = grub_terminfo_checkkey, + .getkey = grub_terminfo_getkey, + .data = &grub_ofconsole_terminfo_input }; static struct grub_term_output grub_ofconsole_term_output = { .name = "ofconsole", .init = grub_ofconsole_init_output, - .putchar = grub_ofconsole_putchar, - .getxy = grub_ofconsole_getxy, + .putchar = grub_terminfo_putchar, + .getxy = grub_terminfo_getxy, .getwh = grub_ofconsole_getwh, - .gotoxy = grub_ofconsole_gotoxy, - .cls = grub_ofconsole_cls, - .setcolorstate = grub_ofconsole_setcolorstate, - .setcolor = grub_ofconsole_setcolor, - .getcolor = grub_ofconsole_getcolor, + .gotoxy = grub_terminfo_gotoxy, + .cls = grub_terminfo_cls, + .setcolorstate = grub_terminfo_setcolorstate, + .setcolor = grub_terminfo_setcolor, + .getcolor = grub_terminfo_getcolor, .setcursor = grub_ofconsole_setcursor, - .refresh = grub_ofconsole_refresh, - .flags = GRUB_TERM_CODE_TYPE_ASCII + .flags = GRUB_TERM_CODE_TYPE_ASCII, + .data = &grub_ofconsole_terminfo_output }; +void grub_terminfo_fini (void); +void grub_terminfo_init (void); + void -grub_console_init (void) +grub_console_init_early (void) { grub_term_register_input ("ofconsole", &grub_ofconsole_term_input); grub_term_register_output ("ofconsole", &grub_ofconsole_term_output); } +void +grub_console_init_lately (void) +{ + const char *type; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI)) + type = "dumb"; + else + type = "ieee1275"; + + grub_terminfo_init (); + grub_terminfo_output_register (&grub_ofconsole_term_output, type); +} + void grub_console_fini (void) { grub_term_unregister_input (&grub_ofconsole_term_input); grub_term_unregister_output (&grub_ofconsole_term_output); + grub_terminfo_output_unregister (&grub_ofconsole_term_output); + + grub_terminfo_fini (); } diff --git a/term/serial.c b/term/serial.c index 61bad192f..82bf6abb7 100644 --- a/term/serial.c +++ b/term/serial.c @@ -27,19 +27,8 @@ #include #include -#define TEXT_WIDTH 80 -#define TEXT_HEIGHT 24 - -static unsigned int xpos, ypos; -static unsigned int keep_track = 1; static unsigned int registered = 0; -/* An input buffer. */ -static int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN]; -static int npending = 0; - -static struct grub_term_output grub_serial_term_output; - /* Argument options. */ static const struct grub_arg_option options[] = { @@ -152,35 +141,6 @@ serial_get_divisor (unsigned int speed) return 0; } -/* The serial version of checkkey. */ -static int -grub_serial_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - if (npending) - return input_buf[0]; - - grub_terminfo_readkey (input_buf, &npending, serial_hw_fetch); - - if (npending) - return input_buf[0]; - - return -1; -} - -/* The serial version of getkey. */ -static int -grub_serial_getkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int ret; - while (! npending) - grub_terminfo_readkey (input_buf, &npending, serial_hw_fetch); - - ret = input_buf[0]; - npending--; - grub_memmove (input_buf, input_buf + 1, npending); - return ret; -} - /* Initialize a serial device. PORT is the port number for a serial device. SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600, 19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used @@ -219,150 +179,56 @@ serial_hw_init (void) #endif /* Drain the input buffer. */ - while (grub_serial_checkkey (0) != -1) - (void) grub_serial_getkey (0); + while (serial_hw_fetch () != -1); /* FIXME: should check if the serial terminal was found. */ return GRUB_ERR_NONE; } -/* The serial version of putchar. */ -static void -grub_serial_putchar (struct grub_term_output *term __attribute__ ((unused)), - const struct grub_unicode_glyph *c) -{ - /* Keep track of the cursor. */ - if (keep_track) - { - switch (c->base) - { - case '\a': - break; - - case '\b': - case 127: - if (xpos > 0) - xpos--; - break; - - case '\n': - if (ypos < TEXT_HEIGHT - 1) - ypos++; - break; - - case '\r': - xpos = 0; - break; - - default: - if ((c->base & 0xC0) == 0x80) - break; - if (xpos + c->estimated_width >= TEXT_WIDTH + 1) - { - xpos = 0; - if (ypos < TEXT_HEIGHT - 1) - ypos++; - serial_hw_put ('\r'); - serial_hw_put ('\n'); - } - xpos += c->estimated_width; - break; - } - } - - serial_hw_put (c->base); -} - static grub_uint16_t grub_serial_getwh (struct grub_term_output *term __attribute__ ((unused))) { + const grub_uint8_t TEXT_WIDTH = 80; + const grub_uint8_t TEXT_HEIGHT = 24; return (TEXT_WIDTH << 8) | TEXT_HEIGHT; } -static grub_uint16_t -grub_serial_getxy (struct grub_term_output *term __attribute__ ((unused))) -{ - return ((xpos << 8) | ypos); -} +struct grub_terminfo_input_state grub_serial_terminfo_input = + { + .readkey = serial_hw_fetch + }; -static void -grub_serial_gotoxy (struct grub_term_output *term __attribute__ ((unused)), - grub_uint8_t x, grub_uint8_t y) -{ - if (x > TEXT_WIDTH || y > TEXT_HEIGHT) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y); - } - else - { - keep_track = 0; - grub_terminfo_gotoxy (x, y, &grub_serial_term_output); - keep_track = 1; - - xpos = x; - ypos = y; - } -} - -static void -grub_serial_cls (struct grub_term_output *term __attribute__ ((unused))) -{ - keep_track = 0; - grub_terminfo_cls (&grub_serial_term_output); - keep_track = 1; - - xpos = ypos = 0; -} - -static void -grub_serial_setcolorstate (struct grub_term_output *term __attribute__ ((unused)), - const grub_term_color_state state) -{ - keep_track = 0; - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - case GRUB_TERM_COLOR_NORMAL: - grub_terminfo_reverse_video_off (&grub_serial_term_output); - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - grub_terminfo_reverse_video_on (&grub_serial_term_output); - break; - default: - break; - } - keep_track = 1; -} - -static void -grub_serial_setcursor (struct grub_term_output *term __attribute__ ((unused)), - const int on) -{ - if (on) - grub_terminfo_cursor_on (&grub_serial_term_output); - else - grub_terminfo_cursor_off (&grub_serial_term_output); -} +struct grub_terminfo_output_state grub_serial_terminfo_output = + { + .put = serial_hw_put, + .normal_color = 0x7, + .highlight_color = 0x70 + }; static struct grub_term_input grub_serial_term_input = { .name = "serial", - .checkkey = grub_serial_checkkey, - .getkey = grub_serial_getkey, + .init = grub_terminfo_input_init, + .checkkey = grub_terminfo_checkkey, + .getkey = grub_terminfo_getkey, + .data = &grub_serial_terminfo_input }; static struct grub_term_output grub_serial_term_output = { .name = "serial", - .putchar = grub_serial_putchar, + .putchar = grub_terminfo_putchar, .getwh = grub_serial_getwh, - .getxy = grub_serial_getxy, - .gotoxy = grub_serial_gotoxy, - .cls = grub_serial_cls, - .setcolorstate = grub_serial_setcolorstate, - .setcursor = grub_serial_setcursor, + .getxy = grub_terminfo_getxy, + .gotoxy = grub_terminfo_gotoxy, + .cls = grub_terminfo_cls, + .setcolorstate = grub_terminfo_setcolorstate, + .setcolor = grub_terminfo_setcolor, + .getcolor = grub_terminfo_getcolor, + .setcursor = grub_terminfo_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, + .data = &grub_serial_terminfo_output }; @@ -466,6 +332,7 @@ grub_cmd_serial (grub_extcmd_t cmd, { grub_term_register_input ("serial", &grub_serial_term_input); grub_term_register_output ("serial", &grub_serial_term_output); + grub_terminfo_output_register (&grub_serial_term_output, "vt100"); registered = 1; } } @@ -482,6 +349,7 @@ grub_cmd_serial (grub_extcmd_t cmd, /* If unable to restore settings, unregister terminal. */ grub_term_unregister_input (&grub_serial_term_input); grub_term_unregister_output (&grub_serial_term_output); + grub_terminfo_output_unregister (&grub_serial_term_output); registered = 0; } } @@ -518,5 +386,6 @@ GRUB_MOD_FINI(serial) { grub_term_unregister_input (&grub_serial_term_input); grub_term_unregister_output (&grub_serial_term_output); + grub_terminfo_output_unregister (&grub_serial_term_output); } } diff --git a/term/terminfo.c b/term/terminfo.c index eb14d47f1..f0e234106 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -34,25 +34,15 @@ #include #include -struct terminfo -{ - char *name; - - char *gotoxy; - char *cls; - char *reverse_video_on; - char *reverse_video_off; - char *cursor_on; - char *cursor_off; -}; - -static struct terminfo term; +static struct grub_term_output *terminfo_outputs; /* Get current terminfo name. */ char * -grub_terminfo_get_current (void) +grub_terminfo_get_current (struct grub_term_output *term) { - return term.name; + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + return data->name; } /* Free *PTR and set *PTR to NULL, to prevent double-free. */ @@ -63,10 +53,29 @@ grub_terminfo_free (char **ptr) *ptr = 0; } +static void +grub_terminfo_all_free (struct grub_term_output *term) +{ + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + /* Free previously allocated memory. */ + grub_terminfo_free (&data->name); + grub_terminfo_free (&data->gotoxy); + grub_terminfo_free (&data->cls); + grub_terminfo_free (&data->reverse_video_on); + grub_terminfo_free (&data->reverse_video_off); + grub_terminfo_free (&data->cursor_on); + grub_terminfo_free (&data->cursor_off); +} + /* Set current terminfo type. */ grub_err_t -grub_terminfo_set_current (const char *str) +grub_terminfo_set_current (struct grub_term_output *term, + const char *str) { + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; /* TODO * Lookup user specified terminfo type. If found, set term variables * as appropriate. Otherwise return an error. @@ -84,93 +93,290 @@ grub_terminfo_set_current (const char *str) * d. Your idea here. */ - /* Free previously allocated memory. */ - grub_terminfo_free (&term.name); - grub_terminfo_free (&term.gotoxy); - grub_terminfo_free (&term.cls); - grub_terminfo_free (&term.reverse_video_on); - grub_terminfo_free (&term.reverse_video_off); - grub_terminfo_free (&term.cursor_on); - grub_terminfo_free (&term.cursor_off); + grub_terminfo_all_free (term); if (grub_strcmp ("vt100", str) == 0) { - term.name = grub_strdup ("vt100"); - term.gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH"); - term.cls = grub_strdup ("\e[H\e[J"); - term.reverse_video_on = grub_strdup ("\e[7m"); - term.reverse_video_off = grub_strdup ("\e[m"); - term.cursor_on = grub_strdup ("\e[?25h"); - term.cursor_off = grub_strdup ("\e[?25l"); + data->name = grub_strdup ("vt100"); + data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH"); + data->cls = grub_strdup ("\e[H\e[J"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + data->cursor_on = grub_strdup ("\e[?25h"); + data->cursor_off = grub_strdup ("\e[?25l"); + data->setcolor = NULL; + return grub_errno; + } + + if (grub_strcmp ("vt100-color", str) == 0) + { + data->name = grub_strdup ("vt100-color"); + data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH"); + data->cls = grub_strdup ("\e[H\e[J"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + data->cursor_on = grub_strdup ("\e[?25h"); + data->cursor_off = grub_strdup ("\e[?25l"); + data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm"); + return grub_errno; + } + + if (grub_strcmp ("ieee1275", str) == 0) + { + data->name = grub_strdup ("ieee1275"); + data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH"); + /* Clear the screen. Using serial console, screen(1) only recognizes the + * ANSI escape sequence. Using video console, Apple Open Firmware + * (version 3.1.1) only recognizes the literal ^L. So use both. */ + data->cls = grub_strdup (" \e[2J"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + data->cursor_on = grub_strdup ("\e[?25h"); + data->cursor_off = grub_strdup ("\e[?25l"); + data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm"); + return grub_errno; + } + + if (grub_strcmp ("dumb", str) == 0) + { + data->name = grub_strdup ("dumb"); + data->gotoxy = NULL; + data->cls = NULL; + data->reverse_video_on = NULL; + data->reverse_video_off = NULL; + data->cursor_on = NULL; + data->cursor_off = NULL; + data->setcolor = NULL; return grub_errno; } return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type"); } -/* Wrapper for grub_putchar to write strings. */ -static void -putstr (const char *str, grub_term_output_t oterm) +grub_err_t +grub_terminfo_output_register (struct grub_term_output *term, + const char *type) { - while (*str) - { - struct grub_unicode_glyph c = - { - .base = *str++, - .variant = 0, - .attributes = 0, - .ncomb = 0, - .combining = 0 - }; - oterm->putchar (oterm, &c); - } + grub_err_t err; + struct grub_terminfo_output_state *data; + + err = grub_terminfo_set_current (term, type); + + if (err) + return err; + + data = (struct grub_terminfo_output_state *) term->data; + data->next = terminfo_outputs; + terminfo_outputs = term; + + data->normal_color = 0x07; + data->highlight_color = 0x70; + + return GRUB_ERR_NONE; } -/* Move the cursor to the given position starting with "0". */ -void -grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, grub_term_output_t oterm) +grub_err_t +grub_terminfo_output_unregister (struct grub_term_output *term) { - putstr (grub_terminfo_tparm (term.gotoxy, y, x), oterm); + struct grub_term_output **ptr; + + for (ptr = &terminfo_outputs; *ptr; + ptr = &((struct grub_terminfo_output_state *) (*ptr)->data)->next) + if (*ptr == term) + { + grub_terminfo_all_free (term); + *ptr = ((struct grub_terminfo_output_state *) (*ptr)->data)->next; + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminal not found"); +} + +/* Wrapper for grub_putchar to write strings. */ +static void +putstr (struct grub_term_output *term, const char *str) +{ + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + while (*str) + data->put (*str++); +} + +grub_uint16_t +grub_terminfo_getxy (struct grub_term_output *term) +{ + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + return ((data->xpos << 8) | data->ypos); +} + +void +grub_terminfo_gotoxy (struct grub_term_output *term, + grub_uint8_t x, grub_uint8_t y) +{ + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + if (x > grub_term_width (term) || y > grub_term_height (term)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y); + return; + } + + if (data->gotoxy) + putstr (term, grub_terminfo_tparm (data->gotoxy, y, x)); + else + { + if ((y == data->ypos) && (x == data->xpos - 1)) + data->put ('\b'); + } + + data->xpos = x; + data->ypos = y; } /* Clear the screen. */ void -grub_terminfo_cls (grub_term_output_t oterm) +grub_terminfo_cls (struct grub_term_output *term) { - putstr (grub_terminfo_tparm (term.cls), oterm); + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + putstr (term, grub_terminfo_tparm (data->cls)); + + data->xpos = data->ypos = 0; } -/* Set reverse video mode on. */ void -grub_terminfo_reverse_video_on (grub_term_output_t oterm) +grub_terminfo_setcolor (struct grub_term_output *term, + grub_uint8_t normal_color, + grub_uint8_t highlight_color) { - putstr (grub_terminfo_tparm (term.reverse_video_on), oterm); + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + /* Discard bright bit. */ + data->normal_color = normal_color & 0x77; + data->highlight_color = highlight_color & 0x77; } -/* Set reverse video mode off. */ void -grub_terminfo_reverse_video_off (grub_term_output_t oterm) +grub_terminfo_getcolor (struct grub_term_output *term, + grub_uint8_t *normal_color, + grub_uint8_t *highlight_color) { - putstr (grub_terminfo_tparm (term.reverse_video_off), oterm); + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + *normal_color = data->normal_color; + *highlight_color = data->highlight_color; } -/* Show cursor. */ void -grub_terminfo_cursor_on (grub_term_output_t oterm) +grub_terminfo_setcolorstate (struct grub_term_output *term, + const grub_term_color_state state) { - putstr (grub_terminfo_tparm (term.cursor_on), oterm); + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + if (data->setcolor) + { + int fg; + int bg; + + switch (state) + { + case GRUB_TERM_COLOR_STANDARD: + case GRUB_TERM_COLOR_NORMAL: + fg = data->normal_color & 0x0f; + bg = data->normal_color >> 4; + break; + case GRUB_TERM_COLOR_HIGHLIGHT: + fg = data->highlight_color & 0x0f; + bg = data->highlight_color >> 4; + break; + default: + return; + } + + putstr (term, grub_terminfo_tparm (data->setcolor, fg, bg)); + return; + } + + switch (state) + { + case GRUB_TERM_COLOR_STANDARD: + case GRUB_TERM_COLOR_NORMAL: + putstr (term, grub_terminfo_tparm (data->reverse_video_off)); + break; + case GRUB_TERM_COLOR_HIGHLIGHT: + putstr (term, grub_terminfo_tparm (data->reverse_video_on)); + break; + default: + break; + } } -/* Hide cursor. */ void -grub_terminfo_cursor_off (grub_term_output_t oterm) +grub_terminfo_setcursor (struct grub_term_output *term, const int on) { - putstr (grub_terminfo_tparm (term.cursor_off), oterm); + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + if (on) + putstr (term, grub_terminfo_tparm (data->cursor_on)); + else + putstr (term, grub_terminfo_tparm (data->cursor_off)); +} + +/* The terminfo version of putchar. */ +void +grub_terminfo_putchar (struct grub_term_output *term, + const struct grub_unicode_glyph *c) +{ + struct grub_terminfo_output_state *data + = (struct grub_terminfo_output_state *) term->data; + + /* Keep track of the cursor. */ + switch (c->base) + { + case '\a': + break; + + case '\b': + case 127: + if (data->xpos > 0) + data->xpos--; + break; + + case '\n': + if (data->ypos < grub_term_height (term) - 1) + data->ypos++; + break; + + case '\r': + data->xpos = 0; + break; + + default: + if (data->xpos + c->estimated_width >= grub_term_width (term) + 1) + { + data->xpos = 0; + if (data->ypos < grub_term_height (term) - 1) + data->ypos++; + data->put ('\r'); + data->put ('\n'); + } + data->xpos += c->estimated_width; + break; + } + + data->put (c->base); } #define ANSI_C0 0x9b -void +static void grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void)) { int c; @@ -276,21 +482,80 @@ grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void)) #undef CONTINUE_READ } +/* The terminfo version of checkkey. */ +int +grub_terminfo_checkkey (struct grub_term_input *termi) +{ + struct grub_terminfo_input_state *data + = (struct grub_terminfo_input_state *) (termi->data); + if (data->npending) + return data->input_buf[0]; + + grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey); + + if (data->npending) + return data->input_buf[0]; + + return -1; +} + +/* The terminfo version of getkey. */ +int +grub_terminfo_getkey (struct grub_term_input *termi) +{ + struct grub_terminfo_input_state *data + = (struct grub_terminfo_input_state *) (termi->data); + int ret; + while (! data->npending) + grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey); + + ret = data->input_buf[0]; + data->npending--; + grub_memmove (data->input_buf, data->input_buf + 1, data->npending); + return ret; +} + +grub_err_t +grub_terminfo_input_init (struct grub_term_input *termi) +{ + struct grub_terminfo_input_state *data + = (struct grub_terminfo_input_state *) (termi->data); + data->npending = 0; + + return GRUB_ERR_NONE; +} + /* GRUB Command. */ static grub_err_t grub_cmd_terminfo (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { + struct grub_term_output *cur; + if (argc == 0) - { - grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current()); - return GRUB_ERR_NONE; - } - else if (argc != 1) + { + grub_printf ("Current terminfo types: \n"); + for (cur = terminfo_outputs; cur; + cur = ((struct grub_terminfo_output_state *) cur->data)->next) + grub_printf ("%s: %s\n", cur->name, + grub_terminfo_get_current(cur)); + + return GRUB_ERR_NONE; + } + + if (argc == 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few parameters"); + if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters"); - else - return grub_terminfo_set_current (args[0]); + + for (cur = terminfo_outputs; cur; + cur = ((struct grub_terminfo_output_state *) cur->data)->next) + if (grub_strcmp (args[0], cur->name) == 0) + return grub_terminfo_set_current (cur, args[1]); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "no terminal %s found or it's not handled by terminfo", + args[0]); } static grub_command_t cmd; @@ -298,8 +563,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(terminfo) { cmd = grub_register_command ("terminfo", grub_cmd_terminfo, - N_("[TERM]"), N_("Set terminfo type.")); - grub_terminfo_set_current ("vt100"); + N_("[TERM TYPE]"), N_("Set terminfo type of TERM to TYPE.")); } GRUB_MOD_FINI(terminfo) diff --git a/term/tparm.c b/term/tparm.c index adf0b3a7c..076a192a5 100644 --- a/term/tparm.c +++ b/term/tparm.c @@ -751,6 +751,9 @@ grub_terminfo_tparm (const char *string, ...) va_list ap; char *result; + if (!string) + return ""; + va_start (ap, string); result = tparam_internal (string, ap); va_end (ap);