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