xref: /freebsd/stand/i386/common/cons.c (revision 6b13d60bf49ee40626d7e3a5d5a80519f0067307)
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/param.h>
17 
18 #include <machine/psl.h>
19 
20 #include <btxv86.h>
21 
22 #include "stand.h"
23 
24 #include "lib.h"
25 #include "rbx.h"
26 #include "cons.h"
27 
28 #define SECOND		18	/* Circa that many ticks in a second. */
29 
30 uint8_t ioctrl = IO_KEYBOARD;
31 
32 void
33 putc(int c)
34 {
35 
36 	v86.ctl = V86_FLAGS;
37 	v86.addr = 0x10;
38 	v86.eax = 0xe00 | (c & 0xff);
39 	v86.ebx = 0x7;
40 	v86int();
41 }
42 
43 void
44 xputc(int c)
45 {
46 
47 	if (ioctrl & IO_KEYBOARD)
48 		putc(c);
49 	if (ioctrl & IO_SERIAL)
50 		sio_putc(c);
51 }
52 
53 static void
54 getcursor(int *row, int *col)
55 {
56 	v86.ctl = V86_FLAGS;
57 	v86.addr = 0x10;
58 	v86.eax = 0x300;
59 	v86.ebx = 0x7;
60 	v86int();
61 
62 	if (row != NULL)
63 		*row = v86.edx >> 8;
64 	if (col != NULL)
65 		*col = v86.edx & 0xff;
66 }
67 
68 void
69 putchar(int c)
70 {
71 	int i, col;
72 
73 	switch (c) {
74 	case '\n':
75 		xputc('\r');
76 		break;
77 	case '\t':
78 		col = 0;
79 		getcursor(NULL, &col);
80 		col = 8 - (col % 8);
81 		for (i = 0; i < col; i++)
82 			xputc(' ');
83 		return;
84 	}
85 	xputc(c);
86 }
87 
88 int
89 getc(int fn)
90 {
91 
92 	v86.ctl = V86_FLAGS;
93 	v86.addr = 0x16;
94 	v86.eax = fn << 8;
95 	v86int();
96 
97 	if (fn == 0)
98 		return (v86.eax);
99 
100 	if (V86_ZR(v86.efl))
101 		return (0);
102 	return (v86.eax);
103 }
104 
105 int
106 xgetc(int fn)
107 {
108 
109 	if (OPT_CHECK(RBX_NOINTR))
110 		return (0);
111 	for (;;) {
112 		if (ioctrl & IO_KEYBOARD && getc(1))
113 			return (fn ? 1 : getc(0));
114 		if (ioctrl & IO_SERIAL && sio_ischar())
115 			return (fn ? 1 : sio_getc());
116 		if (fn)
117 			return (0);
118 	}
119 	/* NOTREACHED */
120 }
121 
122 int
123 getchar(void)
124 {
125 
126 	return (xgetc(0) & 0xff);
127 }
128 
129 int
130 keyhit(unsigned int secs)
131 {
132 	uint32_t t0, t1, c;
133 
134 	if (OPT_CHECK(RBX_NOINTR))
135 		return (0);
136 	secs *= SECOND;
137 	t0 = 0;
138 	for (;;) {
139 		/*
140 		 * The extra comparison is an attempt to work around
141 		 * what appears to be a bug in QEMU and Bochs. Both emulators
142 		 * sometimes report a key-press with scancode one and ascii zero
143 		 * when no such key is pressed in reality. As far as I can tell,
144 		 * this only happens shortly after a reboot.
145 		 */
146 		c = xgetc(1);
147 		if (c != 0 && c != 0x0100)
148 			return (1);
149 		if (secs > 0) {
150 			t1 = *(uint32_t *)PTOV(0x46c);
151 			if (!t0)
152 				t0 = t1;
153 			if (t1 < t0 || t1 >= t0 + secs)
154 				return (0);
155 		}
156 	}
157 	/* NOTREACHED */
158 }
159 
160 void
161 getstr(char *cmdstr, size_t cmdstrsize)
162 {
163 	char *s;
164 	int c;
165 
166 	s = cmdstr;
167 	for (;;) {
168 		c = xgetc(0);
169 
170 		/* Translate some extended codes. */
171 		switch (c) {
172 		case 0x5300:    /* delete */
173 			c = '\177';
174 			break;
175 		default:
176 			c &= 0xff;
177 			break;
178 		}
179 
180 		switch (c) {
181 		case '\177':
182 		case '\b':
183 			if (s > cmdstr) {
184 				s--;
185 				printf("\b \b");
186 			}
187 			break;
188 		case '\n':
189 		case '\r':
190 			*s = 0;
191 			return;
192 		default:
193 			if (c >= 0x20 && c <= 0x7e) {
194 				if (s - cmdstr < cmdstrsize - 1)
195 					*s++ = c;
196 				putchar(c);
197 			}
198 			break;
199 		}
200 	}
201 }
202