Merge branch 'master'
[linux-2.6] / arch / ppc / xmon / start.c
1 /*
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>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/sysrq.h>
12 #include <linux/bitops.h>
13 #include <asm/xmon.h>
14 #include <asm/machdep.h>
15 #include <asm/errno.h>
16 #include <asm/processor.h>
17 #include <asm/delay.h>
18 #include <asm/btext.h>
19
20 static volatile unsigned char *sccc, *sccd;
21 unsigned int TXRDY, RXRDY, DLAB;
22 static int xmon_expect(const char *str, unsigned int timeout);
23
24 static int via_modem;
25
26 #define TB_SPEED        25000000
27
28 static inline unsigned int readtb(void)
29 {
30         unsigned int ret;
31
32         asm volatile("mftb %0" : "=r" (ret) :);
33         return ret;
34 }
35
36 void buf_access(void)
37 {
38         if (DLAB)
39                 sccd[3] &= ~DLAB;       /* reset DLAB */
40 }
41
42
43 #ifdef CONFIG_MAGIC_SYSRQ
44 static void sysrq_handle_xmon(int key, struct pt_regs *regs,
45                               struct tty_struct *tty)
46 {
47         xmon(regs);
48 }
49
50 static 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
58 void
59 xmon_map_scc(void)
60 {
61 #ifdef CONFIG_PPC_MULTIPLATFORM
62         volatile unsigned char *base;
63
64 #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
82 static int scc_initialized;
83
84 void xmon_init_scc(void);
85
86 int
87 xmon_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
102         if (!scc_initialized)
103                 xmon_init_scc();
104         ct = 0;
105         for (i = 0; i < nb; ++i) {
106                 while ((*sccc & TXRDY) == 0)
107                         ;
108                 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
121 #ifdef CONFIG_SMP
122         if (!locked)
123                 clear_bit(0, &xmon_write_lock);
124 #endif
125         return nb;
126 }
127
128 int xmon_wants_key;
129
130
131 int
132 xmon_read(void *handle, void *ptr, int nb)
133 {
134     char *p = ptr;
135     int i;
136
137     if (!scc_initialized)
138         xmon_init_scc();
139     for (i = 0; i < nb; ++i) {
140         while ((*sccc & RXRDY) == 0)
141             ;
142         buf_access();
143         *p++ = *sccd;
144     }
145     return i;
146 }
147
148 int
149 xmon_read_poll(void)
150 {
151         if ((*sccc & RXRDY) == 0) {
152                 ;
153                 return -1;
154         }
155         buf_access();
156         return *sccd;
157 }
158
159 void
160 xmon_init_scc(void)
161 {
162         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
177
178 void *xmon_stdin;
179 void *xmon_stdout;
180 void *xmon_stderr;
181
182 void
183 xmon_init(int arg)
184 {
185         xmon_map_scc();
186 }
187
188 int
189 xmon_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
198 int
199 xmon_putchar(int c)
200 {
201     return xmon_putc(c, xmon_stdout);
202 }
203
204 int
205 xmon_fputs(char *str, void *f)
206 {
207     int n = strlen(str);
208
209     return xmon_write(f, str, n) == n? 0: -1;
210 }
211
212 int
213 xmon_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
228 static char line[256];
229 static char *lineptr;
230 static int lineleft;
231
232 int 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
258 int
259 xmon_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
310 char *
311 xmon_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
331 void
332 xmon_enter(void)
333 {
334 }
335
336 void
337 xmon_leave(void)
338 {
339 }