]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/i386/libi386/vidconsole.c
Merge llvm trunk r338150, and resolve conflicts.
[FreeBSD/FreeBSD.git] / stand / i386 / libi386 / 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  *      Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <stand.h>
34 #include <bootstrap.h>
35 #include <btxv86.h>
36 #include <machine/psl.h>
37 #include "libi386.h"
38
39 #if KEYBOARD_PROBE
40 #include <machine/cpufunc.h>
41
42 static int      probe_keyboard(void);
43 #endif
44 static void     vidc_probe(struct console *cp);
45 static int      vidc_init(int arg);
46 static void     vidc_putchar(int c);
47 static int      vidc_getchar(void);
48 static int      vidc_ischar(void);
49
50 static int      vidc_started;
51
52 #ifdef TERM_EMU
53 #define MAXARGS         8
54 #define DEFAULT_FGCOLOR 7
55 #define DEFAULT_BGCOLOR 0
56
57 void            end_term(void);
58 void            bail_out(int c);
59 void            vidc_term_emu(int c);
60 void            get_pos(int *x, int *y);
61 void            curs_move(int *_x, int *_y, int x, int y);
62 void            write_char(int c, int fg, int bg);
63 void            scroll_up(int rows, int fg, int bg);
64 void            CD(void);
65 void            CM(void);
66 void            HO(void);
67
68 static int      args[MAXARGS], argc;
69 static int      fg_c, bg_c, curx, cury;
70 static int      esc;
71 #endif
72
73
74 struct console vidconsole = {
75     "vidconsole",
76     "internal video/keyboard",
77     0,
78     vidc_probe,
79     vidc_init,
80     vidc_putchar,
81     vidc_getchar,
82     vidc_ischar
83 };
84
85 static void
86 vidc_probe(struct console *cp)
87 {
88     
89     /* look for a keyboard */
90 #if KEYBOARD_PROBE
91     if (probe_keyboard())
92 #endif
93     {
94         
95         cp->c_flags |= C_PRESENTIN;
96     }
97
98     /* XXX for now, always assume we can do BIOS screen output */
99     cp->c_flags |= C_PRESENTOUT;
100 }
101
102 static int
103 vidc_init(int arg)
104 {
105     int         i;
106
107     if (vidc_started && arg == 0)
108         return (0);
109     vidc_started = 1;
110 #ifdef TERM_EMU
111     /* Init terminal emulator */
112     end_term();
113     get_pos(&curx, &cury);
114     curs_move(&curx, &cury, curx, cury);
115     fg_c = DEFAULT_FGCOLOR;
116     bg_c = DEFAULT_BGCOLOR;
117 #endif
118     for (i = 0; i < 10 && vidc_ischar(); i++)
119         (void)vidc_getchar();
120     return (0); /* XXX reinit? */
121 }
122
123 void
124 vidc_biosputchar(int c)
125 {
126
127     v86.ctl = 0;
128     v86.addr = 0x10;
129     v86.eax = 0xe00 | (c & 0xff);
130     v86.ebx = 0x7;
131     v86int();
132 }
133
134 static void
135 vidc_rawputchar(int c)
136 {
137     int         i;
138
139     if (c == '\t')
140         /* lame tab expansion */
141         for (i = 0; i < 8; i++)
142             vidc_rawputchar(' ');
143     else {
144 #ifndef TERM_EMU
145         vidc_biosputchar(c);
146 #else
147         /* Emulate AH=0eh (teletype output) */
148         switch(c) {
149         case '\a':
150             vidc_biosputchar(c);
151             return;
152         case '\r':
153             curx = 0;
154             curs_move(&curx, &cury, curx, cury);
155             return;
156         case '\n':
157             cury++;
158             if (cury > 24) {
159                 scroll_up(1, fg_c, bg_c);
160                 cury--;
161             } else {
162                 curs_move(&curx, &cury, curx, cury);
163             }
164             return;
165         case '\b':
166             if (curx > 0) {
167                 curx--;
168                 curs_move(&curx, &cury, curx, cury);
169                 /* write_char(' ', fg_c, bg_c); XXX destructive(!) */
170                 return;
171             }
172             return;
173         default:
174             write_char(c, fg_c, bg_c);
175             curx++;
176             if (curx > 79) {
177                 curx = 0;
178                 cury++;
179             }
180             if (cury > 24) {
181                 curx = 0;
182                 scroll_up(1, fg_c, bg_c);
183                 cury--;
184             }
185         }
186         curs_move(&curx, &cury, curx, cury);
187 #endif
188     }
189 }
190
191 #ifdef TERM_EMU
192
193 /* Get cursor position on the screen. Result is in edx. Sets
194  * curx and cury appropriately.
195  */
196 void
197 get_pos(int *x, int *y)
198 {
199
200     v86.ctl = 0;
201     v86.addr = 0x10;
202     v86.eax = 0x0300;
203     v86.ebx = 0x0;
204     v86int();
205     *x = v86.edx & 0x00ff;
206     *y = (v86.edx & 0xff00) >> 8;
207 }
208
209 /* Move cursor to x rows and y cols (0-based). */
210 void
211 curs_move(int *_x, int *_y, int x, int y)
212 {
213
214     v86.ctl = 0;
215     v86.addr = 0x10;
216     v86.eax = 0x0200;
217     v86.ebx = 0x0;
218     v86.edx = ((0x00ff & y) << 8) + (0x00ff & x);
219     v86int();
220     *_x = x;
221     *_y = y;
222     /* If there is ctrl char at this position, cursor would be invisible.
223      * Make it a space instead.
224      */
225     v86.ctl = 0;
226     v86.addr = 0x10;
227     v86.eax = 0x0800;
228     v86.ebx = 0x0;
229     v86int();
230 #define isvisible(c)    (((c) >= 32) && ((c) < 255))
231     if (!isvisible(v86.eax & 0x00ff)) {
232         write_char(' ', fg_c, bg_c);
233     }
234 }
235
236 /* Scroll up the whole window by a number of rows. If rows==0,
237  * clear the window. fg and bg are attributes for the new lines
238  * inserted in the window.
239  */
240 void
241 scroll_up(int rows, int fgcol, int bgcol)
242 {
243
244     if (rows == 0)
245         rows = 25;
246     v86.ctl = 0;
247     v86.addr = 0x10;
248     v86.eax = 0x0600 + (0x00ff & rows);
249     v86.ebx = (bgcol << 12) + (fgcol << 8);
250     v86.ecx = 0x0;
251     v86.edx = 0x184f;
252     v86int();
253 }
254
255 /* Write character and attribute at cursor position. */
256 void
257 write_char(int c, int fgcol, int bgcol)
258 {
259
260     v86.ctl = 0;
261     v86.addr = 0x10;
262     v86.eax = 0x0900 + (0x00ff & c);
263     v86.ebx = (bgcol << 4) + fgcol;
264     v86.ecx = 0x1;
265     v86int();
266 }
267
268 /**************************************************************/
269 /*
270  * Screen manipulation functions. They use accumulated data in
271  * args[] and argc variables.
272  *
273  */
274
275 /* Clear display from current position to end of screen */
276 void
277 CD(void)
278 {
279
280     get_pos(&curx, &cury);
281     if (curx > 0) {
282         v86.ctl = 0;
283         v86.addr = 0x10;
284         v86.eax = 0x0600;
285         v86.ebx = (bg_c << 4) + fg_c;
286         v86.ecx = (cury << 8) + curx;
287         v86.edx = (cury << 8) + 79;
288         v86int();
289         if (++cury > 24) {
290             end_term();
291             return;
292         }
293     }
294     v86.ctl = 0;
295     v86.addr = 0x10;
296     v86.eax = 0x0600;
297     v86.ebx = (bg_c << 4) + fg_c;
298     v86.ecx = (cury << 8) + 0;
299     v86.edx = (24 << 8) + 79;
300     v86int();
301     end_term();
302 }
303
304 /* Absolute cursor move to args[0] rows and args[1] columns
305  * (the coordinates are 1-based).
306  */
307 void
308 CM(void)
309 {
310
311     if (args[0] > 0)
312         args[0]--;
313     if (args[1] > 0)
314         args[1]--;
315     curs_move(&curx, &cury, args[1], args[0]);
316     end_term();
317 }
318
319 /* Home cursor (left top corner) */
320 void
321 HO(void)
322 {
323
324     argc = 1;
325     args[0] = args[1] = 1;
326     CM();
327 }
328
329 /* Clear internal state of the terminal emulation code */
330 void
331 end_term(void)
332 {
333
334     esc = 0;
335     argc = -1;
336 }
337
338 /* Gracefully exit ESC-sequence processing in case of misunderstanding */
339 void
340 bail_out(int c)
341 {
342     char buf[16], *ch;
343     int i;
344
345     if (esc) {
346         vidc_rawputchar('\033');
347         if (esc != '\033')
348             vidc_rawputchar(esc);
349         for (i = 0; i <= argc; ++i) {
350             sprintf(buf, "%d", args[i]);
351             ch = buf;
352             while (*ch)
353                 vidc_rawputchar(*ch++);
354         }
355     }
356     vidc_rawputchar(c);
357     end_term();
358 }
359
360 static void
361 get_arg(int c)
362 {
363
364     if (argc < 0)
365         argc = 0;
366     args[argc] *= 10;
367     args[argc] += c - '0';
368 }
369
370 /* Emulate basic capabilities of cons25 terminal */
371 void
372 vidc_term_emu(int c)
373 {
374     static int ansi_col[] = {
375         0, 4, 2, 6, 1, 5, 3, 7,
376     };
377     int t;
378     int i;
379
380     switch (esc) {
381     case 0:
382         switch (c) {
383         case '\033':
384             esc = c;
385             break;
386         default:
387             vidc_rawputchar(c);
388             break;
389         }
390         break;
391
392     case '\033':
393         switch (c) {
394         case '[':
395             esc = c;
396             args[0] = 0;
397             argc = -1;
398             break;
399         default:
400             bail_out(c);
401             break;
402         }
403         break;
404
405     case '[':
406         switch (c) {
407         case ';':
408             if (argc < 0)       /* XXX */
409                 argc = 0;
410             else if (argc + 1 >= MAXARGS)
411                 bail_out(c);
412             else
413                 args[++argc] = 0;
414             break;
415         case 'H':
416             if (argc < 0)
417                 HO();
418             else if (argc == 1)
419                 CM();
420             else
421                 bail_out(c);
422             break;
423         case 'J':
424             if (argc < 0)
425                 CD();
426             else
427                 bail_out(c);
428             break;
429         case 'm':
430             if (argc < 0) {
431                 fg_c = DEFAULT_FGCOLOR;
432                 bg_c = DEFAULT_BGCOLOR;
433             }
434             for (i = 0; i <= argc; ++i) {
435                 switch (args[i]) {
436                 case 0:         /* back to normal */
437                     fg_c = DEFAULT_FGCOLOR;
438                     bg_c = DEFAULT_BGCOLOR;
439                     break;
440                 case 1:         /* bold */
441                     fg_c |= 0x8;
442                     break;
443                 case 4:         /* underline */
444                 case 5:         /* blink */
445                     bg_c |= 0x8;
446                     break;
447                 case 7:         /* reverse */
448                     t = fg_c;
449                     fg_c = bg_c;
450                     bg_c = t;
451                     break;
452                 case 22:        /* normal intensity */
453                     fg_c &= ~0x8;
454                     break;
455                 case 24:        /* not underline */
456                 case 25:        /* not blinking */
457                     bg_c &= ~0x8;
458                     break;
459                 case 30: case 31: case 32: case 33:
460                 case 34: case 35: case 36: case 37:
461                     fg_c = ansi_col[args[i] - 30];
462                     break;
463                 case 39:        /* normal */
464                     fg_c = DEFAULT_FGCOLOR;
465                     break;
466                 case 40: case 41: case 42: case 43:
467                 case 44: case 45: case 46: case 47:
468                     bg_c = ansi_col[args[i] - 40];
469                     break;
470                 case 49:        /* normal */
471                     bg_c = DEFAULT_BGCOLOR;
472                     break;
473                 }
474             }
475             end_term();
476             break;
477         default:
478             if (isdigit(c))
479                 get_arg(c);
480             else
481                 bail_out(c);
482             break;
483         }
484         break;
485
486     default:
487         bail_out(c);
488         break;
489     }
490 }
491 #endif
492
493 static void
494 vidc_putchar(int c)
495 {
496 #ifdef TERM_EMU
497     vidc_term_emu(c);
498 #else
499     vidc_rawputchar(c);
500 #endif
501 }
502
503 static int
504 vidc_getchar(void)
505 {
506
507     if (vidc_ischar()) {
508         v86.ctl = 0;
509         v86.addr = 0x16;
510         v86.eax = 0x0;
511         v86int();
512         return (v86.eax & 0xff);
513     } else {
514         return (-1);
515     }
516 }
517
518 static int
519 vidc_ischar(void)
520 {
521
522     v86.ctl = V86_FLAGS;
523     v86.addr = 0x16;
524     v86.eax = 0x100;
525     v86int();
526     return (!V86_ZR(v86.efl));
527 }
528
529 #if KEYBOARD_PROBE
530
531 #define PROBE_MAXRETRY  5
532 #define PROBE_MAXWAIT   400
533 #define IO_DUMMY        0x84
534 #define IO_KBD          0x060           /* 8042 Keyboard */
535
536 /* selected defines from kbdio.h */
537 #define KBD_STATUS_PORT         4       /* status port, read */
538 #define KBD_DATA_PORT           0       /* data port, read/write 
539                                          * also used as keyboard command
540                                          * and mouse command port 
541                                          */
542 #define KBDC_ECHO               0x00ee
543 #define KBDS_ANY_BUFFER_FULL    0x0001
544 #define KBDS_INPUT_BUFFER_FULL  0x0002
545 #define KBD_ECHO                0x00ee
546
547 /* 7 microsec delay necessary for some keyboard controllers */
548 static void
549 delay7(void)
550 {
551     /* 
552      * I know this is broken, but no timer is available yet at this stage...
553      * See also comments in `delay1ms()'.
554      */
555     inb(IO_DUMMY); inb(IO_DUMMY);
556     inb(IO_DUMMY); inb(IO_DUMMY);
557     inb(IO_DUMMY); inb(IO_DUMMY);
558 }
559
560 /*
561  * This routine uses an inb to an unused port, the time to execute that
562  * inb is approximately 1.25uS.  This value is pretty constant across
563  * all CPU's and all buses, with the exception of some PCI implentations
564  * that do not forward this I/O address to the ISA bus as they know it
565  * is not a valid ISA bus address, those machines execute this inb in
566  * 60 nS :-(.
567  *
568  */
569 static void
570 delay1ms(void)
571 {
572     int i = 800;
573     while (--i >= 0)
574         (void)inb(0x84);
575 }
576
577 /* 
578  * We use the presence/absence of a keyboard to determine whether the internal
579  * console can be used for input.
580  *
581  * Perform a simple test on the keyboard; issue the ECHO command and see
582  * if the right answer is returned. We don't do anything as drastic as
583  * full keyboard reset; it will be too troublesome and take too much time.
584  */
585 static int
586 probe_keyboard(void)
587 {
588     int retry = PROBE_MAXRETRY;
589     int wait;
590     int i;
591
592     while (--retry >= 0) {
593         /* flush any noise */
594         while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
595             delay7();
596             inb(IO_KBD + KBD_DATA_PORT);
597             delay1ms();
598         }
599
600         /* wait until the controller can accept a command */
601         for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
602             if (((i = inb(IO_KBD + KBD_STATUS_PORT)) 
603                 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
604                 break;
605             if (i & KBDS_ANY_BUFFER_FULL) {
606                 delay7();
607                 inb(IO_KBD + KBD_DATA_PORT);
608             }
609             delay1ms();
610         }
611         if (wait <= 0)
612             continue;
613
614         /* send the ECHO command */
615         outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
616
617         /* wait for a response */
618         for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
619              if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
620                  break;
621              delay1ms();
622         }
623         if (wait <= 0)
624             continue;
625
626         delay7();
627         i = inb(IO_KBD + KBD_DATA_PORT);
628 #ifdef PROBE_KBD_BEBUG
629         printf("probe_keyboard: got 0x%x.\n", i);
630 #endif
631         if (i == KBD_ECHO) {
632             /* got the right answer */
633             return (1);
634         }
635     }
636
637     return (0);
638 }
639 #endif /* KEYBOARD_PROBE */