12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fca5dcd4SPaul Mackerras /*
3fca5dcd4SPaul Mackerras * Copyright (C) 1996-2005 Paul Mackerras.
4fca5dcd4SPaul Mackerras */
5fca5dcd4SPaul Mackerras #include <linux/string.h>
633b5cd68SMichael Ellerman #include <asm/udbg.h>
7fca5dcd4SPaul Mackerras #include <asm/time.h>
8fca5dcd4SPaul Mackerras #include "nonstdio.h"
9fca5dcd4SPaul Mackerras
10958b7c80SSam bobroff static bool paginating, paginate_skipping;
11958b7c80SSam bobroff static unsigned long paginate_lpp; /* Lines Per Page */
12958b7c80SSam bobroff static unsigned long paginate_pos;
1333b5cd68SMichael Ellerman
xmon_start_pagination(void)14958b7c80SSam bobroff void xmon_start_pagination(void)
1533b5cd68SMichael Ellerman {
16958b7c80SSam bobroff paginating = true;
17958b7c80SSam bobroff paginate_skipping = false;
18958b7c80SSam bobroff paginate_pos = 0;
19958b7c80SSam bobroff }
20958b7c80SSam bobroff
xmon_end_pagination(void)21958b7c80SSam bobroff void xmon_end_pagination(void)
22958b7c80SSam bobroff {
23958b7c80SSam bobroff paginating = false;
24958b7c80SSam bobroff }
25958b7c80SSam bobroff
xmon_set_pagination_lpp(unsigned long lpp)26958b7c80SSam bobroff void xmon_set_pagination_lpp(unsigned long lpp)
27958b7c80SSam bobroff {
28958b7c80SSam bobroff paginate_lpp = lpp;
2933b5cd68SMichael Ellerman }
3033b5cd68SMichael Ellerman
xmon_readchar(void)3133b5cd68SMichael Ellerman static int xmon_readchar(void)
3233b5cd68SMichael Ellerman {
3333b5cd68SMichael Ellerman if (udbg_getc)
3433b5cd68SMichael Ellerman return udbg_getc();
3533b5cd68SMichael Ellerman return -1;
3633b5cd68SMichael Ellerman }
3733b5cd68SMichael Ellerman
xmon_write(const char * ptr,int nb)38958b7c80SSam bobroff static int xmon_write(const char *ptr, int nb)
39958b7c80SSam bobroff {
40958b7c80SSam bobroff int rv = 0;
41958b7c80SSam bobroff const char *p = ptr, *q;
42958b7c80SSam bobroff const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]";
43958b7c80SSam bobroff
44958b7c80SSam bobroff if (nb <= 0)
45958b7c80SSam bobroff return rv;
46958b7c80SSam bobroff
47958b7c80SSam bobroff if (paginating && paginate_skipping)
48958b7c80SSam bobroff return nb;
49958b7c80SSam bobroff
50958b7c80SSam bobroff if (paginate_lpp) {
51958b7c80SSam bobroff while (paginating && (q = strchr(p, '\n'))) {
52958b7c80SSam bobroff rv += udbg_write(p, q - p + 1);
53958b7c80SSam bobroff p = q + 1;
54958b7c80SSam bobroff paginate_pos++;
55958b7c80SSam bobroff
56958b7c80SSam bobroff if (paginate_pos >= paginate_lpp) {
57958b7c80SSam bobroff udbg_write(msg, strlen(msg));
58958b7c80SSam bobroff
59958b7c80SSam bobroff switch (xmon_readchar()) {
60958b7c80SSam bobroff case 'a':
61958b7c80SSam bobroff paginating = false;
62958b7c80SSam bobroff break;
63958b7c80SSam bobroff case 'q':
64958b7c80SSam bobroff paginate_skipping = true;
65958b7c80SSam bobroff break;
66958b7c80SSam bobroff default:
67958b7c80SSam bobroff /* nothing */
68958b7c80SSam bobroff break;
69958b7c80SSam bobroff }
70958b7c80SSam bobroff
71958b7c80SSam bobroff paginate_pos = 0;
72958b7c80SSam bobroff udbg_write("\r\n", 2);
73958b7c80SSam bobroff
74958b7c80SSam bobroff if (paginate_skipping)
75958b7c80SSam bobroff return nb;
76958b7c80SSam bobroff }
77958b7c80SSam bobroff }
78958b7c80SSam bobroff }
79958b7c80SSam bobroff
80958b7c80SSam bobroff return rv + udbg_write(p, nb - (p - ptr));
81958b7c80SSam bobroff }
82958b7c80SSam bobroff
xmon_putchar(int c)83fca5dcd4SPaul Mackerras int xmon_putchar(int c)
84fca5dcd4SPaul Mackerras {
85fca5dcd4SPaul Mackerras char ch = c;
86fca5dcd4SPaul Mackerras
87fca5dcd4SPaul Mackerras if (c == '\n')
88fca5dcd4SPaul Mackerras xmon_putchar('\r');
89fca5dcd4SPaul Mackerras return xmon_write(&ch, 1) == 1? c: -1;
90fca5dcd4SPaul Mackerras }
91fca5dcd4SPaul Mackerras
92fca5dcd4SPaul Mackerras static char line[256];
93fca5dcd4SPaul Mackerras static char *lineptr;
94fca5dcd4SPaul Mackerras static int lineleft;
95fca5dcd4SPaul Mackerras
xmon_getchar(void)9688c6d626SMichael Ellerman static int xmon_getchar(void)
97fca5dcd4SPaul Mackerras {
98fca5dcd4SPaul Mackerras int c;
99fca5dcd4SPaul Mackerras
100fca5dcd4SPaul Mackerras if (lineleft == 0) {
101fca5dcd4SPaul Mackerras lineptr = line;
102fca5dcd4SPaul Mackerras for (;;) {
103fca5dcd4SPaul Mackerras c = xmon_readchar();
104fca5dcd4SPaul Mackerras if (c == -1 || c == 4)
105fca5dcd4SPaul Mackerras break;
106fca5dcd4SPaul Mackerras if (c == '\r' || c == '\n') {
107fca5dcd4SPaul Mackerras *lineptr++ = '\n';
108fca5dcd4SPaul Mackerras xmon_putchar('\n');
109fca5dcd4SPaul Mackerras break;
110fca5dcd4SPaul Mackerras }
111fca5dcd4SPaul Mackerras switch (c) {
112fca5dcd4SPaul Mackerras case 0177:
113fca5dcd4SPaul Mackerras case '\b':
114fca5dcd4SPaul Mackerras if (lineptr > line) {
115fca5dcd4SPaul Mackerras xmon_putchar('\b');
116fca5dcd4SPaul Mackerras xmon_putchar(' ');
117fca5dcd4SPaul Mackerras xmon_putchar('\b');
118fca5dcd4SPaul Mackerras --lineptr;
119fca5dcd4SPaul Mackerras }
120fca5dcd4SPaul Mackerras break;
121fca5dcd4SPaul Mackerras case 'U' & 0x1F:
122fca5dcd4SPaul Mackerras while (lineptr > line) {
123fca5dcd4SPaul Mackerras xmon_putchar('\b');
124fca5dcd4SPaul Mackerras xmon_putchar(' ');
125fca5dcd4SPaul Mackerras xmon_putchar('\b');
126fca5dcd4SPaul Mackerras --lineptr;
127fca5dcd4SPaul Mackerras }
128fca5dcd4SPaul Mackerras break;
129fca5dcd4SPaul Mackerras default:
130fca5dcd4SPaul Mackerras if (lineptr >= &line[sizeof(line) - 1])
131fca5dcd4SPaul Mackerras xmon_putchar('\a');
132fca5dcd4SPaul Mackerras else {
133fca5dcd4SPaul Mackerras xmon_putchar(c);
134fca5dcd4SPaul Mackerras *lineptr++ = c;
135fca5dcd4SPaul Mackerras }
136fca5dcd4SPaul Mackerras }
137fca5dcd4SPaul Mackerras }
138fca5dcd4SPaul Mackerras lineleft = lineptr - line;
139fca5dcd4SPaul Mackerras lineptr = line;
140fca5dcd4SPaul Mackerras }
141fca5dcd4SPaul Mackerras if (lineleft == 0)
142fca5dcd4SPaul Mackerras return -1;
143fca5dcd4SPaul Mackerras --lineleft;
144fca5dcd4SPaul Mackerras return *lineptr++;
145fca5dcd4SPaul Mackerras }
146fca5dcd4SPaul Mackerras
xmon_gets(char * str,int nb)147fca5dcd4SPaul Mackerras char *xmon_gets(char *str, int nb)
148fca5dcd4SPaul Mackerras {
149fca5dcd4SPaul Mackerras char *p;
150fca5dcd4SPaul Mackerras int c;
151fca5dcd4SPaul Mackerras
152fca5dcd4SPaul Mackerras for (p = str; p < str + nb - 1; ) {
153fca5dcd4SPaul Mackerras c = xmon_getchar();
154fca5dcd4SPaul Mackerras if (c == -1) {
155fca5dcd4SPaul Mackerras if (p == str)
156fca5dcd4SPaul Mackerras return NULL;
157fca5dcd4SPaul Mackerras break;
158fca5dcd4SPaul Mackerras }
159fca5dcd4SPaul Mackerras *p++ = c;
160fca5dcd4SPaul Mackerras if (c == '\n')
161fca5dcd4SPaul Mackerras break;
162fca5dcd4SPaul Mackerras }
163fca5dcd4SPaul Mackerras *p = 0;
164fca5dcd4SPaul Mackerras return str;
165fca5dcd4SPaul Mackerras }
166fca5dcd4SPaul Mackerras
xmon_printf(const char * format,...)167fca5dcd4SPaul Mackerras void xmon_printf(const char *format, ...)
168fca5dcd4SPaul Mackerras {
169fca5dcd4SPaul Mackerras va_list args;
170fca5dcd4SPaul Mackerras static char xmon_outbuf[1024];
171b2bb65f6SMichael Ellerman int rc, n;
172fca5dcd4SPaul Mackerras
173fca5dcd4SPaul Mackerras va_start(args, format);
174fca5dcd4SPaul Mackerras n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
175fca5dcd4SPaul Mackerras va_end(args);
176b2bb65f6SMichael Ellerman
177b2bb65f6SMichael Ellerman rc = xmon_write(xmon_outbuf, n);
178b2bb65f6SMichael Ellerman
179b2bb65f6SMichael Ellerman if (n && rc == 0) {
180b2bb65f6SMichael Ellerman /* No udbg hooks, fallback to printk() - dangerous */
181*7c6c86b3SChristophe Leroy pr_cont("%s", xmon_outbuf);
182b2bb65f6SMichael Ellerman }
183fca5dcd4SPaul Mackerras }
1844d404edcSIshizaki Kou
xmon_puts(const char * str)1854d404edcSIshizaki Kou void xmon_puts(const char *str)
1864d404edcSIshizaki Kou {
1874d404edcSIshizaki Kou xmon_write(str, strlen(str));
1884d404edcSIshizaki Kou }
189