add more serial console support. two new commmands, serial and terminal, are added.

This commit is contained in:
okuji 2000-08-20 06:00:20 +00:00
parent 211c9922c4
commit 7d54a86a52
4 changed files with 301 additions and 27 deletions

View file

@ -1,3 +1,30 @@
2000-08-20 OKUJI Yoshinori <okuji@gnu.org>
Now the serial console support is partially working.
* grub/asmstub.c (serial_checkkey): Specify a pointer to TIMEOUT
as the fifth argument to select.
(serial_get_port): New function. Just a dummy.
(serial_init): If a serial device is opened, close SERIAL_FD
before opeing a new serial device.
Don't specify O_NDELAY to open.
* stage2/builtins.c [SUPPORT_SERIAL]: Include serial.h.
(serial_func): New function.
(builtin_serial): New variable.
(terminal_func): New function.
(builtin_terminal): New variable.
(builtin_table): Add pointers to BUILTIN_SERIAL and
BUILTIN_TERMINAL.
* stage2/char_io.c [SUPPORT_SERIAL]: Include serial.h.
(getkey) [SUPPORT_SERIAL]: If both TERMINAL_CONSOLE and
TERMINAL_SERIAL are set in TERMINAL simultaneously, print a
warning and force the console terminal.
(checkkey) [SUPPORT_SERIAL]: If TERMINAL_SERIAL is set in
TERMINAL, call serial_checkkey.
(grub_putchar) [SUPPORT_SERIAL]: If TERMINAL_SERIAL is set in
TERMINAL, call serial_putchar. If C is a newline, print a
carriage return, before printing a newline.
2000-08-15 OKUJI Yoshinori <okuji@gnu.org>
The image `nbgrub' now relocates itself from 0x10000 to 0x8000,

View file

@ -846,7 +846,7 @@ serial_checkkey (void)
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
return select (serial_fd + 1, &fds, 0, 0, 0) > 0 ? : -1;
return select (serial_fd + 1, &fds, 0, 0, &timeout) > 0 ? : -1;
}
/* The serial version of grub_putchar. */
@ -880,6 +880,14 @@ get_termios_speed (int speed)
return B0;
}
/* Get the port number of the unit UNIT. In the grub shell, this doesn't
make sense. */
unsigned short
serial_get_port (int unit)
{
return 0;
}
/* Initialize a serial device. In the grub shell, PORT is unused. */
int
serial_init (unsigned short port, unsigned int speed,
@ -892,8 +900,12 @@ serial_init (unsigned short port, unsigned int speed,
if (! serial_device)
return 0;
/* If a serial device is already opened, close it first. */
if (serial_fd >= 0)
close (serial_fd);
/* Open the device file. */
serial_fd = open (serial_device, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
serial_fd = open (serial_device, O_RDWR | O_NOCTTY | O_SYNC);
if (serial_fd < 0)
return 0;

View file

@ -26,6 +26,10 @@
# include <etherboot.h>
#endif
#ifdef SUPPORT_SERIAL
# include <serial.h>
#endif
#ifdef GRUB_UTIL
# include <stdio.h>
# include <device.h>
@ -2635,6 +2639,152 @@ static struct builtin builtin_rootnoverify =
" derived from attempting the mount will NOT work correctly."
};
/* serial */
static int
serial_func (char *arg, int flags)
{
#ifdef SUPPORT_SERIAL
unsigned short port = serial_get_port (0);
unsigned int speed = 9600;
int word_len = UART_8BITS_WORD;
int parity = UART_NO_PARITY;
int stop_bit_len = UART_1_STOP_BIT;
/* Process GNU-style long options.
FIXME: We should implement a getopt-like function, to avoid
duplications. */
while (1)
{
if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
{
char *p = arg + sizeof ("--unit=") - 1;
int unit;
if (! safe_parse_maxint (&p, &unit))
return 1;
if (unit < 0 || unit > 3)
{
errnum = ERR_DEV_VALUES;
return 1;
}
port = serial_get_port (unit);
}
else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
{
char *p = arg + sizeof ("--port=") - 1;
int num;
if (! safe_parse_maxint (&p, &num))
return 1;
port = (unsigned short) num;
}
else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
{
char *p = arg + sizeof ("--word=") - 1;
int len;
if (! safe_parse_maxint (&p, &len))
return 1;
switch (len)
{
case 5: word_len = UART_5BITS_WORD; break;
case 6: word_len = UART_6BITS_WORD; break;
case 7: word_len = UART_7BITS_WORD; break;
case 8: word_len = UART_8BITS_WORD; break;
default:
errnum = ERR_BAD_ARGUMENT;
return 1;
}
}
else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
{
char *p = arg + sizeof ("--stop=") - 1;
int len;
if (! safe_parse_maxint (&p, &len))
return 1;
switch (len)
{
case 1: stop_bit_len = UART_1_STOP_BIT; break;
case 2: stop_bit_len = UART_2_STOP_BITS; break;
default:
errnum = ERR_BAD_ARGUMENT;
return 1;
}
}
else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
{
char *p = arg + sizeof ("--parity=") - 1;
if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
parity = UART_NO_PARITY;
else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
parity = UART_ODD_PARITY;
else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
parity = UART_EVEN_PARITY;
else
{
errnum = ERR_BAD_ARGUMENT;
return 1;
}
}
# ifdef GRUB_UTIL
/* In the grub shell, don't use any port number but open a tty
device instead. */
else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
{
char *p = arg + sizeof ("--device=") - 1;
char dev[256]; /* XXX */
char *q = dev;
while (*p && ! grub_isspace (*p))
*q++ = *p++;
*q = 0;
set_serial_device (dev);
}
# endif /* GRUB_UTIL */
else
break;
arg = skip_to (0, arg);
}
/* Initialize the serial unit. */
if (! serial_init (port, speed, word_len, parity, stop_bit_len))
{
errnum = ERR_BAD_ARGUMENT;
return 1;
}
return 0;
#else /* ! SUPPORT_SERIAL */
errnum = ERR_UNRECOGNIZED;
return 1;
#endif /* ! SUPPORT_SERIAL */
}
static struct builtin builtin_serial =
{
"serial",
serial_func,
BUILTIN_MENU | BUILTIN_CMDLINE,
"serial [--unit=UNIT] [--port=PORT] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
"Initialize a serial device. UNIT is a digit that specifies which serial"
" device is used (e.g. 0 == COM1). If you need to specify the port number,"
" set it by --port. WORD is the word length, PARITY is the type of parity,"
" which is one of `no', `odd' and `even'. STOP is the length of stop bit(s)."
" The option --device can be used only in the grub shell, which specifies"
" the file name of a tty device. The default values are COM1, 8N1."
};
/* setkey */
struct keysym
@ -3112,6 +3262,91 @@ static struct builtin builtin_setup =
" to tell GRUB the file name under your OS."
};
/* terminal */
static int
terminal_func (char *arg, int flags)
{
/* If no argument is specified, show current setting. */
if (! *arg)
{
if (terminal & TERMINAL_CONSOLE)
grub_printf ("console\n");
#ifdef SUPPORT_SERIAL
else if (terminal & TERMINAL_SERIAL)
grub_printf ("serial\n");
#endif /* SUPPORT_SERIAL */
return 0;
}
/* Clear current setting. */
terminal = 0;
while (1)
{
if (grub_memcmp (arg, "console", sizeof ("console") - 1) == 0)
terminal |= TERMINAL_CONSOLE;
#ifdef SUPPORT_SERIAL
else if (grub_memcmp (arg, "serial", sizeof ("serial") - 1) == 0)
terminal |= TERMINAL_SERIAL;
#endif /* SUPPORT_SERIAL */
else
break;
arg = skip_to (0, arg);
}
#ifdef SUPPORT_SERIAL
/* If a seial console is turned on, wait until the user pushes any key. */
if (terminal & TERMINAL_SERIAL)
{
int time1, time2 = -1;
/* Get current time. */
while ((time1 = getrtsecs ()) == 0xFF)
;
/* Wait for a key input. */
while (1)
{
if ((terminal & TERMINAL_CONSOLE) && console_checkkey () != -1)
{
terminal = TERMINAL_CONSOLE;
(void) getkey ();
break;
}
else if ((terminal & TERMINAL_SERIAL) && serial_checkkey () != -1)
{
terminal = TERMINAL_SERIAL;
(void) getkey ();
break;
}
/* Prompt the user, once per sec. */
if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
{
grub_printf ("Press any key to continue.\n");
time2 = time1;
}
}
}
#endif /* SUPPORT_SERIAL */
return 0;
}
static struct builtin builtin_terminal =
{
"terminal",
terminal_func,
BUILTIN_MENU | BUILTIN_CMDLINE,
"terminal [console] [serial]",
"Select a terminal. When serial is specified, wait until you push any key"
" to continue. If both console and serial are specified, the terminal"
" to which you input a key first will be selected. If no argument is"
" specified, print current setting."
};
/* testload */
static int
@ -3363,8 +3598,10 @@ struct builtin *builtin_table[] =
&builtin_reboot,
&builtin_root,
&builtin_rootnoverify,
&builtin_serial,
&builtin_setkey,
&builtin_setup,
&builtin_terminal,
&builtin_testload,
&builtin_tftpserver,
&builtin_timeout,

View file

@ -19,7 +19,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "shared.h"
#include <shared.h>
#ifdef SUPPORT_SERIAL
# include <serial.h>
#endif
void
print_error (void)
@ -749,29 +753,18 @@ getkey (void)
if (terminal == TERMINAL_CONSOLE)
c = console_getkey ();
#ifdef serial_console_is_not_implemented_yet
#ifdef SUPPORT_SERIAL
else if (terminal == TERMINAL_SERIAL)
c = serial_getkey ();
else
{
while (1)
{
c = console_checkkey ();
if (c != -1)
{
c = console_getkey ();
break;
}
c = serial_checkkey ();
if (c != -1)
{
c = serial_getkey ();
break;
}
}
grub_printf ("\
Warning: Both the console and serial terminals are enabled in getkey!
The serial terminal will be disabled.\n");
terminal = TERMINAL_CONSOLE;
c = console_getkey ();
}
#endif
#endif /* SUPPORT_SERIAL */
return c;
}
@ -785,10 +778,10 @@ checkkey (void)
if (terminal & TERMINAL_CONSOLE)
c = console_checkkey ();
#ifdef serial_console_is_not_implemented_yet
if (c == -1 && (terminal & TERMINAL_SERIAL))
#ifdef SUPPORT_SERIAL
if (terminal & TERMINAL_SERIAL)
c = serial_checkkey ();
#endif
#endif /* SUPPORT_SERIAL */
return c;
}
@ -809,10 +802,15 @@ grub_putchar (int c)
if (terminal & TERMINAL_CONSOLE)
console_putchar (c);
#ifdef serial_console_is_not_implemented_yet
# ifdef SUPPORT_SERIAL
if (terminal & TERMINAL_SERIAL)
serial_putchar (c);
#endif
{
if (c == '\n')
serial_putchar ('\r');
serial_putchar (c);
}
# endif /* SUPPORT_SERIAL */
#endif /* ! STAGE1_5 */
}