2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
28 * $FreeBSD: src/sys/boot/pc98/libpc98/vidconsole.c,v 1.11 2003/09/08 09:11:20 obrien Exp $
29 * $DragonFly: src/sys/boot/pc98/libpc98/Attic/vidconsole.c,v 1.3 2003/11/10 06:08:39 dillon Exp $
33 #include <bootstrap.h>
35 #include <machine/psl.h>
37 #include <machine/cpufunc.h>
42 #include <machine/cpufunc.h>
44 static int probe_keyboard(void);
46 static void vidc_probe(struct console *cp);
47 static int vidc_init(int arg);
48 static void vidc_putchar(int c);
49 static int vidc_getchar(void);
50 static int vidc_ischar(void);
52 static int vidc_started;
56 #define DEFAULT_FGCOLOR 7
57 #define DEFAULT_BGCOLOR 0
61 void vidc_term_emu(int c);
63 void curs_move(int x, int y);
64 void write_char(int c, int fg, int bg);
65 void scroll_up(int rows, int fg, int bg);
70 static int args[MAXARGS], argc;
71 static int fg_c, bg_c, curx, cury;
76 static unsigned short *crtat, *Crtat;
77 static int row = 25, col = 80;
79 static u_int8_t ibmpc_to_pc98[256] = {
80 0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
81 0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
82 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
83 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
84 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
85 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
86 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
87 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
88 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
89 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
90 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
91 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
92 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
93 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
94 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
95 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
97 0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
98 0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
99 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
100 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
101 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
102 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
103 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
104 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
105 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
106 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
107 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
108 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
109 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
110 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
111 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
112 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
114 #define at2pc98(fg_at, bg_at) ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
115 #endif /* TERM_EMU */
118 struct console vidconsole = {
120 "internal video/keyboard",
130 vidc_probe(struct console *cp)
133 /* look for a keyboard */
135 if (probe_keyboard())
139 cp->c_flags |= C_PRESENTIN;
142 /* XXX for now, always assume we can do BIOS screen output */
143 cp->c_flags |= C_PRESENTOUT;
154 if (vidc_started && arg == 0)
158 Crtat = (unsigned short *)PTOV(0xA0000);
159 while ((inb(0x60) & 0x04) == 0)
162 while ((inb(0x60) & 0x01) == 0)
164 hw_cursor = inb(0x62);
165 hw_cursor |= (inb(0x62) << 8);
169 crtat = Crtat + hw_cursor;
172 /* Init terminal emulator */
175 curs_move(curx, cury);
176 fg_c = DEFAULT_FGCOLOR;
177 bg_c = DEFAULT_BGCOLOR;
179 for (i = 0; i < 10 && vidc_ischar(); i++)
180 (void)vidc_getchar();
181 return (0); /* XXX reinit? */
197 vidc_biosputchar(int c)
204 *crtat = (c == 0x5c ? 0xfc : c);
205 *(crtat + 0x1000) = at2pc98(fg, bg);
212 crtat -= (crtat - Crtat) % col;
218 *crtat = (c == 0x5c ? 0xfc : c);
219 *(crtat++ + 0x1000) = 0xe1;
223 if (crtat >= Crtat + col * row) {
225 for (i = 1; i < row; i++) {
226 bcopy((void *)(cp + col), (void *)cp, col * 2);
229 for (i = 0; i < col; i++) {
235 while ((inb(0x60) & 0x04) == 0) {}
237 outb(0x60, pos & 0xff);
238 outb(0x60, pos >> 8);
244 v86.eax = 0xe00 | (c & 0xff);
252 vidc_rawputchar(int c)
257 /* lame tab expansion */
258 for (i = 0; i < 8; i++)
259 vidc_rawputchar(' ');
261 #if !defined(TERM_EMU) && !defined(PC98)
264 /* Emulate AH=0eh (teletype output) */
275 curs_move(curx, cury);
280 scroll_up(1, fg_c, bg_c);
283 curs_move(curx, cury);
289 curs_move(curx, cury);
290 /* write_char(' ', fg_c, bg_c); XXX destructive(!) */
295 write_char(c, fg_c, bg_c);
303 scroll_up(1, fg_c, bg_c);
307 curs_move(curx, cury);
314 /* Get cursor position on the screen. Result is in edx. Sets
315 * curx and cury appropriately.
321 int pos = crtat - Crtat;
332 curx = v86.edx & 0x00ff;
333 cury = (v86.edx & 0xff00) >> 8;
337 /* Move cursor to x rows and y cols (0-based). */
339 curs_move(int x, int y)
347 while((inb(0x60) & 0x04) == 0) {}
349 outb(0x60, pos & 0xff);
350 outb(0x60, pos >> 8);
353 #define isvisible(c) (((c) >= 32) && ((c) < 255))
354 if (!isvisible(*crtat & 0x00ff)) {
355 write_char(' ', fg_c, bg_c);
363 v86.edx = ((0x00ff & y) << 8) + (0x00ff & x);
367 /* If there is ctrl char at this position, cursor would be invisible.
368 * Make it a space instead.
375 #define isvisible(c) (((c) >= 32) && ((c) < 255))
376 if (!isvisible(v86.eax & 0x00ff)) {
377 write_char(' ', fg_c, bg_c);
382 /* Scroll up the whole window by a number of rows. If rows==0,
383 * clear the window. fg and bg are attributes for the new lines
384 * inserted in the window.
387 scroll_up(int rows, int fgcol, int bgcol)
396 for (i = rows; i < row; i++) {
397 bcopy((void *)(cp + col), (void *)cp, col * 2);
400 for (i = 0; i < col; i++) {
401 *(cp + 0x1000) = at2pc98(fgcol, bgcol);
410 v86.eax = 0x0600 + (0x00ff & rows);
411 v86.ebx = (bgcol << 12) + (fgcol << 8);
418 /* Write character and attribute at cursor position. */
420 write_char(int c, int fgcol, int bgcol)
424 *crtat = (c == 0x5c ? 0xfc : c);
425 *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
429 v86.eax = 0x0900 + (0x00ff & c);
430 v86.ebx = (bgcol << 4) + fgcol;
436 /**************************************************************/
438 * Screen manipulation functions. They use accumulated data in
439 * args[] and argc variables.
443 /* Clear display from current position to end of screen */
451 for (pos = 0; crtat + pos <= Crtat + col * row; pos++) {
452 *(crtat + pos) = ' ';
453 *(crtat + pos + 0x1000) = at2pc98(fg_c, bg_c);
463 v86.ebx = (bg_c << 4) + fg_c;
464 v86.ecx = (cury << 8) + curx;
465 v86.edx = (cury << 8) + 79;
475 v86.ebx = (bg_c << 4) + fg_c;
476 v86.ecx = (cury << 8) + 0;
477 v86.edx = (24 << 8) + 79;
483 /* Absolute cursor move to args[0] rows and args[1] columns
484 * (the coordinates are 1-based).
494 curs_move(args[1], args[0]);
498 /* Home cursor (left top corner) */
504 args[0] = args[1] = 1;
508 /* Clear internal state of the terminal emulation code */
517 /* Gracefully exit ESC-sequence processing in case of misunderstanding */
525 vidc_rawputchar('\033');
527 vidc_rawputchar(esc);
528 for (i = 0; i <= argc; ++i) {
529 sprintf(buf, "%d", args[i]);
532 vidc_rawputchar(*ch++);
546 args[argc] += c - '0';
549 /* Emulate basic capabilities of cons25 terminal */
553 static int ansi_col[] = {
554 0, 4, 2, 6, 1, 5, 3, 7,
587 if (argc < 0) /* XXX */
589 else if (argc + 1 >= MAXARGS)
610 fg_c = DEFAULT_FGCOLOR;
611 bg_c = DEFAULT_BGCOLOR;
613 for (i = 0; i <= argc; ++i) {
615 case 0: /* back to normal */
616 fg_c = DEFAULT_FGCOLOR;
617 bg_c = DEFAULT_BGCOLOR;
622 case 4: /* underline */
626 case 7: /* reverse */
631 case 30: case 31: case 32: case 33:
632 case 34: case 35: case 36: case 37:
633 fg_c = ansi_col[args[i] - 30];
635 case 39: /* normal */
636 fg_c = DEFAULT_FGCOLOR;
638 case 40: case 41: case 42: case 43:
639 case 44: case 45: case 46: case 47:
640 bg_c = ansi_col[args[i] - 40];
642 case 49: /* normal */
643 bg_c = DEFAULT_BGCOLOR;
688 return (v86.eax & 0xff);
703 return ((v86.ebx >> 8) & 0x1);
709 return (!(v86.efl & PSL_Z));
719 return (*(u_char *)PTOV(0xA1481) & 0x48);
722 #define PROBE_MAXRETRY 5
723 #define PROBE_MAXWAIT 400
724 #define IO_DUMMY 0x84
725 #define IO_KBD 0x060 /* 8042 Keyboard */
727 /* selected defines from kbdio.h */
728 #define KBD_STATUS_PORT 4 /* status port, read */
729 #define KBD_DATA_PORT 0 /* data port, read/write
730 * also used as keyboard command
731 * and mouse command port
733 #define KBDC_ECHO 0x00ee
734 #define KBDS_ANY_BUFFER_FULL 0x0001
735 #define KBDS_INPUT_BUFFER_FULL 0x0002
736 #define KBD_ECHO 0x00ee
738 /* 7 microsec delay necessary for some keyboard controllers */
743 * I know this is broken, but no timer is available yet at this stage...
744 * See also comments in `delay1ms()'.
746 inb(IO_DUMMY); inb(IO_DUMMY);
747 inb(IO_DUMMY); inb(IO_DUMMY);
748 inb(IO_DUMMY); inb(IO_DUMMY);
752 * This routine uses an inb to an unused port, the time to execute that
753 * inb is approximately 1.25uS. This value is pretty constant across
754 * all CPU's and all buses, with the exception of some PCI implentations
755 * that do not forward this I/O address to the ISA bus as they know it
756 * is not a valid ISA bus address, those machines execute this inb in
769 * We use the presence/absence of a keyboard to determine whether the internal
770 * console can be used for input.
772 * Perform a simple test on the keyboard; issue the ECHO command and see
773 * if the right answer is returned. We don't do anything as drastic as
774 * full keyboard reset; it will be too troublesome and take too much time.
779 int retry = PROBE_MAXRETRY;
783 while (--retry >= 0) {
784 /* flush any noise */
785 while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
787 inb(IO_KBD + KBD_DATA_PORT);
791 /* wait until the controller can accept a command */
792 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
793 if (((i = inb(IO_KBD + KBD_STATUS_PORT))
794 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
796 if (i & KBDS_ANY_BUFFER_FULL) {
798 inb(IO_KBD + KBD_DATA_PORT);
805 /* send the ECHO command */
806 outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
808 /* wait for a response */
809 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
810 if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
818 i = inb(IO_KBD + KBD_DATA_PORT);
819 #ifdef PROBE_KBD_BEBUG
820 printf("probe_keyboard: got 0x%x.\n", i);
823 /* got the right answer */
831 #endif /* KEYBOARD_PROBE */