1/*
2 * Copyright (C) 1996 Paul Mackerras.
3 */
4#include <linux/string.h>
5#include <asm/machdep.h>
6#include <asm/io.h>
7#include <asm/page.h>
8#include <linux/kernel.h>
9#include <linux/errno.h>
10#include <linux/sysrq.h>
11#include <linux/bitops.h>
12#include <asm/xmon.h>
13#include <asm/machdep.h>
14#include <asm/errno.h>
15#include <asm/processor.h>
16#include <asm/delay.h>
17#include <asm/btext.h>
18#include <asm/ibm4xx.h>
19
20static volatile unsigned char *sccc, *sccd;
21unsigned int TXRDY, RXRDY, DLAB;
22static int xmon_expect(const char *str, unsigned int timeout);
23
24static int via_modem;
25
26#define TB_SPEED	25000000
27
28static inline unsigned int readtb(void)
29{
30	unsigned int ret;
31
32	asm volatile("mftb %0" : "=r" (ret) :);
33	return ret;
34}
35
36void buf_access(void)
37{
38	if (DLAB)
39		sccd[3] &= ~DLAB;	/* reset DLAB */
40}
41
42
43#ifdef CONFIG_MAGIC_SYSRQ
44static void sysrq_handle_xmon(int key, struct pt_regs *regs,
45			      struct tty_struct *tty)
46{
47	xmon(regs);
48}
49
50static struct sysrq_key_op sysrq_xmon_op =
51{
52	.handler =	sysrq_handle_xmon,
53	.help_msg =	"Xmon",
54	.action_msg =	"Entering xmon",
55};
56#endif
57
58void
59xmon_map_scc(void)
60{
61#if defined(CONFIG_405GP)
62	sccd = (volatile unsigned char *)0xef600300;
63#elif defined(CONFIG_440EP)
64	sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8);
65#elif defined(CONFIG_440SP)
66	sccd = (volatile unsigned char *) ioremap64(PPC440SP_UART0_ADDR, 8);
67#elif defined(CONFIG_440SPE)
68	sccd = (volatile unsigned char *) ioremap64(PPC440SPE_UART0_ADDR, 8);
69#elif defined(CONFIG_44x)
70	/* This is the default for 44x platforms.  Any boards that have a
71	   different UART address need to be put in cases before this or the
72	   port will be mapped incorrectly */
73	sccd = (volatile unsigned char *) ioremap64(PPC440GP_UART0_ADDR, 8);
74#endif /* platform */
75
76#ifndef CONFIG_PPC_PREP
77	sccc = sccd + 5;
78	TXRDY = 0x20;
79	RXRDY = 1;
80	DLAB = 0x80;
81#endif
82
83	register_sysrq_key('x', &sysrq_xmon_op);
84}
85
86static int scc_initialized;
87
88void xmon_init_scc(void);
89
90int
91xmon_write(void *handle, void *ptr, int nb)
92{
93	char *p = ptr;
94	int i, c, ct;
95
96#ifdef CONFIG_SMP
97	static unsigned long xmon_write_lock;
98	int lock_wait = 1000000;
99	int locked;
100
101	while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
102		if (--lock_wait == 0)
103			break;
104#endif
105
106	if (!scc_initialized)
107		xmon_init_scc();
108	ct = 0;
109	for (i = 0; i < nb; ++i) {
110		while ((*sccc & TXRDY) == 0)
111			;
112		c = p[i];
113		if (c == '\n' && !ct) {
114			c = '\r';
115			ct = 1;
116			--i;
117		} else {
118			ct = 0;
119		}
120		buf_access();
121		*sccd = c;
122		eieio();
123	}
124
125#ifdef CONFIG_SMP
126	if (!locked)
127		clear_bit(0, &xmon_write_lock);
128#endif
129	return nb;
130}
131
132int xmon_wants_key;
133
134
135int
136xmon_read(void *handle, void *ptr, int nb)
137{
138    char *p = ptr;
139    int i;
140
141    if (!scc_initialized)
142	xmon_init_scc();
143    for (i = 0; i < nb; ++i) {
144	while ((*sccc & RXRDY) == 0)
145	    ;
146	buf_access();
147	*p++ = *sccd;
148    }
149    return i;
150}
151
152int
153xmon_read_poll(void)
154{
155	if ((*sccc & RXRDY) == 0) {
156		;
157		return -1;
158	}
159	buf_access();
160	return *sccd;
161}
162
163void
164xmon_init_scc(void)
165{
166	scc_initialized = 1;
167	if (via_modem) {
168		for (;;) {
169			xmon_write(NULL, "ATE1V1\r", 7);
170			if (xmon_expect("OK", 5)) {
171				xmon_write(NULL, "ATA\r", 4);
172				if (xmon_expect("CONNECT", 40))
173					break;
174			}
175			xmon_write(NULL, "+++", 3);
176			xmon_expect("OK", 3);
177		}
178	}
179}
180
181
182void *xmon_stdin;
183void *xmon_stdout;
184void *xmon_stderr;
185
186void
187xmon_init(int arg)
188{
189	xmon_map_scc();
190}
191
192int
193xmon_putc(int c, void *f)
194{
195    char ch = c;
196
197    if (c == '\n')
198	xmon_putc('\r', f);
199    return xmon_write(f, &ch, 1) == 1? c: -1;
200}
201
202int
203xmon_putchar(int c)
204{
205    return xmon_putc(c, xmon_stdout);
206}
207
208int
209xmon_fputs(char *str, void *f)
210{
211    int n = strlen(str);
212
213    return xmon_write(f, str, n) == n? 0: -1;
214}
215
216int
217xmon_readchar(void)
218{
219    char ch;
220
221    for (;;) {
222	switch (xmon_read(xmon_stdin, &ch, 1)) {
223	case 1:
224	    return ch;
225	case -1:
226	    xmon_printf("read(stdin) returned -1\r\n", 0, 0);
227	    return -1;
228	}
229    }
230}
231
232static char line[256];
233static char *lineptr;
234static int lineleft;
235
236int xmon_expect(const char *str, unsigned int timeout)
237{
238	int c;
239	unsigned int t0;
240
241	timeout *= TB_SPEED;
242	t0 = readtb();
243	do {
244		lineptr = line;
245		for (;;) {
246			c = xmon_read_poll();
247			if (c == -1) {
248				if (readtb() - t0 > timeout)
249					return 0;
250				continue;
251			}
252			if (c == '\n')
253				break;
254			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
255				*lineptr++ = c;
256		}
257		*lineptr = 0;
258	} while (strstr(line, str) == NULL);
259	return 1;
260}
261
262int
263xmon_getchar(void)
264{
265    int c;
266
267    if (lineleft == 0) {
268	lineptr = line;
269	for (;;) {
270	    c = xmon_readchar();
271	    if (c == -1 || c == 4)
272		break;
273	    if (c == '\r' || c == '\n') {
274		*lineptr++ = '\n';
275		xmon_putchar('\n');
276		break;
277	    }
278	    switch (c) {
279	    case 0177:
280	    case '\b':
281		if (lineptr > line) {
282		    xmon_putchar('\b');
283		    xmon_putchar(' ');
284		    xmon_putchar('\b');
285		    --lineptr;
286		}
287		break;
288	    case 'U' & 0x1F:
289		while (lineptr > line) {
290		    xmon_putchar('\b');
291		    xmon_putchar(' ');
292		    xmon_putchar('\b');
293		    --lineptr;
294		}
295		break;
296	    default:
297		if (lineptr >= &line[sizeof(line) - 1])
298		    xmon_putchar('\a');
299		else {
300		    xmon_putchar(c);
301		    *lineptr++ = c;
302		}
303	    }
304	}
305	lineleft = lineptr - line;
306	lineptr = line;
307    }
308    if (lineleft == 0)
309	return -1;
310    --lineleft;
311    return *lineptr++;
312}
313
314char *
315xmon_fgets(char *str, int nb, void *f)
316{
317    char *p;
318    int c;
319
320    for (p = str; p < str + nb - 1; ) {
321	c = xmon_getchar();
322	if (c == -1) {
323	    if (p == str)
324		return NULL;
325	    break;
326	}
327	*p++ = c;
328	if (c == '\n')
329	    break;
330    }
331    *p = 0;
332    return str;
333}
334
335void
336xmon_enter(void)
337{
338}
339
340void
341xmon_leave(void)
342{
343}
344