162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 1996-2005 Paul Mackerras.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/string.h>
662306a36Sopenharmony_ci#include <asm/udbg.h>
762306a36Sopenharmony_ci#include <asm/time.h>
862306a36Sopenharmony_ci#include "nonstdio.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic bool paginating, paginate_skipping;
1162306a36Sopenharmony_cistatic unsigned long paginate_lpp; /* Lines Per Page */
1262306a36Sopenharmony_cistatic unsigned long paginate_pos;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_civoid xmon_start_pagination(void)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	paginating = true;
1762306a36Sopenharmony_ci	paginate_skipping = false;
1862306a36Sopenharmony_ci	paginate_pos = 0;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_civoid xmon_end_pagination(void)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	paginating = false;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid xmon_set_pagination_lpp(unsigned long lpp)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	paginate_lpp = lpp;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int xmon_readchar(void)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	if (udbg_getc)
3462306a36Sopenharmony_ci		return udbg_getc();
3562306a36Sopenharmony_ci	return -1;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int xmon_write(const char *ptr, int nb)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	int rv = 0;
4162306a36Sopenharmony_ci	const char *p = ptr, *q;
4262306a36Sopenharmony_ci	const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]";
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (nb <= 0)
4562306a36Sopenharmony_ci		return rv;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (paginating && paginate_skipping)
4862306a36Sopenharmony_ci		return nb;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (paginate_lpp) {
5162306a36Sopenharmony_ci		while (paginating && (q = strchr(p, '\n'))) {
5262306a36Sopenharmony_ci			rv += udbg_write(p, q - p + 1);
5362306a36Sopenharmony_ci			p = q + 1;
5462306a36Sopenharmony_ci			paginate_pos++;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci			if (paginate_pos >= paginate_lpp) {
5762306a36Sopenharmony_ci				udbg_write(msg, strlen(msg));
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci				switch (xmon_readchar()) {
6062306a36Sopenharmony_ci				case 'a':
6162306a36Sopenharmony_ci					paginating = false;
6262306a36Sopenharmony_ci					break;
6362306a36Sopenharmony_ci				case 'q':
6462306a36Sopenharmony_ci					paginate_skipping = true;
6562306a36Sopenharmony_ci					break;
6662306a36Sopenharmony_ci				default:
6762306a36Sopenharmony_ci					/* nothing */
6862306a36Sopenharmony_ci					break;
6962306a36Sopenharmony_ci				}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci				paginate_pos = 0;
7262306a36Sopenharmony_ci				udbg_write("\r\n", 2);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci				if (paginate_skipping)
7562306a36Sopenharmony_ci					return nb;
7662306a36Sopenharmony_ci			}
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return rv + udbg_write(p, nb - (p - ptr));
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciint xmon_putchar(int c)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	char ch = c;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (c == '\n')
8862306a36Sopenharmony_ci		xmon_putchar('\r');
8962306a36Sopenharmony_ci	return xmon_write(&ch, 1) == 1? c: -1;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic char line[256];
9362306a36Sopenharmony_cistatic char *lineptr;
9462306a36Sopenharmony_cistatic int lineleft;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int xmon_getchar(void)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int c;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (lineleft == 0) {
10162306a36Sopenharmony_ci		lineptr = line;
10262306a36Sopenharmony_ci		for (;;) {
10362306a36Sopenharmony_ci			c = xmon_readchar();
10462306a36Sopenharmony_ci			if (c == -1 || c == 4)
10562306a36Sopenharmony_ci				break;
10662306a36Sopenharmony_ci			if (c == '\r' || c == '\n') {
10762306a36Sopenharmony_ci				*lineptr++ = '\n';
10862306a36Sopenharmony_ci				xmon_putchar('\n');
10962306a36Sopenharmony_ci				break;
11062306a36Sopenharmony_ci			}
11162306a36Sopenharmony_ci			switch (c) {
11262306a36Sopenharmony_ci			case 0177:
11362306a36Sopenharmony_ci			case '\b':
11462306a36Sopenharmony_ci				if (lineptr > line) {
11562306a36Sopenharmony_ci					xmon_putchar('\b');
11662306a36Sopenharmony_ci					xmon_putchar(' ');
11762306a36Sopenharmony_ci					xmon_putchar('\b');
11862306a36Sopenharmony_ci					--lineptr;
11962306a36Sopenharmony_ci				}
12062306a36Sopenharmony_ci				break;
12162306a36Sopenharmony_ci			case 'U' & 0x1F:
12262306a36Sopenharmony_ci				while (lineptr > line) {
12362306a36Sopenharmony_ci					xmon_putchar('\b');
12462306a36Sopenharmony_ci					xmon_putchar(' ');
12562306a36Sopenharmony_ci					xmon_putchar('\b');
12662306a36Sopenharmony_ci					--lineptr;
12762306a36Sopenharmony_ci				}
12862306a36Sopenharmony_ci				break;
12962306a36Sopenharmony_ci			default:
13062306a36Sopenharmony_ci				if (lineptr >= &line[sizeof(line) - 1])
13162306a36Sopenharmony_ci					xmon_putchar('\a');
13262306a36Sopenharmony_ci				else {
13362306a36Sopenharmony_ci					xmon_putchar(c);
13462306a36Sopenharmony_ci					*lineptr++ = c;
13562306a36Sopenharmony_ci				}
13662306a36Sopenharmony_ci			}
13762306a36Sopenharmony_ci		}
13862306a36Sopenharmony_ci		lineleft = lineptr - line;
13962306a36Sopenharmony_ci		lineptr = line;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	if (lineleft == 0)
14262306a36Sopenharmony_ci		return -1;
14362306a36Sopenharmony_ci	--lineleft;
14462306a36Sopenharmony_ci	return *lineptr++;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cichar *xmon_gets(char *str, int nb)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	char *p;
15062306a36Sopenharmony_ci	int c;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	for (p = str; p < str + nb - 1; ) {
15362306a36Sopenharmony_ci		c = xmon_getchar();
15462306a36Sopenharmony_ci		if (c == -1) {
15562306a36Sopenharmony_ci			if (p == str)
15662306a36Sopenharmony_ci				return NULL;
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci		*p++ = c;
16062306a36Sopenharmony_ci		if (c == '\n')
16162306a36Sopenharmony_ci			break;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	*p = 0;
16462306a36Sopenharmony_ci	return str;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_civoid xmon_printf(const char *format, ...)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	va_list args;
17062306a36Sopenharmony_ci	static char xmon_outbuf[1024];
17162306a36Sopenharmony_ci	int rc, n;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	va_start(args, format);
17462306a36Sopenharmony_ci	n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
17562306a36Sopenharmony_ci	va_end(args);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	rc = xmon_write(xmon_outbuf, n);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (n && rc == 0) {
18062306a36Sopenharmony_ci		/* No udbg hooks, fallback to printk() - dangerous */
18162306a36Sopenharmony_ci		pr_cont("%s", xmon_outbuf);
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_civoid xmon_puts(const char *str)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	xmon_write(str, strlen(str));
18862306a36Sopenharmony_ci}
189