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 $
30 * $DragonFly: src/sys/boot/pc98/libpc98/Attic/vidconsole.c,v 1.2 2003/06/17 04:28:18 dillon Exp $
34 #include <bootstrap.h>
36 #include <machine/psl.h>
38 #include <machine/cpufunc.h>
43 #include <machine/cpufunc.h>
45 static int probe_keyboard(void);
47 static void vidc_probe(struct console *cp);
48 static int vidc_init(int arg);
49 static void vidc_putchar(int c);
50 static int vidc_getchar(void);
51 static int vidc_ischar(void);
53 static int vidc_started;
58 void vidc_term_emu(int c);
60 void curs_move(int x, int y);
61 void write_char(int c, int fg, int bg);
62 void scroll_up(int rows, int fg, int bg);
71 static int args[2],argc,br;
73 static int fg_c,bg_c,curx,cury;
78 static unsigned short *crtat, *Crtat;
79 static int row = 25, col = 80;
81 static u_int8_t ibmpc_to_pc98[256] = {
82 0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
83 0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
84 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
85 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
86 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
87 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
88 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
89 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
90 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
91 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
92 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
93 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
94 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
95 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
96 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
97 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
99 0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
100 0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
101 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
102 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
103 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
104 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
105 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
106 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
107 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
108 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
109 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
110 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
111 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
112 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
113 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
114 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
116 #define at2pc98(fg_at, bg_at) ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
117 #endif /* TERM_EMU */
120 struct console vidconsole = {
122 "internal video/keyboard",
132 vidc_probe(struct console *cp)
135 /* look for a keyboard */
137 if (probe_keyboard())
141 cp->c_flags |= C_PRESENTIN;
144 /* XXX for now, always assume we can do BIOS screen output */
145 cp->c_flags |= C_PRESENTOUT;
156 if (vidc_started && arg == 0)
160 Crtat = (unsigned short *)PTOV(0xA0000);
161 while((inb(0x60) & 0x04) == 0);
163 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);
179 for(i = 0; i < 10 && vidc_ischar(); i++)
180 (void)vidc_getchar();
181 return(0); /* XXX reinit? */
196 vidc_biosputchar(int c)
203 *crtat = (c == 0x5c ? 0xfc : c);
204 *(crtat + 0x1000) = at2pc98(fg, bg);
211 crtat -= (crtat - Crtat) % col;
217 *crtat = (c == 0x5c ? 0xfc : c);
218 *(crtat++ + 0x1000) = 0xe1;
222 if (crtat >= Crtat + col * row) {
224 for (i = 1; i < row; i++) {
225 bcopy((void *)(cp+col), (void *)cp, col*2);
228 for (i = 0; i < col; i++) {
234 while((inb(0x60) & 0x04) == 0) {}
236 outb(0x60, pos & 0xff);
237 outb(0x60, pos >> 8);
242 v86.eax = 0xe00 | (c & 0xff);
250 vidc_rawputchar(int c)
255 /* lame tab expansion */
256 for (i = 0; i < 8; i++)
257 vidc_rawputchar(' ');
259 #if !defined(TERM_EMU) && !defined(PC98)
262 /* Emulate AH=0eh (teletype output) */
273 curs_move(curx,cury);
278 scroll_up(1,fg_c,bg_c);
281 curs_move(curx,cury);
287 curs_move(curx,cury);
288 /* write_char(' ',fg_c,bg_c); XXX destructive(!) */
293 write_char(c,fg_c,bg_c);
301 scroll_up(1,fg_c,bg_c);
305 curs_move(curx,cury);
312 /* Get cursor position on the screen. Result is in edx. Sets
313 * curx and cury appropriately.
319 int pos = crtat - Crtat;
328 curx=v86.edx & 0x00ff;
329 cury=(v86.edx & 0xff00)>>8;
333 /* Move cursor to x rows and y cols (0-based). */
335 curs_move(int x, int y)
342 while((inb(0x60) & 0x04) == 0) {}
344 outb(0x60, pos & 0xff);
345 outb(0x60, pos >> 8);
348 #define isvisible(c) (((c)>32) && ((c)<255))
349 if(!isvisible(*crtat & 0x00ff)) {
350 write_char(' ',fg_c,bg_c);
357 v86.edx = ((0x00ff & y)<<8)+(0x00ff & x);
361 /* If there is ctrl char at this position, cursor would be invisible.
362 * Make it a space instead.
369 #define isvisible(c) (((c)>32) && ((c)<255))
370 if(!isvisible(v86.eax & 0x00ff)) {
371 write_char(' ',fg_c,bg_c);
376 /* Scroll up the whole window by a number of rows. If rows==0,
377 * clear the window. fg and bg are attributes for the new lines
378 * inserted in the window.
381 scroll_up(int rows, int fgcol, int bgcol)
389 for (i = rows ; i < row; i++) {
390 bcopy((void *)(cp+col), (void *)cp, col*2);
393 for (i = 0; i < col; i++) {
394 *(cp + 0x1000) = at2pc98(fgcol, bgcol);
401 v86.eax = 0x0600+(0x00ff & rows);
402 v86.ebx = (bgcol<<12)+(fgcol<<8);
409 /* Write character and attribute at cursor position. */
411 write_char(int c, int fgcol, int bgcol)
414 *crtat = (c == 0x5c ? 0xfc : c);
415 *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
419 v86.eax = 0x0900+(0x00ff & c);
420 v86.ebx = (bgcol<<4)+fgcol;
426 /* Calculate power of 10 */
438 /**************************************************************/
440 * Screen manipulation functions. They use accumulated data in
441 * args[] and argc variables.
445 /* Set background color */
452 /* Set foreground color */
460 /* Clear display from current position to end of screen */
466 for(;crtat <= Crtat + col*row; crtat++){
468 *(crtat + 0x1000) = at2pc98(fg_c, bg_c);
474 v86.ebx = (bg_c<<4)+fg_c;
480 curs_move(curx,cury);
484 /* Absolute cursor move to args[0] rows and args[1] columns
485 * (the coordinates are 1-based).
490 if(args[0]>0) args[0]--;
491 if(args[1]>0) args[1]--;
492 curs_move(args[1],args[0]);
496 /* Home cursor (left top corner) */
505 /* Exit attribute mode (reset fore/back-ground colors to defaults) */
514 /* Clear internal state of the terminal emulation code */
525 /* Gracefully exit ESC-sequence processing in case of misunderstanding */
531 if(esc) vidc_rawputchar('\033');
532 if(br) vidc_rawputchar('[');
534 sprintf(buf,"%d",args[0]);
536 while(*ch) vidc_rawputchar(*ch++);
539 vidc_rawputchar(';');
540 sprintf(buf,"%d",args[1]);
542 while(*ch) vidc_rawputchar(*ch++);
549 /* Emulate basic capabilities of cons25 terminal */
563 /* Do ESC sequences processing */
566 /* ESC in ESC sequence - error */
570 /* Check if it's first char after ESC */
578 /* Emulate \E[H (cursor home) and
579 * \E%d;%dH (cursor absolute move) */
586 if(fg) args[0]+=pow10(dig)*3;
587 if(bg) args[0]+=pow10(dig)*4;
596 /* Emulate \EJ (clear to end of screen) */
602 /* perhaps args separator */
603 if(br && (argc>-1)) {
608 /* Change char attributes */
625 /* Carefully collect numeric arguments */
626 /* XXX this is ugly. */
632 /* in case we're in error... */
641 args[argc]=(int)(c-'0');
645 args[argc]=args[argc]*10+(int)(c-'0');
677 return(v86.eax & 0xff);
691 return((v86.ebx >> 8) & 0x1);
697 return(!(v86.efl & PSL_Z));
707 return (*(u_char *)PTOV(0xA1481) & 0x48);
710 #define PROBE_MAXRETRY 5
711 #define PROBE_MAXWAIT 400
712 #define IO_DUMMY 0x84
713 #define IO_KBD 0x060 /* 8042 Keyboard */
715 /* selected defines from kbdio.h */
716 #define KBD_STATUS_PORT 4 /* status port, read */
717 #define KBD_DATA_PORT 0 /* data port, read/write
718 * also used as keyboard command
719 * and mouse command port
721 #define KBDC_ECHO 0x00ee
722 #define KBDS_ANY_BUFFER_FULL 0x0001
723 #define KBDS_INPUT_BUFFER_FULL 0x0002
724 #define KBD_ECHO 0x00ee
726 /* 7 microsec delay necessary for some keyboard controllers */
731 * I know this is broken, but no timer is available yet at this stage...
732 * See also comments in `delay1ms()'.
734 inb(IO_DUMMY); inb(IO_DUMMY);
735 inb(IO_DUMMY); inb(IO_DUMMY);
736 inb(IO_DUMMY); inb(IO_DUMMY);
740 * This routine uses an inb to an unused port, the time to execute that
741 * inb is approximately 1.25uS. This value is pretty constant across
742 * all CPU's and all buses, with the exception of some PCI implentations
743 * that do not forward this I/O address to the ISA bus as they know it
744 * is not a valid ISA bus address, those machines execute this inb in
757 * We use the presence/absence of a keyboard to determine whether the internal
758 * console can be used for input.
760 * Perform a simple test on the keyboard; issue the ECHO command and see
761 * if the right answer is returned. We don't do anything as drastic as
762 * full keyboard reset; it will be too troublesome and take too much time.
767 int retry = PROBE_MAXRETRY;
771 while (--retry >= 0) {
772 /* flush any noise */
773 while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
775 inb(IO_KBD + KBD_DATA_PORT);
779 /* wait until the controller can accept a command */
780 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
781 if (((i = inb(IO_KBD + KBD_STATUS_PORT))
782 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
784 if (i & KBDS_ANY_BUFFER_FULL) {
786 inb(IO_KBD + KBD_DATA_PORT);
793 /* send the ECHO command */
794 outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
796 /* wait for a response */
797 for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
798 if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
806 i = inb(IO_KBD + KBD_DATA_PORT);
807 #ifdef PROBE_KBD_BEBUG
808 printf("probe_keyboard: got 0x%x.\n", i);
811 /* got the right answer */
819 #endif /* KEYBOARD_PROBE */