vidconsole.c revision 40705
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.6 1998/10/11 10:07:52 peter 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    return(!(v86.efl & PSL_Z));
124}
125
126#if KEYBOARD_PROBE
127
128#define PROBE_MAXRETRY	5
129#define PROBE_MAXWAIT	400
130#define IO_DUMMY	0x84
131#define IO_KBD		0x060		/* 8042 Keyboard */
132
133/* selected defines from kbdio.h */
134#define KBD_STATUS_PORT 	4	/* status port, read */
135#define KBD_DATA_PORT		0	/* data port, read/write
136					 * also used as keyboard command
137					 * and mouse command port
138					 */
139#define KBDC_ECHO		0x00ee
140#define KBDS_ANY_BUFFER_FULL	0x0001
141#define KBDS_INPUT_BUFFER_FULL	0x0002
142#define KBD_ECHO		0x00ee
143
144/* 7 microsec delay necessary for some keyboard controllers */
145static void
146delay7(void)
147{
148    /*
149     * I know this is broken, but no timer is avaiable yet at this stage...
150     * See also comments in `delay1ms()'.
151     */
152    inb(IO_DUMMY); inb(IO_DUMMY);
153    inb(IO_DUMMY); inb(IO_DUMMY);
154    inb(IO_DUMMY); inb(IO_DUMMY);
155}
156
157/*
158 * This routine uses an inb to an unused port, the time to execute that
159 * inb is approximately 1.25uS.  This value is pretty constant across
160 * all CPU's and all buses, with the exception of some PCI implentations
161 * that do not forward this I/O adress to the ISA bus as they know it
162 * is not a valid ISA bus address, those machines execute this inb in
163 * 60 nS :-(.
164 *
165 */
166static void
167delay1ms(void)
168{
169    int i = 800;
170    while (--i >= 0)
171	(void)inb(0x84);
172}
173
174/*
175 * We use the presence/absence of a keyboard to determine whether the internal
176 * console can be used for input.
177 *
178 * Perform a simple test on the keyboard; issue the ECHO command and see
179 * if the right answer is returned. We don't do anything as drastic as
180 * full keyboard reset; it will be too troublesome and take too much time.
181 */
182static int
183probe_keyboard(void)
184{
185    int retry = PROBE_MAXRETRY;
186    int wait;
187    int i;
188
189    while (--retry >= 0) {
190	/* flush any noise */
191	while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
192	    delay7();
193	    inb(IO_KBD + KBD_DATA_PORT);
194	    delay1ms();
195	}
196
197	/* wait until the controller can accept a command */
198	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
199	    if (((i = inb(IO_KBD + KBD_STATUS_PORT))
200                & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
201		break;
202	    if (i & KBDS_ANY_BUFFER_FULL) {
203		delay7();
204	        inb(IO_KBD + KBD_DATA_PORT);
205	    }
206	    delay1ms();
207	}
208	if (wait <= 0)
209	    continue;
210
211	/* send the ECHO command */
212	outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
213
214	/* wait for a response */
215	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
216	     if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
217		 break;
218	     delay1ms();
219	}
220	if (wait <= 0)
221	    continue;
222
223	delay7();
224	i = inb(IO_KBD + KBD_DATA_PORT);
225#ifdef PROBE_KBD_BEBUG
226        printf("probe_keyboard: got 0x%x.\n", i);
227#endif
228	if (i == KBD_ECHO) {
229	    /* got the right answer */
230	    return (0);
231	}
232    }
233
234    return (1);
235}
236#endif /* KEYBOARD_PROBE */
237