1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 1996-2005 Paul Mackerras. 4 */ 5 #include <linux/string.h> 6 #include <asm/udbg.h> 7 #include <asm/time.h> 8 #include "nonstdio.h" 9 10 static bool paginating, paginate_skipping; 11 static unsigned long paginate_lpp; /* Lines Per Page */ 12 static unsigned long paginate_pos; 13 14 void xmon_start_pagination(void) 15 { 16 paginating = true; 17 paginate_skipping = false; 18 paginate_pos = 0; 19 } 20 21 void xmon_end_pagination(void) 22 { 23 paginating = false; 24 } 25 26 void xmon_set_pagination_lpp(unsigned long lpp) 27 { 28 paginate_lpp = lpp; 29 } 30 31 static int xmon_readchar(void) 32 { 33 if (udbg_getc) 34 return udbg_getc(); 35 return -1; 36 } 37 38 static int xmon_write(const char *ptr, int nb) 39 { 40 int rv = 0; 41 const char *p = ptr, *q; 42 const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]"; 43 44 if (nb <= 0) 45 return rv; 46 47 if (paginating && paginate_skipping) 48 return nb; 49 50 if (paginate_lpp) { 51 while (paginating && (q = strchr(p, '\n'))) { 52 rv += udbg_write(p, q - p + 1); 53 p = q + 1; 54 paginate_pos++; 55 56 if (paginate_pos >= paginate_lpp) { 57 udbg_write(msg, strlen(msg)); 58 59 switch (xmon_readchar()) { 60 case 'a': 61 paginating = false; 62 break; 63 case 'q': 64 paginate_skipping = true; 65 break; 66 default: 67 /* nothing */ 68 break; 69 } 70 71 paginate_pos = 0; 72 udbg_write("\r\n", 2); 73 74 if (paginate_skipping) 75 return nb; 76 } 77 } 78 } 79 80 return rv + udbg_write(p, nb - (p - ptr)); 81 } 82 83 int xmon_putchar(int c) 84 { 85 char ch = c; 86 87 if (c == '\n') 88 xmon_putchar('\r'); 89 return xmon_write(&ch, 1) == 1? c: -1; 90 } 91 92 static char line[256]; 93 static char *lineptr; 94 static int lineleft; 95 96 static int xmon_getchar(void) 97 { 98 int c; 99 100 if (lineleft == 0) { 101 lineptr = line; 102 for (;;) { 103 c = xmon_readchar(); 104 if (c == -1 || c == 4) 105 break; 106 if (c == '\r' || c == '\n') { 107 *lineptr++ = '\n'; 108 xmon_putchar('\n'); 109 break; 110 } 111 switch (c) { 112 case 0177: 113 case '\b': 114 if (lineptr > line) { 115 xmon_putchar('\b'); 116 xmon_putchar(' '); 117 xmon_putchar('\b'); 118 --lineptr; 119 } 120 break; 121 case 'U' & 0x1F: 122 while (lineptr > line) { 123 xmon_putchar('\b'); 124 xmon_putchar(' '); 125 xmon_putchar('\b'); 126 --lineptr; 127 } 128 break; 129 default: 130 if (lineptr >= &line[sizeof(line) - 1]) 131 xmon_putchar('\a'); 132 else { 133 xmon_putchar(c); 134 *lineptr++ = c; 135 } 136 } 137 } 138 lineleft = lineptr - line; 139 lineptr = line; 140 } 141 if (lineleft == 0) 142 return -1; 143 --lineleft; 144 return *lineptr++; 145 } 146 147 char *xmon_gets(char *str, int nb) 148 { 149 char *p; 150 int c; 151 152 for (p = str; p < str + nb - 1; ) { 153 c = xmon_getchar(); 154 if (c == -1) { 155 if (p == str) 156 return NULL; 157 break; 158 } 159 *p++ = c; 160 if (c == '\n') 161 break; 162 } 163 *p = 0; 164 return str; 165 } 166 167 void xmon_printf(const char *format, ...) 168 { 169 va_list args; 170 static char xmon_outbuf[1024]; 171 int rc, n; 172 173 va_start(args, format); 174 n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); 175 va_end(args); 176 177 rc = xmon_write(xmon_outbuf, n); 178 179 if (n && rc == 0) { 180 /* No udbg hooks, fallback to printk() - dangerous */ 181 pr_cont("%s", xmon_outbuf); 182 } 183 } 184 185 void xmon_puts(const char *str) 186 { 187 xmon_write(str, strlen(str)); 188 } 189