| /* | |
| * Copyright (C) 2010 Piotr JaroszyĆski <p.jaroszynski@gmail.com> | |
| * | |
| * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| */ | |
| FILE_LICENCE(GPL2_OR_LATER); | |
| /** @file | |
| * | |
| * Linux console implementation. | |
| * | |
| */ | |
| #include <ipxe/console.h> | |
| #include <ipxe/init.h> | |
| #include <ipxe/keys.h> | |
| #include <ipxe/linux_api.h> | |
| #include <linux/termios.h> | |
| #include <asm/errno.h> | |
| #include <config/console.h> | |
| /* Set default console usage if applicable */ | |
| #if ! ( defined ( CONSOLE_LINUX ) && CONSOLE_EXPLICIT ( CONSOLE_LINUX ) ) | |
| #undef CONSOLE_LINUX | |
| #define CONSOLE_LINUX ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) | |
| #endif | |
| static void linux_console_putchar(int c) | |
| { | |
| char ch = c; | |
| /* write to stdout */ | |
| if (linux_write(1, &ch, sizeof (ch)) != 1) | |
| DBG("linux_console write failed (%s)\n", linux_strerror(linux_errno)); | |
| } | |
| static int linux_console_getchar() | |
| { | |
| char c; | |
| /* read from stdin */ | |
| if (linux_read(0, &c, 1) < 0) { | |
| DBG("linux_console read failed (%s)\n", linux_strerror(linux_errno)); | |
| return 0; | |
| } | |
| /* backspace seems to be returned as ascii del, map it here */ | |
| if (c == 0x7f) | |
| return KEY_BACKSPACE; | |
| else | |
| return c; | |
| } | |
| static int linux_console_iskey() | |
| { | |
| struct pollfd pfd; | |
| pfd.fd = 0; | |
| pfd.events = POLLIN; | |
| /* poll for data to be read on stdin */ | |
| if (linux_poll(&pfd, 1, 0) == -1) { | |
| DBG("linux_console poll failed (%s)\n", linux_strerror(linux_errno)); | |
| return 0; | |
| } | |
| if (pfd.revents & POLLIN) | |
| return 1; | |
| else | |
| return 0; | |
| } | |
| struct console_driver linux_console __console_driver = { | |
| .disabled = 0, | |
| .putchar = linux_console_putchar, | |
| .getchar = linux_console_getchar, | |
| .iskey = linux_console_iskey, | |
| .usage = CONSOLE_LINUX, | |
| }; | |
| static int linux_tcgetattr(int fd, struct termios *termios_p) | |
| { | |
| return linux_ioctl(fd, TCGETS, termios_p); | |
| } | |
| static int linux_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) | |
| { | |
| unsigned long int cmd; | |
| switch (optional_actions) | |
| { | |
| case TCSANOW: | |
| cmd = TCSETS; | |
| break; | |
| case TCSADRAIN: | |
| cmd = TCSETSW; | |
| break; | |
| case TCSAFLUSH: | |
| cmd = TCSETSF; | |
| break; | |
| default: | |
| linux_errno = EINVAL; | |
| return -1; | |
| } | |
| return linux_ioctl(fd, cmd, termios_p); | |
| } | |
| /** Saved termios attributes */ | |
| static struct termios saved_termios; | |
| /** Setup the terminal for our use */ | |
| static void linux_console_startup(void) | |
| { | |
| struct termios t; | |
| if (linux_tcgetattr(0, &t)) { | |
| DBG("linux_console tcgetattr failed (%s)", linux_strerror(linux_errno)); | |
| return; | |
| } | |
| saved_termios = t; | |
| /* Disable canonical mode and echo. Let readline handle that */ | |
| t.c_lflag &= ~(ECHO | ICANON); | |
| /* stop ^C from sending a signal */ | |
| t.c_cc[VINTR] = 0; | |
| if (linux_tcsetattr(0, TCSAFLUSH, &t)) | |
| DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); | |
| } | |
| /** Restores original terminal attributes on shutdown */ | |
| static void linux_console_shutdown(int flags __unused) | |
| { | |
| if (linux_tcsetattr(0, TCSAFLUSH, &saved_termios)) | |
| DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); | |
| } | |
| struct startup_fn linux_console_startup_fn __startup_fn(STARTUP_EARLY) = { | |
| .name = "linux_console", | |
| .startup = linux_console_startup, | |
| .shutdown = linux_console_shutdown, | |
| }; |