[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: x86 serial support
From: |
Omniflux |
Subject: |
Re: x86 serial support |
Date: |
Tue, 09 Aug 2005 18:41:20 -0600 |
User-agent: |
Mozilla Thunderbird 1.0 (Windows/20041206) |
It's been a few months, but here are some updated patches.
The terminfo patch probably needs to be applied first.
Yoshinori K. Okuji wrote:
> - Naming issues. Since you copied the code from GRUB Legacy, some names
> are not appropriate in GRUB 2. For example, the global function
> declared in terminfo.h do not use the prefix 'grub_' at all.
I think I have fixed these all correctly...
> - Module separation. I think it would be better to have a separate
> module for terminfo, because we might be able to use it for other
> terminals as well as serial console, say, parallel console.
Done.
> - ChangeLog. Please write ChangeLog entries for your changes.
Attached.
> BTW, do you have any suggestion about the so-called "dumb terminal"?
> Because supporting dumb terminal is horrible, I hesitate to support it
> in GRUB 2, if there is no clean way to do it.
The only thing I can think of is to disable the menu and replace clear
screen with a newline, which is what Legacy does IIRC.
I need some input on how to complete the function
grub_terminfo_set_current in term/terminfo.c.
Feedback on anything else would also be appreciated.
Thanks!
--
Omniflux
diff -uNr grub2/conf/i386-pc.rmk grub2.terminfo/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk 2005-08-09 08:39:50.000000000 -0600
+++ grub2.terminfo/conf/i386-pc.rmk 2005-08-09 17:46:45.000000000 -0600
@@ -110,7 +110,7 @@
font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
- help.mod default.mod timeout.mod configfile.mod
+ help.mod default.mod timeout.mod configfile.mod terminfo.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -211,6 +211,10 @@
font_mod_SOURCES = font/manager.c
font_mod_CFLAGS = $(COMMON_CFLAGS)
+# For terminfo.mod.
+terminfo_mod_SOURCES = term/terminfo.c term/tparm.c
+terminfo_mod_CFLAGS = $(COMMON_CFLAGS)
+
# For _multiboot.mod.
_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c
_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
diff -uNr grub2/include/grub/terminfo.h grub2.terminfo/include/grub/terminfo.h
--- grub2/include/grub/terminfo.h 1969-12-31 17:00:00.000000000 -0700
+++ grub2.terminfo/include/grub/terminfo.h 2005-08-09 17:46:45.000000000
-0600
@@ -0,0 +1,49 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_TERMINFO_HEADER
+#define GRUB_TERMINFO_HEADER 1
+
+#include <grub/err.h>
+#include <grub/symbol.h>
+#include <grub/types.h>
+
+typedef struct terminfo
+{
+ char *name;
+
+ char *gotoxy;
+ char *cls;
+ char *reverse_video_on;
+ char *reverse_video_off;
+ char *cursor_on;
+ char *cursor_off;
+} terminfo;
+
+char * EXPORT_FUNC(grub_terminfo_get_current) (void);
+grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (const char *);
+
+void EXPORT_FUNC(grub_terminfo_gotoxy) (const grub_uint8_t x, const
grub_uint8_t y);
+void EXPORT_FUNC(grub_terminfo_cls) (void);
+void EXPORT_FUNC(grub_terminfo_reverse_video_on) (void);
+void EXPORT_FUNC(grub_terminfo_reverse_video_off) (void);
+void EXPORT_FUNC(grub_terminfo_cursor_on) (void);
+void EXPORT_FUNC(grub_terminfo_cursor_off) (void);
+
+#endif /* ! GRUB_TERMINFO_HEADER */
diff -uNr grub2/include/grub/tparm.h grub2.terminfo/include/grub/tparm.h
--- grub2/include/grub/tparm.h 1969-12-31 17:00:00.000000000 -0700
+++ grub2.terminfo/include/grub/tparm.h 2005-08-09 17:46:45.000000000 -0600
@@ -0,0 +1,28 @@
+/* tparm.h - parameter formatting of terminfo */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2005 Free Software Foundation, Inc.
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_TPARM_HEADER
+#define GRUB_TPARM_HEADER 1
+
+
+/* Function prototypes. */
+char *grub_terminfo_tparm (const char *string, ...);
+
+#endif /* ! GRUB_TPARM_HEADER */
diff -uNr grub2/term/terminfo.c grub2.terminfo/term/terminfo.c
--- grub2/term/terminfo.c 1969-12-31 17:00:00.000000000 -0700
+++ grub2.terminfo/term/terminfo.c 2005-08-09 17:46:45.000000000 -0600
@@ -0,0 +1,157 @@
+/* terminfo.c - simple terminfo module */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005 Free Software Foundation, Inc.
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * 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/normal.h>
+#include <grub/term.h>
+#include <grub/terminfo.h>
+#include <grub/tparm.h>
+
+static struct terminfo term;
+
+/* Get current terminfo name. */
+inline char *
+grub_terminfo_get_current (void)
+{
+ return term.name;
+}
+
+/* Set current terminfo type. */
+grub_err_t
+grub_terminfo_set_current (const char *str)
+{
+ /* 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.
+ */
+
+ if (grub_strcmp ("vt100", str) == 0)
+ {
+ term.name = grub_strdup ("vt100");
+ term.gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
+ term.cls = grub_strdup ("\e[H\e[J");
+ term.reverse_video_on = grub_strdup ("\e[7m");
+ term.reverse_video_off = grub_strdup ("\e[m");
+ term.cursor_on = grub_strdup ("\e[?25l");
+ term.cursor_off = grub_strdup ("\e[?25h");
+ return GRUB_ERR_NONE;
+ }
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type.");
+}
+
+/* Wrapper for grub_putchar to write strings. */
+static void putstr (const char *str)
+{
+ while (*str)
+ grub_putchar (*str++);
+}
+
+/* Move the cursor to the given position starting with "0". */
+void
+grub_terminfo_gotoxy (const grub_uint8_t x, const grub_uint8_t y)
+{
+ putstr (grub_terminfo_tparm (term.gotoxy, y, x));
+}
+
+/* Clear the screen. */
+void
+grub_terminfo_cls (void)
+{
+ putstr (grub_terminfo_tparm (term.cls));
+}
+
+/* Set reverse video mode on. */
+void
+grub_terminfo_reverse_video_on (void)
+{
+ putstr (grub_terminfo_tparm (term.reverse_video_on));
+}
+
+/* Set reverse video mode off. */
+void
+grub_terminfo_reverse_video_off (void)
+{
+ putstr (grub_terminfo_tparm (term.reverse_video_off));
+}
+
+/* Show cursor. */
+void
+grub_terminfo_cursor_on (void)
+{
+ putstr (grub_terminfo_tparm (term.cursor_on));
+}
+
+/* Hide cursor. */
+void
+grub_terminfo_cursor_off (void)
+{
+ putstr (grub_terminfo_tparm (term.cursor_off));
+}
+
+/* GRUB Command. */
+
+static grub_err_t
+grub_cmd_terminfo (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc, char **args)
+{
+ if (argc == 0)
+ {
+ grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current());
+ return GRUB_ERR_NONE;
+ }
+ else if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters.");
+ else
+ return grub_terminfo_set_current (args[0]);
+}
+
+GRUB_MOD_INIT
+{
+ (void)mod; /* To stop warning. */
+ grub_register_command ("terminfo", grub_cmd_terminfo, GRUB_COMMAND_FLAG_BOTH,
+ "terminfo [TERM...]", "Set terminfo type.", 0);
+ grub_terminfo_set_current ("vt100");
+}
+
+GRUB_MOD_FINI
+{
+ grub_unregister_command ("terminfo");
+}
diff -uNr grub2/term/tparm.c grub2.terminfo/term/tparm.c
--- grub2/term/tparm.c 1969-12-31 17:00:00.000000000 -0700
+++ grub2.terminfo/term/tparm.c 2005-08-09 17:46:45.000000000 -0600
@@ -0,0 +1,769 @@
+/****************************************************************************
+ * Copyright (c) 1998-2003,2004,2005 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, distribute with modifications, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included *
+ * in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ * *
+ * Except as contained in this notice, the name(s) of the above copyright *
+ * holders shall not be used in advertising or otherwise to promote the *
+ * sale, use or other dealings in this Software without prior written *
+ * authorization. *
+ ****************************************************************************/
+
+/**********************************************************************
+ * 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 <address@hidden> 2002
+ *
+ * Resync with ncurses-5.4 by Omniflux <address@hidden> 2005
+ **********************************************************************/
+
+/****************************************************************************
+ * Author: Zeyd M. Ben-Halim <address@hidden> 1992,1995 *
+ * and: Eric S. Raymond <address@hidden> *
+ * 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: tparm.c,v 1.1 2002/11/29 20:39:24 okuji Exp $")
+
+/*
+ * 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));
+ if (out_buff == 0)
+ // FIX ME! OOM, what now?
+ ;
+ }
+}
+
+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_sprintf(out_buff + out_used, 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_sprintf(out_buff + out_used, 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[] = "";
+
+ 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);
+ *popcount = 0;
+
+ 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;
+
+ va_start(ap, string);
+ result = tparam_internal(string, ap);
+ va_end(ap);
+ return result;
+}
diff -uNr grub2/conf/i386-pc.rmk grub2.serial/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk 2005-08-09 17:37:01.000000000 -0600
+++ grub2.serial/conf/i386-pc.rmk 2005-08-09 17:32:00.000000000 -0600
@@ -110,7 +110,8 @@
font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
- help.mod default.mod timeout.mod configfile.mod terminfo.mod
+ help.mod default.mod timeout.mod configfile.mod terminfo.mod \
+ serial.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -215,6 +216,10 @@
terminfo_mod_SOURCES = term/terminfo.c term/tparm.c
terminfo_mod_CFLAGS = $(COMMON_CFLAGS)
+# For serial.mod.
+serial_mod_SOURCES = term/i386/pc/serial.c
+serial_mod_CFLAGS = $(COMMON_CFLAGS)
+
# For _multiboot.mod.
_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c
_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
diff -uNr grub2/conf/i386-pc.rmk.orig grub2.serial/conf/i386-pc.rmk.orig
--- grub2/conf/i386-pc.rmk.orig 2005-08-09 08:39:50.000000000 -0600
+++ grub2.serial/conf/i386-pc.rmk.orig 2005-08-09 17:31:56.000000000 -0600
@@ -110,7 +110,7 @@
font.mod _multiboot.mod ls.mod boot.mod cmp.mod cat.mod \
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
- help.mod default.mod timeout.mod configfile.mod
+ help.mod default.mod timeout.mod configfile.mod terminfo.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -211,6 +211,10 @@
font_mod_SOURCES = font/manager.c
font_mod_CFLAGS = $(COMMON_CFLAGS)
+# For terminfo.mod.
+terminfo_mod_SOURCES = term/terminfo.c term/tparm.c
+terminfo_mod_CFLAGS = $(COMMON_CFLAGS)
+
# For _multiboot.mod.
_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c
_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
diff -uNr grub2/include/grub/i386/pc/serial.h
grub2.serial/include/grub/i386/pc/serial.h
--- grub2/include/grub/i386/pc/serial.h 1969-12-31 17:00:00.000000000 -0700
+++ grub2.serial/include/grub/i386/pc/serial.h 2005-08-09 17:32:00.000000000
-0600
@@ -0,0 +1,97 @@
+/* serial.h - serial device interface */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000,2001,2002,2005 Free Software Foundation, Inc.
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_SERIAL_MACHINE_HEADER
+#define GRUB_SERIAL_MACHINE_HEADER 1
+
+/* Macros. */
+
+/* The offsets of UART registers. */
+#define UART_TX 0
+#define UART_RX 0
+#define UART_DLL 0
+#define UART_IER 1
+#define UART_DLH 1
+#define UART_IIR 2
+#define UART_FCR 2
+#define UART_LCR 3
+#define UART_MCR 4
+#define UART_LSR 5
+#define UART_MSR 6
+#define UART_SR 7
+
+/* For LSR bits. */
+#define UART_DATA_READY 0x01
+#define UART_EMPTY_TRANSMITTER 0x20
+
+/* The type of parity. */
+#define UART_NO_PARITY 0x00
+#define UART_ODD_PARITY 0x08
+#define UART_EVEN_PARITY 0x18
+
+/* The type of word length. */
+#define UART_5BITS_WORD 0x00
+#define UART_6BITS_WORD 0x01
+#define UART_7BITS_WORD 0x02
+#define UART_8BITS_WORD 0x03
+
+/* The type of the length of stop bit. */
+#define UART_1_STOP_BIT 0x00
+#define UART_2_STOP_BITS 0x04
+
+/* the switch of DLAB. */
+#define UART_DLAB 0x80
+
+/* Enable the FIFO. */
+#define UART_ENABLE_FIFO 0xC7
+
+/* Turn on DTR, RTS, and OUT2. */
+#define UART_ENABLE_MODEM 0x0B
+
+/* Read a byte from a port. */
+static inline unsigned char
+inb (const unsigned short port)
+{
+ unsigned char value;
+
+ asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port));
+ asm volatile ("outb %%al, $0x80" : : );
+
+ return value;
+}
+
+/* Write a byte to a port. */
+static inline void
+outb (const unsigned short port, const unsigned char value)
+{
+ asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port));
+ asm volatile ("outb %%al, $0x80" : : );
+}
+
+/* Return the port number for the UNITth serial device. */
+static inline unsigned short
+serial_hw_get_port (const unsigned short unit)
+{
+ /* The BIOS data area. */
+ const unsigned short *addr = (const unsigned short *) 0x0400;
+ return addr[unit];
+}
+
+#endif /* ! GRUB_SERIAL_MACHINE_HEADER */
diff -uNr grub2/term/i386/pc/serial.c grub2.serial/term/i386/pc/serial.c
--- grub2/term/i386/pc/serial.c 1969-12-31 17:00:00.000000000 -0700
+++ grub2.serial/term/i386/pc/serial.c 2005-08-09 17:36:25.000000000 -0600
@@ -0,0 +1,575 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/machine/serial.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/arg.h>
+#include <grub/terminfo.h>
+
+#define TEXT_WIDTH 80
+#define TEXT_HEIGHT 25
+
+static unsigned int xpos, ypos;
+static unsigned int keep_track = 1;
+static unsigned int registered = 0;
+
+/* An input buffer. */
+static char input_buf[8];
+static unsigned int npending = 0;
+
+/* Argument options. */
+static const struct grub_arg_option options[] =
+{
+ {"unit", 'u', 0, "Set the serial unit", 0, ARG_TYPE_INT},
+ {"port", 'p', 0, "Set the serial port address", 0, ARG_TYPE_STRING},
+ {"speed", 's', 0, "Set the serial port speed", 0, ARG_TYPE_INT},
+ {"word", 'w', 0, "Set the serial port word length", 0, ARG_TYPE_INT},
+ {"parity", 'r', 0, "Set the serial port parity", 0, ARG_TYPE_STRING},
+ {"stop", 't', 0, "Set the serial port stop bits", 0, ARG_TYPE_INT},
+ {0, 0, 0, 0, 0, 0}
+};
+
+/* Serial port settings. */
+struct serial_port
+{
+ unsigned short port;
+ unsigned short divisor;
+ unsigned short word_len;
+ unsigned int parity;
+ unsigned short stop_bits;
+};
+
+/* Serial port settings. */
+static struct serial_port serial_settings;
+
+/* Fetch a key. */
+static int
+serial_hw_fetch (void)
+{
+ if (inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
+ return inb (serial_settings.port + UART_RX);
+
+ return -1;
+}
+
+/* Put a chararacter. */
+static void
+serial_hw_put (const int c)
+{
+ unsigned int timeout = 100000;
+
+ /* Wait until the transmitter holding register is empty. */
+ while ((inb (serial_settings.port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
+ {
+ if (--timeout == 0)
+ /* There is something wrong. But what can I do? */
+ return;
+ }
+
+ outb (serial_settings.port + UART_TX, c);
+}
+
+static void
+serial_translate_key_sequence (void)
+{
+ const struct
+ {
+ char key;
+ char ascii;
+ }
+
+ three_code_table[] =
+ {
+ {'A', 16},
+ {'B', 14},
+ {'C', 6},
+ {'D', 2},
+ {'F', 5},
+ {'H', 1},
+ {'4', 4}
+ };
+
+ const struct
+ {
+ short key;
+ char ascii;
+ }
+
+ four_code_table[] =
+ {
+ {('1' | ('~' << 8)), 1},
+ {('3' | ('~' << 8)), 4},
+ {('5' | ('~' << 8)), 7},
+ {('6' | ('~' << 8)), 3}
+ };
+
+ /* The buffer must start with "ESC [". */
+ if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
+ return;
+
+ if (npending >= 3)
+ {
+ unsigned int i;
+
+ for (i = 0; i < sizeof (three_code_table) / sizeof (three_code_table[0]);
i++)
+ if (three_code_table[i].key == input_buf[2])
+ {
+ input_buf[0] = three_code_table[i].ascii;
+ npending -= 2;
+ grub_memmove (input_buf + 1, input_buf + 3, npending - 1);
+ return;
+ }
+ }
+
+ if (npending >= 4)
+ {
+ unsigned int i;
+ short key = *((short *) (input_buf + 2));
+
+ for (i = 0; i < sizeof (four_code_table) / sizeof (four_code_table[0]);
i++)
+ if (four_code_table[i].key == key)
+ {
+ input_buf[0] = four_code_table[i].ascii;
+ npending -= 3;
+ grub_memmove (input_buf + 1, input_buf + 4, npending - 1);
+ return;
+ }
+ }
+}
+
+static int
+fill_input_buf (const int nowait)
+{
+ int i;
+
+ for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
+ {
+ int c;
+
+ c = serial_hw_fetch ();
+ if (c >= 0)
+ {
+ input_buf[npending++] = c;
+
+ /* Reset the counter to zero, to wait for the same interval. */
+ i = 0;
+ }
+
+ if (nowait)
+ break;
+ }
+
+ /* Translate some key sequences. */
+ serial_translate_key_sequence ();
+
+ return npending;
+}
+
+/* Convert speed to divisor. */
+static unsigned short
+serial_get_divisor (const 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 < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
+ if (divisor_tab[i].speed == speed)
+ return divisor_tab[i].div;
+ return 0;
+}
+
+/* The serial version of checkkey. */
+static int
+grub_serial_checkkey (void)
+{
+ if (fill_input_buf (1))
+ return input_buf[0];
+ else
+ return -1;
+}
+
+/* The serial version of getkey. */
+static int
+grub_serial_getkey (void)
+{
+ int c;
+
+ while (! fill_input_buf (0))
+ ;
+
+ c = input_buf[0];
+ grub_memmove (input_buf, input_buf + 1, --npending);
+
+ return c;
+}
+
+/* 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_init (void)
+{
+ unsigned char status = 0;
+
+ /* Turn off the interupt. */
+ outb (serial_settings.port + UART_IER, 0);
+
+ /* Set DLAB. */
+ outb (serial_settings.port + UART_LCR, UART_DLAB);
+
+ /* Set the baud rate. */
+ outb (serial_settings.port + UART_DLL, serial_settings.divisor & 0xFF);
+ outb (serial_settings.port + UART_DLH, serial_settings.divisor >> 8 );
+
+ /* Set the line status. */
+ status |= serial_settings.parity
+ | serial_settings.word_len
+ | serial_settings.stop_bits;
+ outb (serial_settings.port + UART_LCR, status);
+
+ /* Enable the FIFO. */
+ outb (serial_settings.port + UART_FCR, UART_ENABLE_FIFO);
+
+ /* Turn on DTR, RTS, and OUT2. */
+ outb (serial_settings.port + UART_MCR, UART_ENABLE_MODEM);
+
+ /* Drain the input buffer. */
+ while (grub_serial_checkkey () != -1)
+ (void) grub_serial_getkey ();
+
+ /* FIXME: should check if the serial terminal was found. */
+
+ return GRUB_ERR_NONE;
+}
+
+/* The serial version of putchar. */
+static void
+grub_serial_putchar (grub_uint32_t c)
+{
+ /* Keep track of the cursor. */
+ if (keep_track)
+ {
+ /* The serial terminal does not have VGA fonts. */
+ if (c > 0x7F)
+ {
+ /* Better than nothing. */
+ switch (c)
+ {
+ case GRUB_TERM_DISP_LEFT:
+ c = '<';
+ break;
+
+ case GRUB_TERM_DISP_UP:
+ c = '^';
+ break;
+
+ case GRUB_TERM_DISP_RIGHT:
+ c = '>';
+ break;
+
+ case GRUB_TERM_DISP_DOWN:
+ c = 'v';
+ break;
+
+ case GRUB_TERM_DISP_HLINE:
+ c = '-';
+ break;
+
+ case GRUB_TERM_DISP_VLINE:
+ c = '|';
+ break;
+
+ case GRUB_TERM_DISP_UL:
+ case GRUB_TERM_DISP_UR:
+ case GRUB_TERM_DISP_LL:
+ case GRUB_TERM_DISP_LR:
+ c = '+';
+ break;
+
+ default:
+ break;
+ }
+ }
+ switch (c)
+ {
+ case '\a':
+ break;
+
+ case '\b':
+ case 127:
+ if (xpos > 0)
+ xpos--;
+ break;
+
+ case '\n':
+ if (ypos < TEXT_HEIGHT)
+ ypos++;
+ break;
+
+ case '\r':
+ xpos = 0;
+ break;
+
+ default:
+ if (xpos >= TEXT_WIDTH)
+ {
+ grub_putchar ('\r');
+ grub_putchar ('\n');
+ }
+ xpos++;
+ break;
+ }
+ }
+ serial_hw_put (c);
+}
+
+static grub_uint16_t
+grub_serial_getwh (void)
+{
+ return (TEXT_WIDTH << 8) | TEXT_HEIGHT;
+}
+
+static grub_uint16_t
+grub_serial_getxy (void)
+{
+ return ((xpos << 8) | ypos);
+}
+
+static void
+grub_serial_gotoxy (const grub_uint8_t x, const grub_uint8_t y)
+{
+ if (x > TEXT_WIDTH || y > TEXT_HEIGHT)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y);
+ }
+ else
+ {
+ keep_track = 0;
+ grub_terminfo_gotoxy (x, y);
+ keep_track = 1;
+
+ xpos = x;
+ ypos = y;
+ }
+}
+
+static void
+grub_serial_cls (void)
+{
+ keep_track = 0;
+ grub_terminfo_cls ();
+ keep_track = 1;
+
+ xpos = ypos = 0;
+}
+
+static void
+grub_serial_setcolorstate (const grub_term_color_state state)
+{
+ keep_track = 0;
+ switch (state)
+ {
+ case GRUB_TERM_COLOR_STANDARD:
+ case GRUB_TERM_COLOR_NORMAL:
+ grub_terminfo_reverse_video_off ();
+ break;
+ case GRUB_TERM_COLOR_HIGHLIGHT:
+ grub_terminfo_reverse_video_on ();
+ break;
+ default:
+ break;
+ }
+ keep_track = 1;
+}
+
+static void
+grub_serial_setcolor (const grub_uint8_t normal_color __attribute__
((unused)),
+ const grub_uint8_t highlight_color __attribute__
((unused)))
+{
+ /* FIXME */
+}
+
+static void
+grub_serial_setcursor (const int on)
+{
+ if (on)
+ grub_terminfo_cursor_on ();
+ else
+ grub_terminfo_cursor_off ();
+}
+
+static struct grub_term grub_serial_term =
+{
+ .name = "serial",
+ .init = 0,
+ .fini = 0,
+ .putchar = grub_serial_putchar,
+ .checkkey = grub_serial_checkkey,
+ .getkey = grub_serial_getkey,
+ .getwh = grub_serial_getwh,
+ .getxy = grub_serial_getxy,
+ .gotoxy = grub_serial_gotoxy,
+ .cls = grub_serial_cls,
+ .setcolorstate = grub_serial_setcolorstate,
+ .setcolor = grub_serial_setcolor,
+ .setcursor = grub_serial_setcursor,
+ .flags = 0,
+ .next = 0
+};
+
+static grub_err_t
+grub_cmd_serial (struct grub_arg_list *state,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct serial_port backup_settings = serial_settings;
+ grub_err_t hwiniterr;
+ int arg;
+
+ if (state[0].set)
+ {
+ arg = grub_strtoul (state[0].arg, 0, 0);
+ if (arg >= 0 && arg < 4)
+ serial_settings.port = serial_hw_get_port ((int) arg);
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number.");
+ }
+ if (state[1].set)
+ serial_settings.port = (unsigned short) grub_strtoul (state[1].arg, 0, 0);
+ if (state[2].set) {
+ serial_settings.divisor = serial_get_divisor ((unsigned int) grub_strtoul
(state[2].arg, 0, 0));
+ if (serial_settings.divisor == 0 )
+ {
+ serial_settings = backup_settings;
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed.");
+ }
+ }
+ if (state[3].set)
+ {
+ if (!grub_strcmp (state[3].arg, "5"))
+ serial_settings.word_len = UART_5BITS_WORD;
+ else if (!grub_strcmp (state[3].arg, "6"))
+ serial_settings.word_len = UART_6BITS_WORD;
+ else if (!grub_strcmp (state[3].arg, "7"))
+ serial_settings.word_len = UART_7BITS_WORD;
+ else if (!grub_strcmp (state[3].arg, "8"))
+ serial_settings.word_len = UART_8BITS_WORD;
+ else
+ {
+ serial_settings = backup_settings;
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad word length.");
+ }
+ }
+ if (state[4].set)
+ {
+ if (!grub_strcmp (state[4].arg, "no"))
+ serial_settings.parity = UART_NO_PARITY;
+ else if (!grub_strcmp (state[4].arg, "odd"))
+ serial_settings.parity = UART_ODD_PARITY;
+ else if (!grub_strcmp (state[4].arg, "even"))
+ serial_settings.parity = UART_EVEN_PARITY;
+ else
+ {
+ serial_settings = backup_settings;
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity.");
+ }
+ }
+ if (state[5].set)
+ {
+ if (!grub_strcmp (state[5].arg, "1"))
+ serial_settings.stop_bits = UART_1_STOP_BIT;
+ else if (!grub_strcmp (state[5].arg, "2"))
+ serial_settings.stop_bits = UART_2_STOP_BITS;
+ else
+ {
+ serial_settings = backup_settings;
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits.");
+ }
+ }
+
+ hwiniterr = serial_hw_init (); /* Initialize with new settings. */
+ if (hwiniterr == GRUB_ERR_NONE)
+ {
+ if (registered == 0) /* Register terminal if not yet registered. */
+ {
+ grub_term_register (&grub_serial_term);
+ registered = 1;
+ }
+ }
+ else /* Initialization with new settings failed. */
+ if (registered == 1) /* If terminal is registered, attempt to
restore previous settings. */
+ {
+ serial_settings = backup_settings;
+ if (serial_hw_init () != GRUB_ERR_NONE) /* If unable to restore
settings, unregister terminal. */
+ {
+ grub_term_unregister (&grub_serial_term);
+ registered = 0;
+ }
+ }
+ return hwiniterr;
+}
+
+GRUB_MOD_INIT
+{
+ (void)mod; /* To stop warning. */
+ grub_register_command ("serial", grub_cmd_serial, GRUB_COMMAND_FLAG_BOTH,
+ "serial [OPTIONS...]", "Configure serial port.",
options);
+ /* Set default settings. */
+ serial_settings.port = serial_hw_get_port (0);
+ serial_settings.divisor = serial_get_divisor (9600);
+ serial_settings.word_len = UART_8BITS_WORD;
+ serial_settings.parity = UART_NO_PARITY;
+ serial_settings.stop_bits = UART_1_STOP_BIT;
+}
+
+GRUB_MOD_FINI
+{
+ grub_unregister_command ("serial");
+ if (registered == 1) /* Unregister terminal only if registered. */
+ grub_term_unregister (&grub_serial_term);
+}
* term/terminfo.c: Copy from GRUB Legacy.
include/grub/terminfo.h: Likewise
Update for GRUB 2.
Remove unused functions.
Remove dependency on serial module.
Rename functions to match GRUB 2 coding style.
Add preliminary support for multiple terminfo types.
Add GRUB 2 command.
* term/tparm.c: Copy from GRUB Legacy.
include/grub/tparm.h: Likewise
Resync with ncurses-5.4.
Rename exported function to match GRUB 2 coding style
* conf/i386-pc.rmk (pkgdata_MODULES): Added terminfo.mod.
(terminfo_mod_SOURCES): New variable.
(terminfo_mod_CFLAGS): Likewise.
* term/i386/pc/serial.c: Copy from GRUB Legacy.
include/grub/i386/pc/serial.h: Likewise
Update for GRUB 2.
Rename functions to match GRUB 2 coding style.
Restructure code to minimize scopes and simplify functions.
Make assembly functions inline.
Add GRUB 2 command.
* conf/i386-pc.rmk (pkgdata_MODULES): Added serial.mod.
(serial_mod_SOURCES): New variable.
(serial_mod_CFLAGS): Likewise.
- Re: x86 serial support,
Omniflux <=