From: Omniflux <omniflux+lists@omniflux.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: x86 serial support
Date: Tue, 09 Aug 2005 18:41:20 -0600 [thread overview]
Message-ID: <42F94D30.7030204@omniflux.com> (raw)
In-Reply-To: <200503022233.18661.okuji@enbug.org>
[-- Attachment #1: Type: text/plain, Size: 1175 bytes --]
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
[-- Attachment #2: grub2.terminfo.diff --]
[-- Type: text/plain, Size: 27442 bytes --]
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
+
+\f
+/* 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 <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: 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;
+}
[-- Attachment #3: grub2.serial.diff --]
[-- Type: text/plain, Size: 19381 bytes --]
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);
+}
[-- Attachment #4: grub2.terminfo.changelog --]
[-- Type: text/plain, Size: 556 bytes --]
* 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.
[-- Attachment #5: grub2.serial.changelog --]
[-- Type: text/plain, Size: 390 bytes --]
* 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.
next prev parent reply other threads:[~2005-08-10 0:59 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-02-21 12:38 x86 serial support Omniflux
2005-03-02 21:33 ` Yoshinori K. Okuji
2005-08-10 0:41 ` Omniflux [this message]
2005-08-12 10:51 ` Vladimir Serbinenko
2005-08-12 16:01 ` Marco Gerards
2005-08-12 20:17 ` Yoshinori K. Okuji
2005-08-12 22:19 ` Douglas Wade Needham
2005-08-12 22:18 ` Omniflux
2005-08-14 13:03 ` Marco Gerards
2005-08-14 14:54 ` Yoshinori K. Okuji
2005-09-03 17:08 ` Yoshinori K. Okuji
2005-09-03 23:12 ` Marco Gerards
2005-09-11 19:46 ` Yoshinori K. Okuji
2005-09-04 0:59 ` Omniflux
2005-09-11 19:52 ` Yoshinori K. Okuji
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=42F94D30.7030204@omniflux.com \
--to=omniflux+lists@omniflux.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.