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 (void) |
15 | { |
16 | paginating = true; |
17 | paginate_skipping = false; |
18 | paginate_pos = 0; |
19 | } |
20 | |
21 | void (void) |
22 | { |
23 | paginating = false; |
24 | } |
25 | |
26 | void (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(c: '\r'); |
89 | return xmon_write(ptr: &ch, nb: 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(c: '\n'); |
109 | break; |
110 | } |
111 | switch (c) { |
112 | case 0177: |
113 | case '\b': |
114 | if (lineptr > line) { |
115 | xmon_putchar(c: '\b'); |
116 | xmon_putchar(c: ' '); |
117 | xmon_putchar(c: '\b'); |
118 | --lineptr; |
119 | } |
120 | break; |
121 | case 'U' & 0x1F: |
122 | while (lineptr > line) { |
123 | xmon_putchar(c: '\b'); |
124 | xmon_putchar(c: ' '); |
125 | xmon_putchar(c: '\b'); |
126 | --lineptr; |
127 | } |
128 | break; |
129 | default: |
130 | if (lineptr >= &line[sizeof(line) - 1]) |
131 | xmon_putchar(c: '\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(buf: xmon_outbuf, size: sizeof(xmon_outbuf), fmt: format, args); |
175 | va_end(args); |
176 | |
177 | rc = xmon_write(ptr: xmon_outbuf, nb: 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(ptr: str, strlen(str)); |
188 | } |
189 | |