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 * From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
29 * $FreeBSD: src/sys/boot/pc98/libpc98/vidconsole.c,v 1.5.2.3 2002/02/11 04:50:11 nyan 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;
57 void vidc_term_emu(int c);
59 void curs_move(int x, int y);
60 void write_char(int c, int fg, int bg);
61 void scroll_up(int rows, int fg, int bg);
70 static int args[2],argc,br;
72 static int fg_c,bg_c,curx,cury;
77 static unsigned short *crtat, *Crtat;
78 static int row = 25, col = 80;
80 static u_int8_t ibmpc_to_pc98[256] = {
81 0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
82 0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
83 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
84 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
85 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
86 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
87 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
88 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
89 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
90 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
91 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
92 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
93 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
94 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
95 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
96 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
98 0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
99 0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
100 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
101 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
102 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
103 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
104 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
105 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
106 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
107 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
108 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
109 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
110 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
111 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
112 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
113 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
115 #define at2pc98(fg_at, bg_at) ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
116 #endif /* TERM_EMU */
119 struct console vidconsole = {
121 "internal video/keyboard",
131 vidc_probe(struct console *cp)
134 /* look for a keyboard */
136 if (probe_keyboard())
140 cp->c_flags |= C_PRESENTIN;
143 /* XXX for now, always assume we can do BIOS screen output */
144 cp->c_flags |= C_PRESENTOUT;
155 if (vidc_started && arg == 0)
159 Crtat = (unsigned short *)PTOV(0xA0000);
160 while((inb(0x60) & 0x04) == 0);
162 while((inb(0x60) & 0x01) == 0);
163 hw_cursor = inb(0x62);
164 hw_cursor |= (inb(0x62) << 8);
168 crtat = Crtat + hw_cursor;
171 /* Init terminal emulator */
174 curs_move(curx,cury);
178 for(i = 0; i < 10 && vidc_ischar(); i++)
179 (void)vidc_getchar();
180 return(0); /* XXX reinit? */
195 vidc_biosputchar(int c)
202 *crtat = (c == 0x5c ? 0xfc : c);
203 *(crtat + 0x1000) = at2pc98(fg, bg);
210 crtat -= (crtat - Crtat) % col;
216 *crtat = (c == 0x5c ? 0xfc : c);
217 *(crtat++ + 0x1000) = 0xe1;
221 if (crtat >= Crtat + col * row) {
223 for (i = 1; i < row; i++) {
224 bcopy((void *)(cp+col), (void *)cp, col*2);
227 for (i = 0; i < col; i++) {
233 while((inb(0x60) & 0x04) == 0) {}
235 outb(0x60, pos & 0xff);
236 outb(0x60, pos >> 8);
241 v86.eax = 0xe00 | (c & 0xff);
249 vidc_rawputchar(int c)
254 /* lame tab expansion */
255 for (i = 0; i < 8; i++)
256 vidc_rawputchar(' ');
258 #if !defined(TERM_EMU) && !defined(PC98)
261 /* Emulate AH=0eh (teletype output) */
272 curs_move(curx,cury);
277 scroll_up(1,fg_c,bg_c);
280 curs_move(curx,cury);
286 curs_move(curx,cury);
287 /* write_char(' ',fg_c,bg_c); XXX destructive(!) */
292 write_char(c,fg_c,bg_c);
300 scroll_up(1,fg_c,bg_c);
304 curs_move(curx,cury);
311 /* Get cursor position on the screen. Result is in edx. Sets
312 * curx and cury appropriately.
318 int pos = crtat - Crtat;
327 curx=v86.edx & 0x00ff;
328 cury=(v86.edx & 0xff00)>>8;
332 /* Move cursor to x rows and y cols (0-based). */
334 curs_move(int x, int y)
341 while((inb(0x60) & 0x04) == 0) {}
343 outb(0x60, pos & 0xff);
344 outb(0x60, pos >> 8);
347 #define isvisible(c) (((c)>32) && ((c)<255))
348 if(!isvisible(*crtat & 0x00ff)) {
349 write_char(' ',fg_c,bg_c);
356 v86.edx = ((0x00ff & y)<<8)+(0x00ff & x);
360 /* If there is ctrl char at this position, cursor would be invisible.
361 * Make it a space instead.
368 #define isvisible(c) (((c)>32) && ((c)<255))
369 if(!isvisible(v86.eax & 0x00ff)) {
370 write_char(' ',fg_c,bg_c);
375 /* Scroll up the whole window by a number of rows. If rows==0,
376 * clear the window. fg and bg are attributes for the new lines
377 * inserted in the window.
380 scroll_up(int rows, int fgcol, int bgcol)
388 for (i = rows ; i < row; i++) {
389 bcopy((void *)(cp+col), (void *)cp, col*2);
392 for (i = 0; i < col; i++) {
393 *(cp + 0x1000) = at2pc98(fgcol, bgcol);
400 v86.eax = 0x0600+(0x00ff & rows);
401 v86.ebx = (bgcol<<12)+(fgcol<<8);
408 /* Write character and attribute at cursor position. */
410 write_char(int c, int fgcol, int bgcol)
413 *crtat = (c == 0x5c ? 0xfc : c);
414 *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
418 v86.eax = 0x0900+(0x00ff & c);
419 v86.ebx = (bgcol<<4)+fgcol;
425 /* Calculate power of 10 */
437 /**************************************************************/
439 * Screen manipulation functions. They use accumulated data in
440 * args[] and argc variables.
444 /* Set background color */
451 /* Set foreground color */
459 /* Clear display from current position to end of screen */
465 for(;crtat <= Crtat + col*row; crtat++){
467 *(crtat + 0x1000) = at2pc98(fg_c, bg_c);
473 v86.ebx = (bg_c<<4)+fg_c;
479 curs_move(curx,cury);
483 /* Absolute cursor move to args[0] rows and args[1] columns
484 * (the coordinates are 1-based).
489 if(args[0]>0) args[0]--;
490 if(args[1]>0) args[1]--;
491 curs_move(args[1],args[0]);
495 /* Home cursor (left top corner) */
504 /* Exit attribute mode (reset fore/back-ground colors to defaults) */
513 /* Clear internal state of the terminal emulation code */
524 /* Gracefully exit ESC-sequence processing in case of misunderstanding */
530 if(esc) vidc_rawputchar('\033');
531 if(br) vidc_rawputchar('[');
533 sprintf(buf,"%d",args[0]);
535 while(*ch) vidc_rawputchar(*ch++);
538 vidc_rawputchar(';');
539 sprintf(buf,"%d",args[1]);
541 while(*ch) vidc_rawputchar(*ch++);
548 /* Emulate basic capabilities of cons25 terminal */
562 /* Do ESC sequences processing */
565 /* ESC in ESC sequence - error */
569 /* Check if it's first char after ESC */
577 /* Emulate \E[H (cursor home) and
578 * \E%d;%dH (cursor absolute move) */
585 if(fg) args[0]+=pow10(dig)*3;
586 if(bg) args[0]+=pow10(dig)*4;
595 /* Emulate \EJ (clear to end of screen) */
601 /* perhaps args separator */
602 if(br && (argc>-1)) {
607 /* Change char attributes */
624 /* Carefully collect numeric arguments */
625 /* XXX this is ugly. */
631 /* in case we're in error... */
640 args[argc]=(int)(c-'0');
644 args[argc]=args[argc]*10+(int)(c-'0');
676 return(v86.eax & 0xff);
690 return((v86.ebx >> 8) & 0x1);
696 return(!(v86.efl & PSL_Z));
706 return (*(u_char *)PTOV(0xA1481) & 0x48);
709 #define PROBE_MAXRETRY 5
710 #define PROBE_MAXWAIT 400
711 #define IO_DUMMY 0x84
712 #define IO_KBD 0x060 /* 8042 Keyboard */
714 /* selected defines from kbdio.h */
715 #define KBD_STATUS_PORT 4 /* status port, read */
716 #define KBD_DATA_PORT 0 /* data port, read/write
717 * also used as keyboard command
718 * and mouse command port
720 #define KBDC_ECHO 0x00ee
721 #define KBDS_ANY_BUFFER_FULL 0x0001
722 #define KBDS_INPUT_BUFFER_FULL 0x0002
723 #define KBD_ECHO 0x00ee
725 /* 7 microsec delay necessary for some keyboard controllers */
730 * I know this is broken, but no timer is available yet at this stage...
731 * See also comments in `delay1ms()'.
733 inb(IO_DUMMY); inb(IO_DUMMY);
734 inb(IO_DUMMY); inb(IO_DUMMY);
735 inb(IO_DUMMY); inb(IO_DUMMY);
739 * This routine uses an inb to an unused port, the time to execute that
740 * inb is approximately 1.25uS. This value is pretty constant across
741 * all CPU's and all buses, with the exception of some PCI implentations
742 * that do not forward this I/O address to the ISA bus as they know it
743 * is not a valid ISA bus address, those machines execute this inb in
756 * We use the presence/absence of a keyboard to determine whether the internal
757 * console can be used for input.
759 * Perform a simple test on the keyboard; issue the ECHO command and see
760 * if the right answer is returned. We don't do anything as drastic as
761 * full keyboard reset; it will be too troublesome and take too much time.
766 int retry = PROBE_MAXRETRY;
770 while (--retry >= 0) {
771 /* flush any noise */
772 while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
774 inb(IO_KBD + KBD_DATA_PORT);
778 /* wait until the controller can accept a command */
779 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
780 if (((i = inb(IO_KBD + KBD_STATUS_PORT))
781 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
783 if (i & KBDS_ANY_BUFFER_FULL) {
785 inb(IO_KBD + KBD_DATA_PORT);
792 /* send the ECHO command */
793 outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
795 /* wait for a response */
796 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
797 if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
805 i = inb(IO_KBD + KBD_DATA_PORT);
806 #ifdef PROBE_KBD_BEBUG
807 printf("probe_keyboard: got 0x%x.\n", i);
810 /* got the right answer */
818 #endif /* KEYBOARD_PROBE */