From 7d54a86a526e4ce2ed629367a2fe3c097226bc68 Mon Sep 17 00:00:00 2001 From: okuji Date: Sun, 20 Aug 2000 06:00:20 +0000 Subject: [PATCH] add more serial console support. two new commmands, serial and terminal, are added. --- ChangeLog | 27 ++++++ grub/asmstub.c | 16 +++- stage2/builtins.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++ stage2/char_io.c | 48 +++++----- 4 files changed, 301 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c9d4b8be..6cdca40ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2000-08-20 OKUJI Yoshinori + + 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 The image `nbgrub' now relocates itself from 0x10000 to 0x8000, diff --git a/grub/asmstub.c b/grub/asmstub.c index 5fd336d0f..c8fd93ba7 100644 --- a/grub/asmstub.c +++ b/grub/asmstub.c @@ -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; diff --git a/stage2/builtins.c b/stage2/builtins.c index 4f76d604a..ecbde55af 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -26,6 +26,10 @@ # include #endif +#ifdef SUPPORT_SERIAL +# include +#endif + #ifdef GRUB_UTIL # include # include @@ -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, diff --git a/stage2/char_io.c b/stage2/char_io.c index c5ad71bb9..53d651ed0 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -19,7 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "shared.h" +#include + +#ifdef SUPPORT_SERIAL +# include +#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 */ }