merge mainline into hints
This commit is contained in:
commit
a848c54e34
933 changed files with 126865 additions and 40868 deletions
297
grub-core/term/at_keyboard.c
Normal file
297
grub-core/term/at_keyboard.c
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2007,2008,2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/at_keyboard.h>
|
||||
#include <grub/cpu/at_keyboard.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
static short at_keyboard_status = 0;
|
||||
static int pending_key = -1;
|
||||
|
||||
#define KEYBOARD_STATUS_SHIFT_L (1 << 0)
|
||||
#define KEYBOARD_STATUS_SHIFT_R (1 << 1)
|
||||
#define KEYBOARD_STATUS_ALT_L (1 << 2)
|
||||
#define KEYBOARD_STATUS_ALT_R (1 << 3)
|
||||
#define KEYBOARD_STATUS_CTRL_L (1 << 4)
|
||||
#define KEYBOARD_STATUS_CTRL_R (1 << 5)
|
||||
#define KEYBOARD_STATUS_CAPS_LOCK (1 << 6)
|
||||
#define KEYBOARD_STATUS_NUM_LOCK (1 << 7)
|
||||
|
||||
static grub_uint8_t led_status;
|
||||
|
||||
#define KEYBOARD_LED_SCROLL (1 << 0)
|
||||
#define KEYBOARD_LED_NUM (1 << 1)
|
||||
#define KEYBOARD_LED_CAPS (1 << 2)
|
||||
|
||||
static char keyboard_map[128] =
|
||||
{
|
||||
'\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB,
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
||||
'o', 'p', '[', ']', '\n', '\0', 'a', 's',
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
|
||||
'\'', '`', '\0', '\\', 'z', 'x', 'c', 'v',
|
||||
'b', 'n', 'm', ',', '.', '/', '\0', '*',
|
||||
'\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_HOME,
|
||||
GRUB_TERM_UP, GRUB_TERM_NPAGE, '-', GRUB_TERM_LEFT, '\0', GRUB_TERM_RIGHT, '+', GRUB_TERM_END,
|
||||
GRUB_TERM_DOWN, GRUB_TERM_PPAGE, '\0', GRUB_TERM_DC, '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT,
|
||||
OLPC_RIGHT
|
||||
};
|
||||
|
||||
static char keyboard_map_shift[128] =
|
||||
{
|
||||
'\0', '\0', '!', '@', '#', '$', '%', '^',
|
||||
'&', '*', '(', ')', '_', '+', '\0', '\0',
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
||||
'O', 'P', '{', '}', '\n', '\0', 'A', 'S',
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
|
||||
'\"', '~', '\0', '|', 'Z', 'X', 'C', 'V',
|
||||
'B', 'N', 'M', '<', '>', '?'
|
||||
};
|
||||
|
||||
static grub_uint8_t grub_keyboard_controller_orig;
|
||||
|
||||
static void
|
||||
keyboard_controller_wait_until_ready (void)
|
||||
{
|
||||
while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)));
|
||||
}
|
||||
|
||||
static void
|
||||
grub_keyboard_controller_write (grub_uint8_t c)
|
||||
{
|
||||
keyboard_controller_wait_until_ready ();
|
||||
grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS);
|
||||
grub_outb (c, KEYBOARD_REG_DATA);
|
||||
}
|
||||
|
||||
static grub_uint8_t
|
||||
grub_keyboard_controller_read (void)
|
||||
{
|
||||
keyboard_controller_wait_until_ready ();
|
||||
grub_outb (KEYBOARD_COMMAND_READ, KEYBOARD_REG_STATUS);
|
||||
return grub_inb (KEYBOARD_REG_DATA);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_controller_led (grub_uint8_t leds)
|
||||
{
|
||||
keyboard_controller_wait_until_ready ();
|
||||
grub_outb (0xed, KEYBOARD_REG_DATA);
|
||||
keyboard_controller_wait_until_ready ();
|
||||
grub_outb (leds & 0x7, KEYBOARD_REG_DATA);
|
||||
}
|
||||
|
||||
/* FIXME: This should become an interrupt service routine. For now
|
||||
it's just used to catch events from control keys. */
|
||||
static void
|
||||
grub_keyboard_isr (char key)
|
||||
{
|
||||
char is_make = KEYBOARD_ISMAKE (key);
|
||||
key = KEYBOARD_SCANCODE (key);
|
||||
if (is_make)
|
||||
switch (key)
|
||||
{
|
||||
case SHIFT_L:
|
||||
at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L;
|
||||
break;
|
||||
case SHIFT_R:
|
||||
at_keyboard_status |= KEYBOARD_STATUS_SHIFT_R;
|
||||
break;
|
||||
case CTRL:
|
||||
at_keyboard_status |= KEYBOARD_STATUS_CTRL_L;
|
||||
break;
|
||||
case ALT:
|
||||
at_keyboard_status |= KEYBOARD_STATUS_ALT_L;
|
||||
break;
|
||||
default:
|
||||
/* Skip grub_dprintf. */
|
||||
return;
|
||||
}
|
||||
else
|
||||
switch (key)
|
||||
{
|
||||
case SHIFT_L:
|
||||
at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L;
|
||||
break;
|
||||
case SHIFT_R:
|
||||
at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_R;
|
||||
break;
|
||||
case CTRL:
|
||||
at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L;
|
||||
break;
|
||||
case ALT:
|
||||
at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L;
|
||||
break;
|
||||
default:
|
||||
/* Skip grub_dprintf. */
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG_AT_KEYBOARD
|
||||
grub_dprintf ("atkeyb", "Control key 0x%0x was %s\n", key, is_make ? "pressed" : "unpressed");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If there is a raw key pending, return it; otherwise return -1. */
|
||||
static int
|
||||
grub_keyboard_getkey (void)
|
||||
{
|
||||
grub_uint8_t key;
|
||||
if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
|
||||
return -1;
|
||||
key = grub_inb (KEYBOARD_REG_DATA);
|
||||
/* FIXME */ grub_keyboard_isr (key);
|
||||
if (! KEYBOARD_ISMAKE (key))
|
||||
return -1;
|
||||
return (KEYBOARD_SCANCODE (key));
|
||||
}
|
||||
|
||||
/* If there is a character pending, return it; otherwise return -1. */
|
||||
static int
|
||||
grub_at_keyboard_getkey_noblock (void)
|
||||
{
|
||||
int code, key;
|
||||
code = grub_keyboard_getkey ();
|
||||
if (code == -1)
|
||||
return -1;
|
||||
#ifdef DEBUG_AT_KEYBOARD
|
||||
grub_dprintf ("atkeyb", "Detected key 0x%x\n", key);
|
||||
#endif
|
||||
switch (code)
|
||||
{
|
||||
case CAPS_LOCK:
|
||||
at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK;
|
||||
led_status ^= KEYBOARD_LED_CAPS;
|
||||
keyboard_controller_led (led_status);
|
||||
|
||||
#ifdef DEBUG_AT_KEYBOARD
|
||||
grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK));
|
||||
#endif
|
||||
key = -1;
|
||||
break;
|
||||
case NUM_LOCK:
|
||||
at_keyboard_status ^= KEYBOARD_STATUS_NUM_LOCK;
|
||||
led_status ^= KEYBOARD_LED_NUM;
|
||||
keyboard_controller_led (led_status);
|
||||
|
||||
#ifdef DEBUG_AT_KEYBOARD
|
||||
grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK));
|
||||
#endif
|
||||
key = -1;
|
||||
break;
|
||||
case SCROLL_LOCK:
|
||||
/* For scroll lock we don't keep track of status. Only update its led. */
|
||||
led_status ^= KEYBOARD_LED_SCROLL;
|
||||
keyboard_controller_led (led_status);
|
||||
key = -1;
|
||||
break;
|
||||
default:
|
||||
if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R))
|
||||
key = keyboard_map[code] - 'a' + 1;
|
||||
else if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L | KEYBOARD_STATUS_SHIFT_R))
|
||||
&& keyboard_map_shift[code])
|
||||
key = keyboard_map_shift[code];
|
||||
else
|
||||
key = keyboard_map[code];
|
||||
|
||||
if (key == 0)
|
||||
grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code);
|
||||
|
||||
if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)
|
||||
{
|
||||
if ((key >= 'a') && (key <= 'z'))
|
||||
key += 'A' - 'a';
|
||||
else if ((key >= 'A') && (key <= 'Z'))
|
||||
key += 'a' - 'A';
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_at_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
if (pending_key != -1)
|
||||
return 1;
|
||||
|
||||
pending_key = grub_at_keyboard_getkey_noblock ();
|
||||
|
||||
if (pending_key != -1)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
int key;
|
||||
if (pending_key != -1)
|
||||
{
|
||||
key = pending_key;
|
||||
pending_key = -1;
|
||||
return key;
|
||||
}
|
||||
do
|
||||
{
|
||||
key = grub_at_keyboard_getkey_noblock ();
|
||||
} while (key == -1);
|
||||
return key;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
pending_key = -1;
|
||||
at_keyboard_status = 0;
|
||||
grub_keyboard_controller_orig = grub_keyboard_controller_read ();
|
||||
grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_keyboard_controller_write (grub_keyboard_controller_orig);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_term_input grub_at_keyboard_term =
|
||||
{
|
||||
.name = "at_keyboard",
|
||||
.init = grub_keyboard_controller_init,
|
||||
.fini = grub_keyboard_controller_fini,
|
||||
.checkkey = grub_at_keyboard_checkkey,
|
||||
.getkey = grub_at_keyboard_getkey,
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(at_keyboard)
|
||||
{
|
||||
grub_term_register_input ("at_keyboard", &grub_at_keyboard_term);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(at_keyboard)
|
||||
{
|
||||
grub_term_unregister_input (&grub_at_keyboard_term);
|
||||
}
|
399
grub-core/term/efi/console.c
Normal file
399
grub-core/term/efi/console.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/console.h>
|
||||
|
||||
static const grub_uint8_t
|
||||
grub_console_standard_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_YELLOW,
|
||||
GRUB_EFI_BACKGROUND_BLACK);
|
||||
|
||||
static int read_key = -1;
|
||||
|
||||
static grub_uint32_t
|
||||
map_char (grub_uint32_t c)
|
||||
{
|
||||
/* Map some unicode characters to the EFI character. */
|
||||
switch (c)
|
||||
{
|
||||
case GRUB_UNICODE_LEFTARROW:
|
||||
c = GRUB_UNICODE_BLACK_LEFT_TRIANGLE;
|
||||
break;
|
||||
case GRUB_UNICODE_UPARROW:
|
||||
c = GRUB_UNICODE_BLACK_UP_TRIANGLE;
|
||||
break;
|
||||
case GRUB_UNICODE_RIGHTARROW:
|
||||
c = GRUB_UNICODE_BLACK_RIGHT_TRIANGLE;
|
||||
break;
|
||||
case GRUB_UNICODE_DOWNARROW:
|
||||
c = GRUB_UNICODE_BLACK_DOWN_TRIANGLE;
|
||||
break;
|
||||
case GRUB_UNICODE_HLINE:
|
||||
c = GRUB_UNICODE_LIGHT_HLINE;
|
||||
break;
|
||||
case GRUB_UNICODE_VLINE:
|
||||
c = GRUB_UNICODE_LIGHT_VLINE;
|
||||
break;
|
||||
case GRUB_UNICODE_CORNER_UL:
|
||||
c = GRUB_UNICODE_LIGHT_CORNER_UL;
|
||||
break;
|
||||
case GRUB_UNICODE_CORNER_UR:
|
||||
c = GRUB_UNICODE_LIGHT_CORNER_UR;
|
||||
break;
|
||||
case GRUB_UNICODE_CORNER_LL:
|
||||
c = GRUB_UNICODE_LIGHT_CORNER_LL;
|
||||
break;
|
||||
case GRUB_UNICODE_CORNER_LR:
|
||||
c = GRUB_UNICODE_LIGHT_CORNER_LR;
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)),
|
||||
const struct grub_unicode_glyph *c)
|
||||
{
|
||||
grub_efi_char16_t str[2 + c->ncomb];
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
unsigned i, j;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
|
||||
/* For now, do not try to use a surrogate pair. */
|
||||
if (c->base > 0xffff)
|
||||
str[0] = '?';
|
||||
else
|
||||
str[0] = (grub_efi_char16_t) map_char (c->base & 0xffff);
|
||||
j = 1;
|
||||
for (i = 0; i < c->ncomb; i++)
|
||||
if (c->base < 0xffff)
|
||||
str[j++] = c->combining[i].code;
|
||||
str[j] = 0;
|
||||
|
||||
/* Should this test be cached? */
|
||||
if ((c->base > 0x7f || c->ncomb)
|
||||
&& efi_call_2 (o->test_string, o, str) != GRUB_EFI_SUCCESS)
|
||||
return;
|
||||
|
||||
efi_call_2 (o->output_string, o, str);
|
||||
}
|
||||
|
||||
static int
|
||||
grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_efi_simple_input_interface_t *i;
|
||||
grub_efi_input_key_t key;
|
||||
grub_efi_status_t status;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return 0;
|
||||
|
||||
if (read_key >= 0)
|
||||
return 1;
|
||||
|
||||
i = grub_efi_system_table->con_in;
|
||||
status = efi_call_2 (i->read_key_stroke, i, &key);
|
||||
#if 0
|
||||
switch (status)
|
||||
{
|
||||
case GRUB_EFI_SUCCESS:
|
||||
{
|
||||
grub_uint16_t xy;
|
||||
|
||||
xy = grub_getxy ();
|
||||
grub_gotoxy (0, 0);
|
||||
grub_printf ("scan_code=%x,unicode_char=%x ",
|
||||
(unsigned) key.scan_code,
|
||||
(unsigned) key.unicode_char);
|
||||
grub_gotoxy (xy >> 8, xy & 0xff);
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_NOT_READY:
|
||||
//grub_printf ("not ready ");
|
||||
break;
|
||||
|
||||
default:
|
||||
//grub_printf ("device error ");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status == GRUB_EFI_SUCCESS)
|
||||
{
|
||||
switch (key.scan_code)
|
||||
{
|
||||
case 0x00:
|
||||
read_key = key.unicode_char;
|
||||
break;
|
||||
case 0x01:
|
||||
read_key = GRUB_TERM_UP;
|
||||
break;
|
||||
case 0x02:
|
||||
read_key = GRUB_TERM_DOWN;
|
||||
break;
|
||||
case 0x03:
|
||||
read_key = GRUB_TERM_RIGHT;
|
||||
break;
|
||||
case 0x04:
|
||||
read_key = GRUB_TERM_LEFT;
|
||||
break;
|
||||
case 0x05:
|
||||
read_key = GRUB_TERM_HOME;
|
||||
break;
|
||||
case 0x06:
|
||||
read_key = GRUB_TERM_END;
|
||||
break;
|
||||
case 0x07:
|
||||
break;
|
||||
case 0x08:
|
||||
read_key = GRUB_TERM_DC;
|
||||
break;
|
||||
case 0x09:
|
||||
break;
|
||||
case 0x0a:
|
||||
break;
|
||||
case 0x0b:
|
||||
read_key = 24;
|
||||
break;
|
||||
case 0x0c:
|
||||
read_key = 1;
|
||||
break;
|
||||
case 0x0d:
|
||||
read_key = 5;
|
||||
break;
|
||||
case 0x0e:
|
||||
read_key = 3;
|
||||
break;
|
||||
case 0x17:
|
||||
read_key = '\e';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return read_key;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_console_getkey (struct grub_term_input *term)
|
||||
{
|
||||
grub_efi_simple_input_interface_t *i;
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_uintn_t index;
|
||||
grub_efi_status_t status;
|
||||
int key;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return 0;
|
||||
|
||||
if (read_key >= 0)
|
||||
{
|
||||
key = read_key;
|
||||
read_key = -1;
|
||||
return key;
|
||||
}
|
||||
|
||||
i = grub_efi_system_table->con_in;
|
||||
b = grub_efi_system_table->boot_services;
|
||||
|
||||
do
|
||||
{
|
||||
status = efi_call_3 (b->wait_for_event, 1, &(i->wait_for_key), &index);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return -1;
|
||||
|
||||
grub_console_checkkey (term);
|
||||
}
|
||||
while (read_key < 0);
|
||||
|
||||
key = read_key;
|
||||
read_key = -1;
|
||||
return key;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_console_getwh (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
grub_efi_uintn_t columns, rows;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode,
|
||||
&columns, &rows) != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
/* Why does this fail? */
|
||||
columns = 80;
|
||||
rows = 25;
|
||||
}
|
||||
|
||||
return ((columns << 8) | rows);
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_console_getxy (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return 0;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
return ((o->mode->cursor_column << 8) | o->mode->cursor_row);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
|
||||
grub_uint8_t x, grub_uint8_t y)
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
efi_call_3 (o->set_cursor_position, o, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_console_cls (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
grub_efi_int32_t orig_attr;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
orig_attr = o->mode->attribute;
|
||||
efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK);
|
||||
efi_call_1 (o->clear_screen, o);
|
||||
efi_call_2 (o->set_attributes, o, orig_attr);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_console_setcolorstate (struct grub_term_output *term,
|
||||
grub_term_color_state state)
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
|
||||
switch (state) {
|
||||
case GRUB_TERM_COLOR_STANDARD:
|
||||
efi_call_2 (o->set_attributes, o, grub_console_standard_color);
|
||||
break;
|
||||
case GRUB_TERM_COLOR_NORMAL:
|
||||
efi_call_2 (o->set_attributes, o, term->normal_color);
|
||||
break;
|
||||
case GRUB_TERM_COLOR_HIGHLIGHT:
|
||||
efi_call_2 (o->set_attributes, o, term->highlight_color);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
|
||||
int on)
|
||||
{
|
||||
grub_efi_simple_text_output_interface_t *o;
|
||||
|
||||
if (grub_efi_is_finished)
|
||||
return;
|
||||
|
||||
o = grub_efi_system_table->con_out;
|
||||
efi_call_2 (o->enable_cursor, o, on);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_efi_console_init (struct grub_term_output *term)
|
||||
{
|
||||
grub_console_setcursor (term, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_efi_console_fini (struct grub_term_output *term)
|
||||
{
|
||||
grub_console_setcursor (term, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct grub_term_input grub_console_term_input =
|
||||
{
|
||||
.name = "console",
|
||||
.checkkey = grub_console_checkkey,
|
||||
.getkey = grub_console_getkey,
|
||||
};
|
||||
|
||||
static struct grub_term_output grub_console_term_output =
|
||||
{
|
||||
.name = "console",
|
||||
.init = grub_efi_console_init,
|
||||
.fini = grub_efi_console_fini,
|
||||
.putchar = grub_console_putchar,
|
||||
.getwh = grub_console_getwh,
|
||||
.getxy = grub_console_getxy,
|
||||
.gotoxy = grub_console_gotoxy,
|
||||
.cls = grub_console_cls,
|
||||
.setcolorstate = grub_console_setcolorstate,
|
||||
.setcursor = grub_console_setcursor,
|
||||
.normal_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_LIGHTGRAY,
|
||||
GRUB_EFI_BACKGROUND_BLACK),
|
||||
.highlight_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_BLACK,
|
||||
GRUB_EFI_BACKGROUND_LIGHTGRAY),
|
||||
.flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS
|
||||
};
|
||||
|
||||
void
|
||||
grub_console_init (void)
|
||||
{
|
||||
/* FIXME: it is necessary to consider the case where no console control
|
||||
is present but the default is already in text mode. */
|
||||
if (! grub_efi_set_text_mode (1))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE, "cannot set text mode");
|
||||
return;
|
||||
}
|
||||
|
||||
grub_term_register_input ("console", &grub_console_term_input);
|
||||
grub_term_register_output ("console", &grub_console_term_output);
|
||||
}
|
||||
|
||||
void
|
||||
grub_console_fini (void)
|
||||
{
|
||||
grub_term_unregister_input (&grub_console_term_input);
|
||||
grub_term_unregister_output (&grub_console_term_output);
|
||||
}
|
1221
grub-core/term/gfxterm.c
Normal file
1221
grub-core/term/gfxterm.c
Normal file
File diff suppressed because it is too large
Load diff
83
grub-core/term/i386/pc/console.c
Normal file
83
grub-core/term/i386/pc/console.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2005,2007,2008,2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/machine/console.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
static const struct grub_machine_bios_data_area *bios_data_area =
|
||||
(struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
|
||||
|
||||
#define KEYBOARD_LEFT_SHIFT (1 << 0)
|
||||
#define KEYBOARD_RIGHT_SHIFT (1 << 1)
|
||||
#define KEYBOARD_CTRL (1 << 2)
|
||||
#define KEYBOARD_ALT (1 << 3)
|
||||
|
||||
static int
|
||||
grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_uint8_t status = bios_data_area->keyboard_flag_lower;
|
||||
int mods = 0;
|
||||
|
||||
if (status & (KEYBOARD_LEFT_SHIFT | KEYBOARD_RIGHT_SHIFT))
|
||||
mods |= GRUB_TERM_STATUS_SHIFT;
|
||||
if (status & KEYBOARD_CTRL)
|
||||
mods |= GRUB_TERM_STATUS_CTRL;
|
||||
if (status & KEYBOARD_ALT)
|
||||
mods |= GRUB_TERM_STATUS_ALT;
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
static struct grub_term_input grub_console_term_input =
|
||||
{
|
||||
.name = "console",
|
||||
.checkkey = grub_console_checkkey,
|
||||
.getkey = grub_console_getkey,
|
||||
.getkeystatus = grub_console_getkeystatus,
|
||||
};
|
||||
|
||||
static struct grub_term_output grub_console_term_output =
|
||||
{
|
||||
.name = "console",
|
||||
.putchar = grub_console_putchar,
|
||||
.getwh = grub_console_getwh,
|
||||
.getxy = grub_console_getxy,
|
||||
.gotoxy = grub_console_gotoxy,
|
||||
.cls = grub_console_cls,
|
||||
.setcolorstate = grub_console_setcolorstate,
|
||||
.setcursor = grub_console_setcursor,
|
||||
.flags = GRUB_TERM_CODE_TYPE_CP437,
|
||||
.normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
|
||||
.highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
|
||||
};
|
||||
|
||||
void
|
||||
grub_console_init (void)
|
||||
{
|
||||
grub_term_register_output ("console", &grub_console_term_output);
|
||||
grub_term_register_input ("console", &grub_console_term_input);
|
||||
}
|
||||
|
||||
void
|
||||
grub_console_fini (void)
|
||||
{
|
||||
grub_term_unregister_input (&grub_console_term_input);
|
||||
grub_term_unregister_output (&grub_console_term_output);
|
||||
}
|
606
grub-core/term/i386/pc/vesafb.c
Normal file
606
grub-core/term/i386/pc/vesafb.c
Normal file
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2007,2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TODO: Deprecated and broken. Scheduled for removal as there is VBE driver in Video subsystem.
|
||||
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/machine/vga.h>
|
||||
#include <grub/machine/vbe.h>
|
||||
#include <grub/machine/console.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/font.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
#define DEFAULT_CHAR_WIDTH 8
|
||||
#define DEFAULT_CHAR_HEIGHT 16
|
||||
|
||||
#define DEFAULT_FG_COLOR 0xa
|
||||
#define DEFAULT_BG_COLOR 0x0
|
||||
|
||||
struct grub_colored_char
|
||||
{
|
||||
/* An Unicode codepoint. */
|
||||
grub_uint32_t code;
|
||||
|
||||
/* Color indexes. */
|
||||
unsigned char fg_color;
|
||||
unsigned char bg_color;
|
||||
|
||||
/* The width of this character minus one. */
|
||||
unsigned char width;
|
||||
|
||||
/* The column index of this character. */
|
||||
unsigned char index;
|
||||
};
|
||||
|
||||
struct grub_virtual_screen
|
||||
{
|
||||
/* Dimensions of the virtual screen. */
|
||||
grub_uint32_t width;
|
||||
grub_uint32_t height;
|
||||
|
||||
/* Offset in the display. */
|
||||
grub_uint32_t offset_x;
|
||||
grub_uint32_t offset_y;
|
||||
|
||||
/* TTY Character sizes. */
|
||||
grub_uint32_t char_width;
|
||||
grub_uint32_t char_height;
|
||||
|
||||
/* Virtual screen TTY size. */
|
||||
grub_uint32_t columns;
|
||||
grub_uint32_t rows;
|
||||
|
||||
/* Current cursor details. */
|
||||
grub_uint32_t cursor_x;
|
||||
grub_uint32_t cursor_y;
|
||||
grub_uint8_t cursor_state;
|
||||
grub_uint8_t fg_color;
|
||||
grub_uint8_t bg_color;
|
||||
|
||||
/* Text buffer for virtual screen. Contains (columns * rows) number
|
||||
of entries. */
|
||||
struct grub_colored_char *text_buffer;
|
||||
};
|
||||
|
||||
/* Make sure text buffer is not marked as allocated. */
|
||||
static struct grub_virtual_screen virtual_screen =
|
||||
{
|
||||
.text_buffer = 0
|
||||
};
|
||||
|
||||
static unsigned char *vga_font = 0;
|
||||
static grub_uint32_t old_mode = 0;
|
||||
|
||||
static struct grub_vbe_mode_info_block mode_info;
|
||||
static grub_uint8_t *framebuffer = 0;
|
||||
static grub_uint32_t bytes_per_scan_line = 0;
|
||||
|
||||
static void
|
||||
grub_virtual_screen_free (void)
|
||||
{
|
||||
/* If virtual screen has been allocated, free it. */
|
||||
if (virtual_screen.text_buffer != 0)
|
||||
grub_free (virtual_screen.text_buffer);
|
||||
|
||||
/* Reset virtual screen data. */
|
||||
grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_virtual_screen_setup (grub_uint32_t width,
|
||||
grub_uint32_t height)
|
||||
{
|
||||
/* Free old virtual screen. */
|
||||
grub_virtual_screen_free ();
|
||||
|
||||
/* Initialize with default data. */
|
||||
virtual_screen.width = width;
|
||||
virtual_screen.height = height;
|
||||
virtual_screen.offset_x = 0;
|
||||
virtual_screen.offset_y = 0;
|
||||
virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
|
||||
virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
|
||||
virtual_screen.cursor_x = 0;
|
||||
virtual_screen.cursor_y = 0;
|
||||
virtual_screen.cursor_state = 1;
|
||||
virtual_screen.fg_color = DEFAULT_FG_COLOR;
|
||||
virtual_screen.bg_color = DEFAULT_BG_COLOR;
|
||||
|
||||
/* Calculate size of text buffer. */
|
||||
virtual_screen.columns = virtual_screen.width / virtual_screen.char_width;
|
||||
virtual_screen.rows = virtual_screen.height / virtual_screen.char_height;
|
||||
|
||||
/* Allocate memory for text buffer. */
|
||||
virtual_screen.text_buffer =
|
||||
(struct grub_colored_char *) grub_malloc (virtual_screen.columns
|
||||
* virtual_screen.rows
|
||||
* sizeof (*virtual_screen.text_buffer));
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_vesafb_mod_init (void)
|
||||
{
|
||||
grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE;
|
||||
struct grub_vbe_info_block controller_info;
|
||||
char *modevar;
|
||||
|
||||
/* Use fonts from VGA bios. */
|
||||
vga_font = grub_vga_get_font ();
|
||||
|
||||
/* Check if we have VESA BIOS installed. */
|
||||
if (grub_vbe_probe (&controller_info) != GRUB_ERR_NONE)
|
||||
return grub_errno;
|
||||
|
||||
/* Check existence of vbe_mode environment variable. */
|
||||
modevar = grub_env_get ("vbe_mode");
|
||||
|
||||
if (modevar != 0)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
value = grub_strtoul (modevar, 0, 0);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
use_mode = value;
|
||||
}
|
||||
|
||||
/* Store initial video mode. */
|
||||
if (grub_vbe_get_video_mode (&old_mode) != GRUB_ERR_NONE)
|
||||
return grub_errno;
|
||||
|
||||
/* Setup desired graphics mode. */
|
||||
if (grub_vbe_set_video_mode (use_mode, &mode_info) != GRUB_ERR_NONE)
|
||||
return grub_errno;
|
||||
|
||||
/* Determine framebuffer and bytes per scan line. */
|
||||
framebuffer = (grub_uint8_t *) mode_info.phys_base_addr;
|
||||
|
||||
if (controller_info.version >= 0x300)
|
||||
bytes_per_scan_line = mode_info.lin_bytes_per_scan_line;
|
||||
else
|
||||
bytes_per_scan_line = mode_info.bytes_per_scan_line;
|
||||
|
||||
/* Create virtual screen. */
|
||||
if (grub_virtual_screen_setup (mode_info.x_resolution,
|
||||
mode_info.y_resolution) != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_vbe_set_video_mode (old_mode, 0);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Make sure frame buffer is black. */
|
||||
grub_memset (framebuffer,
|
||||
0,
|
||||
bytes_per_scan_line * mode_info.y_resolution);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_vesafb_mod_fini (void)
|
||||
{
|
||||
grub_virtual_screen_free ();
|
||||
|
||||
grub_vbe_set_video_mode (old_mode, 0);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_virtual_screen_get_glyph (grub_uint32_t code,
|
||||
unsigned char bitmap[32],
|
||||
unsigned *width)
|
||||
{
|
||||
if (code > 0x7f)
|
||||
{
|
||||
/* Map some unicode characters to the VGA font, if possible. */
|
||||
switch (code)
|
||||
{
|
||||
case 0x2190: /* left arrow */
|
||||
code = 0x1b;
|
||||
break;
|
||||
case 0x2191: /* up arrow */
|
||||
code = 0x18;
|
||||
break;
|
||||
case 0x2192: /* right arrow */
|
||||
code = 0x1a;
|
||||
break;
|
||||
case 0x2193: /* down arrow */
|
||||
code = 0x19;
|
||||
break;
|
||||
case 0x2501: /* horizontal line */
|
||||
code = 0xc4;
|
||||
break;
|
||||
case 0x2503: /* vertical line */
|
||||
code = 0xb3;
|
||||
break;
|
||||
case 0x250F: /* upper-left corner */
|
||||
code = 0xda;
|
||||
break;
|
||||
case 0x2513: /* upper-right corner */
|
||||
code = 0xbf;
|
||||
break;
|
||||
case 0x2517: /* lower-left corner */
|
||||
code = 0xc0;
|
||||
break;
|
||||
case 0x251B: /* lower-right corner */
|
||||
code = 0xd9;
|
||||
break;
|
||||
|
||||
default:
|
||||
return grub_font_get_glyph_any (code, bitmap, width);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO This is wrong for the new font module. Should it be fixed? */
|
||||
if (bitmap)
|
||||
grub_memcpy (bitmap,
|
||||
vga_font + code * virtual_screen.char_height,
|
||||
virtual_screen.char_height);
|
||||
*width = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_virtual_screen_invalidate_char (struct grub_colored_char *p)
|
||||
{
|
||||
p->code = 0xFFFF;
|
||||
|
||||
if (p->width)
|
||||
{
|
||||
struct grub_colored_char *q;
|
||||
|
||||
for (q = p + 1; q <= p + p->width; q++)
|
||||
{
|
||||
q->code = 0xFFFF;
|
||||
q->width = 0;
|
||||
q->index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p->width = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
write_char (void)
|
||||
{
|
||||
struct grub_colored_char *p;
|
||||
unsigned char bitmap[32];
|
||||
unsigned width;
|
||||
unsigned y;
|
||||
unsigned offset;
|
||||
|
||||
p = (virtual_screen.text_buffer
|
||||
+ virtual_screen.cursor_x
|
||||
+ (virtual_screen.cursor_y * virtual_screen.columns));
|
||||
|
||||
p -= p->index;
|
||||
|
||||
if (! grub_virtual_screen_get_glyph (p->code, bitmap, &width))
|
||||
{
|
||||
grub_virtual_screen_invalidate_char (p);
|
||||
width = 0;
|
||||
}
|
||||
|
||||
for (y = 0, offset = 0;
|
||||
y < virtual_screen.char_height;
|
||||
y++, offset++)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0;
|
||||
(i < width * virtual_screen.char_width) && (offset < 32);
|
||||
i++)
|
||||
{
|
||||
unsigned char color;
|
||||
|
||||
if (bitmap[offset] & (1 << (8-i)))
|
||||
{
|
||||
color = p->fg_color;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = p->bg_color;
|
||||
}
|
||||
|
||||
grub_vbe_set_pixel_index(i + (virtual_screen.cursor_x
|
||||
* virtual_screen.char_width),
|
||||
y + (virtual_screen.cursor_y
|
||||
* virtual_screen.char_height),
|
||||
color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_cursor (void)
|
||||
{
|
||||
grub_uint32_t x;
|
||||
grub_uint32_t y;
|
||||
|
||||
for (y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
|
||||
y < ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 1;
|
||||
y++)
|
||||
{
|
||||
for (x = virtual_screen.cursor_x * virtual_screen.char_width;
|
||||
x < (virtual_screen.cursor_x + 1) * virtual_screen.char_width;
|
||||
x++)
|
||||
{
|
||||
grub_vbe_set_pixel_index(x, y, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
scroll_up (void)
|
||||
{
|
||||
grub_uint32_t i;
|
||||
|
||||
/* Scroll text buffer with one line to up. */
|
||||
grub_memmove (virtual_screen.text_buffer,
|
||||
virtual_screen.text_buffer + virtual_screen.columns,
|
||||
sizeof (*virtual_screen.text_buffer)
|
||||
* virtual_screen.columns
|
||||
* (virtual_screen.rows - 1));
|
||||
|
||||
/* Clear last line in text buffer. */
|
||||
for (i = virtual_screen.columns * (virtual_screen.rows - 1);
|
||||
i < virtual_screen.columns * virtual_screen.rows;
|
||||
i++)
|
||||
{
|
||||
virtual_screen.text_buffer[i].code = ' ';
|
||||
virtual_screen.text_buffer[i].fg_color = 0;
|
||||
virtual_screen.text_buffer[i].bg_color = 0;
|
||||
virtual_screen.text_buffer[i].width = 0;
|
||||
virtual_screen.text_buffer[i].index = 0;
|
||||
}
|
||||
|
||||
/* Scroll framebuffer with one line to up. */
|
||||
grub_memmove (framebuffer,
|
||||
framebuffer
|
||||
+ bytes_per_scan_line * virtual_screen.char_height,
|
||||
bytes_per_scan_line
|
||||
* (mode_info.y_resolution - virtual_screen.char_height));
|
||||
|
||||
/* Clear last line in framebuffer. */
|
||||
grub_memset (framebuffer
|
||||
+ (bytes_per_scan_line
|
||||
* (mode_info.y_resolution - virtual_screen.char_height)),
|
||||
0,
|
||||
bytes_per_scan_line * virtual_screen.char_height);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vesafb_putchar (grub_uint32_t c)
|
||||
{
|
||||
if (c == '\a')
|
||||
/* FIXME */
|
||||
return;
|
||||
|
||||
if (c == '\b' || c == '\n' || c == '\r')
|
||||
{
|
||||
/* Erase current cursor, if any. */
|
||||
if (virtual_screen.cursor_state)
|
||||
write_char ();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\b':
|
||||
if (virtual_screen.cursor_x > 0)
|
||||
virtual_screen.cursor_x--;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
|
||||
scroll_up ();
|
||||
else
|
||||
virtual_screen.cursor_y++;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
virtual_screen.cursor_x = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (virtual_screen.cursor_state)
|
||||
write_cursor ();
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned width;
|
||||
struct grub_colored_char *p;
|
||||
|
||||
grub_virtual_screen_get_glyph (c, 0, &width);
|
||||
|
||||
if (virtual_screen.cursor_x + width > virtual_screen.columns)
|
||||
grub_putchar ('\n');
|
||||
|
||||
p = (virtual_screen.text_buffer +
|
||||
virtual_screen.cursor_x +
|
||||
virtual_screen.cursor_y * virtual_screen.columns);
|
||||
p->code = c;
|
||||
p->fg_color = virtual_screen.fg_color;
|
||||
p->bg_color = virtual_screen.bg_color;
|
||||
p->width = width - 1;
|
||||
p->index = 0;
|
||||
|
||||
if (width > 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 1; i < width; i++)
|
||||
{
|
||||
p[i].code = ' ';
|
||||
p[i].width = width - 1;
|
||||
p[i].index = i;
|
||||
}
|
||||
}
|
||||
|
||||
write_char ();
|
||||
|
||||
virtual_screen.cursor_x += width;
|
||||
if (virtual_screen.cursor_x >= virtual_screen.columns)
|
||||
{
|
||||
virtual_screen.cursor_x = 0;
|
||||
|
||||
if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
|
||||
scroll_up ();
|
||||
else
|
||||
virtual_screen.cursor_y++;
|
||||
}
|
||||
|
||||
if (virtual_screen.cursor_state)
|
||||
write_cursor ();
|
||||
}
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_vesafb_getcharwidth (grub_uint32_t c)
|
||||
{
|
||||
unsigned width;
|
||||
|
||||
if (! grub_virtual_screen_get_glyph (c, 0, &width))
|
||||
return 0;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_virtual_screen_getwh (void)
|
||||
{
|
||||
return (virtual_screen.columns << 8) | virtual_screen.rows;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_virtual_screen_getxy (void)
|
||||
{
|
||||
return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vesafb_gotoxy (grub_uint8_t x, grub_uint8_t y)
|
||||
{
|
||||
if (x >= virtual_screen.columns || y >= virtual_screen.rows)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)",
|
||||
(unsigned) x, (unsigned) y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (virtual_screen.cursor_state)
|
||||
write_char ();
|
||||
|
||||
virtual_screen.cursor_x = x;
|
||||
virtual_screen.cursor_y = y;
|
||||
|
||||
if (virtual_screen.cursor_state)
|
||||
write_cursor ();
|
||||
}
|
||||
|
||||
static void
|
||||
grub_virtual_screen_cls (void)
|
||||
{
|
||||
grub_uint32_t i;
|
||||
|
||||
for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
|
||||
{
|
||||
virtual_screen.text_buffer[i].code = ' ';
|
||||
virtual_screen.text_buffer[i].fg_color = 0;
|
||||
virtual_screen.text_buffer[i].bg_color = 0;
|
||||
virtual_screen.text_buffer[i].width = 0;
|
||||
virtual_screen.text_buffer[i].index = 0;
|
||||
}
|
||||
|
||||
virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vesafb_cls (void)
|
||||
{
|
||||
grub_virtual_screen_cls ();
|
||||
|
||||
grub_memset (framebuffer,
|
||||
0,
|
||||
mode_info.y_resolution * bytes_per_scan_line);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_virtual_screen_setcolorstate (grub_term_color_state state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case GRUB_TERM_COLOR_STANDARD:
|
||||
case GRUB_TERM_COLOR_NORMAL:
|
||||
virtual_screen.fg_color = DEFAULT_FG_COLOR;
|
||||
virtual_screen.bg_color = DEFAULT_BG_COLOR;
|
||||
break;
|
||||
case GRUB_TERM_COLOR_HIGHLIGHT:
|
||||
virtual_screen.fg_color = DEFAULT_BG_COLOR;
|
||||
virtual_screen.bg_color = DEFAULT_FG_COLOR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vesafb_setcursor (int on)
|
||||
{
|
||||
if (virtual_screen.cursor_state != on)
|
||||
{
|
||||
if (virtual_screen.cursor_state)
|
||||
write_char ();
|
||||
else
|
||||
write_cursor ();
|
||||
|
||||
virtual_screen.cursor_state = on;
|
||||
}
|
||||
}
|
||||
|
||||
static struct grub_term_output grub_vesafb_term =
|
||||
{
|
||||
.name = "vesafb",
|
||||
.init = grub_vesafb_mod_init,
|
||||
.fini = grub_vesafb_mod_fini,
|
||||
.putchar = grub_vesafb_putchar,
|
||||
.getcharwidth = grub_vesafb_getcharwidth,
|
||||
.getwh = grub_virtual_screen_getwh,
|
||||
.getxy = grub_virtual_screen_getxy,
|
||||
.gotoxy = grub_vesafb_gotoxy,
|
||||
.cls = grub_vesafb_cls,
|
||||
.setcolorstate = grub_virtual_screen_setcolorstate,
|
||||
.setcursor = grub_vesafb_setcursor,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(vesafb)
|
||||
{
|
||||
grub_term_register_output ("vesafb", &grub_vesafb_term);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(vesafb)
|
||||
{
|
||||
grub_term_unregister_output (&grub_vesafb_term);
|
||||
}
|
173
grub-core/term/i386/pc/vga_text.c
Normal file
173
grub-core/term/i386/pc/vga_text.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2007, 2008 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/i386/vga_common.h>
|
||||
#include <grub/i386/io.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/vga.h>
|
||||
|
||||
#define COLS 80
|
||||
#define ROWS 25
|
||||
|
||||
static int grub_curr_x, grub_curr_y;
|
||||
|
||||
#define VGA_TEXT_SCREEN 0xb8000
|
||||
|
||||
static void
|
||||
screen_write_char (int x, int y, short c)
|
||||
{
|
||||
((short *) VGA_TEXT_SCREEN)[y * COLS + x] = c;
|
||||
}
|
||||
|
||||
static short
|
||||
screen_read_char (int x, int y)
|
||||
{
|
||||
return ((short *) VGA_TEXT_SCREEN)[y * COLS + x];
|
||||
}
|
||||
|
||||
static void
|
||||
update_cursor (void)
|
||||
{
|
||||
unsigned int pos = grub_curr_y * COLS + grub_curr_x;
|
||||
grub_vga_cr_write (pos >> 8, GRUB_VGA_CR_CURSOR_ADDR_HIGH);
|
||||
grub_vga_cr_write (pos & 0xFF, GRUB_VGA_CR_CURSOR_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void
|
||||
inc_y (void)
|
||||
{
|
||||
grub_curr_x = 0;
|
||||
if (grub_curr_y < ROWS - 1)
|
||||
grub_curr_y++;
|
||||
else
|
||||
{
|
||||
int x, y;
|
||||
for (y = 0; y < ROWS - 1; y++)
|
||||
for (x = 0; x < COLS; x++)
|
||||
screen_write_char (x, y, screen_read_char (x, y + 1));
|
||||
for (x = 0; x < COLS; x++)
|
||||
screen_write_char (x, ROWS - 1, ' ' | (grub_console_cur_color << 8));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
inc_x (void)
|
||||
{
|
||||
if (grub_curr_x >= COLS - 1)
|
||||
inc_y ();
|
||||
else
|
||||
grub_curr_x++;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vga_text_putchar (struct grub_term_output *term __attribute__ ((unused)),
|
||||
const struct grub_unicode_glyph *c)
|
||||
{
|
||||
switch (c->base)
|
||||
{
|
||||
case '\b':
|
||||
if (grub_curr_x != 0)
|
||||
screen_write_char (grub_curr_x--, grub_curr_y, ' ');
|
||||
break;
|
||||
case '\n':
|
||||
inc_y ();
|
||||
break;
|
||||
case '\r':
|
||||
grub_curr_x = 0;
|
||||
break;
|
||||
default:
|
||||
screen_write_char (grub_curr_x, grub_curr_y,
|
||||
c->base | (grub_console_cur_color << 8));
|
||||
inc_x ();
|
||||
}
|
||||
|
||||
update_cursor ();
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_vga_text_getxy (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
return (grub_curr_x << 8) | grub_curr_y;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vga_text_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
|
||||
grub_uint8_t x, grub_uint8_t y)
|
||||
{
|
||||
grub_curr_x = x;
|
||||
grub_curr_y = y;
|
||||
update_cursor ();
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vga_text_cls (struct grub_term_output *term)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ROWS * COLS; i++)
|
||||
((short *) VGA_TEXT_SCREEN)[i] = ' ' | (grub_console_cur_color << 8);
|
||||
grub_vga_text_gotoxy (term, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_vga_text_setcursor (struct grub_term_output *term __attribute__ ((unused)),
|
||||
int on)
|
||||
{
|
||||
grub_uint8_t old;
|
||||
old = grub_vga_cr_read (GRUB_VGA_CR_CURSOR_START);
|
||||
if (on)
|
||||
grub_vga_cr_write (old & ~GRUB_VGA_CR_CURSOR_START_DISABLE,
|
||||
GRUB_VGA_CR_CURSOR_START);
|
||||
else
|
||||
grub_vga_cr_write (old | GRUB_VGA_CR_CURSOR_START_DISABLE,
|
||||
GRUB_VGA_CR_CURSOR_START);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_vga_text_init_fini (struct grub_term_output *term)
|
||||
{
|
||||
grub_vga_text_cls (term);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct grub_term_output grub_vga_text_term =
|
||||
{
|
||||
.name = "vga_text",
|
||||
.init = grub_vga_text_init_fini,
|
||||
.fini = grub_vga_text_init_fini,
|
||||
.putchar = grub_vga_text_putchar,
|
||||
.getwh = grub_console_getwh,
|
||||
.getxy = grub_vga_text_getxy,
|
||||
.gotoxy = grub_vga_text_gotoxy,
|
||||
.cls = grub_vga_text_cls,
|
||||
.setcolorstate = grub_console_setcolorstate,
|
||||
.setcursor = grub_vga_text_setcursor,
|
||||
.flags = GRUB_TERM_CODE_TYPE_CP437,
|
||||
.normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
|
||||
.highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(vga_text)
|
||||
{
|
||||
grub_term_register_output ("vga_text", &grub_vga_text_term);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(vga_text)
|
||||
{
|
||||
grub_term_unregister_output (&grub_vga_text_term);
|
||||
}
|
48
grub-core/term/i386/vga_common.c
Normal file
48
grub-core/term/i386/vga_common.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2005,2007,2008 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/i386/vga_common.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
grub_uint8_t grub_console_cur_color = 0x7;
|
||||
|
||||
grub_uint16_t
|
||||
grub_console_getwh (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
return (80 << 8) | 25;
|
||||
}
|
||||
|
||||
void
|
||||
grub_console_setcolorstate (struct grub_term_output *term,
|
||||
grub_term_color_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case GRUB_TERM_COLOR_STANDARD:
|
||||
grub_console_cur_color = GRUB_TERM_DEFAULT_STANDARD_COLOR & 0x7f;
|
||||
break;
|
||||
case GRUB_TERM_COLOR_NORMAL:
|
||||
grub_console_cur_color = term->normal_color & 0x7f;
|
||||
break;
|
||||
case GRUB_TERM_COLOR_HIGHLIGHT:
|
||||
grub_console_cur_color = term->highlight_color & 0x7f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
251
grub-core/term/ieee1275/ofconsole.c
Normal file
251
grub-core/term/ieee1275/ofconsole.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* ofconsole.c -- Open Firmware console for GRUB. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,2005,2007,2008,2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/terminfo.h>
|
||||
#include <grub/ieee1275/console.h>
|
||||
#include <grub/ieee1275/ieee1275.h>
|
||||
|
||||
static grub_ieee1275_ihandle_t stdout_ihandle;
|
||||
static grub_ieee1275_ihandle_t stdin_ihandle;
|
||||
|
||||
static grub_uint8_t grub_ofconsole_width;
|
||||
static grub_uint8_t grub_ofconsole_height;
|
||||
|
||||
struct color
|
||||
{
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
};
|
||||
|
||||
/* Use serial colors as they are default on most firmwares and some firmwares
|
||||
ignore set-color!. Additionally output may be redirected to serial. */
|
||||
static struct color colors[] =
|
||||
{
|
||||
// {R, G, B}
|
||||
{0x00, 0x00, 0x00}, // 0 = black
|
||||
{0xA8, 0x00, 0x00}, // 1 = red
|
||||
{0x00, 0xA8, 0x00}, // 2 = green
|
||||
{0xFE, 0xFE, 0x54}, // 3 = yellow
|
||||
{0x00, 0x00, 0xA8}, // 4 = blue
|
||||
{0xA8, 0x00, 0xA8}, // 5 = magenta
|
||||
{0x00, 0xA8, 0xA8}, // 6 = cyan
|
||||
{0xFE, 0xFE, 0xFE} // 7 = white
|
||||
};
|
||||
|
||||
static void
|
||||
put (struct grub_term_output *term __attribute__ ((unused)), const int c)
|
||||
{
|
||||
char chr = c;
|
||||
|
||||
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
readkey (struct grub_term_input *term __attribute__ ((unused)))
|
||||
{
|
||||
grub_uint8_t c;
|
||||
grub_ssize_t actual = 0;
|
||||
|
||||
grub_ieee1275_read (stdin_ihandle, &c, 1, &actual);
|
||||
if (actual > 0)
|
||||
return c;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_ofconsole_dimensions (void)
|
||||
{
|
||||
grub_ieee1275_ihandle_t options;
|
||||
grub_ssize_t lval;
|
||||
|
||||
if (! grub_ieee1275_finddevice ("/options", &options)
|
||||
&& options != (grub_ieee1275_ihandle_t) -1)
|
||||
{
|
||||
if (! grub_ieee1275_get_property_length (options, "screen-#columns",
|
||||
&lval)
|
||||
&& lval >= 0 && lval < 1024)
|
||||
{
|
||||
char val[lval];
|
||||
|
||||
if (! grub_ieee1275_get_property (options, "screen-#columns",
|
||||
val, lval, 0))
|
||||
grub_ofconsole_width = (grub_uint8_t) grub_strtoul (val, 0, 10);
|
||||
}
|
||||
if (! grub_ieee1275_get_property_length (options, "screen-#rows", &lval)
|
||||
&& lval >= 0 && lval < 1024)
|
||||
{
|
||||
char val[lval];
|
||||
if (! grub_ieee1275_get_property (options, "screen-#rows",
|
||||
val, lval, 0))
|
||||
grub_ofconsole_height = (grub_uint8_t) grub_strtoul (val, 0, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use a small console by default. */
|
||||
if (! grub_ofconsole_width)
|
||||
grub_ofconsole_width = 80;
|
||||
if (! grub_ofconsole_height)
|
||||
grub_ofconsole_height = 24;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_ofconsole_getwh (struct grub_term_output *term __attribute__ ((unused)))
|
||||
{
|
||||
return (grub_ofconsole_width << 8) | grub_ofconsole_height;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_ofconsole_setcursor (struct grub_term_output *term,
|
||||
int on)
|
||||
{
|
||||
grub_terminfo_setcursor (term, on);
|
||||
|
||||
if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF))
|
||||
return;
|
||||
|
||||
/* Understood by the Open Firmware flavour in OLPC. */
|
||||
if (on)
|
||||
grub_ieee1275_interpret ("cursor-on", 0);
|
||||
else
|
||||
grub_ieee1275_interpret ("cursor-off", 0);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ofconsole_init_input (struct grub_term_input *term)
|
||||
{
|
||||
grub_ssize_t actual;
|
||||
|
||||
if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "stdin", &stdin_ihandle,
|
||||
sizeof stdin_ihandle, &actual)
|
||||
|| actual != sizeof stdin_ihandle)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdin");
|
||||
|
||||
return grub_terminfo_input_init (term);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ofconsole_init_output (struct grub_term_output *term)
|
||||
{
|
||||
grub_ssize_t actual;
|
||||
|
||||
/* The latest PowerMacs don't actually initialize the screen for us, so we
|
||||
* use this trick to re-open the output device (but we avoid doing this on
|
||||
* platforms where it's known to be broken). */
|
||||
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT))
|
||||
grub_ieee1275_interpret ("output-device output", 0);
|
||||
|
||||
if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "stdout", &stdout_ihandle,
|
||||
sizeof stdout_ihandle, &actual)
|
||||
|| actual != sizeof stdout_ihandle)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdout");
|
||||
|
||||
/* Initialize colors. */
|
||||
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS))
|
||||
{
|
||||
unsigned col;
|
||||
for (col = 0; col < ARRAY_SIZE (colors); col++)
|
||||
grub_ieee1275_set_color (stdout_ihandle, col, colors[col].red,
|
||||
colors[col].green, colors[col].blue);
|
||||
|
||||
/* Set the right fg and bg colors. */
|
||||
grub_terminfo_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
}
|
||||
|
||||
grub_ofconsole_dimensions ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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_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_terminfo_putchar,
|
||||
.getxy = grub_terminfo_getxy,
|
||||
.getwh = grub_ofconsole_getwh,
|
||||
.gotoxy = grub_terminfo_gotoxy,
|
||||
.cls = grub_terminfo_cls,
|
||||
.setcolorstate = grub_terminfo_setcolorstate,
|
||||
.setcursor = grub_ofconsole_setcursor,
|
||||
.flags = GRUB_TERM_CODE_TYPE_ASCII,
|
||||
.data = &grub_ofconsole_terminfo_output,
|
||||
.normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
|
||||
.highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
|
||||
};
|
||||
|
||||
void grub_terminfo_fini (void);
|
||||
void grub_terminfo_init (void);
|
||||
|
||||
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 ();
|
||||
}
|
263
grub-core/term/ns8250.c
Normal file
263
grub-core/term/ns8250.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/serial.h>
|
||||
#include <grub/ns8250.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
|
||||
#define GRUB_SERIAL_PORT_NUM 4
|
||||
#else
|
||||
#include <grub/machine/serial.h>
|
||||
static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS;
|
||||
#define GRUB_SERIAL_PORT_NUM (ARRAY_SIZE(serial_hw_io_addr))
|
||||
#endif
|
||||
|
||||
/* Convert speed to divisor. */
|
||||
static unsigned short
|
||||
serial_get_divisor (unsigned int speed)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* The structure for speed vs. divisor. */
|
||||
struct divisor
|
||||
{
|
||||
unsigned int speed;
|
||||
unsigned short div;
|
||||
};
|
||||
|
||||
/* The table which lists common configurations. */
|
||||
/* 1843200 / (speed * 16) */
|
||||
static struct divisor divisor_tab[] =
|
||||
{
|
||||
{ 2400, 0x0030 },
|
||||
{ 4800, 0x0018 },
|
||||
{ 9600, 0x000C },
|
||||
{ 19200, 0x0006 },
|
||||
{ 38400, 0x0003 },
|
||||
{ 57600, 0x0002 },
|
||||
{ 115200, 0x0001 }
|
||||
};
|
||||
|
||||
/* Set the baud rate. */
|
||||
for (i = 0; i < ARRAY_SIZE (divisor_tab); i++)
|
||||
if (divisor_tab[i].speed == speed)
|
||||
/* UART in Yeeloong runs twice the usual rate. */
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
return 2 * divisor_tab[i].div;
|
||||
#else
|
||||
return divisor_tab[i].div;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
do_real_config (struct grub_serial_port *port)
|
||||
{
|
||||
int divisor;
|
||||
unsigned char status = 0;
|
||||
const unsigned char parities[] = {
|
||||
[GRUB_SERIAL_PARITY_NONE] = UART_NO_PARITY,
|
||||
[GRUB_SERIAL_PARITY_ODD] = UART_ODD_PARITY,
|
||||
[GRUB_SERIAL_PARITY_EVEN] = UART_EVEN_PARITY
|
||||
};
|
||||
const unsigned char stop_bits[] = {
|
||||
[GRUB_SERIAL_STOP_BITS_1] = UART_1_STOP_BIT,
|
||||
[GRUB_SERIAL_STOP_BITS_2] = UART_2_STOP_BITS,
|
||||
};
|
||||
|
||||
if (port->configured)
|
||||
return;
|
||||
|
||||
divisor = serial_get_divisor (port->config.speed);
|
||||
|
||||
/* Turn off the interrupt. */
|
||||
grub_outb (0, port->port + UART_IER);
|
||||
|
||||
/* Set DLAB. */
|
||||
grub_outb (UART_DLAB, port->port + UART_LCR);
|
||||
|
||||
/* Set the baud rate. */
|
||||
grub_outb (divisor & 0xFF, port->port + UART_DLL);
|
||||
grub_outb (divisor >> 8, port->port + UART_DLH);
|
||||
|
||||
/* Set the line status. */
|
||||
status |= (parities[port->config.parity]
|
||||
| (port->config.word_len - 5)
|
||||
| stop_bits[port->config.stop_bits]);
|
||||
grub_outb (status, port->port + UART_LCR);
|
||||
|
||||
/* In Yeeloong serial port has only 3 wires. */
|
||||
#ifndef GRUB_MACHINE_MIPS_YEELOONG
|
||||
/* Enable the FIFO. */
|
||||
grub_outb (UART_ENABLE_FIFO_TRIGGER1, port->port + UART_FCR);
|
||||
|
||||
/* Turn on DTR and RTS. */
|
||||
grub_outb (UART_ENABLE_DTRRTS, port->port + UART_MCR);
|
||||
#else
|
||||
/* Enable the FIFO. */
|
||||
grub_outb (UART_ENABLE_FIFO_TRIGGER14, port->port + UART_FCR);
|
||||
|
||||
/* Turn on DTR, RTS, and OUT2. */
|
||||
grub_outb (UART_ENABLE_DTRRTS | UART_ENABLE_OUT2, port->port + UART_MCR);
|
||||
#endif
|
||||
|
||||
/* Drain the input buffer. */
|
||||
while (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
|
||||
grub_inb (port->port + UART_RX);
|
||||
|
||||
port->configured = 1;
|
||||
}
|
||||
|
||||
/* Fetch a key. */
|
||||
static int
|
||||
serial_hw_fetch (struct grub_serial_port *port)
|
||||
{
|
||||
do_real_config (port);
|
||||
if (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
|
||||
return grub_inb (port->port + UART_RX);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put a character. */
|
||||
static void
|
||||
serial_hw_put (struct grub_serial_port *port, const int c)
|
||||
{
|
||||
unsigned int timeout = 100000;
|
||||
|
||||
do_real_config (port);
|
||||
|
||||
/* Wait until the transmitter holding register is empty. */
|
||||
while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
|
||||
{
|
||||
if (--timeout == 0)
|
||||
/* There is something wrong. But what can I do? */
|
||||
return;
|
||||
}
|
||||
|
||||
grub_outb (c, port->port + UART_TX);
|
||||
}
|
||||
|
||||
/* 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
|
||||
for the device. Likewise, PARITY is the type of the parity and
|
||||
STOP_BIT_LEN is the length of the stop bit. The possible values for
|
||||
WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
|
||||
macros. */
|
||||
static grub_err_t
|
||||
serial_hw_configure (struct grub_serial_port *port,
|
||||
struct grub_serial_config *config)
|
||||
{
|
||||
unsigned short divisor;
|
||||
|
||||
divisor = serial_get_divisor (config->speed);
|
||||
if (divisor == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
|
||||
|
||||
if (config->parity != GRUB_SERIAL_PARITY_NONE
|
||||
&& config->parity != GRUB_SERIAL_PARITY_ODD
|
||||
&& config->parity != GRUB_SERIAL_PARITY_EVEN)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
|
||||
|
||||
if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
|
||||
&& config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
|
||||
|
||||
if (config->word_len < 5 || config->word_len > 8)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length");
|
||||
|
||||
port->config = *config;
|
||||
port->configured = 0;
|
||||
|
||||
/* FIXME: should check if the serial terminal was found. */
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
struct grub_serial_driver grub_ns8250_driver =
|
||||
{
|
||||
.configure = serial_hw_configure,
|
||||
.fetch = serial_hw_fetch,
|
||||
.put = serial_hw_put
|
||||
};
|
||||
|
||||
static char com_names[GRUB_SERIAL_PORT_NUM][20];
|
||||
static struct grub_serial_port com_ports[GRUB_SERIAL_PORT_NUM];
|
||||
|
||||
void
|
||||
grub_ns8250_init (void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
|
||||
if (serial_hw_io_addr[i])
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_snprintf (com_names[i], sizeof (com_names[i]), "com%d", i);
|
||||
com_ports[i].name = com_names[i];
|
||||
com_ports[i].driver = &grub_ns8250_driver;
|
||||
com_ports[i].port = serial_hw_io_addr[i];
|
||||
err = grub_serial_config_defaults (&com_ports[i]);
|
||||
if (err)
|
||||
grub_print_error ();
|
||||
|
||||
grub_serial_register (&com_ports[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the port number for the UNITth serial device. */
|
||||
grub_port_t
|
||||
grub_ns8250_hw_get_port (const unsigned int unit)
|
||||
{
|
||||
if (unit < GRUB_SERIAL_PORT_NUM)
|
||||
return serial_hw_io_addr[unit];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_serial_ns8250_add_port (grub_port_t port)
|
||||
{
|
||||
struct grub_serial_port *p;
|
||||
unsigned i;
|
||||
for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
|
||||
if (com_ports[i].port == port)
|
||||
return com_names[i];
|
||||
p = grub_malloc (sizeof (*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->name = grub_xasprintf ("port%lx", (unsigned long) port);
|
||||
if (!p->name)
|
||||
{
|
||||
grub_free (p);
|
||||
return NULL;
|
||||
}
|
||||
p->driver = &grub_ns8250_driver;
|
||||
grub_serial_config_defaults (p);
|
||||
p->port = port;
|
||||
grub_serial_register (p);
|
||||
|
||||
return p->name;
|
||||
}
|
363
grub-core/term/serial.c
Normal file
363
grub-core/term/serial.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/serial.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/terminfo.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/list.h>
|
||||
|
||||
#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
|
||||
|
||||
/* Argument options. */
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"unit", 'u', 0, N_("Set the serial unit."), 0, ARG_TYPE_INT},
|
||||
{"port", 'p', 0, N_("Set the serial port address."), 0, ARG_TYPE_STRING},
|
||||
{"speed", 's', 0, N_("Set the serial port speed."), 0, ARG_TYPE_INT},
|
||||
{"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT},
|
||||
{"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING},
|
||||
{"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
struct grub_serial_port *grub_serial_ports;
|
||||
|
||||
struct grub_serial_output_state
|
||||
{
|
||||
struct grub_terminfo_output_state tinfo;
|
||||
struct grub_serial_port *port;
|
||||
};
|
||||
|
||||
struct grub_serial_input_state
|
||||
{
|
||||
struct grub_terminfo_input_state tinfo;
|
||||
struct grub_serial_port *port;
|
||||
};
|
||||
|
||||
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 void
|
||||
serial_put (grub_term_output_t term, const int c)
|
||||
{
|
||||
struct grub_serial_output_state *data = term->data;
|
||||
data->port->driver->put (data->port, c);
|
||||
}
|
||||
|
||||
static int
|
||||
serial_fetch (grub_term_input_t term)
|
||||
{
|
||||
struct grub_serial_input_state *data = term->data;
|
||||
return data->port->driver->fetch (data->port);
|
||||
}
|
||||
|
||||
struct grub_serial_input_state grub_serial_terminfo_input =
|
||||
{
|
||||
.tinfo =
|
||||
{
|
||||
.readkey = serial_fetch
|
||||
}
|
||||
};
|
||||
|
||||
struct grub_serial_output_state grub_serial_terminfo_output =
|
||||
{
|
||||
.tinfo =
|
||||
{
|
||||
.put = serial_put
|
||||
}
|
||||
};
|
||||
|
||||
int registered = 0;
|
||||
|
||||
static struct grub_term_input grub_serial_term_input =
|
||||
{
|
||||
.name = "serial",
|
||||
.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_terminfo_putchar,
|
||||
.getwh = grub_serial_getwh,
|
||||
.getxy = grub_terminfo_getxy,
|
||||
.gotoxy = grub_terminfo_gotoxy,
|
||||
.cls = grub_terminfo_cls,
|
||||
.setcolorstate = grub_terminfo_setcolorstate,
|
||||
.setcursor = grub_terminfo_setcursor,
|
||||
.flags = GRUB_TERM_CODE_TYPE_ASCII,
|
||||
.data = &grub_serial_terminfo_output,
|
||||
.normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
|
||||
.highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct grub_serial_port *
|
||||
grub_serial_find (char *name)
|
||||
{
|
||||
struct grub_serial_port *port;
|
||||
|
||||
FOR_SERIAL_PORTS (port)
|
||||
if (grub_strcmp (port->name, name) == 0)
|
||||
break;
|
||||
|
||||
#ifndef GRUB_MACHINE_EMU
|
||||
if (!port && grub_memcmp (name, "port", sizeof ("port") - 1) == 0
|
||||
&& grub_isdigit (name [sizeof ("port") - 1]))
|
||||
{
|
||||
name = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") - 1],
|
||||
0, 16));
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
FOR_SERIAL_PORTS (port)
|
||||
if (grub_strcmp (port->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
char pname[40];
|
||||
char *name = NULL;
|
||||
struct grub_serial_port *port;
|
||||
struct grub_serial_config config;
|
||||
grub_err_t err;
|
||||
|
||||
if (state[0].set)
|
||||
{
|
||||
grub_snprintf (pname, sizeof (pname), "com%ld",
|
||||
grub_strtoul (state[0].arg, 0, 0));
|
||||
name = pname;
|
||||
}
|
||||
|
||||
if (state[1].set)
|
||||
{
|
||||
grub_snprintf (pname, sizeof (pname), "port%lx",
|
||||
grub_strtoul (state[1].arg, 0, 0));
|
||||
name = pname;
|
||||
}
|
||||
|
||||
if (argc >= 1)
|
||||
name = args[0];
|
||||
|
||||
if (!name)
|
||||
name = "com0";
|
||||
|
||||
port = grub_serial_find (name);
|
||||
if (!port)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown serial port");
|
||||
|
||||
config = port->config;
|
||||
|
||||
if (state[2].set)
|
||||
config.speed = grub_strtoul (state[2].arg, 0, 0);
|
||||
|
||||
if (state[3].set)
|
||||
config.word_len = grub_strtoul (state[3].arg, 0, 0);
|
||||
|
||||
if (state[4].set)
|
||||
{
|
||||
if (! grub_strcmp (state[4].arg, "no"))
|
||||
config.parity = GRUB_SERIAL_PARITY_NONE;
|
||||
else if (! grub_strcmp (state[4].arg, "odd"))
|
||||
config.parity = GRUB_SERIAL_PARITY_ODD;
|
||||
else if (! grub_strcmp (state[4].arg, "even"))
|
||||
config.parity = GRUB_SERIAL_PARITY_EVEN;
|
||||
else
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity");
|
||||
}
|
||||
|
||||
if (state[5].set)
|
||||
{
|
||||
if (! grub_strcmp (state[5].arg, "1"))
|
||||
config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
|
||||
else if (! grub_strcmp (state[5].arg, "2"))
|
||||
config.stop_bits = GRUB_SERIAL_STOP_BITS_2;
|
||||
else
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits");
|
||||
}
|
||||
|
||||
/* Initialize with new settings. */
|
||||
err = port->driver->configure (port, &config);
|
||||
if (err)
|
||||
return err;
|
||||
#ifndef GRUB_MACHINE_EMU
|
||||
/* Compatibility kludge. */
|
||||
if (port->driver == &grub_ns8250_driver)
|
||||
{
|
||||
if (!registered)
|
||||
{
|
||||
grub_term_register_input ("serial", &grub_serial_term_input);
|
||||
grub_term_register_output ("serial", &grub_serial_term_output);
|
||||
}
|
||||
grub_serial_terminfo_output.port = port;
|
||||
grub_serial_terminfo_input.port = port;
|
||||
registered = 1;
|
||||
}
|
||||
#endif
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_serial_register (struct grub_serial_port *port)
|
||||
{
|
||||
struct grub_term_input *in;
|
||||
struct grub_term_output *out;
|
||||
struct grub_serial_input_state *indata;
|
||||
struct grub_serial_output_state *outdata;
|
||||
|
||||
in = grub_malloc (sizeof (*in));
|
||||
if (!in)
|
||||
return grub_errno;
|
||||
|
||||
indata = grub_malloc (sizeof (*indata));
|
||||
if (!indata)
|
||||
{
|
||||
grub_free (in);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_memcpy (in, &grub_serial_term_input, sizeof (*in));
|
||||
in->data = indata;
|
||||
in->name = grub_xasprintf ("serial_%s", port->name);
|
||||
grub_memcpy (indata, &grub_serial_terminfo_input, sizeof (*indata));
|
||||
|
||||
if (!in->name)
|
||||
{
|
||||
grub_free (in);
|
||||
grub_free (indata);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
out = grub_malloc (sizeof (*out));
|
||||
if (!out)
|
||||
{
|
||||
grub_free (in);
|
||||
grub_free (indata);
|
||||
grub_free ((char *) in->name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
outdata = grub_malloc (sizeof (*outdata));
|
||||
if (!outdata)
|
||||
{
|
||||
grub_free (in);
|
||||
grub_free (indata);
|
||||
grub_free ((char *) in->name);
|
||||
grub_free (out);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_memcpy (out, &grub_serial_term_output, sizeof (*out));
|
||||
out->data = outdata;
|
||||
out->name = in->name;
|
||||
grub_memcpy (outdata, &grub_serial_terminfo_output, sizeof (*outdata));
|
||||
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port));
|
||||
((struct grub_serial_input_state *) in->data)->port = port;
|
||||
((struct grub_serial_output_state *) out->data)->port = port;
|
||||
port->term_in = in;
|
||||
port->term_out = out;
|
||||
grub_terminfo_output_register (out, "vt100");
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
if (grub_strcmp (port->name, "com0") == 0)
|
||||
{
|
||||
grub_term_register_input_active ("serial_*", in);
|
||||
grub_term_register_output_active ("serial_*", out);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
grub_term_register_input ("serial_*", in);
|
||||
grub_term_register_output ("serial_*", out);
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_serial_unregister (struct grub_serial_port *port)
|
||||
{
|
||||
if (port->driver->fini)
|
||||
port->driver->fini (port);
|
||||
|
||||
if (port->term_in)
|
||||
grub_term_unregister_input (port->term_in);
|
||||
if (port->term_out)
|
||||
grub_term_unregister_output (port->term_out);
|
||||
|
||||
grub_list_remove (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port));
|
||||
}
|
||||
|
||||
void
|
||||
grub_serial_unregister_driver (struct grub_serial_driver *driver)
|
||||
{
|
||||
struct grub_serial_port *port, *next;
|
||||
for (port = grub_serial_ports; port; port = next)
|
||||
{
|
||||
next = port->next;
|
||||
if (port->driver == driver)
|
||||
grub_serial_unregister (port);
|
||||
}
|
||||
}
|
||||
|
||||
static grub_extcmd_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(serial)
|
||||
{
|
||||
cmd = grub_register_extcmd ("serial", grub_cmd_serial,
|
||||
GRUB_COMMAND_FLAG_BOTH,
|
||||
N_("[OPTIONS...]"),
|
||||
N_("Configure serial port."), options);
|
||||
#ifndef GRUB_MACHINE_EMU
|
||||
grub_ns8250_init ();
|
||||
#endif
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(serial)
|
||||
{
|
||||
while (grub_serial_ports)
|
||||
grub_serial_unregister (grub_serial_ports);
|
||||
if (registered)
|
||||
{
|
||||
grub_term_unregister_input (&grub_serial_term_input);
|
||||
grub_term_unregister_output (&grub_serial_term_output);
|
||||
}
|
||||
grub_unregister_extcmd (cmd);
|
||||
}
|
630
grub-core/term/terminfo.c
Normal file
630
grub-core/term/terminfo.c
Normal file
|
@ -0,0 +1,630 @@
|
|||
/* terminfo.c - simple terminfo module */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains various functions dealing with different
|
||||
* terminal capabilities. For example, vt52 and vt100.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/terminfo.h>
|
||||
#include <grub/tparm.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
static struct grub_term_output *terminfo_outputs;
|
||||
|
||||
/* Get current terminfo name. */
|
||||
char *
|
||||
grub_terminfo_get_current (struct grub_term_output *term)
|
||||
{
|
||||
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. */
|
||||
static void
|
||||
grub_terminfo_free (char **ptr)
|
||||
{
|
||||
grub_free (*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 (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.
|
||||
*
|
||||
* How should this be done?
|
||||
* a. A static table included in this module.
|
||||
* - I do not like this idea.
|
||||
* b. A table stored in the configuration directory.
|
||||
* - Users must convert their terminfo settings if we have not already.
|
||||
* c. Look for terminfo files in the configuration directory.
|
||||
* - /usr/share/terminfo is 6.3M on my system.
|
||||
* - /usr/share/terminfo is not on most users boot partition.
|
||||
* + Copying the terminfo files you want to use to the grub
|
||||
* configuration directory is easier then (b).
|
||||
* d. Your idea here.
|
||||
*/
|
||||
|
||||
grub_terminfo_all_free (term);
|
||||
|
||||
if (grub_strcmp ("vt100", str) == 0)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_terminfo_output_register (struct grub_term_output *term,
|
||||
const char *type)
|
||||
{
|
||||
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;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_terminfo_output_unregister (struct grub_term_output *term)
|
||||
{
|
||||
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 (term, *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 (term, '\b');
|
||||
}
|
||||
|
||||
data->xpos = x;
|
||||
data->ypos = y;
|
||||
}
|
||||
|
||||
/* Clear the screen. */
|
||||
void
|
||||
grub_terminfo_cls (struct grub_term_output *term)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
grub_terminfo_setcolorstate (struct grub_term_output *term,
|
||||
const grub_term_color_state state)
|
||||
{
|
||||
struct grub_terminfo_output_state *data
|
||||
= (struct grub_terminfo_output_state *) term->data;
|
||||
|
||||
if (data->setcolor)
|
||||
{
|
||||
int fg;
|
||||
int bg;
|
||||
/* Map from VGA to terminal colors. */
|
||||
const int colormap[8]
|
||||
= { 0, /* Black. */
|
||||
4, /* Blue. */
|
||||
2, /* Green. */
|
||||
6, /* Cyan. */
|
||||
1, /* Red. */
|
||||
5, /* Magenta. */
|
||||
3, /* Yellow. */
|
||||
7, /* White. */
|
||||
};
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case GRUB_TERM_COLOR_STANDARD:
|
||||
case GRUB_TERM_COLOR_NORMAL:
|
||||
fg = term->normal_color & 0x0f;
|
||||
bg = term->normal_color >> 4;
|
||||
break;
|
||||
case GRUB_TERM_COLOR_HIGHLIGHT:
|
||||
fg = term->highlight_color & 0x0f;
|
||||
bg = term->highlight_color >> 4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
putstr (term, grub_terminfo_tparm (data->setcolor, colormap[fg & 7],
|
||||
colormap[bg & 7]));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_terminfo_setcursor (struct grub_term_output *term, const int on)
|
||||
{
|
||||
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 (term, '\r');
|
||||
data->put (term, '\n');
|
||||
}
|
||||
data->xpos += c->estimated_width;
|
||||
break;
|
||||
}
|
||||
|
||||
data->put (term, c->base);
|
||||
}
|
||||
|
||||
#define ANSI_C0 0x9b
|
||||
|
||||
static void
|
||||
grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
|
||||
int (*readkey) (struct grub_term_input *term))
|
||||
{
|
||||
int c;
|
||||
|
||||
#define CONTINUE_READ \
|
||||
{ \
|
||||
grub_uint64_t start; \
|
||||
/* On 9600 we have to wait up to 12 milliseconds. */ \
|
||||
start = grub_get_time_ms (); \
|
||||
do \
|
||||
c = readkey (term); \
|
||||
while (c == -1 && grub_get_time_ms () - start < 12); \
|
||||
if (c == -1) \
|
||||
return; \
|
||||
\
|
||||
keys[*len] = c; \
|
||||
(*len)++; \
|
||||
}
|
||||
|
||||
c = readkey (term);
|
||||
if (c < 0)
|
||||
{
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
*len = 1;
|
||||
keys[0] = c;
|
||||
if (c != ANSI_C0 && c != '\e')
|
||||
{
|
||||
/* Backspace: Ctrl-h. */
|
||||
if (c == 0x7f)
|
||||
c = '\b';
|
||||
*len = 1;
|
||||
keys[0] = c;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
static struct
|
||||
{
|
||||
char key;
|
||||
char ascii;
|
||||
}
|
||||
three_code_table[] =
|
||||
{
|
||||
{'4', GRUB_TERM_DC},
|
||||
{'A', GRUB_TERM_UP},
|
||||
{'B', GRUB_TERM_DOWN},
|
||||
{'C', GRUB_TERM_RIGHT},
|
||||
{'D', GRUB_TERM_LEFT},
|
||||
{'F', GRUB_TERM_END},
|
||||
{'H', GRUB_TERM_HOME},
|
||||
{'K', GRUB_TERM_END},
|
||||
{'P', GRUB_TERM_DC},
|
||||
{'?', GRUB_TERM_PPAGE},
|
||||
{'/', GRUB_TERM_NPAGE}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
char key;
|
||||
char ascii;
|
||||
}
|
||||
four_code_table[] =
|
||||
{
|
||||
{'1', GRUB_TERM_HOME},
|
||||
{'3', GRUB_TERM_DC},
|
||||
{'5', GRUB_TERM_PPAGE},
|
||||
{'6', GRUB_TERM_NPAGE}
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
if (c == '\e')
|
||||
{
|
||||
CONTINUE_READ;
|
||||
|
||||
if (c != '[')
|
||||
return;
|
||||
}
|
||||
|
||||
CONTINUE_READ;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (three_code_table); i++)
|
||||
if (three_code_table[i].key == c)
|
||||
{
|
||||
keys[0] = three_code_table[i].ascii;
|
||||
*len = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (four_code_table); i++)
|
||||
if (four_code_table[i].key == c)
|
||||
{
|
||||
CONTINUE_READ;
|
||||
if (c != '~')
|
||||
return;
|
||||
keys[0] = three_code_table[i].ascii;
|
||||
*len = 1;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#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 (termi, 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 (termi, 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
|
||||
print_terminfo (void)
|
||||
{
|
||||
const char *encoding_names[(GRUB_TERM_CODE_TYPE_MASK
|
||||
>> GRUB_TERM_CODE_TYPE_SHIFT) + 1]
|
||||
= {
|
||||
/* VGA and glyph descriptor types are just for completeness,
|
||||
they are not used on terminfo terminals.
|
||||
*/
|
||||
[GRUB_TERM_CODE_TYPE_ASCII >> GRUB_TERM_CODE_TYPE_SHIFT] = _("ASCII"),
|
||||
[GRUB_TERM_CODE_TYPE_CP437 >> GRUB_TERM_CODE_TYPE_SHIFT] = "CP-437",
|
||||
[GRUB_TERM_CODE_TYPE_UTF8_LOGICAL >> GRUB_TERM_CODE_TYPE_SHIFT]
|
||||
= _("UTF-8"),
|
||||
[GRUB_TERM_CODE_TYPE_UTF8_VISUAL >> GRUB_TERM_CODE_TYPE_SHIFT]
|
||||
= _("UTF-8 visual"),
|
||||
[GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS >> GRUB_TERM_CODE_TYPE_SHIFT]
|
||||
= "Glyph descriptors",
|
||||
_("Unknown"), _("Unknown"), _("Unknown")
|
||||
};
|
||||
struct grub_term_output *cur;
|
||||
|
||||
grub_printf ("Current terminfo types: \n");
|
||||
for (cur = terminfo_outputs; cur;
|
||||
cur = ((struct grub_terminfo_output_state *) cur->data)->next)
|
||||
grub_printf ("%s: %s\t%s\n", cur->name,
|
||||
grub_terminfo_get_current(cur),
|
||||
encoding_names[(cur->flags & GRUB_TERM_CODE_TYPE_MASK)
|
||||
>> GRUB_TERM_CODE_TYPE_SHIFT]);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_terminfo (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
struct grub_term_output *cur;
|
||||
int encoding = GRUB_TERM_CODE_TYPE_ASCII;
|
||||
int i;
|
||||
char *name = NULL, *type = NULL;
|
||||
|
||||
if (argc == 0)
|
||||
return print_terminfo ();
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (grub_strcmp (args[i], "-a") == 0
|
||||
|| grub_strcmp (args[i], "--ascii") == 0)
|
||||
{
|
||||
encoding = GRUB_TERM_CODE_TYPE_ASCII;
|
||||
continue;
|
||||
}
|
||||
if (grub_strcmp (args[i], "-u") == 0
|
||||
|| grub_strcmp (args[i], "--utf8") == 0)
|
||||
{
|
||||
encoding = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL;
|
||||
continue;
|
||||
}
|
||||
if (grub_strcmp (args[i], "-v") == 0
|
||||
|| grub_strcmp (args[i], "--visual-utf8") == 0)
|
||||
{
|
||||
encoding = GRUB_TERM_CODE_TYPE_UTF8_VISUAL;
|
||||
continue;
|
||||
}
|
||||
if (!name)
|
||||
{
|
||||
name = args[i];
|
||||
continue;
|
||||
}
|
||||
if (!type)
|
||||
{
|
||||
type = args[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters");
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few parameters");
|
||||
|
||||
for (cur = terminfo_outputs; cur;
|
||||
cur = ((struct grub_terminfo_output_state *) cur->data)->next)
|
||||
if (grub_strcmp (name, cur->name) == 0)
|
||||
{
|
||||
cur->flags = (cur->flags & ~GRUB_TERM_CODE_TYPE_MASK) | encoding;
|
||||
if (!type)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
return grub_terminfo_set_current (cur, type);
|
||||
}
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"no terminal %s found or it's not handled by terminfo",
|
||||
name);
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(terminfo)
|
||||
{
|
||||
cmd = grub_register_command ("terminfo", grub_cmd_terminfo,
|
||||
N_("[[-a|-u|-v] TERM [TYPE]]"),
|
||||
N_("Set terminfo type of TERM to TYPE.\n"
|
||||
"-a, --ascii Terminal is ASCII-only [default].\n"
|
||||
"-u, --utf8 Terminal is logical-ordered UTF-8.\n"
|
||||
"-v, --visual-utf8 Terminal is visually-ordered UTF-8.")
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(terminfo)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
761
grub-core/term/tparm.c
Normal file
761
grub-core/term/tparm.c
Normal file
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1998-2003,2004,2005 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**********************************************************************
|
||||
* This code is a modification of lib_tparm.c found in ncurses-5.2. The
|
||||
* modification are for use in grub by replacing all libc function through
|
||||
* special grub functions. This also meant to delete all dynamic memory
|
||||
* allocation and replace it by a number of fixed buffers.
|
||||
*
|
||||
* Modifications by Tilmann Bubeck <t.bubeck@reinform.de> 2002
|
||||
*
|
||||
* Resync with ncurses-5.4 by Omniflux <omniflux+devel@omniflux.com> 2005
|
||||
**********************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
|
||||
* and: Eric S. Raymond <esr@snark.thyrsus.com> *
|
||||
* and: Thomas E. Dickey, 1996 on *
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* tparm.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/tparm.h>
|
||||
|
||||
/*
|
||||
* Common/troublesome character definitions
|
||||
*/
|
||||
typedef char grub_bool_t;
|
||||
#ifndef FALSE
|
||||
# define FALSE (0)
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
# define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define NUM_PARM 9
|
||||
#define NUM_VARS 26
|
||||
#define STACKSIZE 20
|
||||
#define MAX_FORMAT_LEN 256
|
||||
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
|
||||
|
||||
#define UChar(c) ((unsigned char)(c))
|
||||
|
||||
//MODULE_ID("$Id$")
|
||||
|
||||
/*
|
||||
* char *
|
||||
* tparm(string, ...)
|
||||
*
|
||||
* Substitute the given parameters into the given string by the following
|
||||
* rules (taken from terminfo(5)):
|
||||
*
|
||||
* Cursor addressing and other strings requiring parame-
|
||||
* ters in the terminal are described by a parameterized string
|
||||
* capability, with like escapes %x in it. For example, to
|
||||
* address the cursor, the cup capability is given, using two
|
||||
* parameters: the row and column to address to. (Rows and
|
||||
* columns are numbered from zero and refer to the physical
|
||||
* screen visible to the user, not to any unseen memory.) If
|
||||
* the terminal has memory relative cursor addressing, that can
|
||||
* be indicated by
|
||||
*
|
||||
* The parameter mechanism uses a stack and special %
|
||||
* codes to manipulate it. Typically a sequence will push one
|
||||
* of the parameters onto the stack and then print it in some
|
||||
* format. Often more complex operations are necessary.
|
||||
*
|
||||
* The % encodings have the following meanings:
|
||||
*
|
||||
* %% outputs `%'
|
||||
* %c print pop() like %c in printf()
|
||||
* %s print pop() like %s in printf()
|
||||
* %[[:]flags][width[.precision]][doxXs]
|
||||
* as in printf, flags are [-+#] and space
|
||||
* The ':' is used to avoid making %+ or %-
|
||||
* patterns (see below).
|
||||
*
|
||||
* %p[1-9] push ith parm
|
||||
* %P[a-z] set dynamic variable [a-z] to pop()
|
||||
* %g[a-z] get dynamic variable [a-z] and push it
|
||||
* %P[A-Z] set static variable [A-Z] to pop()
|
||||
* %g[A-Z] get static variable [A-Z] and push it
|
||||
* %l push strlen(pop)
|
||||
* %'c' push char constant c
|
||||
* %{nn} push integer constant nn
|
||||
*
|
||||
* %+ %- %* %/ %m
|
||||
* arithmetic (%m is mod): push(pop() op pop())
|
||||
* %& %| %^ bit operations: push(pop() op pop())
|
||||
* %= %> %< logical operations: push(pop() op pop())
|
||||
* %A %O logical and & or operations for conditionals
|
||||
* %! %~ unary operations push(op pop())
|
||||
* %i add 1 to first two parms (for ANSI terminals)
|
||||
*
|
||||
* %? expr %t thenpart %e elsepart %;
|
||||
* if-then-else, %e elsepart is optional.
|
||||
* else-if's are possible ala Algol 68:
|
||||
* %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
|
||||
*
|
||||
* For those of the above operators which are binary and not commutative,
|
||||
* the stack works in the usual way, with
|
||||
* %gx %gy %m
|
||||
* resulting in x mod y, not the reverse.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
int num;
|
||||
char *str;
|
||||
} data;
|
||||
grub_bool_t num_type;
|
||||
} stack_frame;
|
||||
|
||||
static stack_frame stack[STACKSIZE];
|
||||
static int stack_ptr;
|
||||
static const char *tparam_base = "";
|
||||
|
||||
static char *out_buff;
|
||||
static grub_size_t out_size;
|
||||
static grub_size_t out_used;
|
||||
|
||||
static char *fmt_buff;
|
||||
static grub_size_t fmt_size;
|
||||
|
||||
static inline void
|
||||
get_space(grub_size_t need)
|
||||
{
|
||||
need += out_used;
|
||||
if (need > out_size) {
|
||||
out_size = need * 2;
|
||||
out_buff = grub_realloc(out_buff, out_size*sizeof(char));
|
||||
/* FIX ME! handle out_buff == 0. */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_text(const char *fmt, const char *s, int len)
|
||||
{
|
||||
grub_size_t s_len = grub_strlen(s);
|
||||
if (len > (int) s_len)
|
||||
s_len = len;
|
||||
|
||||
get_space(s_len + 1);
|
||||
|
||||
(void) grub_snprintf(out_buff + out_used, s_len + 1, fmt, s);
|
||||
out_used += grub_strlen(out_buff + out_used);
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_number(const char *fmt, int number, int len)
|
||||
{
|
||||
if (len < 30)
|
||||
len = 30; /* actually log10(MAX_INT)+1 */
|
||||
|
||||
get_space((unsigned) len + 1);
|
||||
|
||||
(void) grub_snprintf(out_buff + out_used, len + 1, fmt, number);
|
||||
out_used += grub_strlen(out_buff + out_used);
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_char(int c)
|
||||
{
|
||||
if (c == 0)
|
||||
c = 0200;
|
||||
get_space(1);
|
||||
out_buff[out_used++] = c;
|
||||
}
|
||||
|
||||
static inline void
|
||||
npush(int x)
|
||||
{
|
||||
if (stack_ptr < STACKSIZE) {
|
||||
stack[stack_ptr].num_type = TRUE;
|
||||
stack[stack_ptr].data.num = x;
|
||||
stack_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
npop(void)
|
||||
{
|
||||
int result = 0;
|
||||
if (stack_ptr > 0) {
|
||||
stack_ptr--;
|
||||
if (stack[stack_ptr].num_type)
|
||||
result = stack[stack_ptr].data.num;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spush(char *x)
|
||||
{
|
||||
if (stack_ptr < STACKSIZE) {
|
||||
stack[stack_ptr].num_type = FALSE;
|
||||
stack[stack_ptr].data.str = x;
|
||||
stack_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *
|
||||
spop(void)
|
||||
{
|
||||
static char dummy[] = ""; /* avoid const-cast */
|
||||
char *result = dummy;
|
||||
if (stack_ptr > 0) {
|
||||
stack_ptr--;
|
||||
if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
|
||||
result = stack[stack_ptr].data.str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
parse_format(const char *s, char *format, int *len)
|
||||
{
|
||||
*len = 0;
|
||||
if (format != 0) {
|
||||
grub_bool_t done = FALSE;
|
||||
grub_bool_t allowminus = FALSE;
|
||||
grub_bool_t dot = FALSE;
|
||||
grub_bool_t err = FALSE;
|
||||
char *fmt = format;
|
||||
int my_width = 0;
|
||||
int my_prec = 0;
|
||||
int value = 0;
|
||||
|
||||
*len = 0;
|
||||
*format++ = '%';
|
||||
while (*s != '\0' && !done) {
|
||||
switch (*s) {
|
||||
case 'c': /* FALLTHRU */
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
case 's':
|
||||
*format++ = *s;
|
||||
done = TRUE;
|
||||
break;
|
||||
case '.':
|
||||
*format++ = *s++;
|
||||
if (dot) {
|
||||
err = TRUE;
|
||||
} else { /* value before '.' is the width */
|
||||
dot = TRUE;
|
||||
my_width = value;
|
||||
}
|
||||
value = 0;
|
||||
break;
|
||||
case '#':
|
||||
*format++ = *s++;
|
||||
break;
|
||||
case ' ':
|
||||
*format++ = *s++;
|
||||
break;
|
||||
case ':':
|
||||
s++;
|
||||
allowminus = TRUE;
|
||||
break;
|
||||
case '-':
|
||||
if (allowminus) {
|
||||
*format++ = *s++;
|
||||
} else {
|
||||
done = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (isdigit(UChar(*s))) {
|
||||
value = (value * 10) + (*s - '0');
|
||||
if (value > 10000)
|
||||
err = TRUE;
|
||||
*format++ = *s++;
|
||||
} else {
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found an error, ignore (and remove) the flags.
|
||||
*/
|
||||
if (err) {
|
||||
my_width = my_prec = value = 0;
|
||||
format = fmt;
|
||||
*format++ = '%';
|
||||
*format++ = *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any value after '.' is the precision. If we did not see '.', then
|
||||
* the value is the width.
|
||||
*/
|
||||
if (dot)
|
||||
my_prec = value;
|
||||
else
|
||||
my_width = value;
|
||||
|
||||
*format = '\0';
|
||||
/* return maximum string length in print */
|
||||
*len = (my_width > my_prec) ? my_width : my_prec;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze the string to see how many parameters we need from the varargs list,
|
||||
* and what their types are. We will only accept string parameters if they
|
||||
* appear as a %l or %s format following an explicit parameter reference (e.g.,
|
||||
* %p2%s). All other parameters are numbers.
|
||||
*
|
||||
* 'number' counts coarsely the number of pop's we see in the string, and
|
||||
* 'popcount' shows the highest parameter number in the string. We would like
|
||||
* to simply use the latter count, but if we are reading termcap strings, there
|
||||
* may be cases that we cannot see the explicit parameter numbers.
|
||||
*/
|
||||
static inline int
|
||||
analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount)
|
||||
{
|
||||
grub_size_t len2;
|
||||
int i;
|
||||
int lastpop = -1;
|
||||
int len;
|
||||
int number = 0;
|
||||
const char *cp = string;
|
||||
static char dummy[] = "";
|
||||
|
||||
*popcount = 0;
|
||||
|
||||
if (cp == 0)
|
||||
return 0;
|
||||
|
||||
if ((len2 = grub_strlen(cp)) > fmt_size) {
|
||||
fmt_size = len2 + fmt_size + 2;
|
||||
if ((fmt_buff = grub_realloc(fmt_buff, fmt_size*sizeof(char))) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM);
|
||||
|
||||
while ((cp - string) < (int) len2) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
cp = parse_format(cp, fmt_buff, &len);
|
||||
switch (*cp) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
case 'c': /* FALLTHRU */
|
||||
if (lastpop <= 0)
|
||||
number++;
|
||||
lastpop = -1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 's':
|
||||
if (lastpop > 0)
|
||||
p_is_s[lastpop - 1] = dummy;
|
||||
++number;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cp++;
|
||||
i = (UChar(*cp) - '0');
|
||||
if (i >= 0 && i <= NUM_PARM) {
|
||||
lastpop = i;
|
||||
if (lastpop > *popcount)
|
||||
*popcount = lastpop;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
++number;
|
||||
++cp;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
cp++;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
cp += 2;
|
||||
lastpop = -1;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
cp++;
|
||||
while (isdigit(UChar(*cp))) {
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case 'm':
|
||||
case 'A':
|
||||
case 'O':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
lastpop = -1;
|
||||
number += 2;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
case '~':
|
||||
lastpop = -1;
|
||||
++number;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
/* will add 1 to first (usually two) parameters */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*cp != '\0')
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (number > NUM_PARM)
|
||||
number = NUM_PARM;
|
||||
return number;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
tparam_internal(const char *string, va_list ap)
|
||||
{
|
||||
char *p_is_s[NUM_PARM];
|
||||
long param[NUM_PARM];
|
||||
int popcount;
|
||||
int number;
|
||||
int len;
|
||||
int level;
|
||||
int x, y;
|
||||
int i;
|
||||
const char *cp = string;
|
||||
grub_size_t len2;
|
||||
static int dynamic_var[NUM_VARS];
|
||||
static int static_vars[NUM_VARS];
|
||||
|
||||
if (cp == 0)
|
||||
return 0;
|
||||
|
||||
out_used = out_size = fmt_size = 0;
|
||||
|
||||
len2 = (int) grub_strlen(cp);
|
||||
|
||||
/*
|
||||
* Find the highest parameter-number referred to in the format string.
|
||||
* Use this value to limit the number of arguments copied from the
|
||||
* variable-length argument list.
|
||||
*/
|
||||
number = analyze(cp, p_is_s, &popcount);
|
||||
if (fmt_buff == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < max(popcount, number); i++) {
|
||||
/*
|
||||
* A few caps (such as plab_norm) have string-valued parms.
|
||||
* We'll have to assume that the caller knows the difference, since
|
||||
* a char* and an int may not be the same size on the stack.
|
||||
*/
|
||||
if (p_is_s[i] != 0) {
|
||||
p_is_s[i] = va_arg(ap, char *);
|
||||
} else {
|
||||
param[i] = va_arg(ap, long int);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a termcap compatibility hack. If there are no explicit pop
|
||||
* operations in the string, load the stack in such a way that
|
||||
* successive pops will grab successive parameters. That will make
|
||||
* the expansion of (for example) \E[%d;%dH work correctly in termcap
|
||||
* style, which means tparam() will expand termcap strings OK.
|
||||
*/
|
||||
stack_ptr = 0;
|
||||
if (popcount == 0) {
|
||||
popcount = number;
|
||||
for (i = number - 1; i >= 0; i--)
|
||||
npush(param[i]);
|
||||
}
|
||||
|
||||
while ((cp - string) < (int) len2) {
|
||||
if (*cp != '%') {
|
||||
save_char(UChar(*cp));
|
||||
} else {
|
||||
tparam_base = cp++;
|
||||
cp = parse_format(cp, fmt_buff, &len);
|
||||
switch (*cp) {
|
||||
default:
|
||||
break;
|
||||
case '%':
|
||||
save_char('%');
|
||||
break;
|
||||
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
save_number(fmt_buff, npop(), len);
|
||||
break;
|
||||
|
||||
case 'c': /* FALLTHRU */
|
||||
save_char(npop());
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
save_number("%d", (int) grub_strlen(spop()), 0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
save_text(fmt_buff, spop(), len);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cp++;
|
||||
i = (UChar(*cp) - '1');
|
||||
if (i >= 0 && i < NUM_PARM) {
|
||||
if (p_is_s[i])
|
||||
spush(p_is_s[i]);
|
||||
else
|
||||
npush(param[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
cp++;
|
||||
if (isUPPER(*cp)) {
|
||||
i = (UChar(*cp) - 'A');
|
||||
static_vars[i] = npop();
|
||||
} else if (isLOWER(*cp)) {
|
||||
i = (UChar(*cp) - 'a');
|
||||
dynamic_var[i] = npop();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
cp++;
|
||||
if (isUPPER(*cp)) {
|
||||
i = (UChar(*cp) - 'A');
|
||||
npush(static_vars[i]);
|
||||
} else if (isLOWER(*cp)) {
|
||||
i = (UChar(*cp) - 'a');
|
||||
npush(dynamic_var[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
cp++;
|
||||
npush(UChar(*cp));
|
||||
cp++;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
number = 0;
|
||||
cp++;
|
||||
while (isdigit(UChar(*cp))) {
|
||||
number = (number * 10) + (UChar(*cp) - '0');
|
||||
cp++;
|
||||
}
|
||||
npush(number);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
npush(npop() + npop());
|
||||
break;
|
||||
|
||||
case '-':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x - y);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
npush(npop() * npop());
|
||||
break;
|
||||
|
||||
case '/':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(y ? (x / y) : 0);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(y ? (x % y) : 0);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
npush(npop() && npop());
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
npush(npop() || npop());
|
||||
break;
|
||||
|
||||
case '&':
|
||||
npush(npop() & npop());
|
||||
break;
|
||||
|
||||
case '|':
|
||||
npush(npop() | npop());
|
||||
break;
|
||||
|
||||
case '^':
|
||||
npush(npop() ^ npop());
|
||||
break;
|
||||
|
||||
case '=':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x == y);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x < y);
|
||||
break;
|
||||
|
||||
case '>':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x > y);
|
||||
break;
|
||||
|
||||
case '!':
|
||||
npush(!npop());
|
||||
break;
|
||||
|
||||
case '~':
|
||||
npush(~npop());
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (p_is_s[0] == 0)
|
||||
param[0]++;
|
||||
if (p_is_s[1] == 0)
|
||||
param[1]++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
case 't':
|
||||
x = npop();
|
||||
if (!x) {
|
||||
/* scan forward for %e or %; at level zero */
|
||||
cp++;
|
||||
level = 0;
|
||||
while (*cp) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
if (*cp == '?')
|
||||
level++;
|
||||
else if (*cp == ';') {
|
||||
if (level > 0)
|
||||
level--;
|
||||
else
|
||||
break;
|
||||
} else if (*cp == 'e' && level == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
/* scan forward for a %; at level zero */
|
||||
cp++;
|
||||
level = 0;
|
||||
while (*cp) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
if (*cp == '?')
|
||||
level++;
|
||||
else if (*cp == ';') {
|
||||
if (level > 0)
|
||||
level--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ';':
|
||||
break;
|
||||
|
||||
} /* endswitch (*cp) */
|
||||
} /* endelse (*cp == '%') */
|
||||
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
cp++;
|
||||
} /* endwhile (*cp) */
|
||||
|
||||
get_space(1);
|
||||
out_buff[out_used] = '\0';
|
||||
|
||||
return (out_buff);
|
||||
}
|
||||
|
||||
char *
|
||||
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);
|
||||
return result;
|
||||
}
|
316
grub-core/term/usb_keyboard.c
Normal file
316
grub-core/term/usb_keyboard.c
Normal file
|
@ -0,0 +1,316 @@
|
|||
/* Support for the HID Boot Protocol. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008, 2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/term.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/usb.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
|
||||
static char keyboard_map[128] =
|
||||
{
|
||||
'\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
|
||||
'3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[',
|
||||
']', '\\', '#', ';', '\'', '`', ',', '.',
|
||||
'/', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', GRUB_TERM_HOME, GRUB_TERM_PPAGE, GRUB_TERM_DC, GRUB_TERM_END, GRUB_TERM_NPAGE, GRUB_TERM_RIGHT,
|
||||
GRUB_TERM_LEFT, GRUB_TERM_DOWN, GRUB_TERM_UP
|
||||
};
|
||||
|
||||
static char keyboard_map_shift[128] =
|
||||
{
|
||||
'\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D',
|
||||
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
||||
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
|
||||
'#', '$', '%', '^', '&', '*', '(', ')',
|
||||
'\n', '\0', '\0', '\0', ' ', '_', '+', '{',
|
||||
'}', '|', '#', ':', '"', '`', '<', '>',
|
||||
'?'
|
||||
};
|
||||
|
||||
|
||||
/* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
|
||||
#define USB_HID_GET_REPORT 0x01
|
||||
#define USB_HID_GET_IDLE 0x02
|
||||
#define USB_HID_GET_PROTOCOL 0x03
|
||||
#define USB_HID_SET_REPORT 0x09
|
||||
#define USB_HID_SET_IDLE 0x0A
|
||||
#define USB_HID_SET_PROTOCOL 0x0B
|
||||
|
||||
#define USB_HID_BOOT_SUBCLASS 0x01
|
||||
#define USB_HID_KBD_PROTOCOL 0x01
|
||||
|
||||
static int grub_usb_keyboard_checkkey (struct grub_term_input *term);
|
||||
static int grub_usb_keyboard_getkey (struct grub_term_input *term);
|
||||
static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term);
|
||||
|
||||
static struct grub_term_input grub_usb_keyboard_term =
|
||||
{
|
||||
.checkkey = grub_usb_keyboard_checkkey,
|
||||
.getkey = grub_usb_keyboard_getkey,
|
||||
.getkeystatus = grub_usb_keyboard_getkeystatus,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
struct grub_usb_keyboard_data
|
||||
{
|
||||
grub_usb_device_t usbdev;
|
||||
grub_uint8_t status;
|
||||
int key;
|
||||
struct grub_usb_desc_endp *endp;
|
||||
};
|
||||
|
||||
static struct grub_term_input grub_usb_keyboards[16];
|
||||
|
||||
static void
|
||||
grub_usb_keyboard_detach (grub_usb_device_t usbdev,
|
||||
int config __attribute__ ((unused)),
|
||||
int interface __attribute__ ((unused)))
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
|
||||
{
|
||||
struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
|
||||
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
if (data->usbdev != usbdev)
|
||||
continue;
|
||||
|
||||
grub_term_unregister_input (&grub_usb_keyboards[i]);
|
||||
grub_free ((char *) grub_usb_keyboards[i].name);
|
||||
grub_usb_keyboards[i].name = NULL;
|
||||
grub_free (grub_usb_keyboards[i].data);
|
||||
grub_usb_keyboards[i].data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||
{
|
||||
unsigned curnum;
|
||||
struct grub_usb_keyboard_data *data;
|
||||
struct grub_usb_desc_endp *endp = NULL;
|
||||
int j;
|
||||
|
||||
grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
|
||||
usbdev->descdev.class, usbdev->descdev.subclass,
|
||||
usbdev->descdev.protocol, configno, interfno);
|
||||
|
||||
for (curnum = 0; curnum < ARRAY_SIZE (grub_usb_keyboards); curnum++)
|
||||
if (!grub_usb_keyboards[curnum].data)
|
||||
break;
|
||||
|
||||
if (curnum == ARRAY_SIZE (grub_usb_keyboards))
|
||||
return 0;
|
||||
|
||||
if (usbdev->descdev.class != 0
|
||||
|| usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
|
||||
return 0;
|
||||
|
||||
if (usbdev->config[configno].interf[interfno].descif->subclass
|
||||
!= USB_HID_BOOT_SUBCLASS
|
||||
|| usbdev->config[configno].interf[interfno].descif->protocol
|
||||
!= USB_HID_KBD_PROTOCOL)
|
||||
return 0;
|
||||
|
||||
for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt;
|
||||
j++)
|
||||
{
|
||||
endp = &usbdev->config[configno].interf[interfno].descendp[j];
|
||||
|
||||
if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
|
||||
== GRUB_USB_EP_INTERRUPT)
|
||||
break;
|
||||
}
|
||||
if (j == usbdev->config[configno].interf[interfno].descif->endpointcnt)
|
||||
return 0;
|
||||
|
||||
grub_dprintf ("usb_keyboard", "HID found!\n");
|
||||
|
||||
data = grub_malloc (sizeof (*data));
|
||||
if (!data)
|
||||
{
|
||||
grub_print_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->usbdev = usbdev;
|
||||
data->endp = endp;
|
||||
|
||||
/* Place the device in boot mode. */
|
||||
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||
USB_HID_SET_PROTOCOL, 0, 0, 0, 0);
|
||||
|
||||
/* Reports every time an event occurs and not more often than that. */
|
||||
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
||||
USB_HID_SET_IDLE, 0<<8, 0, 0, 0);
|
||||
|
||||
grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
|
||||
sizeof (grub_usb_keyboards[curnum]));
|
||||
grub_usb_keyboards[curnum].data = data;
|
||||
usbdev->config[configno].interf[interfno].detach_hook
|
||||
= grub_usb_keyboard_detach;
|
||||
grub_usb_keyboards[curnum].name = grub_xasprintf ("usb_keyboard%d", curnum);
|
||||
if (!grub_usb_keyboards[curnum].name)
|
||||
{
|
||||
grub_print_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
grub_uint8_t report[8];
|
||||
grub_usb_err_t err;
|
||||
grub_memset (report, 0, sizeof (report));
|
||||
err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN,
|
||||
USB_HID_GET_REPORT, 0x0000, interfno,
|
||||
sizeof (report), (char *) report);
|
||||
if (err)
|
||||
{
|
||||
data->status = 0;
|
||||
data->key = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->status = report[0];
|
||||
data->key = report[2] ? : -1;
|
||||
}
|
||||
}
|
||||
|
||||
grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
grub_usb_keyboard_checkkey (struct grub_term_input *term)
|
||||
{
|
||||
grub_uint8_t data[8];
|
||||
grub_usb_err_t err;
|
||||
struct grub_usb_keyboard_data *termdata = term->data;
|
||||
grub_size_t actual;
|
||||
|
||||
if (termdata->key != -1)
|
||||
return termdata->key;
|
||||
|
||||
data[2] = 0;
|
||||
/* Poll interrupt pipe. */
|
||||
err = grub_usb_bulk_read_extended (termdata->usbdev,
|
||||
termdata->endp->endp_addr, sizeof (data),
|
||||
(char *) data, 10, &actual);
|
||||
if (err || actual < 1)
|
||||
return -1;
|
||||
|
||||
termdata->status = data[0];
|
||||
|
||||
if (actual < 3 || !data[2])
|
||||
return -1;
|
||||
|
||||
grub_dprintf ("usb_keyboard",
|
||||
"report: 0x%02x 0x%02x 0x%02x 0x%02x"
|
||||
" 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5], data[6], data[7]);
|
||||
|
||||
/* Check if the Control or Shift key was pressed. */
|
||||
if (data[0] & 0x01 || data[0] & 0x10)
|
||||
termdata->key = keyboard_map[data[2]] - 'a' + 1;
|
||||
else if (data[0] & 0x02 || data[0] & 0x20)
|
||||
termdata->key = keyboard_map_shift[data[2]];
|
||||
else
|
||||
termdata->key = keyboard_map[data[2]];
|
||||
|
||||
if (termdata->key == 0)
|
||||
grub_printf ("Unknown key 0x%x detected\n", data[2]);
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
return termdata->key;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_usb_keyboard_getkey (struct grub_term_input *term)
|
||||
{
|
||||
int ret;
|
||||
struct grub_usb_keyboard_data *termdata = term->data;
|
||||
|
||||
while (termdata->key == -1)
|
||||
grub_usb_keyboard_checkkey (term);
|
||||
|
||||
ret = termdata->key;
|
||||
|
||||
termdata->key = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
|
||||
{
|
||||
struct grub_usb_keyboard_data *termdata = term->data;
|
||||
int mods = 0;
|
||||
|
||||
/* Check Shift, Control, and Alt status. */
|
||||
if (termdata->status & 0x02 || termdata->status & 0x20)
|
||||
mods |= GRUB_TERM_STATUS_SHIFT;
|
||||
if (termdata->status & 0x01 || termdata->status & 0x10)
|
||||
mods |= GRUB_TERM_STATUS_CTRL;
|
||||
if (termdata->status & 0x04 || termdata->status & 0x40)
|
||||
mods |= GRUB_TERM_STATUS_ALT;
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
struct grub_usb_attach_desc attach_hook =
|
||||
{
|
||||
.class = GRUB_USB_CLASS_HID,
|
||||
.hook = grub_usb_keyboard_attach
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(usb_keyboard)
|
||||
{
|
||||
grub_usb_register_attach_hook_class (&attach_hook);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(usb_keyboard)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
|
||||
if (grub_usb_keyboards[i].data)
|
||||
{
|
||||
grub_term_unregister_input (&grub_usb_keyboards[i]);
|
||||
grub_free ((char *) grub_usb_keyboards[i].name);
|
||||
grub_usb_keyboards[i].name = NULL;
|
||||
grub_usb_keyboards[i].data = 0;
|
||||
}
|
||||
grub_usb_unregister_attach_hook_class (&attach_hook);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue