1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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__FBSDID("$FreeBSD$");
31
32#include "opt_syscons.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/module.h>
38#include <sys/bus.h>
39#include <sys/cons.h>
40#include <sys/kbio.h>
41#include <sys/consio.h>
42#include <sys/sysctl.h>
43
44#if defined(__i386__) || defined(__amd64__)
45
46#include <machine/clock.h>
47#include <machine/md_var.h>
48#include <machine/pc/bios.h>
49
50#include <vm/vm.h>
51#include <vm/pmap.h>
52#include <vm/vm_param.h>
53
54#define BIOS_CLKED	(1 << 6)
55#define BIOS_NLKED	(1 << 5)
56#define BIOS_SLKED	(1 << 4)
57#define BIOS_ALKED	0
58
59#endif
60
61#include <dev/syscons/syscons.h>
62
63#include <isa/isavar.h>
64
65static devclass_t	sc_devclass;
66
67static sc_softc_t	main_softc;
68
69static void
70scidentify(driver_t *driver, device_t parent)
71{
72
73	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "sc", 0);
74}
75
76static int
77scprobe(device_t dev)
78{
79
80	/* No pnp support */
81	if (isa_get_vendorid(dev))
82		return (ENXIO);
83
84	device_set_desc(dev, "System console");
85	return (sc_probe_unit(device_get_unit(dev), device_get_flags(dev)));
86}
87
88static int
89scattach(device_t dev)
90{
91
92	return (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) |
93	    SC_AUTODETECT_KBD));
94}
95
96int
97sc_max_unit(void)
98{
99
100	return (devclass_get_maxunit(sc_devclass));
101}
102
103sc_softc_t
104*sc_get_softc(int unit, int flags)
105{
106	sc_softc_t *sc;
107
108	if (unit < 0)
109		return (NULL);
110	if ((flags & SC_KERNEL_CONSOLE) != 0) {
111		/* FIXME: clear if it is wired to another unit! */
112		sc = &main_softc;
113	} else {
114	        sc = device_get_softc(devclass_get_device(sc_devclass, unit));
115		if (sc == NULL)
116			return (NULL);
117	}
118	sc->unit = unit;
119	if ((sc->flags & SC_INIT_DONE) == 0) {
120		sc->adapter = -1;
121		sc->cursor_char = SC_CURSOR_CHAR;
122		sc->mouse_char = SC_MOUSE_CHAR;
123	}
124	return (sc);
125}
126
127sc_softc_t
128*sc_find_softc(struct video_adapter *adp, struct keyboard *kbd)
129{
130	sc_softc_t *sc;
131	int i;
132	int units;
133
134	sc = &main_softc;
135	if ((adp == NULL || adp == sc->adp) &&
136	    (kbd == NULL || kbd == sc->kbd))
137		return (sc);
138	units = devclass_get_maxunit(sc_devclass);
139	for (i = 0; i < units; ++i) {
140	        sc = device_get_softc(devclass_get_device(sc_devclass, i));
141		if (sc == NULL)
142			continue;
143		if ((adp == NULL || adp == sc->adp) &&
144		    (kbd == NULL || kbd == sc->kbd))
145			return (sc);
146	}
147	return (NULL);
148}
149
150int
151sc_get_cons_priority(int *unit, int *flags)
152{
153	const char *at;
154	int f, u;
155
156	*unit = -1;
157	for (u = 0; u < 16; u++) {
158		if (resource_disabled(SC_DRIVER_NAME, u))
159			continue;
160		if (resource_string_value(SC_DRIVER_NAME, u, "at", &at) != 0)
161			continue;
162		if (resource_int_value(SC_DRIVER_NAME, u, "flags", &f) != 0)
163			f = 0;
164		if (f & SC_KERNEL_CONSOLE) {
165			/* the user designates this unit to be the console */
166			*unit = u;
167			*flags = f;
168			break;
169		}
170		if (*unit < 0) {
171			/* ...otherwise remember the first found unit */
172			*unit = u;
173			*flags = f;
174		}
175	}
176	if (*unit < 0) {
177		*unit = 0;
178		*flags = 0;
179	}
180#if 0
181	return ((*flags & SC_KERNEL_CONSOLE) != 0 ? CN_INTERNAL : CN_NORMAL);
182#endif
183	return (CN_INTERNAL);
184}
185
186void
187sc_get_bios_values(bios_values_t *values)
188{
189#if defined(__i386__) || defined(__amd64__)
190	uint8_t shift;
191
192	shift = *(uint8_t *)BIOS_PADDRTOVADDR(0x417);
193	values->shift_state = ((shift & BIOS_CLKED) != 0 ? CLKED : 0) |
194	    ((shift & BIOS_NLKED) != 0 ? NLKED : 0) |
195	    ((shift & BIOS_SLKED) != 0 ? SLKED : 0) |
196	    ((shift & BIOS_ALKED) != 0 ? ALKED : 0);
197#endif
198	values->bell_pitch = BELL_PITCH;
199}
200
201int
202sc_tone(int herz)
203{
204
205#if defined(HAS_TIMER_SPKR)
206	if (herz) {
207		if (timer_spkr_acquire())
208			return (EBUSY);
209		timer_spkr_setfreq(herz);
210	} else
211		timer_spkr_release();
212#endif
213
214	return (0);
215}
216
217static device_method_t sc_methods[] = {
218	DEVMETHOD(device_identify,	scidentify),
219	DEVMETHOD(device_probe,         scprobe),
220	DEVMETHOD(device_attach,        scattach),
221	{ 0, 0 }
222};
223
224static driver_t sc_driver = {
225	SC_DRIVER_NAME,
226	sc_methods,
227	sizeof(sc_softc_t),
228};
229
230DRIVER_MODULE(sc, isa, sc_driver, sc_devclass, 0, 0);
231