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