URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [io.c] - Rev 856
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // io.c // // RedBoot I/O support // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 Free Software Foundation, Inc. // // eCos 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 or (at your option) any later // version. // // eCos 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 eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas,hmt,jlarmour // Date: 2000-07-14 // Purpose: // Description: // // This code is part of RedBoot (tm). // //####DESCRIPTIONEND#### // //========================================================================== #include "redboot.h" #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS // GDB interface functions extern void ungetDebugChar(char c); #endif static void do_channel(int argc, char *argv[]); #ifdef CYGPKG_REDBOOT_ANY_CONSOLE RedBoot_cmd("channel", "Display/switch console channel", "[-1|<channel number>]", do_channel ); #else RedBoot_cmd("channel", "Display/switch console channel", "[<channel number>]", do_channel ); #endif static void do_channel(int argc, char *argv[]) { int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); if (argc == 2) { #ifdef CYGPKG_REDBOOT_ANY_CONSOLE if (strcmp( argv[1], "-1") == 0) { console_selected = false; console_echo = true; } else #endif { unsigned long chan; if ( !parse_num( argv[1], &chan, NULL, NULL) ) { diag_printf("** Error: invalid channel '%s'\n", argv[1]); } else { if (chan < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) { CYGACC_CALL_IF_SET_CONSOLE_COMM(chan); CYGACC_CALL_IF_SET_DEBUG_COMM(chan); if (chan != cur) console_echo = true; } else { diag_printf("**Error: bad channel number '%s'\n", argv[1]); } } } } /* else display */ else { diag_printf("Current console channel id: "); #ifdef CYGPKG_REDBOOT_ANY_CONSOLE if (!console_selected) diag_printf("-1\n"); else #endif diag_printf("%d\n", cur); } } void mon_write_char(unsigned char c) { hal_virtual_comm_table_t *__chan; #ifdef CYGPKG_REDBOOT_ANY_CONSOLE if (!console_selected) { int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); int i; // Send output to all channels for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) { CYGACC_CALL_IF_SET_CONSOLE_COMM(i); __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); CYGACC_COMM_IF_PUTC(*__chan, c); } CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); } else #endif { __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); if (__chan) CYGACC_COMM_IF_PUTC(*__chan, c); else { __chan = CYGACC_CALL_IF_DEBUG_PROCS(); CYGACC_COMM_IF_PUTC(*__chan, c); } } } static void mon_read_char(unsigned char *c) { hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); if (__chan) *c = CYGACC_COMM_IF_GETC(*__chan); else { __chan = CYGACC_CALL_IF_DEBUG_PROCS(); *c = CYGACC_COMM_IF_GETC(*__chan); } } #ifdef CYGPKG_REDBOOT_ANY_CONSOLE static int _mon_timeout; #endif bool mon_read_char_with_timeout(unsigned char *c) { bool res = false; hal_virtual_comm_table_t *__chan; #ifdef CYGPKG_REDBOOT_ANY_CONSOLE if (!console_selected) { int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); int i, j, tot; // Try input from all channels tot = 0; while (tot < _mon_timeout) { for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++, tot++) { CYGACC_CALL_IF_SET_CONSOLE_COMM(i); __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c); if (res) { // Input available on this channel, make it be the console if (*c != '\0') { // Don't chose this unless real data have arrived console_selected = true; CYGACC_CALL_IF_SET_DEBUG_COMM(i); // Disable interrupts on all channels but this one for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; j++) { if (i != j) { CYGACC_CALL_IF_SET_CONSOLE_COMM(j); __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE); } } CYGACC_CALL_IF_SET_CONSOLE_COMM(i); return res; } } } } CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); } else #endif { __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); if (__chan) res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c); else { __chan = CYGACC_CALL_IF_DEBUG_PROCS(); res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c); } } return res; } void mon_set_read_char_timeout(int ms) { hal_virtual_comm_table_t *__chan; #ifdef CYGPKG_REDBOOT_ANY_CONSOLE if (!console_selected) { int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); int i; // Set timeout to minimum on each channel; total amounts to desired value _mon_timeout = ms; ms = 1; for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) { CYGACC_CALL_IF_SET_CONSOLE_COMM(i); if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) { CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms); } } CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); } else #endif { if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) { CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms); } if ((__chan = CYGACC_CALL_IF_DEBUG_PROCS()) != 0) { CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms); } } } // // Test for ^C on the console. CAUTION! discards all console input // bool _rb_break(int timeout) { unsigned char c; mon_set_read_char_timeout(timeout); if (mon_read_char_with_timeout(&c)) { if (c == '\x03') { // Test for ^C return true; } } return false; } #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT #define __STRINGIFY(x) #x #define _STRINGIFY(x) __STRINGIFY(x) #define _STARTUP_STR _STRINGIFY(CYG_HAL_STARTUP) "}" // // Read a character from script. // Return true if script character found, false if not. // static int getc_script(char *cp) { static bool newline = true; bool skip; while (script && *script) { if (newline && *script == '{') { skip = false; ++script; // skip if it isn't for this startup type if (strncmp(script, _STARTUP_STR, strlen(_STARTUP_STR))) skip = true; // skip past "{...}" while (*script && *script++ != '}') ; // skip script line if neccessary if (skip) { while (*script && *script++ != '\n') ; } else newline = false; } else { *cp = *script++; if (*cp == '\n') { newline = true; } else { newline = false; } return true; } } return false; } #endif #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 #define _CL_NUM_LINES CYGNUM_REDBOOT_CMD_LINE_EDITING // Number of lines to keep static char _cl_lines[_CL_NUM_LINES][CYGPKG_REDBOOT_MAX_CMD_LINE]; static int _cl_index = -1; // Last known command line static int _cl_max_index = -1; // Last command in buffers static int _cl_real_index = 0; // Virtual command index (0..N) #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY static void expand_history(char *); #endif #endif // // Read a line of input from the user // Return: // _GETS_OK: 'n' valid characters received // _GETS_GDB: '$' (GDB lead-in) // _GETS_TIMEOUT: No input before timeout // _GETS_CTRLC: ^C typed // // if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 // Command line history support // ^P - Select previous line from history // ^N - Select next line from history // ^A - Move insertion [cursor] to start of line // ^E - Move cursor to end of line // ^B - Move cursor back [previous character] // ^F - Move cursor forward [next character] // "standard" arrow keys work as well // left ^[[D == ^B // right ^[[C == ^F // up ^[[A == ^P // down ^[[B == ^N // home ^[[H/^[1~ == ^A // end ^[[F/^[OF == ^E // del ^[3~ == ^D // int _rb_gets_preloaded(char *buf, int buflen, int timeout) { char *ip = buf; // Insertion point char *eol = buf; // End of line char c; bool res = false; static char last_ch = '\0'; int _timeout; #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 int _index = _cl_index; // Last saved line char *xp; #ifdef CYGSEM_REDBOOT_CMD_LINE_ANSI_SEQUENCES int ansi_state = 0; // Used to drive ANSI parser char ansi_char = '\0'; #endif #endif // Display current buffer data while (*eol) { mon_write_char(*eol++); } ip = eol; while (true) { #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT if (getc_script(&c)) do_idle(false); else #endif if ((timeout > 0) && (eol == buf)) { #define MIN_TIMEOUT 50 _timeout = timeout > MIN_TIMEOUT ? MIN_TIMEOUT : timeout; mon_set_read_char_timeout(_timeout); while (timeout > 0) { res = mon_read_char_with_timeout(&c); if (res) { // Got a character do_idle(false); break; } timeout -= _timeout; } if (res == false) { do_idle(true); return _GETS_TIMEOUT; // Input timed out } } else { mon_read_char(&c); } *eol = '\0'; #define CTRL(c) ((c)&0x1F) #ifdef CYGSEM_REDBOOT_CMD_LINE_ANSI_SEQUENCES // Special handling of ANSI keyboard sequences (arrows, etc) if (c == '\x1B') { // Leadin for ANSI keyboard sequence ansi_state = 1; continue; } switch (ansi_state) { case 0: // No ANSI sequence in progress break; case 1: // ESC seen, look for '[' if (c == '[') { ansi_state = 2; } else if (c == 'O') { ansi_state = 4; } else { // Handle bad sequences? ansi_state = 0; } continue; case 2: // ESC+[ seen, process key ansi_state = 0; switch (c) { case 'A': c = CTRL('P'); break; case 'B': c = CTRL('N'); break; case 'C': c = CTRL('F'); break; case 'D': c = CTRL('B'); break; case 'F': c = CTRL('E'); break; case 'H': c = CTRL('A'); break; case '1': ansi_char = CTRL('A'); ansi_state = 3; continue; case '3': ansi_char = CTRL('D'); ansi_state = 3; continue; default: // Handle bad sequences? continue; } break; case 3: // Sequences like ^[[1~ == ^H ansi_state = 0; if (c == '~') { c = ansi_char; } else { // Handle bad sequences? continue; } break; case 4: // Sequences like ^[OF == ^E ansi_state = 0; if (c == 'F') { c = CTRL('E'); } else { // Handle bad sequences? continue; } break; } #endif switch (c) { #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 case CTRL('P'): // Fetch the previous line into the buffer if (_index >= 0) { // Erase the previous line [crude] while (ip != buf) { mon_write_char('\b'); mon_write_char(' '); mon_write_char('\b'); ip--; } strcpy(buf, _cl_lines[_index]); while (*ip) { mon_write_char(*ip++); } eol = ip; // Move to previous line _index--; if (_index < 0) { _index = _cl_max_index; } } else { mon_write_char(0x07); // Audible bell on most devices } break; case CTRL('N'): // Fetch the next line into the buffer if (_index >= 0) { if (++_index > _cl_max_index) _index = 0; // Erase the previous line [crude] while (ip != buf) { mon_write_char('\b'); mon_write_char(' '); mon_write_char('\b'); ip--; } strcpy(buf, _cl_lines[_index]); while (*ip) { mon_write_char(*ip++); } eol = ip; } else { mon_write_char(0x07); // Audible bell on most devices } break; case CTRL('B'): // Move insertion point backwards if (ip != buf) { mon_write_char('\b'); ip--; } break; case CTRL('F'): // Move insertion point forwards if (ip != eol) { mon_write_char(*ip++); } break; case CTRL('E'): // Move insertion point to end of line while (ip != eol) { mon_write_char(*ip++); } break; case CTRL('A'): // Move insertion point to beginning of line if (ip != buf) { xp = ip; while (xp-- != buf) { mon_write_char('\b'); } } ip = buf; break; case CTRL('K'): // Kill to the end of line if (ip != eol) { xp = ip; while (xp++ != eol) { mon_write_char(' '); } while (--xp != ip) { mon_write_char('\b'); } eol = ip; } break; case CTRL('D'): // Erase the character under the cursor if (ip != eol) { xp = ip; eol--; while (xp != eol) { *xp = *(xp+1); mon_write_char(*xp++); } mon_write_char(' '); // Erases last character mon_write_char('\b'); while (xp-- != ip) { mon_write_char('\b'); } } break; #endif // CYGNUM_REDBOOT_CMD_LINE_EDITING case CTRL('C'): // ^C // Abort current input diag_printf("^C\n"); *buf = '\0'; // Nothing useful in buffer return _GETS_CTRLC; case '\n': case '\r': // If previous character was the "other" end-of-line, ignore this one if (((c == '\n') && (last_ch == '\r')) || ((c == '\r') && (last_ch == '\n'))) { c = '\0'; break; } // End of line if (console_echo) { mon_write_char('\r'); mon_write_char('\n'); } last_ch = c; #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 if (cmd_history) { // History handling - only when enabled #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY expand_history(buf); #endif if (*buf != '\0') { if (++_cl_index == _CL_NUM_LINES) { _cl_index = 0; } if (_cl_index > _cl_max_index) _cl_max_index = _cl_index; strcpy(_cl_lines[_cl_index], buf); _cl_real_index++; } } #endif return _GETS_OK; case '\b': case 0x7F: // DEL if (ip != buf) { #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 if (ip != eol) { ip--; mon_write_char('\b'); xp = ip; while (xp != (eol-1)) { *xp = *(xp+1); mon_write_char(*xp++); } mon_write_char(' '); // Erases last character mon_write_char('\b'); while (xp-- != ip) { mon_write_char('\b'); } } else { if (console_echo) { mon_write_char('\b'); mon_write_char(' '); mon_write_char('\b'); } ip--; } eol--; #else if (console_echo) { mon_write_char('\b'); mon_write_char(' '); mon_write_char('\b'); } ip--; eol--; #endif } break; #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS case '+': // fall through case '$': if (ip == buf || last_ch != '\\') { // Give up and try GDB protocol ungetDebugChar(c); // Push back character so stubs will see it return _GETS_GDB; } if (last_ch == '\\') { #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 if (ip == eol) { // Just save \$ as $ eol = --ip; } else { mon_write_char('\b'); *--ip = c; mon_write_char(c); break; } #else ip--; // Save \$ as $ #endif } // else fall through #endif default: #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 // If the insertion point is not at the end of line, make space for it if (ip != eol) { xp = eol; *++eol = '\0'; while (xp != ip) { *xp = *(xp-1); xp--; } } #endif if (console_echo) { mon_write_char((unsigned char)c); } if (ip == eol) { // Advance both pointers *ip++ = c; eol = ip; #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0 } else { // Just insert the character *ip++ = c; xp = ip; while (xp != eol) { mon_write_char(*xp++); } while (xp-- != ip) { mon_write_char('\b'); } #endif } } last_ch = c; if (ip == buf + buflen - 1) { // Buffer full *ip = '\0'; return buflen; } } } int _rb_gets(char *buf, int buflen, int timeout) { *buf = '\0'; // Empty buffer return _rb_gets_preloaded(buf, buflen, timeout); } static bool _verify_action(int timeout, char *fmt, va_list ap) { char ans[8]; int ret; #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT // Don't ask if we're executing a script if (script && *script) return 1; #endif diag_vprintf(fmt, ap); diag_printf(" - continue (y/n)? "); if ((ret = _rb_gets(ans, sizeof(ans), timeout)) > 0) { return ((ans[0] == 'y') || (ans[0] == 'Y')); } else { if (ret == _GETS_TIMEOUT) { diag_printf(" ** Timed out!\n"); } return 0; // Timed out or ^C } } bool verify_action(char *fmt, ...) { va_list ap; va_start(ap, fmt); return _verify_action(0, fmt, ap); } bool verify_action_with_timeout(int timeout, char *fmt, ...) { va_list ap; va_start(ap, fmt); return _verify_action(timeout, fmt, ap); } #ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY // parse for history index number. Return number or -1 if not // an index number. static int parse_history_index(char *s) { int val = 0; while ('0' <= *s && *s <= '9') val = (val * 10) + (*s++ - '0'); if (*s) return -1; return val; } // Check input line to see if it needs history expansion. If so, // try to find matching command and replace buffer as appropriate. static void expand_history(char *buf) { int ncmds = _cl_max_index + 1; int i, index, len; if (buf[0] != '!' || buf[1] == '\0') return; if (ncmds > 0) { if (!strcmp(buf, "!!")) { strcpy(buf, _cl_lines[_cl_index]); return; } if ((index = parse_history_index(buf + 1)) >= 0) { if (index <= _cl_real_index) { while (index >= _CL_NUM_LINES) { index -= _CL_NUM_LINES; } strcpy(buf, _cl_lines[index]); return; } } else { len = strlen(buf + 1); for (i = 0, index = _cl_index; i < ncmds; i++) { if (!strncmp(_cl_lines[index], buf+1, len)) { strcpy(buf, _cl_lines[index]); return; } if (--index < 0) index = _cl_max_index; } } } diag_printf("%s: event not found\n", buf); *buf = '\0'; } static void do_history(int argc, char *argv[]) { int ncmds = _cl_max_index + 1; int i, index; if (_cl_index == _cl_max_index) { // history has not wrapped around for (i = 0; i < ncmds; i++) diag_printf("%3d %s\n", i, _cl_lines[i]); } else { diag_printf("_cl_index = %d\n", _cl_index); for (i = 0, index = _cl_index + 1; i < ncmds; i++) { diag_printf("%3d %s\n", i+_cl_real_index-_CL_NUM_LINES, _cl_lines[index++]); if (index > _cl_max_index) index = 0; } } } RedBoot_cmd("history", "Display command history", "", do_history ); #endif // CYGBLD_REDBOOT_CMD_LINE_HISTORY
Go to most recent revision | Compare with Previous | Blame | View Log