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