vidconsole.c revision 40212
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.5 1998/10/07 07:34:31 msmith Exp $
30 */
31
32#include <stand.h>
33#include <bootstrap.h>
34#include <btxv86.h>
35#include <machine/psl.h>
36#include "libi386.h"
37
38#if KEYBOARD_PROBE
39#include <machine/cpufunc.h>
40
41static int	probe_keyboard(void);
42#endif
43static void	vidc_probe(struct console *cp);
44static int	vidc_init(int arg);
45static void	vidc_putchar(int c);
46static int	vidc_getchar(void);
47static int	vidc_ischar(void);
48
49static int	vidc_started;
50
51struct console vidconsole = {
52    "vidconsole",
53    "internal video/keyboard",
54    0,
55    vidc_probe,
56    vidc_init,
57    vidc_putchar,
58    vidc_getchar,
59    vidc_ischar
60};
61
62static void
63vidc_probe(struct console *cp)
64{
65
66    /* look for a keyboard */
67#if KEYBOARD_PROBE
68    if (probe_keyboard())
69#endif
70    {
71
72	cp->c_flags |= C_PRESENTIN;
73    }
74
75    /* XXX for now, always assume we can do BIOS screen output */
76    cp->c_flags |= C_PRESENTOUT;
77}
78
79static int
80vidc_init(int arg)
81{
82    int		i;
83
84    if (vidc_started && arg == 0)
85	return;
86    vidc_started = 1;
87    for(i = 0; i < 10 && vidc_ischar(); i++)
88	  (void)vidc_getchar();
89    return(0);	/* XXX reinit? */
90}
91
92static void
93vidc_putchar(int c)
94{
95    v86.ctl = 0;
96    v86.addr = 0x10;
97    v86.eax = 0xe00 | c;
98    v86.ebx = 0x7;
99    v86int();
100}
101
102static int
103vidc_getchar(void)
104{
105    if (vidc_ischar()) {
106	v86.ctl = 0;
107	v86.addr = 0x16;
108	v86.eax = 0x0;
109	v86int();
110	return(v86.eax & 0xff);
111    } else {
112	return(-1);
113    }
114}
115
116static int
117vidc_ischar(void)
118{
119    v86.ctl = V86_FLAGS;
120    v86.addr = 0x16;
121    v86.eax = 0x100;
122    v86int();
123    if (!(v86.efl & PSL_Z))
124	return(v86.eax & 0xff);
125    return(0);
126}
127
128#if KEYBOARD_PROBE
129
130#define PROBE_MAXRETRY	5
131#define PROBE_MAXWAIT	400
132#define IO_DUMMY	0x84
133#define IO_KBD		0x060		/* 8042 Keyboard */
134
135/* selected defines from kbdio.h */
136#define KBD_STATUS_PORT 	4	/* status port, read */
137#define KBD_DATA_PORT		0	/* data port, read/write
138					 * also used as keyboard command
139					 * and mouse command port
140					 */
141#define KBDC_ECHO		0x00ee
142#define KBDS_ANY_BUFFER_FULL	0x0001
143#define KBDS_INPUT_BUFFER_FULL	0x0002
144#define KBD_ECHO		0x00ee
145
146/* 7 microsec delay necessary for some keyboard controllers */
147static void
148delay7(void)
149{
150    /*
151     * I know this is broken, but no timer is avaiable yet at this stage...
152     * See also comments in `delay1ms()'.
153     */
154    inb(IO_DUMMY); inb(IO_DUMMY);
155    inb(IO_DUMMY); inb(IO_DUMMY);
156    inb(IO_DUMMY); inb(IO_DUMMY);
157}
158
159/*
160 * This routine uses an inb to an unused port, the time to execute that
161 * inb is approximately 1.25uS.  This value is pretty constant across
162 * all CPU's and all buses, with the exception of some PCI implentations
163 * that do not forward this I/O adress to the ISA bus as they know it
164 * is not a valid ISA bus address, those machines execute this inb in
165 * 60 nS :-(.
166 *
167 */
168static void
169delay1ms(void)
170{
171    int i = 800;
172    while (--i >= 0)
173	(void)inb(0x84);
174}
175
176/*
177 * We use the presence/absence of a keyboard to determine whether the internal
178 * console can be used for input.
179 *
180 * Perform a simple test on the keyboard; issue the ECHO command and see
181 * if the right answer is returned. We don't do anything as drastic as
182 * full keyboard reset; it will be too troublesome and take too much time.
183 */
184static int
185probe_keyboard(void)
186{
187    int retry = PROBE_MAXRETRY;
188    int wait;
189    int i;
190
191    while (--retry >= 0) {
192	/* flush any noise */
193	while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
194	    delay7();
195	    inb(IO_KBD + KBD_DATA_PORT);
196	    delay1ms();
197	}
198
199	/* wait until the controller can accept a command */
200	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
201	    if (((i = inb(IO_KBD + KBD_STATUS_PORT))
202                & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
203		break;
204	    if (i & KBDS_ANY_BUFFER_FULL) {
205		delay7();
206	        inb(IO_KBD + KBD_DATA_PORT);
207	    }
208	    delay1ms();
209	}
210	if (wait <= 0)
211	    continue;
212
213	/* send the ECHO command */
214	outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
215
216	/* wait for a response */
217	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
218	     if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
219		 break;
220	     delay1ms();
221	}
222	if (wait <= 0)
223	    continue;
224
225	delay7();
226	i = inb(IO_KBD + KBD_DATA_PORT);
227#ifdef PROBE_KBD_BEBUG
228        printf("probe_keyboard: got 0x%x.\n", i);
229#endif
230	if (i == KBD_ECHO) {
231	    /* got the right answer */
232	    return (0);
233	}
234    }
235
236    return (1);
237}
238#endif /* KEYBOARD_PROBE */
239