b1b797cb1b
* commands/blocklist.c: Add include file <grub/command.h>, remove <grub/normal.h> and <grub/arg.h>. (grub_cmd_blocklist): Use the new command interface. (GRUB_MOD_INIT): Likewise. (GRUB_MOD_FINI): Likewise. * commands/boot.c: Likewise. * commands/cat.c: Likewise. * commands/cmp.c: Likewise. * commands/configfile.c: Likewise. * commands/crc.c: Likewise. * commands/echo.c: Likewise. * commands/halt.c: Likewise. * commands/handler.c: Likewise. * commands/hdparm.c: Likewise. * commands/help.c: Likewise. * commands/hexdump.c: Likewise. * commands/loadenv.c: Likewise. * commands/ls.c: Likewise. * commands/lsmmap.c: Likewise. * commands/lspci.c: Likewise. * commands/loadenv.c: Likewise. * commands/read.c: Likewise. * commands/reboot.c: Likewise. * commands/search.c: Likewise. * commands/sleep.c: Likewise. * commands/test.c: Likewise. * commands/usbtest.c: Likewise. * commands/videotest.c: Likewise. * commands/i386/cpuid.c: Likewise. * commands/i386/pc/halt.c: Likewise. * commands/i386/pc/play.c: Likewise. * commands/i386/pc/pxecmd.c: Likewise. * commands/i386/pc/vbeinfo.c: Likewise. * commands/i386/pc/vbetest.c: Likewise. * commands/ieee1275/suspend.c: Likewise. * disk/loopback.c: Likewise. * font/font_cmd.c: Likewise. * hello/hello.c: Likewise. * loader/efi/appleloader.c: Likewise. * loader/efi/chainloader.c: Likewise. * loader/i386/bsd.c: Likewise. * loader/i386/efi/linux.c: Likewise. * loader/i386/ieee1275/linux.c: Likewise. * loader/i386/linux.c: Likewise. * loader/i386/pc/chainloader.c: Likewise. * loader/i386/pc/linux.c: Likewise. * loader/powerpc/ieee1275/linux.c: Likewise. * loader/multiboot_loader.c: Likewise. * term/gfxterm.c: Likewise. * term/i386/pc/serial.c: Likewise. * term/terminfo.c: Likewise. * term/i386/pc/vesafb.c: Removed <grub/arg.h>. * term/i386/pc/vga.c: Likewise. * video/readers/jpeg.c: Likewise. * video/readers/png.c: Likewise. * video/readers/tga.c: Likewise. * util/grub-fstest (cmd_loopback): Removed. (cmd_blocklist): Likewise. (cmd_ls): Likewise. (grub_register_command): Likewise. (grub_unregister_command): Likewise. (execute_command): Use grub_command_find to locate command and execute it. * include/grub/efi/chainloader.h: Removed. * loader/efi/chainloader_normal.c: Likewise. * loader/i386/bsd_normal.c: Likewise. * loader/i386/pc/chainloader_normal.c: Likewise. * loader/i386/pc/multiboot_normal.c: Likewise. * loader/linux_normal.c: Likewise. * loader/multiboot_loader_normal.c: Likewise. * loader/powerpc/ieee1275/linux_normal.c: Likewise. * gencmdlist.sh: Scan new registration command grub_register_extcmd and grub_register_command_p1. * conf/common.rmk (grub_fstest_SOURCES): Add kern/list.c, kern/command.c, lib/arg.c and commands/extcmd.c. (pkglib_MODULES): Remove boot.mod, and minicmd.mod and extcmd.mod. (minicmd_mod_SOURCES): New variable. (minicmd_mod_CFLAGS): Likewise. (minicmd_mod_LDFLAGS): Likewise. (extcmd_mod_SOURCES): Likewise. (extcmd_mod_CFLAGS): Likewise. (extcmd_mod_LDFLAGS): Likewise. (boot_mod_SOURCES): Removed. (boot_mod_CFLAGS): Likewise. (boot_mod_LDFLAGS): Likewise. * conf/i386-pc.rmk (kernel_img_SOURCES): Add kern/command.c and kern/corecmd.c. (kernel_img_HEADERS): Add command.h. (grub_emu_SOURCES): Remove commands/boot.c and normal/arg.c, add commands/minicmd.c, kern/command.c, kern/corecmd.c, commands/extcmd.c and lib/arg.c. (pkglib_MODULES): Change _linux.mod, _chain.mod, _bsd.mod and _multiboot.mod as linux.mod, chain.mod, bsd.mod and multiboot.mod, remove the corresponding normal mode command. (normal_mod_SOURCES): Remove normal/arg.c. * conf/i386-coreboot.rmk: Likewise. * conf/i386-efi.rmk: Likewise. * conf/i386-ieee1275.rmk: Likewise. * conf/powerpc-ieee1275.rmk: Likewise. * conf/x86_64-efi.rmk: Likewise. * include/grub/arg.h: Move from here ... * include/grub/lib/arg.h: ... to here. * normal/arg.c: Move from here ... * lib/arg.c: ... to here. * commands/extcmd.c: New file. * commands/minicmd.c: Likewise. * include/grub/command.h: Likewise. * include/grub/extcmd.h: Likewise. * kern/command.c: Likewise. * kern/corecmd.c: Likewise. * kern/list.c (grub_list_iterate): Return int instead of void. (grub_list_insert): New function. (grub_prio_list_insert): Likewise. * kern/rescue.c (grub_rescue_command): Removed. (grub_rescue_command_list): Likewise. (grub_rescue_register_command): Likewise. (grub_rescue_unregister_command): Likewise. (grub_rescue_cmd_boot): Move to minicmd.c (grub_rescue_cmd_help): Likewise. (grub_rescue_cmd_info): Likewise. (grub_rescue_cmd_boot): Likewise. (grub_rescue_cmd_testload): Likewise. (grub_rescue_cmd_dump): Likewise. (grub_rescue_cmd_rmmod): Likewise. (grub_rescue_cmd_lsmod): Likewise. (grub_rescue_cmd_exit): Likewise. (grub_rescue_print_devices): Moved to corecmd.c. (grub_rescue_print_files): Likewise. (grub_rescue_cmd_ls): Likewise. (grub_rescue_cmd_insmod): Likewise. (grub_rescue_cmd_set): Likewise. (grub_rescue_cmd_unset): Likewise. (attemp_normal_mode): Use grub_command_find to get normal module. (grub_enter_rescue_mode): Use grub_register_core_commands to register commands, remove grub_rescue_regiter_command calls. * normal/command.c (grub_regiser_command): Removed. (grub_unregister_command): Likewise. (grub_command_find): Likewise. (grub_iterate_commands): Likewise. (rescue_command): Likewise. (export_command): Moved to corecmd.c. (set_command): Removed. (unset_command): Likewise. (insmod_command): Likewise. (rmmod_command): Likewise. (lsmod_command): Likewise. (grub_command_init): Likewise. * normal/completion.c (iterate_command): Use cmd->prio to check for active command. (complete_arguments): Use grub_extcmd_t structure to find options. (grub_normal_do_completion): Change function grub_iterate_commands to grub_command_iterate. * normal/execute.c (grub_script_execute_cmd): No need to parse argument here. * normal/main.c (grub_dyncmd_dispatcher): New function. (read_command_list): Register unload commands as dyncmd. (grub_cmd_normal): Use new command interface, register rescue, unregister normal at entry, register normal, unregister rescue at exit. * include/grub/list.h (grub_list_test_t): New type. (grub_list_iterate): Return int instead of void. (grub_list_insert): New function. (GRUB_AS_NAMED_LIST_P): New macro. (GRUB_AS_PRIO_LIST): Likewise. (GRUB_AS_PRIO_LIST_P): Likewise. (GRUB_PRIO_LIST_PRIO_MASK): New constant. (GRUB_PRIO_LIST_FLAG_ACTIVE): Likewise. (grub_prio_list): New structure. (grub_prio_list_insert): New function. (grub_prio_list_remove): New inline function. * include/grub/normal.h: Remove <grub/arg.h>, add <grub/command.h>. (GRUB_COMMAND_FLAG_CMDLINE): Moved to command.h. (GRUB_COMMAND_FLAG_MENU): Likewise. (GRUB_COMMAND_FLAG_BOTH): Likewise. (GRUB_COMMAND_FLAG_TITLE): Likewise. (GRUB_COMMAND_FLAG_NO_ECHO): Likewise. (GRUB_COMMAND_FLAG_NO_ARG_PARSE): Removed. (GRUB_COMMAND_FLAG_NOT_LOADED): Likewise. (grub_command): Likewise. (grub_register_command): Likewise. (grub_command_find): Likewise. (grub_iterate_commands): Likewise. (grub_command_init): Likewise. (grub_arg_parse): Likewise. (grub_arg_show_help): Likewise. * include/grub/rescue.h (grub_rescue_register_command): Removed. (grub_rescue_unregister_command): Likewise. * include/grub/i386/bsd.h: Remove grub_rescue_cmd_freebsd, grub_rescue_cmd_openbsd, grub_rescue_cmd_netbsd, grub_rescue_cmd_freebsd_loadenv and grub_rescue_cmd_freebsd_module. * include/grub/i386/efi/loader.h: Remove grub_rescue_cmd_linux and grub_rescue_cmd_initrd. * include/grub/i386/loader.h: Likewise. * include/grub/x86_64/loader.h: Likewise. * include/grub/i386/pc/chainloader.h: Remove grub_chainloader_cmd.
632 lines
14 KiB
C
632 lines
14 KiB
C
/*
|
||
* GRUB -- GRand Unified Bootloader
|
||
* Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc.
|
||
*
|
||
* GRUB is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* GRUB is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include <grub/machine/machine.h>
|
||
#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/terminfo.h>
|
||
#include <grub/cpu/io.h>
|
||
#include <grub/extcmd.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;
|
||
|
||
#ifdef GRUB_MACHINE_PCBIOS
|
||
/* The BIOS data area. */
|
||
static const unsigned short *serial_hw_io_addr = (const unsigned short *) 0x0400;
|
||
#define GRUB_SERIAL_PORT_NUM 4
|
||
#else
|
||
static const unsigned short serial_hw_io_addr[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
|
||
#define GRUB_SERIAL_PORT_NUM (sizeof(serial_hw_io_addr)/sizeof(serial_hw_io_addr[0]))
|
||
#endif
|
||
|
||
/* Return the port number for the UNITth serial device. */
|
||
static inline unsigned short
|
||
serial_hw_get_port (const unsigned int unit)
|
||
{
|
||
if (unit < GRUB_SERIAL_PORT_NUM)
|
||
return serial_hw_io_addr[unit];
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
/* Fetch a key. */
|
||
static int
|
||
serial_hw_fetch (void)
|
||
{
|
||
if (grub_inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
|
||
return grub_inb (serial_settings.port + UART_RX);
|
||
|
||
return -1;
|
||
}
|
||
|
||
/* Put a character. */
|
||
static void
|
||
serial_hw_put (const int c)
|
||
{
|
||
unsigned int timeout = 100000;
|
||
|
||
/* Wait until the transmitter holding register is empty. */
|
||
while ((grub_inb (serial_settings.port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
|
||
{
|
||
if (--timeout == 0)
|
||
/* There is something wrong. But what can I do? */
|
||
return;
|
||
}
|
||
|
||
grub_outb (c, serial_settings.port + UART_TX);
|
||
}
|
||
|
||
static void
|
||
serial_translate_key_sequence (void)
|
||
{
|
||
static struct
|
||
{
|
||
char key;
|
||
char ascii;
|
||
}
|
||
three_code_table[] =
|
||
{
|
||
{'A', 16},
|
||
{'B', 14},
|
||
{'C', 6},
|
||
{'D', 2},
|
||
{'F', 5},
|
||
{'H', 1},
|
||
{'4', 4}
|
||
};
|
||
|
||
static 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 (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 interrupt. */
|
||
grub_outb (0, serial_settings.port + UART_IER);
|
||
|
||
/* Set DLAB. */
|
||
grub_outb (UART_DLAB, serial_settings.port + UART_LCR);
|
||
|
||
/* Set the baud rate. */
|
||
grub_outb (serial_settings.divisor & 0xFF, serial_settings.port + UART_DLL);
|
||
grub_outb (serial_settings.divisor >> 8, serial_settings.port + UART_DLH);
|
||
|
||
/* Set the line status. */
|
||
status |= (serial_settings.parity
|
||
| serial_settings.word_len
|
||
| serial_settings.stop_bits);
|
||
grub_outb (status, serial_settings.port + UART_LCR);
|
||
|
||
/* Enable the FIFO. */
|
||
grub_outb (UART_ENABLE_FIFO, serial_settings.port + UART_FCR);
|
||
|
||
/* Turn on DTR, RTS, and OUT2. */
|
||
grub_outb (UART_ENABLE_MODEM, serial_settings.port + UART_MCR);
|
||
|
||
/* 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:
|
||
c = '?';
|
||
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_ssize_t
|
||
grub_serial_getcharwidth (grub_uint32_t c __attribute__ ((unused)))
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
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 (grub_uint8_t x, 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_setcursor (const int on)
|
||
{
|
||
if (on)
|
||
grub_terminfo_cursor_on ();
|
||
else
|
||
grub_terminfo_cursor_off ();
|
||
}
|
||
|
||
static struct grub_term_input grub_serial_term_input =
|
||
{
|
||
.name = "serial",
|
||
.checkkey = grub_serial_checkkey,
|
||
.getkey = grub_serial_getkey,
|
||
};
|
||
|
||
static struct grub_term_output grub_serial_term_output =
|
||
{
|
||
.name = "serial",
|
||
.putchar = grub_serial_putchar,
|
||
.getcharwidth = grub_serial_getcharwidth,
|
||
.getwh = grub_serial_getwh,
|
||
.getxy = grub_serial_getxy,
|
||
.gotoxy = grub_serial_gotoxy,
|
||
.cls = grub_serial_cls,
|
||
.setcolorstate = grub_serial_setcolorstate,
|
||
.setcursor = grub_serial_setcursor,
|
||
.flags = 0,
|
||
};
|
||
|
||
|
||
|
||
static grub_err_t
|
||
grub_cmd_serial (grub_extcmd_t cmd,
|
||
int argc __attribute__ ((unused)),
|
||
char **args __attribute__ ((unused)))
|
||
{
|
||
struct grub_arg_list *state = cmd->state;
|
||
struct serial_port backup_settings = serial_settings;
|
||
grub_err_t hwiniterr;
|
||
|
||
if (state[0].set)
|
||
{
|
||
unsigned int unit;
|
||
|
||
unit = grub_strtoul (state[0].arg, 0, 0);
|
||
serial_settings.port = serial_hw_get_port (unit);
|
||
if (!serial_settings.port)
|
||
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)
|
||
{
|
||
unsigned long speed;
|
||
|
||
speed = grub_strtoul (state[2].arg, 0, 0);
|
||
serial_settings.divisor = serial_get_divisor ((unsigned int) speed);
|
||
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");
|
||
}
|
||
}
|
||
|
||
/* Initialize with new settings. */
|
||
hwiniterr = serial_hw_init ();
|
||
|
||
if (hwiniterr == GRUB_ERR_NONE)
|
||
{
|
||
/* Register terminal if not yet registered. */
|
||
if (registered == 0)
|
||
{
|
||
grub_term_register_input (&grub_serial_term_input);
|
||
grub_term_register_output (&grub_serial_term_output);
|
||
registered = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Initialization with new settings failed. */
|
||
if (registered == 1)
|
||
{
|
||
/* If the 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_input (&grub_serial_term_input);
|
||
grub_term_unregister_output (&grub_serial_term_output);
|
||
registered = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return hwiniterr;
|
||
}
|
||
|
||
static grub_extcmd_t cmd;
|
||
|
||
GRUB_MOD_INIT(serial)
|
||
{
|
||
(void) mod; /* To stop warning. */
|
||
cmd = grub_register_extcmd ("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(serial)
|
||
{
|
||
grub_unregister_extcmd (cmd);
|
||
if (registered == 1) /* Unregister terminal only if registered. */
|
||
{
|
||
grub_term_unregister_input (&grub_serial_term_input);
|
||
grub_term_unregister_output (&grub_serial_term_output);
|
||
}
|
||
}
|