vidconsole.c revision 85065
1/*
2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 *
27 * 	From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
28 *
29 * $FreeBSD: head/sys/boot/pc98/libpc98/vidconsole.c 85065 2001-10-17 15:15:01Z nyan $
30 */
31
32#include <stand.h>
33#include <bootstrap.h>
34#include <btxv86.h>
35#include <machine/psl.h>
36#ifdef PC98
37#include <machine/cpufunc.h>
38#endif
39#include "libi386.h"
40
41#if KEYBOARD_PROBE
42#include <machine/cpufunc.h>
43
44static int	probe_keyboard(void);
45#endif
46static void	vidc_probe(struct console *cp);
47static int	vidc_init(int arg);
48static void	vidc_putchar(int c);
49static int	vidc_getchar(void);
50static int	vidc_ischar(void);
51
52static int	vidc_started;
53
54#ifdef TERM_EMU
55#define MAXARGS		8
56#define DEFAULT_FGCOLOR	7
57#define DEFAULT_BGCOLOR	0
58
59void		end_term(void);
60void		bail_out(int c);
61void		vidc_term_emu(int c);
62void		get_pos(void);
63void		curs_move(int x, int y);
64void		write_char(int c, int fg, int bg);
65void		scroll_up(int rows, int fg, int bg);
66void		CD(void);
67void		CM(void);
68void		HO(void);
69
70static int	args[MAXARGS], argc;
71static int	fg_c, bg_c, curx, cury;
72static int	esc;
73#endif
74
75#ifdef PC98
76static unsigned short *crtat, *Crtat;
77static int row = 25, col = 80;
78#ifdef TERM_EMU
79static 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,
96
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,
113};
114#define	at2pc98(fg_at, bg_at)	ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
115#endif /* TERM_EMU */
116#endif /* PC98 */
117
118struct console vidconsole = {
119    "vidconsole",
120    "internal video/keyboard",
121    0,
122    vidc_probe,
123    vidc_init,
124    vidc_putchar,
125    vidc_getchar,
126    vidc_ischar
127};
128
129static void
130vidc_probe(struct console *cp)
131{
132
133    /* look for a keyboard */
134#if KEYBOARD_PROBE
135    if (probe_keyboard())
136#endif
137    {
138
139	cp->c_flags |= C_PRESENTIN;
140    }
141
142    /* XXX for now, always assume we can do BIOS screen output */
143    cp->c_flags |= C_PRESENTOUT;
144}
145
146static int
147vidc_init(int arg)
148{
149    int		i;
150#ifdef PC98
151    int		hw_cursor;
152#endif
153
154    if (vidc_started && arg == 0)
155	return (0);
156    vidc_started = 1;
157#ifdef PC98
158    Crtat = (unsigned short *)PTOV(0xA0000);
159    while ((inb(0x60) & 0x04) == 0)
160	;
161    outb(0x62, 0xe0);
162    while ((inb(0x60) & 0x01) == 0)
163	;
164    hw_cursor = inb(0x62);
165    hw_cursor |= (inb(0x62) << 8);
166    inb(0x62);
167    inb(0x62);
168    inb(0x62);
169    crtat = Crtat + hw_cursor;
170#endif
171#ifdef TERM_EMU
172    /* Init terminal emulator */
173    end_term();
174    get_pos();
175    curs_move(curx, cury);
176    fg_c = DEFAULT_FGCOLOR;
177    bg_c = DEFAULT_BGCOLOR;
178#endif
179    for (i = 0; i < 10 && vidc_ischar(); i++)
180	(void)vidc_getchar();
181    return (0);	/* XXX reinit? */
182}
183
184#ifdef PC98
185static void
186beep(void)
187{
188
189	outb(0x37, 6);
190	delay(40000);
191	outb(0x37, 7);
192}
193#endif
194
195#if 0
196static void
197vidc_biosputchar(int c)
198{
199#ifdef PC98
200    unsigned short *cp;
201    int i, pos;
202
203#ifdef TERM_EMU
204    *crtat = (c == 0x5c ? 0xfc : c);
205    *(crtat + 0x1000) = at2pc98(fg, bg);
206#else
207    switch(c) {
208    case '\b':
209        crtat--;
210	break;
211    case '\r':
212        crtat -= (crtat - Crtat) % col;
213	break;
214    case '\n':
215        crtat += col;
216	break;
217    default:
218        *crtat = (c == 0x5c ? 0xfc : c);
219	*(crtat++ + 0x1000) = 0xe1;
220	break;
221    }
222
223    if (crtat >= Crtat + col * row) {
224        cp = Crtat;
225	for (i = 1; i < row; i++) {
226	    bcopy((void *)(cp + col), (void *)cp, col * 2);
227	    cp += col;
228	}
229	for (i = 0; i < col; i++) {
230	    *cp++ = ' ';
231	}
232	crtat -= col;
233    }
234    pos = crtat - Crtat;
235    while ((inb(0x60) & 0x04) == 0) {}
236    outb(0x62, 0x49);
237    outb(0x60, pos & 0xff);
238    outb(0x60, pos >> 8);
239#endif
240#else
241
242    v86.ctl = 0;
243    v86.addr = 0x10;
244    v86.eax = 0xe00 | (c & 0xff);
245    v86.ebx = 0x7;
246    v86int();
247#endif
248}
249#endif
250
251static void
252vidc_rawputchar(int c)
253{
254    int		i;
255
256    if (c == '\t')
257	/* lame tab expansion */
258	for (i = 0; i < 8; i++)
259	    vidc_rawputchar(' ');
260    else {
261#if !defined(TERM_EMU) && !defined(PC98)
262        vidc_biosputchar(c);
263#else
264	/* Emulate AH=0eh (teletype output) */
265	switch(c) {
266	case '\a':
267#ifdef PC98
268	    beep();
269#else
270	    vidc_biosputchar(c);
271#endif
272	    return;
273	case '\r':
274	    curx = 0;
275	    curs_move(curx, cury);
276	    return;
277	case '\n':
278	    cury++;
279	    if (cury > 24) {
280		scroll_up(1, fg_c, bg_c);
281		cury--;
282	    } else {
283		curs_move(curx, cury);
284	    }
285	    return;
286	case '\b':
287	    if (curx > 0) {
288		curx--;
289		curs_move(curx, cury);
290		/* write_char(' ', fg_c, bg_c); XXX destructive(!) */
291		return;
292	    }
293	    return;
294	default:
295	    write_char(c, fg_c, bg_c);
296	    curx++;
297	    if (curx > 79) {
298		curx = 0;
299		cury++;
300	    }
301	    if (cury > 24) {
302		curx = 0;
303		scroll_up(1, fg_c, bg_c);
304		cury--;
305	    }
306	}
307	curs_move(curx, cury);
308#endif
309    }
310}
311
312#ifdef TERM_EMU
313
314/* Get cursor position on the screen. Result is in edx. Sets
315 * curx and cury appropriately.
316 */
317void
318get_pos(void)
319{
320#ifdef PC98
321    int pos = crtat - Crtat;
322
323    curx = pos % col;
324    cury = pos / col;
325#else
326
327    v86.ctl = 0;
328    v86.addr = 0x10;
329    v86.eax = 0x0300;
330    v86.ebx = 0x0;
331    v86int();
332    curx = v86.edx & 0x00ff;
333    cury = (v86.edx & 0xff00) >> 8;
334#endif
335}
336
337/* Move cursor to x rows and y cols (0-based). */
338void
339curs_move(int x, int y)
340{
341#ifdef PC98
342    int pos;
343
344    pos = x + y * col;
345    crtat = Crtat + pos;
346    pos = crtat - Crtat;
347    while((inb(0x60) & 0x04) == 0) {}
348    outb(0x62, 0x49);
349    outb(0x60, pos & 0xff);
350    outb(0x60, pos >> 8);
351    curx = x;
352    cury = y;
353#define isvisible(c)	(((c) >= 32) && ((c) < 255))
354    if (!isvisible(*crtat & 0x00ff)) {
355	write_char(' ', fg_c, bg_c);
356    }
357#else
358
359    v86.ctl = 0;
360    v86.addr = 0x10;
361    v86.eax = 0x0200;
362    v86.ebx = 0x0;
363    v86.edx = ((0x00ff & y) << 8) + (0x00ff & x);
364    v86int();
365    curx = x;
366    cury = y;
367    /* If there is ctrl char at this position, cursor would be invisible.
368     * Make it a space instead.
369     */
370    v86.ctl = 0;
371    v86.addr = 0x10;
372    v86.eax = 0x0800;
373    v86.ebx = 0x0;
374    v86int();
375#define isvisible(c)	(((c) >= 32) && ((c) < 255))
376    if (!isvisible(v86.eax & 0x00ff)) {
377	write_char(' ', fg_c, bg_c);
378    }
379#endif
380}
381
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.
385 */
386void
387scroll_up(int rows, int fgcol, int bgcol)
388{
389#ifdef PC98
390    unsigned short *cp;
391    int i;
392
393    if (rows == 0)
394	rows = 25;
395    cp = Crtat;
396    for (i = rows; i < row; i++) {
397	bcopy((void *)(cp + col), (void *)cp, col * 2);
398	cp += col;
399    }
400    for (i = 0; i < col; i++) {
401	*(cp + 0x1000) = at2pc98(fgcol, bgcol);
402	*cp++ = ' ';
403    }
404#else
405
406    if (rows == 0)
407	rows = 25;
408    v86.ctl = 0;
409    v86.addr = 0x10;
410    v86.eax = 0x0600 + (0x00ff & rows);
411    v86.ebx = (bgcol << 12) + (fgcol << 8);
412    v86.ecx = 0x0;
413    v86.edx = 0x184f;
414    v86int();
415#endif
416}
417
418/* Write character and attribute at cursor position. */
419void
420write_char(int c, int fgcol, int bgcol)
421{
422
423#ifdef PC98
424    *crtat = (c == 0x5c ? 0xfc : c);
425    *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
426#else
427    v86.ctl = 0;
428    v86.addr = 0x10;
429    v86.eax = 0x0900 + (0x00ff & c);
430    v86.ebx = (bgcol << 4) + fgcol;
431    v86.ecx = 0x1;
432    v86int();
433#endif
434}
435
436/**************************************************************/
437/*
438 * Screen manipulation functions. They use accumulated data in
439 * args[] and argc variables.
440 *
441 */
442
443/* Clear display from current position to end of screen */
444void
445CD(void)
446{
447#ifdef PC98
448    int pos;
449
450    get_pos();
451    for (pos = 0; crtat + pos <= Crtat + col * row; pos++) {
452	*(crtat + pos) = ' ';
453	*(crtat + pos + 0x1000) = at2pc98(fg_c, bg_c);
454    }
455    end_term();
456#else
457
458    get_pos();
459    if (curx > 0) {
460	v86.ctl = 0;
461	v86.addr = 0x10;
462	v86.eax = 0x0600;
463	v86.ebx = (bg_c << 4) + fg_c;
464	v86.ecx = (cury << 8) + curx;
465	v86.edx = (cury << 8) + 79;
466	v86int();
467	if (++cury > 24) {
468	    end_term();
469	    return;
470	}
471    }
472    v86.ctl = 0;
473    v86.addr = 0x10;
474    v86.eax = 0x0600;
475    v86.ebx = (bg_c << 4) + fg_c;
476    v86.ecx = (cury << 8) + 0;
477    v86.edx = (24 << 8) + 79;
478    v86int();
479    end_term();
480#endif
481}
482
483/* Absolute cursor move to args[0] rows and args[1] columns
484 * (the coordinates are 1-based).
485 */
486void
487CM(void)
488{
489
490    if (args[0] > 0)
491	args[0]--;
492    if (args[1] > 0)
493	args[1]--;
494    curs_move(args[1], args[0]);
495    end_term();
496}
497
498/* Home cursor (left top corner) */
499void
500HO(void)
501{
502
503    argc = 1;
504    args[0] = args[1] = 1;
505    CM();
506}
507
508/* Clear internal state of the terminal emulation code */
509void
510end_term(void)
511{
512
513    esc = 0;
514    argc = -1;
515}
516
517/* Gracefully exit ESC-sequence processing in case of misunderstanding */
518void
519bail_out(int c)
520{
521    char buf[16], *ch;
522    int i;
523
524    if (esc) {
525	vidc_rawputchar('\033');
526	if (esc != '\033')
527	    vidc_rawputchar(esc);
528	for (i = 0; i <= argc; ++i) {
529	    sprintf(buf, "%d", args[i]);
530	    ch = buf;
531	    while (*ch)
532		vidc_rawputchar(*ch++);
533	}
534    }
535    vidc_rawputchar(c);
536    end_term();
537}
538
539static void
540get_arg(c)
541{
542
543    if (argc < 0)
544	argc = 0;
545    args[argc] *= 10;
546    args[argc] += c - '0';
547}
548
549/* Emulate basic capabilities of cons25 terminal */
550void
551vidc_term_emu(int c)
552{
553    static int ansi_col[] = {
554	0, 4, 2, 6, 1, 5, 3, 7,
555    };
556    int t;
557    int i;
558
559    switch (esc) {
560    case 0:
561	switch (c) {
562	case '\033':
563	    esc = c;
564	    break;
565	default:
566	    vidc_rawputchar(c);
567	    break;
568	}
569	break;
570
571    case '\033':
572	switch (c) {
573	case '[':
574	    esc = c;
575	    args[0] = 0;
576	    argc = -1;
577	    break;
578	default:
579	    bail_out(c);
580	    break;
581	}
582	break;
583
584    case '[':
585	switch (c) {
586	case ';':
587	    if (argc < 0)	/* XXX */
588		argc = 0;
589	    else if (argc + 1 >= MAXARGS)
590		bail_out(c);
591	    else
592		args[++argc] = 0;
593	    break;
594	case 'H':
595	    if (argc < 0)
596		HO();
597	    else if (argc == 1)
598		CM();
599	    else
600		bail_out(c);
601	    break;
602	case 'J':
603	    if (argc < 0)
604		CD();
605	    else
606		bail_out(c);
607	    break;
608	case 'm':
609	    if (argc < 0) {
610		fg_c = DEFAULT_FGCOLOR;
611		bg_c = DEFAULT_BGCOLOR;
612	    }
613	    for (i = 0; i <= argc; ++i) {
614		switch (args[i]) {
615		case 0:		/* back to normal */
616		    fg_c = DEFAULT_FGCOLOR;
617		    bg_c = DEFAULT_BGCOLOR;
618		    break;
619		case 1:		/* bold */
620		    fg_c |= 0x8;
621		    break;
622		case 4:		/* underline */
623		case 5:		/* blink */
624		    bg_c |= 0x8;
625		    break;
626		case 7:		/* reverse */
627		    t = fg_c;
628		    fg_c = bg_c;
629		    bg_c = t;
630		    break;
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];
634		    break;
635		case 39:	/* normal */
636		    fg_c = DEFAULT_FGCOLOR;
637		    break;
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];
641		    break;
642		case 49:	/* normal */
643		    bg_c = DEFAULT_BGCOLOR;
644		    break;
645		}
646	    }
647	    end_term();
648	    break;
649	default:
650	    if (isdigit(c))
651		get_arg(c);
652	    else
653		bail_out(c);
654	    break;
655	}
656	break;
657
658    default:
659	bail_out(c);
660	break;
661    }
662}
663#endif
664
665static void
666vidc_putchar(int c)
667{
668#ifdef TERM_EMU
669    vidc_term_emu(c);
670#else
671    vidc_rawputchar(c);
672#endif
673}
674
675static int
676vidc_getchar(void)
677{
678
679    if (vidc_ischar()) {
680	v86.ctl = 0;
681#ifdef PC98
682	v86.addr = 0x18;
683#else
684	v86.addr = 0x16;
685#endif
686	v86.eax = 0x0;
687	v86int();
688	return (v86.eax & 0xff);
689    } else {
690	return (-1);
691    }
692}
693
694static int
695vidc_ischar(void)
696{
697
698#ifdef PC98
699    v86.ctl = 0;
700    v86.addr = 0x18;
701    v86.eax = 0x100;
702    v86int();
703    return ((v86.ebx >> 8) & 0x1);
704#else
705    v86.ctl = V86_FLAGS;
706    v86.addr = 0x16;
707    v86.eax = 0x100;
708    v86int();
709    return (!(v86.efl & PSL_Z));
710#endif
711}
712
713#if KEYBOARD_PROBE
714
715#ifdef PC98
716static int
717probe_keyboard(void)
718{
719    return (*(u_char *)PTOV(0xA1481) & 0x48);
720}
721#else   /* PC98 */
722#define PROBE_MAXRETRY	5
723#define PROBE_MAXWAIT	400
724#define IO_DUMMY	0x84
725#define IO_KBD		0x060		/* 8042 Keyboard */
726
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
732					 */
733#define KBDC_ECHO		0x00ee
734#define KBDS_ANY_BUFFER_FULL	0x0001
735#define KBDS_INPUT_BUFFER_FULL	0x0002
736#define KBD_ECHO		0x00ee
737
738/* 7 microsec delay necessary for some keyboard controllers */
739static void
740delay7(void)
741{
742    /*
743     * I know this is broken, but no timer is available yet at this stage...
744     * See also comments in `delay1ms()'.
745     */
746    inb(IO_DUMMY); inb(IO_DUMMY);
747    inb(IO_DUMMY); inb(IO_DUMMY);
748    inb(IO_DUMMY); inb(IO_DUMMY);
749}
750
751/*
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
757 * 60 nS :-(.
758 *
759 */
760static void
761delay1ms(void)
762{
763    int i = 800;
764    while (--i >= 0)
765	(void)inb(0x84);
766}
767
768/*
769 * We use the presence/absence of a keyboard to determine whether the internal
770 * console can be used for input.
771 *
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.
775 */
776static int
777probe_keyboard(void)
778{
779    int retry = PROBE_MAXRETRY;
780    int wait;
781    int i;
782
783    while (--retry >= 0) {
784	/* flush any noise */
785	while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
786	    delay7();
787	    inb(IO_KBD + KBD_DATA_PORT);
788	    delay1ms();
789	}
790
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)
795		break;
796	    if (i & KBDS_ANY_BUFFER_FULL) {
797		delay7();
798	        inb(IO_KBD + KBD_DATA_PORT);
799	    }
800	    delay1ms();
801	}
802	if (wait <= 0)
803	    continue;
804
805	/* send the ECHO command */
806	outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
807
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)
811		 break;
812	     delay1ms();
813	}
814	if (wait <= 0)
815	    continue;
816
817	delay7();
818	i = inb(IO_KBD + KBD_DATA_PORT);
819#ifdef PROBE_KBD_BEBUG
820        printf("probe_keyboard: got 0x%x.\n", i);
821#endif
822	if (i == KBD_ECHO) {
823	    /* got the right answer */
824	    return (0);
825	}
826    }
827
828    return (1);
829}
830#endif /* PC98 */
831#endif /* KEYBOARD_PROBE */
832