/* * Copyright (C) 2010 Piotr JaroszyƄski * * 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 #include #include #include #include #include #include /* 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, };