xref: /openbmc/linux/arch/powerpc/xmon/nonstdio.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
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