xref: /illumos-gate/usr/src/boot/i386/common/cons.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 
18 #include <sys/param.h>
19 
20 #include <machine/psl.h>
21 
22 #include <btxv86.h>
23 
24 #include "lib.h"
25 #include "rbx.h"
26 #include "util.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 keyhit(unsigned int secs)
125 {
126 	uint32_t t0, t1, c;
127 
128 	if (OPT_CHECK(RBX_NOINTR))
129 		return (0);
130 	secs *= SECOND;
131 	t0 = 0;
132 	for (;;) {
133 		/*
134 		 * The extra comparison is an attempt to work around
135 		 * what appears to be a bug in QEMU and Bochs. Both emulators
136 		 * sometimes report a key-press with scancode one and ascii zero
137 		 * when no such key is pressed in reality. As far as I can tell,
138 		 * this only happens shortly after a reboot.
139 		 */
140 		c = xgetc(1);
141 		if (c != 0 && c != 0x0100)
142 			return (1);
143 		if (secs > 0) {
144 			t1 = *(uint32_t *)PTOV(0x46c);
145 			if (!t0)
146 				t0 = t1;
147 			if (t1 < t0 || t1 >= t0 + secs)
148 				return (0);
149 		}
150 	}
151 	/* NOTREACHED */
152 }
153 
154 void
155 getstr(char *cmdstr, size_t cmdstrsize)
156 {
157 	char *s;
158 	int c;
159 
160 	s = cmdstr;
161 	for (;;) {
162 		c = xgetc(0);
163 
164 		/* Translate some extended codes. */
165 		switch (c) {
166 		case 0x5300:	/* delete */
167 			c = '\177';
168 			break;
169 		default:
170 			c &= 0xff;
171 			break;
172 		}
173 
174 		switch (c) {
175 		case '\177':
176 		case '\b':
177 			if (s > cmdstr) {
178 				s--;
179 				printf("\b \b");
180 			}
181 			break;
182 		case '\n':
183 		case '\r':
184 			*s = 0;
185 			return;
186 		default:
187 			if (c >= 0x20 && c <= 0x7e) {
188 				if (s - cmdstr < cmdstrsize - 1)
189 					*s++ = c;
190 				putchar(c);
191 			}
192 			break;
193 		}
194 	}
195 }
196 
197 int
198 getchar(void)
199 {
200 	return (xgetc(0) & 0xff);
201 }
202