blob: a2b829db185ff6a16d3d339cd57d0b66f5af75c1 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* lib.c - MemTest-86 Version 3.4
2 *
3 * Released under version 2 of the Gnu Public License.
4 * By Chris Brady
5 */
6#include "io.h"
7#include "serial.h"
8#include "test.h"
9#include "config.h"
10#include "screen_buffer.h"
11#include "stdint.h"
12#include "cpuid.h"
13#include "smp.h"
14
15
16int slock = 0, lsr = 0;
17short serial_cons = SERIAL_CONSOLE_DEFAULT;
18#if SERIAL_TTY != 0 && SERIAL_TTY != 1
19#error Bad SERIAL_TTY. Only ttyS0 and ttyS1 are supported.
20#endif
21short serial_tty = SERIAL_TTY;
22const short serial_base_ports[] = {0x3f8, 0x2f8};
23
24#if ((115200%SERIAL_BAUD_RATE) != 0)
25#error Bad default baud rate
26#endif
27int serial_baud_rate = SERIAL_BAUD_RATE;
28unsigned char serial_parity = 0;
29unsigned char serial_bits = 8;
30
31struct ascii_map_str {
32 int ascii;
33 int keycode;
34};
35
36inline void reboot(void)
37{
38
39 /* tell the BIOS to do a cold start */
40 *((unsigned short *)0x472) = 0x0;
41
42 while(1)
43 {
44 outb(0xFE, 0x64);
45 outb(0x02, 0xcf9); /* reset that doesn't rely on the keyboard controller */
46 outb(0x04, 0xcf9);
47 outb(0x0E, 0xcf9);
48 }
49}
50
51int strlen(char * string){
52 int i=0;
53 while(*string++){i++;};
54 return i;
55}
56
57int strstr(char *haystack, char * needle)
58{
59 int i=0,j=0;
60 int here=0;
61 while(1){
62 if(needle[i]==haystack[j])
63 {
64 if(here==0)
65 here=j;
66 i++;j++;
67 if(i>=strlen(needle))
68 {
69 return here;
70 }
71 if(j>=strlen(haystack))
72 {
73 return -1;
74 }
75 } else {
76 j++;i=0;here=0;
77 }
78 }
79}
80
81int memcmp(const void *s1, const void *s2, ulong count)
82{
83 const unsigned char *src1 = s1, *src2 = s2;
84 int i;
85 for(i = 0; i < count; i++) {
86 if (src1[i] != src2[i]) {
87 return (int)src1[i] - (int)src2[i];
88 }
89 }
90 return 0;
91}
92
93int strncmp(const char *s1, const char *s2, ulong n) {
94 signed char res = 0;
95 while (n) {
96 res = *s1 - *s2;
97 if (res != 0)
98 return res;
99 if (*s1 == '\0')
100 return 0;
101 ++s1, ++s2;
102 --n;
103 }
104 return res;
105}
106
107void *memmove(void *dest, const void *src, ulong n)
108{
109 long i;
110 char *d = (char *)dest, *s = (char *)src;
111
112 /* If src == dest do nothing */
113 if (dest < src) {
114 for(i = 0; i < n; i++) {
115 d[i] = s[i];
116 }
117 }
118 else if (dest > src) {
119 for(i = n -1; i >= 0; i--) {
120 d[i] = s[i];
121 }
122 }
123 return dest;
124}
125
126char toupper(char c)
127{
128 if (c >= 'a' && c <= 'z')
129 return c + 'A' -'a';
130 else
131 return c;
132}
133
134int isdigit(char c)
135{
136 return c >= '0' && c <= '9';
137}
138
139int isxdigit(char c)
140{
141 return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); }
142
143unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) {
144 unsigned long result = 0, value;
145
146 if (!base) {
147 base = 10;
148 if (*cp == '0') {
149 base = 8;
150 cp++;
151 if (toupper(*cp) == 'X' && isxdigit(cp[1])) {
152 cp++;
153 base = 16;
154 }
155 }
156 } else if (base == 16) {
157 if (cp[0] == '0' && toupper(cp[1]) == 'X')
158 cp += 2;
159 }
160 while (isxdigit(*cp) &&
161 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
162 result = result*base + value;
163 cp++;
164 }
165 if (endp)
166 *endp = (char *)cp;
167 return result;
168}
169
170/*
171 * Scroll the error message area of the screen as needed
172 * Starts at line LINE_SCROLL and ends at line 23
173 */
174void scroll(void)
175{
176 int i, j;
177 char *s, tmp;
178
179 /* Only scroll if at the bottom of the screen */
180 if (v->msg_line < 23) {
181 v->msg_line++;
182 } else {
183 /* If scroll lock is on, loop till it is cleared */
184 while (slock) {
185 check_input();
186 }
187 for (i=LINE_SCROLL; i<23; i++) {
188 s = (char *)(SCREEN_ADR + ((i+1) * 160));
189 for (j=0; j<160; j+=2, s+=2) {
190 *(s-160) = *s;
191 tmp = get_scrn_buf(i+1, j/2);
192 set_scrn_buf(i, j/2, tmp);
193 }
194 }
195 /* Clear the newly opened line */
196 s = (char *)(SCREEN_ADR + (23 * 160));
197 for (j=0; j<80; j++) {
198 *s = ' ';
199 set_scrn_buf(23, j, ' ');
200 s += 2;
201 }
202 tty_print_region(LINE_SCROLL, 0, 23, 79);
203 }
204}
205
206/*
207 * Clear scroll region
208 */
209void clear_scroll(void)
210{
211 int i;
212 char *s;
213
214 s = (char*)(SCREEN_ADR+LINE_HEADER*160);
215 for(i=0; i<80*(24-LINE_HEADER); i++) {
216 *s++ = ' ';
217 *s++ = 0x17;
218 }
219}
220
221/*
222 * Place a single character on screen
223 */
224void cplace(int y, int x, const char c)
225{
226 char *dptr;
227
228 dptr = (char *)(SCREEN_ADR + (160*y) + (2*x));
229 *dptr = c;
230}
231
232/*
233 * Print characters on screen
234 */
235void cprint(int y, int x, const char *text)
236{
237 register int i;
238 char *dptr;
239
240 dptr = (char *)(SCREEN_ADR + (160*y) + (2*x));
241 for (i=0; text[i]; i++) {
242 *dptr = text[i];
243 dptr += 2;
244 }
245 tty_print_line(y, x, text);
246}
247
248void itoa(char s[], int n)
249{
250 int i, sign;
251
252 if((sign = n) < 0)
253 n = -n;
254 i=0;
255 do {
256 s[i++] = n % 10 + '0';
257 } while ((n /= 10) > 0);
258 if(sign < 0)
259 s[i++] = '-';
260 s[i] = '\0';
261 reverse(s);
262}
263
264void reverse(char s[])
265{
266 int c, i, j;
267 for(j = 0; s[j] != 0; j++)
268 ;
269
270 for(i=0, j = j - 1; i < j; i++, j--) {
271 c = s[i];
272 s[i] = s[j];
273 s[j] = c;
274 }
275}
276void memcpy (void *dst, void *src, int len)
277{
278 char *s = (char*)src;
279 char *d = (char*)dst;
280 int i;
281
282 if (len <= 0) {
283 return;
284 }
285 for (i = 0 ; i < len; i++) {
286 *d++ = *s++;
287 }
288}
289
290/*
291 * Print a people friendly address
292 */
293void aprint(int y, int x, ulong page)
294{
295 /* page is in multiples of 4K */
296 if ((page << 2) < 9999) {
297 dprint(y, x, page << 2, 4, 0);
298 cprint(y, x+4, "K");
299 }
300 else if ((page >>8) < 9999) {
301 dprint(y, x, (page + (1 << 7)) >> 8, 4, 0);
302 cprint(y, x+4, "M");
303 }
304 else if ((page >>18) < 9999) {
305 dprint(y, x, (page + (1 << 17)) >> 18, 4, 0);
306 cprint(y, x+4, "G");
307 }
308 else {
309 dprint(y, x, (page + (1 << 27)) >> 28, 4, 0);
310 cprint(y, x+4, "T");
311 }
312}
313
314/*
315 * Print a decimal number on screen
316 */
317void dprint(int y, int x, ulong val, int len, int right)
318{
319 ulong j, k;
320 int i, flag=0;
321 char buf[18];
322
323 if (val > 999999999 || len > 9) {
324 return;
325 }
326 for(i=0, j=1; i<len-1; i++) {
327 j *= 10;
328 }
329 if (!right) {
330 for (i=0; j>0; j/=10) {
331 k = val/j;
332 if (k > 9) {
333 j *= 100;
334 continue;
335 }
336 if (flag || k || j == 1) {
337 buf[i++] = k + '0';
338 flag++;
339 } else {
340 buf[i++] = ' ';
341 }
342 val -= k * j;
343 }
344 } else {
345 for(i=0; i<len; j/=10) {
346 if (j) {
347 k = val/j;
348 if (k > 9) {
349 j *= 100;
350 len++;
351 continue;
352 }
353 if (k == 0 && flag == 0) {
354 continue;
355 }
356 buf[i++] = k + '0';
357 val -= k * j;
358 } else {
359 if (flag == 0 && i < len-1) {
360 buf[i++] = '0';
361 } else {
362 buf[i++] = ' ';
363 }
364 }
365 flag++;
366 }
367 }
368 buf[i] = 0;
369 cprint(y,x,buf);
370}
371
372/*
373 * Print a hex number on screen at least digits long
374 */
375void hprint2(int y,int x, unsigned long val, int digits)
376{
377 unsigned long j;
378 int i, idx, flag = 0;
379 char buf[18];
380
381 for (i=0, idx=0; i<8; i++) {
382 j = val >> (28 - (4 * i));
383 j &= 0xf;
384 if (j < 10) {
385 if (flag || j || i == 7) {
386 buf[idx++] = j + '0';
387 flag++;
388 } else {
389 buf[idx++] = '0';
390 }
391 } else {
392 buf[idx++] = j + 'a' - 10;
393 flag++;
394 }
395 }
396 if (digits > 8) {
397 digits = 8;
398 }
399 if (flag > digits) {
400 digits = flag;
401 }
402 buf[idx] = 0;
403 cprint(y,x,buf + (idx - digits));
404}
405
406/*
407 * Print a hex number on screen exactly digits long
408 */
409void hprint3(int y,int x, unsigned long val, int digits)
410{
411 unsigned long j;
412 int i, idx, flag = 0;
413 char buf[18];
414
415 for (i=0, idx=0; i<digits; i++) {
416 j = 0xf & val;
417 val /= 16;
418
419 if (j < 10) {
420 if (flag || j || i == 7) {
421 buf[digits - ++idx] = j + '0';
422 flag++;
423 } else {
424 buf[digits - ++idx] = '0';
425 }
426 } else {
427 buf[digits - ++idx] = j + 'a' - 10;
428 flag++;
429 }
430 }
431 buf[idx] = 0;
432 cprint(y,x,buf);
433}
434
435/*
436 * Print a hex number on screen
437 */
438void hprint(int y, int x, unsigned long val)
439{
440 return hprint2(y, x, val, 8);
441}
442
443/*
444 * Print an address in 0000m0000k0000 notation
445 */
446void xprint(int y,int x, ulong val)
447{
448 ulong j;
449
450 j = (val & 0xffc00000) >> 20;
451 dprint(y, x, j, 4, 0);
452 cprint(y, x+4, "m");
453 j = (val & 0xffc00) >> 10;
454 dprint(y, x+5, j, 4, 0);
455 cprint(y, x+9, "k");
456 j = val & 0x3ff;
457 dprint(y, x+10, j, 4, 0);
458}
459
460char *codes[] = {
461 " Divide",
462 " Debug",
463 " NMI",
464 " Brkpnt",
465 "Overflow",
466 " Bound",
467 " Inv_Op",
468 " No_Math",
469 "Double_Fault",
470 "Seg_Over",
471 " Inv_TSS",
472 " Seg_NP",
473 "Stack_Fault",
474 "Gen_Prot",
475 "Page_Fault",
476 " Resvd",
477 " FPE",
478 "Alignment",
479 " Mch_Chk",
480 "SIMD FPE"
481};
482
483struct eregs {
484 ulong ss;
485 ulong ds;
486 ulong esp;
487 ulong ebp;
488 ulong esi;
489 ulong edi;
490 ulong edx;
491 ulong ecx;
492 ulong ebx;
493 ulong eax;
494 ulong vect;
495 ulong code;
496 ulong eip;
497 ulong cs;
498 ulong eflag;
499};
500
501/* Handle an interrupt */
502void inter(struct eregs *trap_regs)
503{
504 int i, line;
505 unsigned char *pp;
506 ulong address = 0;
507 int my_cpu_num = smp_my_cpu_num();
508
509 /* Get the page fault address */
510 if (trap_regs->vect == 14) {
511 __asm__("movl %%cr2,%0":"=r" (address));
512 }
513#ifdef PARITY_MEM
514
515 /* Check for a parity error */
516 if (trap_regs->vect == 2) {
517 parity_err(trap_regs->edi, trap_regs->esi);
518 return;
519 }
520#endif
521
522 /* clear scrolling region */
523 pp=(unsigned char *)(SCREEN_ADR+(2*80*(LINE_SCROLL-2)));
524 for(i=0; i<2*80*(24-LINE_SCROLL-2); i++, pp+=2) {
525 *pp = ' ';
526 }
527 line = LINE_SCROLL-2;
528
529 cprint(line, 0, "Unexpected Interrupt - Halting CPU");
530 dprint(line, COL_MID + 4, my_cpu_num, 2, 1);
531 cprint(line+2, 0, " Type: ");
532 if (trap_regs->vect <= 19) {
533 cprint(line+2, 7, codes[trap_regs->vect]);
534 } else {
535 hprint(line+2, 7, trap_regs->vect);
536 }
537 cprint(line+3, 0, " PC: ");
538 hprint(line+3, 7, trap_regs->eip);
539 cprint(line+4, 0, " CS: ");
540 hprint(line+4, 7, trap_regs->cs);
541 cprint(line+5, 0, "Eflag: ");
542 hprint(line+5, 7, trap_regs->eflag);
543 cprint(line+6, 0, " Code: ");
544 hprint(line+6, 7, trap_regs->code);
545 cprint(line+7, 0, " DS: ");
546 hprint(line+7, 7, trap_regs->ds);
547 cprint(line+8, 0, " SS: ");
548 hprint(line+8, 7, trap_regs->ss);
549 if (trap_regs->vect == 14) {
550 /* Page fault address */
551 cprint(line+7, 0, " Addr: ");
552 hprint(line+7, 7, address);
553 }
554
555 cprint(line+2, 20, "eax: ");
556 hprint(line+2, 25, trap_regs->eax);
557 cprint(line+3, 20, "ebx: ");
558 hprint(line+3, 25, trap_regs->ebx);
559 cprint(line+4, 20, "ecx: ");
560 hprint(line+4, 25, trap_regs->ecx);
561 cprint(line+5, 20, "edx: ");
562 hprint(line+5, 25, trap_regs->edx);
563 cprint(line+6, 20, "edi: ");
564 hprint(line+6, 25, trap_regs->edi);
565 cprint(line+7, 20, "esi: ");
566 hprint(line+7, 25, trap_regs->esi);
567 cprint(line+8, 20, "ebp: ");
568 hprint(line+8, 25, trap_regs->ebp);
569 cprint(line+9, 20, "esp: ");
570 hprint(line+9, 25, trap_regs->esp);
571
572 cprint(line+1, 38, "Stack:");
573 for (i=0; i<10; i++) {
574 hprint(line+2+i, 38, trap_regs->esp+(4*i));
575 hprint(line+2+i, 47, *(ulong*)(trap_regs->esp+(4*i)));
576 hprint(line+2+i, 57, trap_regs->esp+(4*(i+10)));
577 hprint(line+2+i, 66, *(ulong*)(trap_regs->esp+(4*(i+10))));
578 }
579
580 cprint(line+11, 0, "CS:EIP: ");
581 pp = (unsigned char *)trap_regs->eip;
582 for(i = 0; i < 9; i++) {
583 hprint2(line+11, 8+(3*i), pp[i], 2);
584 }
585
586 while(1) {
587 check_input();
588 }
589}
590
591void set_cache(int val)
592{
593 switch(val) {
594 case 0:
595 cache_off();
596 break;
597 case 1:
598 cache_on();
599 break;
600 }
601}
602
603int get_key() {
604 int c;
605
606 c = inb(0x64);
607 if ((c & 1) == 0) {
608 if (serial_cons) {
609 int comstat;
610 comstat = serial_echo_inb(UART_LSR);
611 if (comstat & UART_LSR_DR) {
612 c = serial_echo_inb(UART_RX);
613 /* Pressing '.' has same effect as 'c'
614 on a keyboard.
615 Oct 056 Dec 46 Hex 2E Ascii .
616 */
617 return (ascii_to_keycode(c));
618 }
619 }
620 return(0);
621 }
622 c = inb(0x60);
623 return((c));
624}
625
626void check_input(void)
627{
628 unsigned char c;
629
630 if ((c = get_key())) {
631 switch(c & 0x7f) {
632 case 1:
633 /* "ESC" key was pressed, bail out. */
634 cprint(LINE_RANGE, COL_MID+23, "Halting... ");
635 reboot();
636 break;
637 case 46:
638 /* c - Configure */
639 get_config();
640 break;
641 case 28:
642 /* CR - clear scroll lock */
643 slock = 0;
644 footer();
645 break;
646 case 57:
647 /* SP - set scroll lock */
648 slock = 1;
649 footer();
650 break;
651 case 0x26:
652 /* ^L/L - redraw the display */
653 tty_print_screen();
654 break;
655 }
656 }
657}
658
659void footer()
660{
661 cprint(24, 0, "(ESC)exit (c)configuration (SP)scroll_lock (CR)scroll_unlock");
662 if (slock) {
663 cprint(24, 74, "Locked");
664 } else {
665 cprint(24, 74, " ");
666 }
667}
668
669ulong getval(int x, int y, int result_shift)
670{
671 unsigned long val;
672 int done;
673 int c;
674 int i, n;
675 int base;
676 int shift;
677 char buf[16];
678
679 for(i = 0; i < sizeof(buf)/sizeof(buf[0]); i++ ) {
680 buf[i] = ' ';
681 }
682 buf[sizeof(buf)/sizeof(buf[0]) -1] = '\0';
683
684 wait_keyup();
685 done = 0;
686 n = 0;
687 base = 10;
688 while(!done) {
689 /* Read a new character and process it */
690 c = get_key();
691 switch(c) {
692 case 0x26: /* ^L/L - redraw the display */
693 tty_print_screen();
694 break;
695 case 0x1c: /* CR */
696 /* If something has been entered we are done */
697 if(n) done = 1;
698 break;
699 case 0x19: /* p */ buf[n] = 'p'; break;
700 case 0x22: /* g */ buf[n] = 'g'; break;
701 case 0x32: /* m */ buf[n] = 'm'; break;
702 case 0x25: /* k */ buf[n] = 'k'; break;
703 case 0x2d: /* x */
704 /* Only allow 'x' after an initial 0 */
705 if (n == 1 && (buf[0] == '0')) {
706 buf[n] = 'x';
707 }
708 break;
709 case 0x0e: /* BS */
710 if (n > 0) {
711 n -= 1;
712 buf[n] = ' ';
713 }
714 break;
715 /* Don't allow entering a number not in our current base */
716 case 0x0B: if (base >= 1) buf[n] = '0'; break;
717 case 0x02: if (base >= 2) buf[n] = '1'; break;
718 case 0x03: if (base >= 3) buf[n] = '2'; break;
719 case 0x04: if (base >= 4) buf[n] = '3'; break;
720 case 0x05: if (base >= 5) buf[n] = '4'; break;
721 case 0x06: if (base >= 6) buf[n] = '5'; break;
722 case 0x07: if (base >= 7) buf[n] = '6'; break;
723 case 0x08: if (base >= 8) buf[n] = '7'; break;
724 case 0x09: if (base >= 9) buf[n] = '8'; break;
725 case 0x0A: if (base >= 10) buf[n] = '9'; break;
726 case 0x1e: if (base >= 11) buf[n] = 'a'; break;
727 case 0x30: if (base >= 12) buf[n] = 'b'; break;
728 case 0x2e: if (base >= 13) buf[n] = 'c'; break;
729 case 0x20: if (base >= 14) buf[n] = 'd'; break;
730 case 0x12: if (base >= 15) buf[n] = 'e'; break;
731 case 0x21: if (base >= 16) buf[n] = 'f'; break;
732 default:
733 break;
734 }
735 /* Don't allow anything to be entered after a suffix */
736 if (n > 0 && (
737 (buf[n-1] == 'p') || (buf[n-1] == 'g') ||
738 (buf[n-1] == 'm') || (buf[n-1] == 'k'))) {
739 buf[n] = ' ';
740 }
741 /* If we have entered a character increment n */
742 if (buf[n] != ' ') {
743 n++;
744 }
745 buf[n] = ' ';
746 /* Print the current number */
747 cprint(x, y, buf);
748
749 /* Find the base we are entering numbers in */
750 base = 10;
751 if ((buf[0] == '0') && (buf[1] == 'x')) {
752 base = 16;
753 }
754 else if (buf[0] == '0') {
755 base = 8;
756 }
757 }
758 /* Compute our current shift */
759 shift = 0;
760 switch(buf[n-1]) {
761 case 'g': /* gig */ shift = 30; break;
762 case 'm': /* meg */ shift = 20; break;
763 case 'p': /* page */ shift = 12; break;
764 case 'k': /* kilo */ shift = 10; break;
765 }
766 shift -= result_shift;
767
768 /* Compute our current value */
769 val = simple_strtoul(buf, 0, base);
770 if (shift > 0) {
771 if (shift >= 32) {
772 val = 0xffffffff;
773 } else {
774 val <<= shift;
775 }
776 } else {
777 if (-shift >= 32) {
778 val = 0;
779 }
780 else {
781 val >>= -shift;
782 }
783 }
784 return val;
785}
786
787void ttyprint(int y, int x, const char *p)
788{
789 static char sx[3];
790 static char sy[3];
791
792 sx[0]='\0';
793 sy[0]='\0';
794 x++; y++;
795 itoa(sx, x);
796 itoa(sy, y);
797 serial_echo_print("[");
798 serial_echo_print(sy);
799 serial_echo_print(";");
800 serial_echo_print(sx);
801 serial_echo_print("H");
802 serial_echo_print(p);
803}
804
805void serial_echo_init(void)
806{
807 int comstat, hi, lo, serial_div;
808 unsigned char lcr;
809
810 /* read the Divisor Latch */
811 comstat = serial_echo_inb(UART_LCR);
812 serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
813 hi = serial_echo_inb(UART_DLM);
814 lo = serial_echo_inb(UART_DLL);
815 serial_echo_outb(comstat, UART_LCR);
816
817 /* now do hardwired init */
818 lcr = serial_parity | (serial_bits - 5);
819 serial_echo_outb(lcr, UART_LCR); /* No parity, 8 data bits, 1 stop */
820 serial_div = 115200 / serial_baud_rate;
821 serial_echo_outb(0x80|lcr, UART_LCR); /* Access divisor latch */
822 serial_echo_outb(serial_div & 0xff, UART_DLL); /* baud rate divisor */
823 serial_echo_outb((serial_div >> 8) & 0xff, UART_DLM);
824 serial_echo_outb(lcr, UART_LCR); /* Done with divisor */
825
826 /* Prior to disabling interrupts, read the LSR and RBR
827 * registers */
828 comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
829 comstat = serial_echo_inb(UART_RX); /* COM? RBR */
830 serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
831
832 clear_screen_buf();
833
834 return;
835}
836
837/*
838 * Get_number of digits
839 */
840int getnum(ulong val)
841{
842 int len = 0;
843 int i = 1;
844
845 while(i <= val)
846 {
847 len++;
848 i *= 10;
849 }
850
851 return len;
852
853}
854
855
856void serial_echo_print(const char *p)
857{
858 if (!serial_cons) {
859 return;
860 }
861 /* Now, do each character */
862 while (*p) {
863 WAIT_FOR_XMITR;
864
865 /* Send the character out. */
866 serial_echo_outb(*p, UART_TX);
867 if(*p==10) {
868 WAIT_FOR_XMITR;
869 serial_echo_outb(13, UART_TX);
870 }
871 p++;
872 }
873}
874
875/* Except for multi-character key sequences this mapping
876 * table is complete. So it should not need to be updated
877 * when new keys are searched for. However the key handling
878 * should really be turned around and only in get_key should
879 * we worry about the exact keycode that was pressed. Everywhere
880 * else we should switch on the character...
881 */
882struct ascii_map_str ser_map[] =
883/*ascii keycode ascii keycode*/
884{
885 /* Special cases come first so I can leave
886 * their ``normal'' mapping in the table,
887 * without it being activated.
888 */
889 { 27, 0x01}, /* ^[/ESC -> ESC */
890 { 127, 0x0e}, /* DEL -> BS */
891 { 8, 0x0e}, /* ^H/BS -> BS */
892 { 10, 0x1c}, /* ^L/NL -> CR */
893 { 13, 0x1c}, /* ^M/CR -> CR */
894 { 9, 0x0f}, /* ^I/TAB -> TAB */
895 { 19, 0x39}, /* ^S -> SP */
896 { 17, 28}, /* ^Q -> CR */
897
898 { ' ', 0x39}, /* SP -> SP */
899 { 'a', 0x1e},
900 { 'A', 0x1e},
901 { 1, 0x1e}, /* ^A -> A */
902 { 'b', 0x30},
903 { 'B', 0x30},
904 { 2, 0x30}, /* ^B -> B */
905 { 'c', 0x2e},
906 { 'C', 0x2e},
907 { 3, 0x2e}, /* ^C -> C */
908 { 'd', 0x20},
909 { 'D', 0x20},
910 { 4, 0x20}, /* ^D -> D */
911 { 'e', 0x12},
912 { 'E', 0x12},
913 { 5, 0x12}, /* ^E -> E */
914 { 'f', 0x21},
915 { 'F', 0x21},
916 { 6, 0x21}, /* ^F -> F */
917 { 'g', 0x22},
918 { 'G', 0x22},
919 { 7, 0x22}, /* ^G -> G */
920 { 'h', 0x23},
921 { 'H', 0x23},
922 { 8, 0x23}, /* ^H -> H */
923 { 'i', 0x17},
924 { 'I', 0x17},
925 { 9, 0x17}, /* ^I -> I */
926 { 'j', 0x24},
927 { 'J', 0x24},
928 { 10, 0x24}, /* ^J -> J */
929 { 'k', 0x25},
930 { 'K', 0x25},
931 { 11, 0x25}, /* ^K -> K */
932 { 'l', 0x26},
933 { 'L', 0x26},
934 { 12, 0x26}, /* ^L -> L */
935 { 'm', 0x32},
936 { 'M', 0x32},
937 { 13, 0x32}, /* ^M -> M */
938 { 'n', 0x31},
939 { 'N', 0x31},
940 { 14, 0x31}, /* ^N -> N */
941 { 'o', 0x18},
942 { 'O', 0x18},
943 { 15, 0x18}, /* ^O -> O */
944 { 'p', 0x19},
945 { 'P', 0x19},
946 { 16, 0x19}, /* ^P -> P */
947 { 'q', 0x10},
948 { 'Q', 0x10},
949 { 17, 0x10}, /* ^Q -> Q */
950 { 'r', 0x13},
951 { 'R', 0x13},
952 { 18, 0x13}, /* ^R -> R */
953 { 's', 0x1f},
954 { 'S', 0x1f},
955 { 19, 0x1f}, /* ^S -> S */
956 { 't', 0x14},
957 { 'T', 0x14},
958 { 20, 0x14}, /* ^T -> T */
959 { 'u', 0x16},
960 { 'U', 0x16},
961 { 21, 0x16}, /* ^U -> U */
962 { 'v', 0x2f},
963 { 'V', 0x2f},
964 { 22, 0x2f}, /* ^V -> V */
965 { 'w', 0x11},
966 { 'W', 0x11},
967 { 23, 0x11}, /* ^W -> W */
968 { 'x', 0x2d},
969 { 'X', 0x2d},
970 { 24, 0x2d}, /* ^X -> X */
971 { 'y', 0x15},
972 { 'Y', 0x15},
973 { 25, 0x15}, /* ^Y -> Y */
974 { 'z', 0x2c},
975 { 'Z', 0x2c},
976 { 26, 0x2c}, /* ^Z -> Z */
977 { '-', 0x0c},
978 { '_', 0x0c},
979 { 31, 0x0c}, /* ^_ -> _ */
980 { '=', 0x0c},
981 { '+', 0x0c},
982 { '[', 0x1a},
983 { '{', 0x1a},
984 { 27, 0x1a}, /* ^[ -> [ */
985 { ']', 0x1b},
986 { '}', 0x1b},
987 { 29, 0x1b}, /* ^] -> ] */
988 { ';', 0x27},
989 { ':', 0x27},
990 { '\'', 0x28},
991 { '"', 0x28},
992 { '`', 0x29},
993 { '~', 0x29},
994 { '\\', 0x2b},
995 { '|', 0x2b},
996 { 28, 0x2b}, /* ^\ -> \ */
997 { ',', 0x33},
998 { '<', 0x33},
999 { '.', 0x34},
1000 { '>', 0x34},
1001 { '/', 0x35},
1002 { '?', 0x35},
1003 { '1', 0x02},
1004 { '!', 0x02},
1005 { '2', 0x03},
1006 { '@', 0x03},
1007 { '3', 0x04},
1008 { '#', 0x04},
1009 { '4', 0x05},
1010 { '$', 0x05},
1011 { '5', 0x06},
1012 { '%', 0x06},
1013 { '6', 0x07},
1014 { '^', 0x07},
1015 { 30, 0x07}, /* ^^ -> 6 */
1016 { '7', 0x08},
1017 { '&', 0x08},
1018 { '8', 0x09},
1019 { '*', 0x09},
1020 { '9', 0x0a},
1021 { '(', 0x0a},
1022 { '0', 0x0b},
1023 { ')', 0x0b},
1024 { 0, 0}
1025};
1026
1027/*
1028 * Given an ascii character, return the keycode
1029 *
1030 * Uses ser_map definition above.
1031 *
1032 * It would be more efficient to use an array of 255 characters
1033 * and directly index into it.
1034 */
1035int ascii_to_keycode (int in)
1036{
1037 struct ascii_map_str *p;
1038 for (p = ser_map; p->ascii; p++) {
1039 if (in ==p->ascii)
1040 return p->keycode;
1041 }
1042 return 0;
1043}
1044
1045/*
1046 * Call this when you want to wait for the user to lift the
1047 * finger off of a key. It is a noop if you are using a
1048 * serial console.
1049 */
1050void wait_keyup( void ) {
1051 /* Check to see if someone lifted the keyboard key */
1052 while (1) {
1053 if ((get_key() & 0x80) != 0) {
1054 return;
1055 }
1056 /* Trying to simulate waiting for a key release with
1057 * the serial port is to nasty to let live.
1058 * In particular some menus don't even display until
1059 * you release the key that caused to to get there.
1060 * With the serial port this results in double pressing
1061 * or something worse for just about every key.
1062 */
1063 if (serial_cons) {
1064 return;
1065 }
1066 }
1067}
1068
1069/*
1070 * Handles "console=<param>" command line option
1071 *
1072 * Examples of accepted params:
1073 * ttyS0
1074 * ttyS1
1075 * ttyS0,115200
1076 * ttyS0,9600e8
1077 */
1078void serial_console_setup(char *param)
1079{
1080 char *option, *end;
1081 unsigned long tty;
1082 unsigned long baud_rate;
1083 unsigned char parity, bits;
1084
1085 if (strncmp(param, "ttyS", 4))
1086 return; /* not a serial port */
1087
1088 param += 4;
1089
1090 tty = simple_strtoul(param, &option, 10);
1091
1092 if (option == param)
1093 return; /* there were no digits */
1094
1095 if (tty > 1)
1096 return; /* only ttyS0 and ttyS1 supported */
1097
1098 if (*option == '\0' || *option == ' ')
1099 goto save_tty; /* no options given, just ttyS? */
1100
1101 if (*option != ',')
1102 return; /* missing the comma separator */
1103
1104 /* baud rate must follow */
1105 option++;
1106 baud_rate = simple_strtoul(option, &end, 10);
1107
1108 if (end == option)
1109 return; /* no baudrate after comma */
1110
1111 if (baud_rate == 0 || (115200 % baud_rate) != 0)
1112 return; /* wrong baud rate */
1113
1114 if (*end == '\0' || *end == ' ')
1115 goto save_baud_rate; /* no more options given */
1116
1117 switch (toupper(*end)) {
1118 case 'N':
1119 parity = 0;
1120 break;
1121 case 'O':
1122 parity = UART_LCR_PARITY;
1123 break;
1124 case 'E':
1125 parity = UART_LCR_PARITY | UART_LCR_EPAR;
1126 break;
1127 default:
1128 /* Unknown parity */
1129 return;
1130 }
1131
1132 end++;
1133 if (*end == '\0' || *end == ' ')
1134 goto save_parity;
1135
1136 /* word length (bits) */
1137 if (*end < '7' || *end > '8')
1138 return; /* invalid number of bits */
1139
1140 bits = *end - '0';
1141
1142 end++;
1143
1144 if (*end != '\0' || *end != ' ')
1145 return; /* garbage at the end */
1146
1147 serial_bits = bits;
1148 save_parity:
1149 serial_parity = parity;
1150 save_baud_rate:
1151 serial_baud_rate = (int) baud_rate;
1152 save_tty:
1153 serial_tty = (short) tty;
1154 serial_cons = 1;
1155}
1156
1157/* Get a comma seperated list of numbers */
1158void get_list(int x, int y, int len, char *buf)
1159{
1160 int c, n = 0;
1161
1162 len--;
1163 wait_keyup();
1164 while(1) {
1165 /* Read a new character and process it */
1166 c = get_key();
1167 switch(c) {
1168 case 0x1c: /* CR */
1169 /* If something has been entered we are done */
1170 if(n) {
1171 buf[n] = 0;
1172 return;
1173 }
1174 break;
1175 case 0x0e: /* BS */
1176 if (n > 0) {
1177 n -= 1;
1178 buf[n] = ' ';
1179 }
1180 break;
1181 case 0x0B: buf[n++] = '0'; break;
1182 case 0x02: buf[n++] = '1'; break;
1183 case 0x03: buf[n++] = '2'; break;
1184 case 0x04: buf[n++] = '3'; break;
1185 case 0x05: buf[n++] = '4'; break;
1186 case 0x06: buf[n++] = '5'; break;
1187 case 0x07: buf[n++] = '6'; break;
1188 case 0x08: buf[n++] = '7'; break;
1189 case 0x09: buf[n++] = '8'; break;
1190 case 0x0a: buf[n++] = '9'; break;
1191 case 0x33: buf[n++] = ','; break;
1192 }
1193 cprint(x, y, buf);
1194 if (n >= len) {
1195 buf[n] = 0;
1196 return;
1197 }
1198 }
1199}