vidconsole.c revision 38466
198752Sjmallett/*
298752Sjmallett * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
398755Sjmallett * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
498755Sjmallett * All rights reserved.
598755Sjmallett *
698755Sjmallett * Redistribution and use in source and binary forms, with or without
798755Sjmallett * modification, are permitted provided that the following conditions
898752Sjmallett * are met:
998752Sjmallett * 1. Redistributions of source code must retain the above copyright
1098752Sjmallett *    notice, this list of conditions and the following disclaimer.
1198752Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
1298752Sjmallett *    notice, this list of conditions and the following disclaimer in the
1398752Sjmallett *    documentation and/or other materials provided with the distribution.
1498752Sjmallett *
1598752Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1698752Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1798812Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1898812Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1998812Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2098812Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21137587Snik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2298812Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2398812Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24137587Snik * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2598812Sjmallett * SUCH DAMAGE.
2698812Sjmallett *
2798755Sjmallett * 	From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
2898755Sjmallett *
2998755Sjmallett *	$Id$
3098755Sjmallett */
3198752Sjmallett
32263227Sjmmv#include <stand.h>
3398812Sjmallett
3498752Sjmallett#include <machine/cpufunc.h>
3598758Sjmallett
3698758Sjmallett#include "bootstrap.h"
3798758Sjmallett
3898812Sjmallett/* in vidconsole.S */
3998758Sjmallettextern void	vidputc(int c);
4098758Sjmallettextern int	kbdgetc(void);
4198758Sjmallettextern int	kbdiskey(void);
4298758Sjmallett
4398758Sjmallettstatic int	probe_keyboard(void);
44263227Sjmmvstatic void	vidc_probe(struct console *cp);
4598812Sjmallettstatic int	vidc_init(int arg);
4698758Sjmallettstatic int	vidc_in(void);
4798758Sjmallett
4898758Sjmallettstruct console vidconsole = {
4998758Sjmallett    "vidconsole",
5098758Sjmallett    "internal video/keyboard",
51137587Snik    0,
5298758Sjmallett    vidc_probe,
5398758Sjmallett    vidc_init,
5498755Sjmallett    vidputc,
5598755Sjmallett    vidc_in,
5698755Sjmallett    kbdiskey
5798755Sjmallett};
5898752Sjmallett
5998752Sjmallettstatic 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