143105Sdfr/*-
243105Sdfr * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
343105Sdfr * All rights reserved.
443105Sdfr *
543105Sdfr * Redistribution and use in source and binary forms, with or without
643105Sdfr * modification, are permitted provided that the following conditions
743105Sdfr * are met:
843105Sdfr * 1. Redistributions of source code must retain the above copyright
943105Sdfr *    notice, this list of conditions and the following disclaimer as
1043105Sdfr *    the first lines of this file unmodified.
1143105Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1243105Sdfr *    notice, this list of conditions and the following disclaimer in the
1343105Sdfr *    documentation and/or other materials provided with the distribution.
1443105Sdfr *
1543105Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1643105Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1743105Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1843105Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1943105Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2043105Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2143105Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2243105Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2343105Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2443105Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543105Sdfr */
2643105Sdfr
27116181Sobrien#include <sys/cdefs.h>
28116181Sobrien__FBSDID("$FreeBSD$");
29116181Sobrien
3043105Sdfr#include "opt_syscons.h"
3143105Sdfr
3243105Sdfr#include <sys/param.h>
3343105Sdfr#include <sys/systm.h>
3443105Sdfr#include <sys/kernel.h>
3543105Sdfr#include <sys/module.h>
3643105Sdfr#include <sys/bus.h>
3749558Sphk#include <sys/cons.h>
3866834Sphk#include <sys/kbio.h>
3966834Sphk#include <sys/consio.h>
40109279Smdodd#include <sys/sysctl.h>
4143105Sdfr
42135690Speter#if defined(__i386__) || defined(__amd64__)
4343105Sdfr
4448104Syokota#include <machine/clock.h>
4548104Syokota#include <machine/md_var.h>
4648104Syokota#include <machine/pc/bios.h>
4748104Syokota
4848104Syokota#include <vm/vm.h>
4948104Syokota#include <vm/pmap.h>
50130312Sjhb#include <vm/vm_param.h>
5148104Syokota
5248104Syokota#define BIOS_CLKED	(1 << 6)
5348104Syokota#define BIOS_NLKED	(1 << 5)
5448104Syokota#define BIOS_SLKED	(1 << 4)
5548104Syokota#define BIOS_ALKED	0
5648104Syokota
57135690Speter#endif
5848104Syokota
5943105Sdfr#include <dev/syscons/syscons.h>
6043105Sdfr
6143105Sdfr#include <isa/isavar.h>
6243105Sdfr
63156243Srink#include "opt_xbox.h"
64156243Srink
65156243Srink#ifdef XBOX
66156243Srink#include <machine/xbox.h>
67156243Srink#endif
68156243Srink
6948104Syokotastatic devclass_t	sc_devclass;
7043105Sdfr
71208412Sjkimstatic sc_softc_t	main_softc;
7243105Sdfr
7362225Speterstatic void
74208412Sjkimscidentify(driver_t *driver, device_t parent)
7562225Speter{
76208412Sjkim
7762225Speter	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "sc", 0);
7862225Speter}
7943105Sdfr
8043105Sdfrstatic int
8143105Sdfrscprobe(device_t dev)
8243105Sdfr{
83208412Sjkim
8447618Sdfr	/* No pnp support */
8547618Sdfr	if (isa_get_vendorid(dev))
8647618Sdfr		return (ENXIO);
8747618Sdfr
8843105Sdfr	device_set_desc(dev, "System console");
89208412Sjkim	return (sc_probe_unit(device_get_unit(dev), device_get_flags(dev)));
9043105Sdfr}
9143105Sdfr
9243105Sdfrstatic int
9343105Sdfrscattach(device_t dev)
9443105Sdfr{
95189421Sjhb
96189421Sjhb	return (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) |
97189421Sjhb	    SC_AUTODETECT_KBD));
9843105Sdfr}
9943105Sdfr
10048104Syokotaint
10148104Syokotasc_max_unit(void)
10248104Syokota{
103208412Sjkim
104208412Sjkim	return (devclass_get_maxunit(sc_devclass));
10548104Syokota}
10648104Syokota
10748104Syokotasc_softc_t
10848104Syokota*sc_get_softc(int unit, int flags)
10948104Syokota{
11048104Syokota	sc_softc_t *sc;
11148104Syokota
11256836Speter	if (unit < 0)
113208412Sjkim		return (NULL);
114208412Sjkim	if ((flags & SC_KERNEL_CONSOLE) != 0) {
11548104Syokota		/* FIXME: clear if it is wired to another unit! */
11655849Syokota		sc = &main_softc;
11748104Syokota	} else {
118208412Sjkim	        sc = device_get_softc(devclass_get_device(sc_devclass, unit));
11956836Speter		if (sc == NULL)
120208412Sjkim			return (NULL);
12148104Syokota	}
12255849Syokota	sc->unit = unit;
123208412Sjkim	if ((sc->flags & SC_INIT_DONE) == 0) {
12455849Syokota		sc->keyboard = -1;
12555849Syokota		sc->adapter = -1;
12658872Syokota		sc->cursor_char = SC_CURSOR_CHAR;
12755849Syokota		sc->mouse_char = SC_MOUSE_CHAR;
12855849Syokota	}
129208412Sjkim	return (sc);
13048104Syokota}
13148104Syokota
13248104Syokotasc_softc_t
13348104Syokota*sc_find_softc(struct video_adapter *adp, struct keyboard *kbd)
13448104Syokota{
13548104Syokota	sc_softc_t *sc;
136208412Sjkim	int i;
13748104Syokota	int units;
13848104Syokota
13948104Syokota	sc = &main_softc;
140208412Sjkim	if ((adp == NULL || adp == sc->adp) &&
141208412Sjkim	    (kbd == NULL || kbd == sc->kbd))
142208412Sjkim		return (sc);
14348104Syokota	units = devclass_get_maxunit(sc_devclass);
14448104Syokota	for (i = 0; i < units; ++i) {
145208412Sjkim	        sc = device_get_softc(devclass_get_device(sc_devclass, i));
14648104Syokota		if (sc == NULL)
14748104Syokota			continue;
148208412Sjkim		if ((adp == NULL || adp == sc->adp) &&
149208412Sjkim		    (kbd == NULL || kbd == sc->kbd))
150208412Sjkim			return (sc);
15148104Syokota	}
152208412Sjkim	return (NULL);
15348104Syokota}
15448104Syokota
15548104Syokotaint
15648104Syokotasc_get_cons_priority(int *unit, int *flags)
15748104Syokota{
15878262Speter	const char *at;
159208413Sjkim	int f, u;
16048104Syokota
161156243Srink#ifdef XBOX
162156243Srink	/*
163156243Srink	 * The XBox Loader does not support hints, which makes our initial
164156243Srink	 * console probe fail. Therefore, if an XBox is found, we hardcode the
165156243Srink	 * existence of the console, as it is always there anyway.
166156243Srink	 */
167156243Srink	if (arch_i386_is_xbox) {
168156243Srink		*unit = 0;
169156243Srink		*flags = SC_KERNEL_CONSOLE;
170208412Sjkim		return (CN_INTERNAL);
171156243Srink	}
172156243Srink#endif
173156243Srink
17448104Syokota	*unit = -1;
17561704Speter	for (u = 0; u < 16; u++) {
176117167Sjhb		if (resource_disabled(SC_DRIVER_NAME, u))
17748104Syokota			continue;
17861704Speter		if (resource_string_value(SC_DRIVER_NAME, u, "at", &at) != 0)
17961704Speter			continue;
18048104Syokota		if (resource_int_value(SC_DRIVER_NAME, u, "flags", &f) != 0)
18148104Syokota			f = 0;
18248104Syokota		if (f & SC_KERNEL_CONSOLE) {
18348104Syokota			/* the user designates this unit to be the console */
18448104Syokota			*unit = u;
18548104Syokota			*flags = f;
18648104Syokota			break;
18748104Syokota		}
18848104Syokota		if (*unit < 0) {
18948104Syokota			/* ...otherwise remember the first found unit */
19048104Syokota			*unit = u;
19148104Syokota			*flags = f;
19248104Syokota		}
19348104Syokota	}
194189421Sjhb	if (*unit < 0) {
195189421Sjhb		*unit = 0;
196189421Sjhb		*flags = 0;
197189421Sjhb	}
19848104Syokota#if 0
199208412Sjkim	return ((*flags & SC_KERNEL_CONSOLE) != 0 ? CN_INTERNAL : CN_NORMAL);
20048104Syokota#endif
201208412Sjkim	return (CN_INTERNAL);
20248104Syokota}
20348104Syokota
20448104Syokotavoid
20548104Syokotasc_get_bios_values(bios_values_t *values)
20648104Syokota{
207135690Speter#if defined(__i386__) || defined(__amd64__)
208208412Sjkim	uint8_t shift;
20948104Syokota
210208412Sjkim	values->cursor_start = *(uint8_t *)BIOS_PADDRTOVADDR(0x461);
211208412Sjkim	values->cursor_end = *(uint8_t *)BIOS_PADDRTOVADDR(0x460);
212208412Sjkim	shift = *(uint8_t *)BIOS_PADDRTOVADDR(0x417);
213208412Sjkim	values->shift_state = ((shift & BIOS_CLKED) != 0 ? CLKED : 0) |
214208412Sjkim	    ((shift & BIOS_NLKED) != 0 ? NLKED : 0) |
215208412Sjkim	    ((shift & BIOS_SLKED) != 0 ? SLKED : 0) |
216208412Sjkim	    ((shift & BIOS_ALKED) != 0 ? ALKED : 0);
217135690Speter#else
21848104Syokota	values->cursor_start = 0;
21948104Syokota	values->cursor_end = 32;
22048104Syokota	values->shift_state = 0;
221135690Speter#endif
22248104Syokota	values->bell_pitch = BELL_PITCH;
22348104Syokota}
22448104Syokota
22548104Syokotaint
22648104Syokotasc_tone(int herz)
22748104Syokota{
228208412Sjkim
229177650Sphk#if defined(HAS_TIMER_SPKR)
23048104Syokota	if (herz) {
231146211Snyan		if (timer_spkr_acquire())
232208412Sjkim			return (EBUSY);
233177642Sphk		timer_spkr_setfreq(herz);
234208412Sjkim	} else
235146211Snyan		timer_spkr_release();
236135690Speter#endif
23748104Syokota
238208412Sjkim	return (0);
23948104Syokota}
24048104Syokota
24162225Speterstatic device_method_t sc_methods[] = {
24262225Speter	DEVMETHOD(device_identify,	scidentify),
24362225Speter	DEVMETHOD(device_probe,         scprobe),
24462225Speter	DEVMETHOD(device_attach,        scattach),
24562225Speter	{ 0, 0 }
24662225Speter};
24762225Speter
24862225Speterstatic driver_t sc_driver = {
24962225Speter	SC_DRIVER_NAME,
25062225Speter	sc_methods,
25162225Speter	sizeof(sc_softc_t),
25262225Speter};
25362225Speter
25443105SdfrDRIVER_MODULE(sc, isa, sc_driver, sc_devclass, 0, 0);
255