blob: f7e92986952a2e669ae2fff8e5f45d1caf325041 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 1996 Paul Mackerras.
3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004#include <linux/string.h>
5#include <asm/machdep.h>
6#include <asm/io.h>
7#include <asm/page.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
9#include <linux/errno.h>
10#include <linux/sysrq.h>
11#include <linux/bitops.h>
12#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/machdep.h>
14#include <asm/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <asm/processor.h>
16#include <asm/delay.h>
17#include <asm/btext.h>
18
19static volatile unsigned char *sccc, *sccd;
20unsigned int TXRDY, RXRDY, DLAB;
21static int xmon_expect(const char *str, unsigned int timeout);
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023static int via_modem;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#define TB_SPEED 25000000
26
27static inline unsigned int readtb(void)
28{
29 unsigned int ret;
30
31 asm volatile("mftb %0" : "=r" (ret) :);
32 return ret;
33}
34
35void buf_access(void)
36{
37 if (DLAB)
38 sccd[3] &= ~DLAB; /* reset DLAB */
39}
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_MAGIC_SYSRQ
43static void sysrq_handle_xmon(int key, struct pt_regs *regs,
44 struct tty_struct *tty)
45{
46 xmon(regs);
47}
48
49static struct sysrq_key_op sysrq_xmon_op =
50{
51 .handler = sysrq_handle_xmon,
52 .help_msg = "Xmon",
53 .action_msg = "Entering xmon",
54};
55#endif
56
57void
58xmon_map_scc(void)
59{
Paul Mackerras0a26b132006-03-28 10:22:10 +110060#ifdef CONFIG_PPC_PREP
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 volatile unsigned char *base;
62
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#elif defined(CONFIG_GEMINI)
64 /* should already be mapped by the kernel boot */
65 sccc = (volatile unsigned char *) 0xffeffb0d;
66 sccd = (volatile unsigned char *) 0xffeffb08;
67 TXRDY = 0x20;
68 RXRDY = 1;
69 DLAB = 0x80;
70#elif defined(CONFIG_405GP)
71 sccc = (volatile unsigned char *)0xef600305;
72 sccd = (volatile unsigned char *)0xef600300;
73 TXRDY = 0x20;
74 RXRDY = 1;
75 DLAB = 0x80;
76#endif /* platform */
77
78 register_sysrq_key('x', &sysrq_xmon_op);
79}
80
Olaf Heringc57914a2006-02-21 21:06:41 +010081static int scc_initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83void xmon_init_scc(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85int
86xmon_write(void *handle, void *ptr, int nb)
87{
88 char *p = ptr;
89 int i, c, ct;
90
91#ifdef CONFIG_SMP
92 static unsigned long xmon_write_lock;
93 int lock_wait = 1000000;
94 int locked;
95
96 while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
97 if (--lock_wait == 0)
98 break;
99#endif
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (!scc_initialized)
102 xmon_init_scc();
103 ct = 0;
104 for (i = 0; i < nb; ++i) {
105 while ((*sccc & TXRDY) == 0)
Olaf Hering0728a2f2006-02-11 18:21:47 +0100106 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 c = p[i];
108 if (c == '\n' && !ct) {
109 c = '\r';
110 ct = 1;
111 --i;
112 } else {
113 ct = 0;
114 }
115 buf_access();
116 *sccd = c;
117 eieio();
118 }
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#ifdef CONFIG_SMP
121 if (!locked)
122 clear_bit(0, &xmon_write_lock);
123#endif
124 return nb;
125}
126
127int xmon_wants_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130int
131xmon_read(void *handle, void *ptr, int nb)
132{
133 char *p = ptr;
134 int i;
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 if (!scc_initialized)
137 xmon_init_scc();
138 for (i = 0; i < nb; ++i) {
139 while ((*sccc & RXRDY) == 0)
Olaf Heringc57914a2006-02-21 21:06:41 +0100140 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 buf_access();
142 *p++ = *sccd;
143 }
144 return i;
145}
146
147int
148xmon_read_poll(void)
149{
150 if ((*sccc & RXRDY) == 0) {
Olaf Heringc57914a2006-02-21 21:06:41 +0100151 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 return -1;
153 }
154 buf_access();
155 return *sccd;
156}
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158void
159xmon_init_scc(void)
160{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 scc_initialized = 1;
162 if (via_modem) {
163 for (;;) {
164 xmon_write(NULL, "ATE1V1\r", 7);
165 if (xmon_expect("OK", 5)) {
166 xmon_write(NULL, "ATA\r", 4);
167 if (xmon_expect("CONNECT", 40))
168 break;
169 }
170 xmon_write(NULL, "+++", 3);
171 xmon_expect("OK", 3);
172 }
173 }
174}
175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177void *xmon_stdin;
178void *xmon_stdout;
179void *xmon_stderr;
180
181void
Paul Mackerrasfd582ec2005-10-11 22:08:12 +1000182xmon_init(int arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
Paul Mackerrasfd582ec2005-10-11 22:08:12 +1000184 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
187int
188xmon_putc(int c, void *f)
189{
190 char ch = c;
191
192 if (c == '\n')
193 xmon_putc('\r', f);
194 return xmon_write(f, &ch, 1) == 1? c: -1;
195}
196
197int
198xmon_putchar(int c)
199{
200 return xmon_putc(c, xmon_stdout);
201}
202
203int
204xmon_fputs(char *str, void *f)
205{
206 int n = strlen(str);
207
208 return xmon_write(f, str, n) == n? 0: -1;
209}
210
211int
212xmon_readchar(void)
213{
214 char ch;
215
216 for (;;) {
217 switch (xmon_read(xmon_stdin, &ch, 1)) {
218 case 1:
219 return ch;
220 case -1:
221 xmon_printf("read(stdin) returned -1\r\n", 0, 0);
222 return -1;
223 }
224 }
225}
226
227static char line[256];
228static char *lineptr;
229static int lineleft;
230
231int xmon_expect(const char *str, unsigned int timeout)
232{
233 int c;
234 unsigned int t0;
235
236 timeout *= TB_SPEED;
237 t0 = readtb();
238 do {
239 lineptr = line;
240 for (;;) {
241 c = xmon_read_poll();
242 if (c == -1) {
243 if (readtb() - t0 > timeout)
244 return 0;
245 continue;
246 }
247 if (c == '\n')
248 break;
249 if (c != '\r' && lineptr < &line[sizeof(line) - 1])
250 *lineptr++ = c;
251 }
252 *lineptr = 0;
253 } while (strstr(line, str) == NULL);
254 return 1;
255}
256
257int
258xmon_getchar(void)
259{
260 int c;
261
262 if (lineleft == 0) {
263 lineptr = line;
264 for (;;) {
265 c = xmon_readchar();
266 if (c == -1 || c == 4)
267 break;
268 if (c == '\r' || c == '\n') {
269 *lineptr++ = '\n';
270 xmon_putchar('\n');
271 break;
272 }
273 switch (c) {
274 case 0177:
275 case '\b':
276 if (lineptr > line) {
277 xmon_putchar('\b');
278 xmon_putchar(' ');
279 xmon_putchar('\b');
280 --lineptr;
281 }
282 break;
283 case 'U' & 0x1F:
284 while (lineptr > line) {
285 xmon_putchar('\b');
286 xmon_putchar(' ');
287 xmon_putchar('\b');
288 --lineptr;
289 }
290 break;
291 default:
292 if (lineptr >= &line[sizeof(line) - 1])
293 xmon_putchar('\a');
294 else {
295 xmon_putchar(c);
296 *lineptr++ = c;
297 }
298 }
299 }
300 lineleft = lineptr - line;
301 lineptr = line;
302 }
303 if (lineleft == 0)
304 return -1;
305 --lineleft;
306 return *lineptr++;
307}
308
309char *
310xmon_fgets(char *str, int nb, void *f)
311{
312 char *p;
313 int c;
314
315 for (p = str; p < str + nb - 1; ) {
316 c = xmon_getchar();
317 if (c == -1) {
318 if (p == str)
319 return NULL;
320 break;
321 }
322 *p++ = c;
323 if (c == '\n')
324 break;
325 }
326 *p = 0;
327 return str;
328}
329
330void
331xmon_enter(void)
332{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
335void
336xmon_leave(void)
337{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}