vidconsole.c revision 38465
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$
30 */
31
32#include <stand.h>
33
34#include <machine/cpufunc.h>
35
36#include "bootstrap.h"
37
38/* in vidconsole.S */
39extern void	vidputc(int c);
40extern int	kbdgetc(void);
41extern int	kbdiskey(void);
42
43static int	probe_keyboard(void);
44static void	vidc_probe(struct console *cp);
45static int	vidc_init(int arg);
46static int	vidc_in(void);
47
48struct console vidconsole = {
49    "vidconsole",
50    "internal video/keyboard",
51    0,
52    vidc_probe,
53    vidc_init,
54    vidputc,
55    vidc_in,
56    kbdiskey
57};
58
59static void
60vidc_probe(struct console *cp)
61{
62
63    /* look for a keyboard */
64#if 0
65    if (probe_keyboard()) {
66#else
67    if (1) {
68#endif
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 int
83vidc_in(void)
84{
85    if (kbdiskey()) {
86	return(kbdgetc());
87    } else {
88	return(-1);
89    }
90}
91
92#define PROBE_MAXRETRY	5
93#define PROBE_MAXWAIT	400
94#define IO_DUMMY	0x84
95#define IO_KBD		0x060		/* 8042 Keyboard */
96
97/* selected defines from kbdio.h */
98#define KBD_STATUS_PORT 	4	/* status port, read */
99#define KBD_DATA_PORT		0	/* data port, read/write
100					 * also used as keyboard command
101					 * and mouse command port
102					 */
103#define KBDC_ECHO		0x00ee
104#define KBDS_ANY_BUFFER_FULL	0x0001
105#define KBDS_INPUT_BUFFER_FULL	0x0002
106#define KBD_ECHO		0x00ee
107
108/* 7 microsec delay necessary for some keyboard controllers */
109static void
110delay7(void)
111{
112    /*
113     * I know this is broken, but no timer is avaiable yet at this stage...
114     * See also comments in `delay1ms()'.
115     */
116    inb(IO_DUMMY); inb(IO_DUMMY);
117    inb(IO_DUMMY); inb(IO_DUMMY);
118    inb(IO_DUMMY); inb(IO_DUMMY);
119}
120
121/*
122 * This routine uses an inb to an unused port, the time to execute that
123 * inb is approximately 1.25uS.  This value is pretty constant across
124 * all CPU's and all buses, with the exception of some PCI implentations
125 * that do not forward this I/O adress to the ISA bus as they know it
126 * is not a valid ISA bus address, those machines execute this inb in
127 * 60 nS :-(.
128 *
129 */
130static void
131delay1ms(void)
132{
133    int i = 800;
134    while (--i >= 0)
135	(void)inb(0x84);
136}
137
138/*
139 * We use the presence/absence of a keyboard to determine whether the internal
140 * console can be used for input.
141 *
142 * Perform a simple test on the keyboard; issue the ECHO command and see
143 * if the right answer is returned. We don't do anything as drastic as
144 * full keyboard reset; it will be too troublesome and take too much time.
145 */
146static int
147probe_keyboard(void)
148{
149    int retry = PROBE_MAXRETRY;
150    int wait;
151    int i;
152
153    while (--retry >= 0) {
154	/* flush any noise */
155	while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
156	    delay7();
157	    inb(IO_KBD + KBD_DATA_PORT);
158	    delay1ms();
159	}
160
161	/* wait until the controller can accept a command */
162	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
163	    if (((i = inb(IO_KBD + KBD_STATUS_PORT))
164                & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
165		break;
166	    if (i & KBDS_ANY_BUFFER_FULL) {
167		delay7();
168	        inb(IO_KBD + KBD_DATA_PORT);
169	    }
170	    delay1ms();
171	}
172	if (wait <= 0)
173	    continue;
174
175	/* send the ECHO command */
176	outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
177
178	/* wait for a response */
179	for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
180	     if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
181		 break;
182	     delay1ms();
183	}
184	if (wait <= 0)
185	    continue;
186
187	delay7();
188	i = inb(IO_KBD + KBD_DATA_PORT);
189#ifdef PROBE_KBD_BEBUG
190        printf("probe_keyboard: got 0x%x.\n", i);
191#endif
192	if (i == KBD_ECHO) {
193	    /* got the right answer */
194	    return (0);
195	}
196    }
197
198    return (1);
199}
200