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