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
31uint8_t ioctrl = IO_KEYBOARD;
32
33void
34putc(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
44void
45xputc(int c)
46{
47
48	if (ioctrl & IO_KEYBOARD)
49		putc(c);
50	if (ioctrl & IO_SERIAL)
51		sio_putc(c);
52}
53
54static void
55getcursor(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
69void
70putchar(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
89int
90getc(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
106int
107xgetc(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
123int
124keyhit(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
154void
155getstr(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
197int
198getchar(void)
199{
200	return (xgetc(0) & 0xff);
201}
202