blob: cfc2d6ad464ddcbdd31a59a59fb024a5a19cd83c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 1996 Paul Mackerras.
3 */
4#include <linux/config.h>
5#include <linux/string.h>
6#include <asm/machdep.h>
7#include <asm/io.h>
8#include <asm/page.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/kernel.h>
10#include <linux/errno.h>
11#include <linux/sysrq.h>
12#include <linux/bitops.h>
13#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <asm/machdep.h>
15#include <asm/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <asm/processor.h>
17#include <asm/delay.h>
18#include <asm/btext.h>
19
20static volatile unsigned char *sccc, *sccd;
21unsigned int TXRDY, RXRDY, DLAB;
22static int xmon_expect(const char *str, unsigned int timeout);
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024static int via_modem;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
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{
Paul Mackerras0a26b132006-03-28 10:22:10 +110061#ifdef CONFIG_PPC_PREP
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 volatile unsigned char *base;
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#elif defined(CONFIG_GEMINI)
65 /* should already be mapped by the kernel boot */
66 sccc = (volatile unsigned char *) 0xffeffb0d;
67 sccd = (volatile unsigned char *) 0xffeffb08;
68 TXRDY = 0x20;
69 RXRDY = 1;
70 DLAB = 0x80;
71#elif defined(CONFIG_405GP)
72 sccc = (volatile unsigned char *)0xef600305;
73 sccd = (volatile unsigned char *)0xef600300;
74 TXRDY = 0x20;
75 RXRDY = 1;
76 DLAB = 0x80;
77#endif /* platform */
78
79 register_sysrq_key('x', &sysrq_xmon_op);
80}
81
Olaf Heringc57914a2006-02-21 21:06:41 +010082static int scc_initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84void xmon_init_scc(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86int
87xmon_write(void *handle, void *ptr, int nb)
88{
89 char *p = ptr;
90 int i, c, ct;
91
92#ifdef CONFIG_SMP
93 static unsigned long xmon_write_lock;
94 int lock_wait = 1000000;
95 int locked;
96
97 while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
98 if (--lock_wait == 0)
99 break;
100#endif
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 if (!scc_initialized)
103 xmon_init_scc();
104 ct = 0;
105 for (i = 0; i < nb; ++i) {
106 while ((*sccc & TXRDY) == 0)
Olaf Hering0728a2f2006-02-11 18:21:47 +0100107 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 c = p[i];
109 if (c == '\n' && !ct) {
110 c = '\r';
111 ct = 1;
112 --i;
113 } else {
114 ct = 0;
115 }
116 buf_access();
117 *sccd = c;
118 eieio();
119 }
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#ifdef CONFIG_SMP
122 if (!locked)
123 clear_bit(0, &xmon_write_lock);
124#endif
125 return nb;
126}
127
128int xmon_wants_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131int
132xmon_read(void *handle, void *ptr, int nb)
133{
134 char *p = ptr;
135 int i;
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 if (!scc_initialized)
138 xmon_init_scc();
139 for (i = 0; i < nb; ++i) {
140 while ((*sccc & RXRDY) == 0)
Olaf Heringc57914a2006-02-21 21:06:41 +0100141 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 buf_access();
143 *p++ = *sccd;
144 }
145 return i;
146}
147
148int
149xmon_read_poll(void)
150{
151 if ((*sccc & RXRDY) == 0) {
Olaf Heringc57914a2006-02-21 21:06:41 +0100152 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return -1;
154 }
155 buf_access();
156 return *sccd;
157}
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159void
160xmon_init_scc(void)
161{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 scc_initialized = 1;
163 if (via_modem) {
164 for (;;) {
165 xmon_write(NULL, "ATE1V1\r", 7);
166 if (xmon_expect("OK", 5)) {
167 xmon_write(NULL, "ATA\r", 4);
168 if (xmon_expect("CONNECT", 40))
169 break;
170 }
171 xmon_write(NULL, "+++", 3);
172 xmon_expect("OK", 3);
173 }
174 }
175}
176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178void *xmon_stdin;
179void *xmon_stdout;
180void *xmon_stderr;
181
182void
Paul Mackerrasfd582ec2005-10-11 22:08:12 +1000183xmon_init(int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
Paul Mackerrasfd582ec2005-10-11 22:08:12 +1000185 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
188int
189xmon_putc(int c, void *f)
190{
191 char ch = c;
192
193 if (c == '\n')
194 xmon_putc('\r', f);
195 return xmon_write(f, &ch, 1) == 1? c: -1;
196}
197
198int
199xmon_putchar(int c)
200{
201 return xmon_putc(c, xmon_stdout);
202}
203
204int
205xmon_fputs(char *str, void *f)
206{
207 int n = strlen(str);
208
209 return xmon_write(f, str, n) == n? 0: -1;
210}
211
212int
213xmon_readchar(void)
214{
215 char ch;
216
217 for (;;) {
218 switch (xmon_read(xmon_stdin, &ch, 1)) {
219 case 1:
220 return ch;
221 case -1:
222 xmon_printf("read(stdin) returned -1\r\n", 0, 0);
223 return -1;
224 }
225 }
226}
227
228static char line[256];
229static char *lineptr;
230static int lineleft;
231
232int xmon_expect(const char *str, unsigned int timeout)
233{
234 int c;
235 unsigned int t0;
236
237 timeout *= TB_SPEED;
238 t0 = readtb();
239 do {
240 lineptr = line;
241 for (;;) {
242 c = xmon_read_poll();
243 if (c == -1) {
244 if (readtb() - t0 > timeout)
245 return 0;
246 continue;
247 }
248 if (c == '\n')
249 break;
250 if (c != '\r' && lineptr < &line[sizeof(line) - 1])
251 *lineptr++ = c;
252 }
253 *lineptr = 0;
254 } while (strstr(line, str) == NULL);
255 return 1;
256}
257
258int
259xmon_getchar(void)
260{
261 int c;
262
263 if (lineleft == 0) {
264 lineptr = line;
265 for (;;) {
266 c = xmon_readchar();
267 if (c == -1 || c == 4)
268 break;
269 if (c == '\r' || c == '\n') {
270 *lineptr++ = '\n';
271 xmon_putchar('\n');
272 break;
273 }
274 switch (c) {
275 case 0177:
276 case '\b':
277 if (lineptr > line) {
278 xmon_putchar('\b');
279 xmon_putchar(' ');
280 xmon_putchar('\b');
281 --lineptr;
282 }
283 break;
284 case 'U' & 0x1F:
285 while (lineptr > line) {
286 xmon_putchar('\b');
287 xmon_putchar(' ');
288 xmon_putchar('\b');
289 --lineptr;
290 }
291 break;
292 default:
293 if (lineptr >= &line[sizeof(line) - 1])
294 xmon_putchar('\a');
295 else {
296 xmon_putchar(c);
297 *lineptr++ = c;
298 }
299 }
300 }
301 lineleft = lineptr - line;
302 lineptr = line;
303 }
304 if (lineleft == 0)
305 return -1;
306 --lineleft;
307 return *lineptr++;
308}
309
310char *
311xmon_fgets(char *str, int nb, void *f)
312{
313 char *p;
314 int c;
315
316 for (p = str; p < str + nb - 1; ) {
317 c = xmon_getchar();
318 if (c == -1) {
319 if (p == str)
320 return NULL;
321 break;
322 }
323 *p++ = c;
324 if (c == '\n')
325 break;
326 }
327 *p = 0;
328 return str;
329}
330
331void
332xmon_enter(void)
333{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336void
337xmon_leave(void)
338{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339}