|  | /* | 
|  | * Copyright (C) 1996-2005 Paul Mackerras. | 
|  | * | 
|  | *      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 (at your option) any later version. | 
|  | */ | 
|  | #include <linux/string.h> | 
|  | #include <asm/udbg.h> | 
|  | #include <asm/time.h> | 
|  | #include "nonstdio.h" | 
|  |  | 
|  | static bool paginating, paginate_skipping; | 
|  | static unsigned long paginate_lpp; /* Lines Per Page */ | 
|  | static unsigned long paginate_pos; | 
|  |  | 
|  | void xmon_start_pagination(void) | 
|  | { | 
|  | paginating = true; | 
|  | paginate_skipping = false; | 
|  | paginate_pos = 0; | 
|  | } | 
|  |  | 
|  | void xmon_end_pagination(void) | 
|  | { | 
|  | paginating = false; | 
|  | } | 
|  |  | 
|  | void xmon_set_pagination_lpp(unsigned long lpp) | 
|  | { | 
|  | paginate_lpp = lpp; | 
|  | } | 
|  |  | 
|  | static int xmon_readchar(void) | 
|  | { | 
|  | if (udbg_getc) | 
|  | return udbg_getc(); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static int xmon_write(const char *ptr, int nb) | 
|  | { | 
|  | int rv = 0; | 
|  | const char *p = ptr, *q; | 
|  | const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]"; | 
|  |  | 
|  | if (nb <= 0) | 
|  | return rv; | 
|  |  | 
|  | if (paginating && paginate_skipping) | 
|  | return nb; | 
|  |  | 
|  | if (paginate_lpp) { | 
|  | while (paginating && (q = strchr(p, '\n'))) { | 
|  | rv += udbg_write(p, q - p + 1); | 
|  | p = q + 1; | 
|  | paginate_pos++; | 
|  |  | 
|  | if (paginate_pos >= paginate_lpp) { | 
|  | udbg_write(msg, strlen(msg)); | 
|  |  | 
|  | switch (xmon_readchar()) { | 
|  | case 'a': | 
|  | paginating = false; | 
|  | break; | 
|  | case 'q': | 
|  | paginate_skipping = true; | 
|  | break; | 
|  | default: | 
|  | /* nothing */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | paginate_pos = 0; | 
|  | udbg_write("\r\n", 2); | 
|  |  | 
|  | if (paginate_skipping) | 
|  | return nb; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return rv + udbg_write(p, nb - (p - ptr)); | 
|  | } | 
|  |  | 
|  | int xmon_putchar(int c) | 
|  | { | 
|  | char ch = c; | 
|  |  | 
|  | if (c == '\n') | 
|  | xmon_putchar('\r'); | 
|  | return xmon_write(&ch, 1) == 1? c: -1; | 
|  | } | 
|  |  | 
|  | static char line[256]; | 
|  | static char *lineptr; | 
|  | static int lineleft; | 
|  |  | 
|  | static int xmon_getchar(void) | 
|  | { | 
|  | int c; | 
|  |  | 
|  | if (lineleft == 0) { | 
|  | lineptr = line; | 
|  | for (;;) { | 
|  | c = xmon_readchar(); | 
|  | if (c == -1 || c == 4) | 
|  | break; | 
|  | if (c == '\r' || c == '\n') { | 
|  | *lineptr++ = '\n'; | 
|  | xmon_putchar('\n'); | 
|  | break; | 
|  | } | 
|  | switch (c) { | 
|  | case 0177: | 
|  | case '\b': | 
|  | if (lineptr > line) { | 
|  | xmon_putchar('\b'); | 
|  | xmon_putchar(' '); | 
|  | xmon_putchar('\b'); | 
|  | --lineptr; | 
|  | } | 
|  | break; | 
|  | case 'U' & 0x1F: | 
|  | while (lineptr > line) { | 
|  | xmon_putchar('\b'); | 
|  | xmon_putchar(' '); | 
|  | xmon_putchar('\b'); | 
|  | --lineptr; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | if (lineptr >= &line[sizeof(line) - 1]) | 
|  | xmon_putchar('\a'); | 
|  | else { | 
|  | xmon_putchar(c); | 
|  | *lineptr++ = c; | 
|  | } | 
|  | } | 
|  | } | 
|  | lineleft = lineptr - line; | 
|  | lineptr = line; | 
|  | } | 
|  | if (lineleft == 0) | 
|  | return -1; | 
|  | --lineleft; | 
|  | return *lineptr++; | 
|  | } | 
|  |  | 
|  | char *xmon_gets(char *str, int nb) | 
|  | { | 
|  | char *p; | 
|  | int c; | 
|  |  | 
|  | for (p = str; p < str + nb - 1; ) { | 
|  | c = xmon_getchar(); | 
|  | if (c == -1) { | 
|  | if (p == str) | 
|  | return NULL; | 
|  | break; | 
|  | } | 
|  | *p++ = c; | 
|  | if (c == '\n') | 
|  | break; | 
|  | } | 
|  | *p = 0; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | void xmon_printf(const char *format, ...) | 
|  | { | 
|  | va_list args; | 
|  | static char xmon_outbuf[1024]; | 
|  | int rc, n; | 
|  |  | 
|  | va_start(args, format); | 
|  | n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); | 
|  | va_end(args); | 
|  |  | 
|  | rc = xmon_write(xmon_outbuf, n); | 
|  |  | 
|  | if (n && rc == 0) { | 
|  | /* No udbg hooks, fallback to printk() - dangerous */ | 
|  | printk("%s", xmon_outbuf); | 
|  | } | 
|  | } | 
|  |  | 
|  | void xmon_puts(const char *str) | 
|  | { | 
|  | xmon_write(str, strlen(str)); | 
|  | } |