1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer as
12 *    the first lines of this file unmodified.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30#include "opt_syscons.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/module.h>
36#include <sys/bus.h>
37#include <sys/cons.h>
38#include <sys/kbio.h>
39#include <sys/consio.h>
40#include <sys/sysctl.h>
41
42#if defined(__i386__) || defined(__amd64__)
43
44#include <machine/clock.h>
45#include <machine/md_var.h>
46#include <machine/pc/bios.h>
47
48#include <vm/vm.h>
49#include <vm/pmap.h>
50#include <vm/vm_param.h>
51
52#define BIOS_CLKED	(1 << 6)
53#define BIOS_NLKED	(1 << 5)
54#define BIOS_SLKED	(1 << 4)
55#define BIOS_ALKED	0
56
57#endif
58
59#include <dev/syscons/syscons.h>
60
61#include <isa/isavar.h>
62
63static sc_softc_t	main_softc;
64
65static void
66scidentify(driver_t *driver, device_t parent)
67{
68
69	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "sc", 0);
70}
71
72static int
73scprobe(device_t dev)
74{
75
76	/* No pnp support */
77	if (isa_get_vendorid(dev))
78		return (ENXIO);
79
80	device_set_desc(dev, "System console");
81	return (sc_probe_unit(device_get_unit(dev), device_get_flags(dev)));
82}
83
84static int
85scattach(device_t dev)
86{
87
88	return (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) |
89	    SC_AUTODETECT_KBD));
90}
91
92int
93sc_max_unit(void)
94{
95
96	return (devclass_get_maxunit(devclass_find("sc")));
97}
98
99sc_softc_t
100*sc_get_softc(int unit, int flags)
101{
102	sc_softc_t *sc;
103
104	if (unit < 0)
105		return (NULL);
106	if ((flags & SC_KERNEL_CONSOLE) != 0) {
107		/* FIXME: clear if it is wired to another unit! */
108		sc = &main_softc;
109	} else {
110	        sc = device_get_softc(devclass_get_device(devclass_find("sc"),
111		    unit));
112		if (sc == NULL)
113			return (NULL);
114	}
115	sc->unit = unit;
116	if ((sc->flags & SC_INIT_DONE) == 0) {
117		sc->adapter = -1;
118		sc->cursor_char = SC_CURSOR_CHAR;
119		sc->mouse_char = SC_MOUSE_CHAR;
120	}
121	return (sc);
122}
123
124sc_softc_t
125*sc_find_softc(struct video_adapter *adp, struct keyboard *kbd)
126{
127	devclass_t dc;
128	sc_softc_t *sc;
129	int i;
130	int units;
131
132	sc = &main_softc;
133	if ((adp == NULL || adp == sc->adp) &&
134	    (kbd == NULL || kbd == sc->kbd))
135		return (sc);
136	dc = devclass_find("sc");
137	units = devclass_get_maxunit(dc);
138	for (i = 0; i < units; ++i) {
139	        sc = device_get_softc(devclass_get_device(dc, i));
140		if (sc == NULL)
141			continue;
142		if ((adp == NULL || adp == sc->adp) &&
143		    (kbd == NULL || kbd == sc->kbd))
144			return (sc);
145	}
146	return (NULL);
147}
148
149int
150sc_get_cons_priority(int *unit, int *flags)
151{
152	const char *at;
153	int f, u;
154
155	*unit = -1;
156	for (u = 0; u < 16; u++) {
157		if (resource_disabled(SC_DRIVER_NAME, u))
158			continue;
159		if (resource_string_value(SC_DRIVER_NAME, u, "at", &at) != 0)
160			continue;
161		if (resource_int_value(SC_DRIVER_NAME, u, "flags", &f) != 0)
162			f = 0;
163		if (f & SC_KERNEL_CONSOLE) {
164			/* the user designates this unit to be the console */
165			*unit = u;
166			*flags = f;
167			break;
168		}
169		if (*unit < 0) {
170			/* ...otherwise remember the first found unit */
171			*unit = u;
172			*flags = f;
173		}
174	}
175	if (*unit < 0) {
176		*unit = 0;
177		*flags = 0;
178	}
179#if 0
180	return ((*flags & SC_KERNEL_CONSOLE) != 0 ? CN_INTERNAL : CN_NORMAL);
181#endif
182	return (CN_INTERNAL);
183}
184
185void
186sc_get_bios_values(bios_values_t *values)
187{
188#if defined(__i386__) || defined(__amd64__)
189	uint8_t shift;
190
191	shift = *(uint8_t *)BIOS_PADDRTOVADDR(0x417);
192	values->shift_state = ((shift & BIOS_CLKED) != 0 ? CLKED : 0) |
193	    ((shift & BIOS_NLKED) != 0 ? NLKED : 0) |
194	    ((shift & BIOS_SLKED) != 0 ? SLKED : 0) |
195	    ((shift & BIOS_ALKED) != 0 ? ALKED : 0);
196#endif
197	values->bell_pitch = BELL_PITCH;
198}
199
200int
201sc_tone(int herz)
202{
203
204#if defined(HAS_TIMER_SPKR)
205	if (herz) {
206		if (timer_spkr_acquire())
207			return (EBUSY);
208		timer_spkr_setfreq(herz);
209	} else
210		timer_spkr_release();
211#endif
212
213	return (0);
214}
215
216static device_method_t sc_methods[] = {
217	DEVMETHOD(device_identify,	scidentify),
218	DEVMETHOD(device_probe,         scprobe),
219	DEVMETHOD(device_attach,        scattach),
220	{ 0, 0 }
221};
222
223static driver_t sc_driver = {
224	SC_DRIVER_NAME,
225	sc_methods,
226	sizeof(sc_softc_t),
227};
228
229DRIVER_MODULE(sc, isa, sc_driver, 0, 0);
230