| /* |
| * 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) |
| { |
| /* write to stdout */ |
| if (linux_write(1, &c, 1) != 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, |
| }; |