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