vidconsole.c revision 39896
1/*
2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * 	From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
28 *
29 *	$Id: vidconsole.c,v 1.2 1998/09/17 23:52:10 msmith Exp $
30 */
31
32#include <stand.h>
33#include <bootstrap.h>
34#include <btxv86.h>
35#include "libi386.h"
36
37#if KEYBOARD_PROBE
38#include <machine/cpufunc.h>
39
40static int	probe_keyboard(void);
41#endif
42static void	vidc_probe(struct console *cp);
43static int	vidc_init(int arg);
44static void	vidc_putchar(int c);
45static int	vidc_getchar(void);
46static int	vidc_ischar(void);
47
48struct console vidconsole = {
49    "vidconsole",
50    "internal video/keyboard",
51    0,
52    vidc_probe,
53    vidc_init,
54    vidc_putchar,
55    vidc_getchar,
56    vidc_ischar
57};
58
59static void
60vidc_probe(struct console *cp)
61{
62
63    /* look for a keyboard */
64#if KEYBOARD_PROBE
65    if (probe_keyboard())
66#endif
67    {
68
69	cp->c_flags |= C_PRESENTIN;
70    }
71
72    /* XXX for now, always assume we can do BIOS screen output */
73    cp->c_flags |= C_PRESENTOUT;
74}
75
76static int
77vidc_init(int arg)
78{
79    return(0);	/* XXX reinit? */
80}
81
82static void
83vidc_putchar(int c)
84{
85    v86.ctl = 0;
86    v86.addr = 0x10;
87    v86.eax = 0xe00 | c;
88    v86.ebx = 0x7;
89    v86int();
90}
91
92static int
93vidc_getchar(void)
94{
95    if (vidc_ischar()) {
96	v86.ctl = 0;
97	v86.addr = 0x16;
98	v86.eax = 0x0;
99	v86int();
100	return(v86.eax & 0xff);
101    } else {
102	return(-1);
103    }
104}
105
106static int
107vidc_ischar(void)
108{
109    v86.ctl = 0;
110    v86.addr = 0x16;
111    v86.eax = 0x100;
112    v86int();
113    return(v86.eax);
114}
115
116#if KEYBOARD_PROBE
117
118#define PROBE_MAXRETRY	5
119#define PROBE_MAXWAIT	400
120#define IO_DUMMY	0x84
121#define IO_KBD		0x060		/* 8042 Keyboard */
122
123/* selected defines from kbdio.h */
124#define KBD_STATUS_PORT 	4	/* status port, read */
125#define KBD_DATA_PORT		0	/* data port, read/write
126					 * also used as keyboard command
127					 * and mouse command port
128					 */
129#define KBDC_ECHO		0x00ee
130#define KBDS_ANY_BUFFER_FULL	0x0001
131#define KBDS_INPUT_BUFFER_FULL	0x0002
132#define KBD_ECHO		0x00ee
133
134/* 7 microsec delay necessary for some keyboard controllers */
135static void
136delay7(void)
137{
138    /*
139     * I know this is broken, but no timer is avaiable yet at this stage...
140     * See also comments in `delay1ms()'.
141     */
142    inb(IO_DUMMY); inb(IO_DUMMY);
143    inb(IO_DUMMY); inb(IO_DUMMY);
144    inb(IO_DUMMY); inb(IO_DUMMY);
145}
146
147/*
148 * This routine uses an inb to an unused port, the time to execute that
149 * inb is approximately 1.25uS.  This value is pretty constant across
150 * all CPU's and all buses, with the exception of some PCI implentations
151 * that do not forward this I/O adress to the ISA bus as they know it
152 * is not a valid ISA bus address, those machines execute this inb in
153 * 60 nS :-(.
154 *
155 */
156static void
157delay1ms(void)
158{
159    int i = 800;
160    while (--i >= 0)
161	(void)inb(0x84);
162}
163
164/*
165 * We use the presence/absence of a keyboard to determine whether the internal
166 * console can be used for input.
167 *
168 * Perform a simple test on the keyboard; issue the ECHO command and see
169 * if the right answer is returned. We don't do anything as drastic as
170 * full keyboard reset; it will be too troublesome and take too much time.
171 */
172static int
173probe_keyboard(void)
174{
175    int retry = PROBE_MAXRETRY;
176    int wait;
177    int i;
178
179    while (--retry >= 0) {
180	/* flush any noise */
181	while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
182	    delay7();
183	    inb(IO_KBD + KBD_DATA_PORT);
184	    delay1ms();
185	}
186
187	/* wait until the controller can accept a command */
188	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
189	    if (((i = inb(IO_KBD + KBD_STATUS_PORT))
190                & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
191		break;
192	    if (i & KBDS_ANY_BUFFER_FULL) {
193		delay7();
194	        inb(IO_KBD + KBD_DATA_PORT);
195	    }
196	    delay1ms();
197	}
198	if (wait <= 0)
199	    continue;
200
201	/* send the ECHO command */
202	outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
203
204	/* wait for a response */
205	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
206	     if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
207		 break;
208	     delay1ms();
209	}
210	if (wait <= 0)
211	    continue;
212
213	delay7();
214	i = inb(IO_KBD + KBD_DATA_PORT);
215#ifdef PROBE_KBD_BEBUG
216        printf("probe_keyboard: got 0x%x.\n", i);
217#endif
218	if (i == KBD_ECHO) {
219	    /* got the right answer */
220	    return (0);
221	}
222    }
223
224    return (1);
225}
226#endif /* KEYBOARD_PROBE */
227