2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/sys/isa/atkbdc_isa.c,v 1.14.2.1 2000/03/31 12:52:05 yokota Exp $
27 * $DragonFly: src/sys/dev/misc/atkbdc_layer/atkbdc_isa.c,v 1.9 2007/04/22 10:54:42 y0netan1 Exp $
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
36 #include <sys/malloc.h>
39 #include <dev/misc/kbd/atkbdcreg.h>
41 #include <bus/isa/isareg.h>
42 #include <bus/isa/isavar.h>
44 MALLOC_DEFINE(M_ATKBDDEV
, "atkbddev", "AT Keyboard device");
47 typedef struct atkbdc_device
{
48 int flags
; /* configuration flags */
49 int irq
; /* ISA IRQ mask */
57 devclass_t atkbdc_devclass
;
59 static int atkbdc_probe(device_t dev
);
60 static int atkbdc_attach(device_t dev
);
61 static int atkbdc_print_child(device_t bus
, device_t dev
);
62 static int atkbdc_read_ivar(device_t bus
, device_t dev
, int index
,
64 static int atkbdc_write_ivar(device_t bus
, device_t dev
, int index
,
67 static device_method_t atkbdc_methods
[] = {
68 DEVMETHOD(device_probe
, atkbdc_probe
),
69 DEVMETHOD(device_attach
, atkbdc_attach
),
70 DEVMETHOD(device_suspend
, bus_generic_suspend
),
71 DEVMETHOD(device_resume
, bus_generic_resume
),
73 DEVMETHOD(bus_print_child
, atkbdc_print_child
),
74 DEVMETHOD(bus_read_ivar
, atkbdc_read_ivar
),
75 DEVMETHOD(bus_write_ivar
, atkbdc_write_ivar
),
76 DEVMETHOD(bus_alloc_resource
, bus_generic_alloc_resource
),
77 DEVMETHOD(bus_release_resource
, bus_generic_release_resource
),
78 DEVMETHOD(bus_activate_resource
, bus_generic_activate_resource
),
79 DEVMETHOD(bus_deactivate_resource
, bus_generic_deactivate_resource
),
80 DEVMETHOD(bus_setup_intr
, bus_generic_setup_intr
),
81 DEVMETHOD(bus_teardown_intr
, bus_generic_teardown_intr
),
86 static driver_t atkbdc_driver
= {
89 sizeof(atkbdc_softc_t
*),
92 static struct isa_pnp_id atkbdc_ids
[] = {
93 { 0x0303d041, "Keyboard controller (i8042)" }, /* PNP0303 */
98 atkbdc_probe(device_t dev
)
100 struct resource
*port0
;
101 struct resource
*port1
;
104 #if defined(__i386__)
106 bus_space_handle_t ioh1
;
111 if (ISA_PNP_PROBE(device_get_parent(dev
), dev
, atkbdc_ids
) == ENXIO
)
114 device_set_desc(dev
, "Keyboard controller (i8042)");
117 port0
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &rid
, 0, ~0, 1,
122 if (bus_get_resource_start(dev
, SYS_RES_IOPORT
, 1) <= 0) {
123 bus_set_resource(dev
, SYS_RES_IOPORT
, 1,
124 rman_get_start(port0
) + KBD_STATUS_PORT
, 1);
127 port1
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &rid
, 0, ~0, 1,
130 bus_release_resource(dev
, SYS_RES_IOPORT
, 0, port0
);
134 #if defined(__i386__)
136 * Check if we really have AT keyboard controller. Poll status
137 * register until we get "all clear" indication. If no such
138 * indication comes, it probably means that there is no AT
139 * keyboard controller present. Give up in such case. Check relies
140 * on the fact that reading from non-existing in/out port returns
141 * 0xff on i386. May or may not be true on other platforms.
143 tag
= rman_get_bustag(port0
);
144 ioh1
= rman_get_bushandle(port1
);
145 for (i
= 65536; i
!= 0; --i
) {
146 if ((bus_space_read_1(tag
, ioh1
, 0) & 0x2) == 0)
151 bus_release_resource(dev
, SYS_RES_IOPORT
, 0, port0
);
152 bus_release_resource(dev
, SYS_RES_IOPORT
, 1, port1
);
157 error
= atkbdc_probe_unit(device_get_unit(dev
), port0
, port1
);
159 bus_release_resource(dev
, SYS_RES_IOPORT
, 0, port0
);
160 bus_release_resource(dev
, SYS_RES_IOPORT
, 1, port1
);
166 atkbdc_add_device(device_t dev
, const char *name
, int unit
)
168 atkbdc_device_t
*kdev
;
172 if (resource_int_value(name
, unit
, "disabled", &t
) == 0 && t
!= 0)
175 kdev
= kmalloc(sizeof(struct atkbdc_device
), M_ATKBDDEV
,
178 if (resource_int_value(name
, unit
, "irq", &t
) == 0)
183 if (resource_int_value(name
, unit
, "flags", &t
) == 0)
188 child
= device_add_child(dev
, name
, unit
);
189 device_set_ivars(child
, kdev
);
193 atkbdc_attach(device_t dev
)
201 unit
= device_get_unit(dev
);
202 sc
= *(atkbdc_softc_t
**)device_get_softc(dev
);
205 * We have to maintain two copies of the kbdc_softc struct,
206 * as the low-level console needs to have access to the
207 * keyboard controller before kbdc is probed and attached.
208 * kbdc_soft[] contains the default entry for that purpose.
211 sc
= atkbdc_get_softc(unit
);
217 sc
->port0
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &rid
, 0, ~0, 1,
219 if (sc
->port0
== NULL
)
222 sc
->port1
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &rid
, 0, ~0, 1,
224 if (sc
->port1
== NULL
) {
225 bus_release_resource(dev
, SYS_RES_IOPORT
, 0, sc
->port0
);
229 error
= atkbdc_attach_unit(unit
, sc
, sc
->port0
, sc
->port1
);
231 bus_release_resource(dev
, SYS_RES_IOPORT
, 0, sc
->port0
);
232 bus_release_resource(dev
, SYS_RES_IOPORT
, 1, sc
->port1
);
235 *(atkbdc_softc_t
**)device_get_softc(dev
) = sc
;
238 * Add all devices configured to be attached to atkbdc0.
240 for (i
= resource_query_string(-1, "at", device_get_nameunit(dev
));
242 i
= resource_query_string(i
, "at", device_get_nameunit(dev
))) {
243 atkbdc_add_device(dev
, resource_query_name(i
),
244 resource_query_unit(i
));
250 for (i
= resource_query_string(-1, "at", device_get_name(dev
));
252 i
= resource_query_string(i
, "at", device_get_name(dev
))) {
253 atkbdc_add_device(dev
, resource_query_name(i
),
254 resource_query_unit(i
));
257 bus_generic_attach(dev
);
263 atkbdc_print_child(device_t bus
, device_t dev
)
265 atkbdc_device_t
*kbdcdev
;
268 kbdcdev
= (atkbdc_device_t
*)device_get_ivars(dev
);
270 retval
+= bus_print_child_header(bus
, dev
);
271 if (kbdcdev
->flags
!= 0)
272 retval
+= kprintf(" flags 0x%x", kbdcdev
->flags
);
273 if (kbdcdev
->irq
!= -1)
274 retval
+= kprintf(" irq %d", kbdcdev
->irq
);
275 retval
+= bus_print_child_footer(bus
, dev
);
281 atkbdc_read_ivar(device_t bus
, device_t dev
, int index
, u_long
*val
)
283 atkbdc_device_t
*ivar
;
285 ivar
= (atkbdc_device_t
*)device_get_ivars(dev
);
288 *val
= (u_long
)ivar
->irq
;
290 case KBDC_IVAR_FLAGS
:
291 *val
= (u_long
)ivar
->flags
;
293 case KBDC_IVAR_VENDORID
:
294 *val
= (u_long
)ivar
->vendorid
;
296 case KBDC_IVAR_SERIAL
:
297 *val
= (u_long
)ivar
->serial
;
299 case KBDC_IVAR_LOGICALID
:
300 *val
= (u_long
)ivar
->logicalid
;
302 case KBDC_IVAR_COMPATID
:
303 *val
= (u_long
)ivar
->compatid
;
312 atkbdc_write_ivar(device_t bus
, device_t dev
, int index
, u_long val
)
314 atkbdc_device_t
*ivar
;
316 ivar
= (atkbdc_device_t
*)device_get_ivars(dev
);
319 ivar
->irq
= (int)val
;
321 case KBDC_IVAR_FLAGS
:
322 ivar
->flags
= (int)val
;
324 case KBDC_IVAR_VENDORID
:
325 ivar
->vendorid
= (u_int32_t
)val
;
327 case KBDC_IVAR_SERIAL
:
328 ivar
->serial
= (u_int32_t
)val
;
330 case KBDC_IVAR_LOGICALID
:
331 ivar
->logicalid
= (u_int32_t
)val
;
333 case KBDC_IVAR_COMPATID
:
334 ivar
->compatid
= (u_int32_t
)val
;
342 DRIVER_MODULE(atkbdc
, isa
, atkbdc_driver
, atkbdc_devclass
, 0, 0);