1 /*-
2  * (MPSAFE)
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  * $FreeBSD: src/sys/isa/atkbdc_isa.c,v 1.14.2.1 2000/03/31 12:52:05 yokota Exp $
29  */
30 
31 #include "opt_kbd.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/bus.h>
37 #include <sys/malloc.h>
38 #include <sys/rman.h>
39 #include <sys/thread.h>
40 
41 #include <dev/misc/kbd/atkbdcreg.h>
42 
43 #include <bus/isa/isareg.h>
44 #include <bus/isa/isavar.h>
45 
46 #if 0
47 #define lwkt_gettoken(x)
48 #define lwkt_reltoken(x)
49 #endif
50 
51 MALLOC_DEFINE(M_ATKBDDEV, "atkbddev", "AT Keyboard device");
52 
53 /* children */
54 typedef struct atkbdc_device {
55 	int flags;	/* configuration flags */
56 	int irq;	/* ISA IRQ mask */
57 	u_int32_t vendorid;
58 	u_int32_t serial;
59 	u_int32_t logicalid;
60 	u_int32_t compatid;
61 } atkbdc_device_t;
62 
63 /* kbdc */
64 devclass_t atkbdc_devclass;
65 
66 static int	atkbdc_probe(device_t dev);
67 static int	atkbdc_attach(device_t dev);
68 static int	atkbdc_print_child(device_t bus, device_t dev);
69 static int	atkbdc_read_ivar(device_t bus, device_t dev, int index,
70 				 u_long *val);
71 static int	atkbdc_write_ivar(device_t bus, device_t dev, int index,
72 				  u_long val);
73 
74 static device_method_t atkbdc_methods[] = {
75 	DEVMETHOD(device_probe,		atkbdc_probe),
76 	DEVMETHOD(device_attach,	atkbdc_attach),
77 	DEVMETHOD(device_suspend,	bus_generic_suspend),
78 	DEVMETHOD(device_resume,	bus_generic_resume),
79 
80 	DEVMETHOD(bus_print_child,	atkbdc_print_child),
81 	DEVMETHOD(bus_read_ivar,	atkbdc_read_ivar),
82 	DEVMETHOD(bus_write_ivar,	atkbdc_write_ivar),
83 	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
84 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
85 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
86 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
87 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
88 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
89 
90 	DEVMETHOD_END
91 };
92 
93 static driver_t atkbdc_driver = {
94 	ATKBDC_DRIVER_NAME,
95 	atkbdc_methods,
96 	sizeof(atkbdc_softc_t *),
97 };
98 
99 static struct isa_pnp_id atkbdc_ids[] = {
100 	{ 0x0303d041, "Keyboard controller (i8042)" },	/* PNP0303 */
101 	{ 0x0703d041, "Keyboard controller (i8042)" },	/* PNP0307 */
102 	{ 0x0b03d041, "Keyboard controller (i8042)" },	/* PNP030B */
103 	/* Japanese */
104 	{ 0x2003d041, "Keyboard controller (i8042)" },	/* PNP0320 */
105 	{ 0x2103d041, "Keyboard controller (i8042)" },	/* PNP0321 */
106 	{ 0x2203d041, "Keyboard controller (i8042)" },	/* PNP0322 */
107 	{ 0x2303d041, "Keyboard controller (i8042)" },	/* PNP0323 */
108 	{ 0x2403d041, "Keyboard controller (i8042)" },	/* PNP0324 */
109 	{ 0x2503d041, "Keyboard controller (i8042)" },	/* PNP0325 */
110 	{ 0x2603d041, "Keyboard controller (i8042)" },	/* PNP0326 */
111 	{ 0x2703d041, "Keyboard controller (i8042)" },	/* PNP0327 */
112 	/* Korean */
113 	{ 0x4003d041, "Keyboard controller (i8042)" },	/* PNP0340 */
114 	{ 0x4103d041, "Keyboard controller (i8042)" },	/* PNP0341 */
115 	{ 0x4203d041, "Keyboard controller (i8042)" },	/* PNP0342 */
116 	{ 0x4303d041, "Keyboard controller (i8042)" },	/* PNP0343 */
117 	{ 0x4403d041, "Keyboard controller (i8042)" },	/* PNP0344 */
118 	{ 0 }
119 };
120 
121 extern int acpi_fadt_8042_nolegacy;
122 
123 static int
124 atkbdc_probe(device_t dev)
125 {
126 	device_t parent = device_get_parent(dev);
127 	struct resource	*port0;
128 	struct resource	*port1;
129 	int		error;
130 	int		rid;
131 #if defined(__x86_64__)
132 	bus_space_tag_t	tag;
133 	bus_space_handle_t ioh1;
134 	volatile int	i;
135 #endif
136 
137 	if (strcmp(device_get_name(parent), "acpi") != 0 &&
138 	    acpi_fadt_8042_nolegacy != 0) {
139 		device_t acpidev = devclass_find_unit("acpi", 0);
140 
141 		/*
142 		 * If acpi didn't attach, we should go ahead with the legacy
143 		 * i8042 probing.
144 		 */
145 		if (acpidev != NULL && device_is_attached(acpidev)) {
146 			/* We should find i8042 via the ACPI namespace. */
147 			return ENXIO;
148 		}
149 	}
150 
151 	/* check PnP IDs */
152 	if (ISA_PNP_PROBE(parent, dev, atkbdc_ids) == ENXIO)
153 		return ENXIO;
154 
155 	device_set_desc(dev, "Keyboard controller (i8042)");
156 
157 	rid = 0;
158 	port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
159 				   RF_ACTIVE);
160 	if (port0 == NULL)
161 		return ENXIO;
162 	/* XXX */
163 	if (bus_get_resource_start(dev, SYS_RES_IOPORT, 1) <= 0) {
164 		bus_set_resource(dev, SYS_RES_IOPORT, 1,
165 		    rman_get_start(port0) + KBD_STATUS_PORT, 1, -1);
166 	}
167 	rid = 1;
168 	port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
169 				   RF_ACTIVE);
170 	if (port1 == NULL) {
171 		bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
172 		return ENXIO;
173 	}
174 
175 #if defined(__x86_64__)
176 	/*
177 	 * Check if we really have AT keyboard controller. Poll status
178 	 * register until we get "all clear" indication. If no such
179 	 * indication comes, it probably means that there is no AT
180 	 * keyboard controller present. Give up in such case. Check relies
181 	 * on the fact that reading from non-existing in/out port returns
182 	 * 0xff on i386. May or may not be true on other platforms.
183 	 */
184 	tag = rman_get_bustag(port0);
185 	ioh1 = rman_get_bushandle(port1);
186 	for (i = 65536; i != 0; --i) {
187 		if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0)
188 			break;
189 		DELAY(16);
190 	}
191 	if (i == 0) {
192 		bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
193 		bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
194 		return ENXIO;
195 	}
196 #endif
197 
198 	error = atkbdc_probe_unit(device_get_unit(dev), port0, port1);
199 
200 	bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
201 	bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
202 
203 	return error;
204 }
205 
206 static void
207 atkbdc_add_device(device_t dev, const char *name, int unit)
208 {
209 	atkbdc_device_t	*kdev;
210 	device_t	child;
211 	int		t;
212 
213 	if (resource_int_value(name, unit, "disabled", &t) == 0 && t != 0)
214 		return;
215 
216 	kdev = kmalloc(sizeof(struct atkbdc_device), M_ATKBDDEV,
217 			M_WAITOK | M_ZERO);
218 
219 	if (resource_int_value(name, unit, "irq", &t) == 0)
220 		kdev->irq = t;
221 	else
222 		kdev->irq = -1;
223 
224 	if (resource_int_value(name, unit, "flags", &t) == 0)
225 		kdev->flags = t;
226 	else
227 		kdev->flags = 0;
228 
229 	child = device_add_child(dev, name, unit);
230 	device_set_ivars(child, kdev);
231 }
232 
233 static int
234 atkbdc_attach(device_t dev)
235 {
236 	atkbdc_softc_t	*sc;
237 	int		unit;
238 	int		error;
239 	int		rid;
240 	int		i;
241 
242 	lwkt_gettoken(&kbd_token);
243 	unit = device_get_unit(dev);
244 	sc = *(atkbdc_softc_t **)device_get_softc(dev);
245 	if (sc == NULL) {
246 		/*
247 		 * We have to maintain two copies of the kbdc_softc struct,
248 		 * as the low-level console needs to have access to the
249 		 * keyboard controller before kbdc is probed and attached.
250 		 * kbdc_soft[] contains the default entry for that purpose.
251 		 * See atkbdc.c. XXX
252 		 */
253 		sc = atkbdc_get_softc(unit);
254 		if (sc == NULL) {
255 			lwkt_reltoken(&kbd_token);
256 			return ENOMEM;
257 		}
258 	}
259 
260 	rid = 0;
261 	sc->port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
262 				       RF_ACTIVE);
263 	if (sc->port0 == NULL) {
264 		lwkt_reltoken(&kbd_token);
265 		return ENXIO;
266 	}
267 	rid = 1;
268 	sc->port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
269 				       RF_ACTIVE);
270 	if (sc->port1 == NULL) {
271 		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
272 		lwkt_reltoken(&kbd_token);
273 		return ENXIO;
274 	}
275 
276 	error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1);
277 	if (error) {
278 		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
279 		bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1);
280 		lwkt_reltoken(&kbd_token);
281 		return error;
282 	}
283 	*(atkbdc_softc_t **)device_get_softc(dev) = sc;
284 
285 	/*
286 	 * Add all devices configured to be attached to atkbdc0.
287 	 */
288 	for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
289 	     i != -1;
290 	     i = resource_query_string(i, "at", device_get_nameunit(dev))) {
291 		atkbdc_add_device(dev, resource_query_name(i),
292 				  resource_query_unit(i));
293 	}
294 
295 	/*
296 	 * and atkbdc?
297 	 */
298 	for (i = resource_query_string(-1, "at", device_get_name(dev));
299 	     i != -1;
300 	     i = resource_query_string(i, "at", device_get_name(dev))) {
301 		atkbdc_add_device(dev, resource_query_name(i),
302 				  resource_query_unit(i));
303 	}
304 
305 	bus_generic_attach(dev);
306 
307 	lwkt_reltoken(&kbd_token);
308 	return 0;
309 }
310 
311 static int
312 atkbdc_print_child(device_t bus, device_t dev)
313 {
314 	atkbdc_device_t *kbdcdev;
315 	int retval = 0;
316 
317 	kbdcdev = (atkbdc_device_t *)device_get_ivars(dev);
318 
319 	retval += bus_print_child_header(bus, dev);
320 	if (kbdcdev->flags != 0)
321 		retval += kprintf(" flags 0x%x", kbdcdev->flags);
322 	if (kbdcdev->irq != -1)
323 		retval += kprintf(" irq %d", kbdcdev->irq);
324 	retval += bus_print_child_footer(bus, dev);
325 
326 	return (retval);
327 }
328 
329 static int
330 atkbdc_read_ivar(device_t bus, device_t dev, int index, u_long *val)
331 {
332 	atkbdc_device_t *ivar;
333 
334 	lwkt_gettoken(&kbd_token);
335 	ivar = (atkbdc_device_t *)device_get_ivars(dev);
336 	switch (index) {
337 	case KBDC_IVAR_IRQ:
338 		*val = (u_long)ivar->irq;
339 		break;
340 	case KBDC_IVAR_FLAGS:
341 		*val = (u_long)ivar->flags;
342 		break;
343 	case KBDC_IVAR_VENDORID:
344 		*val = (u_long)ivar->vendorid;
345 		break;
346 	case KBDC_IVAR_SERIAL:
347 		*val = (u_long)ivar->serial;
348 		break;
349 	case KBDC_IVAR_LOGICALID:
350 		*val = (u_long)ivar->logicalid;
351 		break;
352 	case KBDC_IVAR_COMPATID:
353 		*val = (u_long)ivar->compatid;
354 		break;
355 	default:
356 		lwkt_reltoken(&kbd_token);
357 		return ENOENT;
358 	}
359 
360 	lwkt_reltoken(&kbd_token);
361 	return 0;
362 }
363 
364 static int
365 atkbdc_write_ivar(device_t bus, device_t dev, int index, u_long val)
366 {
367 	atkbdc_device_t *ivar;
368 
369 	lwkt_gettoken(&kbd_token);
370 	ivar = (atkbdc_device_t *)device_get_ivars(dev);
371 	switch (index) {
372 	case KBDC_IVAR_IRQ:
373 		ivar->irq = (int)val;
374 		break;
375 	case KBDC_IVAR_FLAGS:
376 		ivar->flags = (int)val;
377 		break;
378 	case KBDC_IVAR_VENDORID:
379 		ivar->vendorid = (u_int32_t)val;
380 		break;
381 	case KBDC_IVAR_SERIAL:
382 		ivar->serial = (u_int32_t)val;
383 		break;
384 	case KBDC_IVAR_LOGICALID:
385 		ivar->logicalid = (u_int32_t)val;
386 		break;
387 	case KBDC_IVAR_COMPATID:
388 		ivar->compatid = (u_int32_t)val;
389 		break;
390 	default:
391 		lwkt_reltoken(&kbd_token);
392 		return ENOENT;
393 	}
394 
395 	lwkt_reltoken(&kbd_token);
396 	return 0;
397 }
398 
399 DRIVER_MODULE(atkbdc, isa, atkbdc_driver, atkbdc_devclass, NULL, NULL);
400 DRIVER_MODULE(atkbdc, acpi, atkbdc_driver, atkbdc_devclass, NULL, NULL);
401