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