xref: /freebsd/stand/i386/common/cons.c (revision 389e4940069316fe667ffa263fa7d6390d0a960f)
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15 
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
18 
19 #include <sys/param.h>
20 
21 #include <machine/psl.h>
22 
23 #include <btxv86.h>
24 
25 #include "stand.h"
26 
27 #include "lib.h"
28 #include "rbx.h"
29 #include "cons.h"
30 
31 #define SECOND		18	/* Circa that many ticks in a second. */
32 
33 uint8_t ioctrl = IO_KEYBOARD;
34 
35 void
36 putc(int c)
37 {
38 
39 	v86.ctl = V86_FLAGS;
40 	v86.addr = 0x10;
41 	v86.eax = 0xe00 | (c & 0xff);
42 	v86.ebx = 0x7;
43 	v86int();
44 }
45 
46 void
47 xputc(int c)
48 {
49 
50 	if (ioctrl & IO_KEYBOARD)
51 		putc(c);
52 	if (ioctrl & IO_SERIAL)
53 		sio_putc(c);
54 }
55 
56 void
57 putchar(int c)
58 {
59 
60 	if (c == '\n')
61 		xputc('\r');
62 	xputc(c);
63 }
64 
65 int
66 getc(int fn)
67 {
68 
69 	v86.ctl = V86_FLAGS;
70 	v86.addr = 0x16;
71 	v86.eax = fn << 8;
72 	v86int();
73 
74 	if (fn == 0)
75 		return (v86.eax);
76 
77 	if (V86_ZR(v86.efl))
78 		return (0);
79 	return (v86.eax);
80 }
81 
82 int
83 xgetc(int fn)
84 {
85 
86 	if (OPT_CHECK(RBX_NOINTR))
87 		return (0);
88 	for (;;) {
89 		if (ioctrl & IO_KEYBOARD && getc(1))
90 			return (fn ? 1 : getc(0));
91 		if (ioctrl & IO_SERIAL && sio_ischar())
92 			return (fn ? 1 : sio_getc());
93 		if (fn)
94 			return (0);
95 	}
96 	/* NOTREACHED */
97 }
98 
99 int
100 getchar(void)
101 {
102 
103 	return (xgetc(0));
104 }
105 
106 int
107 keyhit(unsigned int secs)
108 {
109 	uint32_t t0, t1, c;
110 
111 	if (OPT_CHECK(RBX_NOINTR))
112 		return (0);
113 	secs *= SECOND;
114 	t0 = 0;
115 	for (;;) {
116 		/*
117 		 * The extra comparison is an attempt to work around
118 		 * what appears to be a bug in QEMU and Bochs. Both emulators
119 		 * sometimes report a key-press with scancode one and ascii zero
120 		 * when no such key is pressed in reality. As far as I can tell,
121 		 * this only happens shortly after a reboot.
122 		 */
123 		c = xgetc(1);
124 		if (c != 0 && c != 0x0100)
125 			return (1);
126 		if (secs > 0) {
127 			t1 = *(uint32_t *)PTOV(0x46c);
128 			if (!t0)
129 				t0 = t1;
130 			if (t1 < t0 || t1 >= t0 + secs)
131 				return (0);
132 		}
133 	}
134 	/* NOTREACHED */
135 }
136 
137 void
138 getstr(char *cmdstr, size_t cmdstrsize)
139 {
140 	char *s;
141 	int c;
142 
143 	s = cmdstr;
144 	for (;;) {
145 		c = xgetc(0);
146 
147 		/* Translate some extended codes. */
148 		switch (c) {
149 		case 0x5300:    /* delete */
150 			c = '\177';
151 			break;
152 		default:
153 			c &= 0xff;
154 			break;
155 		}
156 
157 		switch (c) {
158 		case '\177':
159 		case '\b':
160 			if (s > cmdstr) {
161 				s--;
162 				printf("\b \b");
163 			}
164 			break;
165 		case '\n':
166 		case '\r':
167 			*s = 0;
168 			return;
169 		default:
170 			if (c >= 0x20 && c <= 0x7e) {
171 				if (s - cmdstr < cmdstrsize - 1)
172 					*s++ = c;
173 				putchar(c);
174 			}
175 			break;
176 		}
177 	}
178 }
179