Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/atkbdc/atkbdc_isa.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 1999 Kazutaka YOKOTA <[email protected]>
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_kbd.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/malloc.h>
38
#include <machine/resource.h>
39
#include <sys/rman.h>
40
#include <machine/bus.h>
41
42
#include <dev/atkbdc/atkbdc_subr.h>
43
#include <dev/atkbdc/atkbdcreg.h>
44
45
#include <isa/isareg.h>
46
#include <isa/isavar.h>
47
48
static int atkbdc_isa_probe(device_t dev);
49
static int atkbdc_isa_attach(device_t dev);
50
static device_t atkbdc_isa_add_child(device_t bus, u_int order, const char *name,
51
int unit);
52
static struct resource *atkbdc_isa_alloc_resource(device_t dev, device_t child,
53
int type, int *rid, rman_res_t start, rman_res_t end,
54
rman_res_t count, u_int flags);
55
static int atkbdc_isa_release_resource(device_t dev, device_t child,
56
struct resource *r);
57
58
static device_method_t atkbdc_isa_methods[] = {
59
DEVMETHOD(device_probe, atkbdc_isa_probe),
60
DEVMETHOD(device_attach, atkbdc_isa_attach),
61
DEVMETHOD(device_suspend, bus_generic_suspend),
62
DEVMETHOD(device_resume, bus_generic_resume),
63
64
DEVMETHOD(bus_add_child, atkbdc_isa_add_child),
65
DEVMETHOD(bus_print_child, atkbdc_print_child),
66
DEVMETHOD(bus_read_ivar, atkbdc_read_ivar),
67
DEVMETHOD(bus_write_ivar, atkbdc_write_ivar),
68
DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list),
69
DEVMETHOD(bus_alloc_resource, atkbdc_isa_alloc_resource),
70
DEVMETHOD(bus_release_resource, atkbdc_isa_release_resource),
71
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
72
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
73
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
74
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
75
DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
76
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
77
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
78
{ 0, 0 }
79
};
80
81
static driver_t atkbdc_isa_driver = {
82
ATKBDC_DRIVER_NAME,
83
atkbdc_isa_methods,
84
sizeof(atkbdc_softc_t *),
85
};
86
87
static struct isa_pnp_id atkbdc_ids[] = {
88
{ 0x0303d041, "Keyboard controller (i8042)" }, /* PNP0303 */
89
{ 0x0b03d041, "Keyboard controller (i8042)" }, /* PNP030B */
90
{ 0x2003d041, "Keyboard controller (i8042)" }, /* PNP0320 */
91
{ 0 }
92
};
93
94
static int
95
atkbdc_isa_probe(device_t dev)
96
{
97
struct resource *port0;
98
struct resource *port1;
99
rman_res_t start;
100
rman_res_t count;
101
int error;
102
int rid;
103
#if defined(__i386__) || defined(__amd64__)
104
bus_space_tag_t tag;
105
bus_space_handle_t ioh1;
106
volatile int i;
107
register_t flags;
108
#endif
109
110
/* check PnP IDs */
111
if (ISA_PNP_PROBE(device_get_parent(dev), dev, atkbdc_ids) == ENXIO)
112
return ENXIO;
113
114
device_set_desc(dev, "Keyboard controller (i8042)");
115
116
/*
117
* Adjust I/O port resources.
118
* The AT keyboard controller uses two ports (a command/data port
119
* 0x60 and a status port 0x64), which may be given to us in
120
* one resource (0x60 through 0x64) or as two separate resources
121
* (0x60 and 0x64). Some brain-damaged ACPI BIOS has reversed
122
* command/data port and status port. Furthermore, /boot/device.hints
123
* may contain just one port, 0x60. We shall adjust resource settings
124
* so that these two ports are available as two separate resources
125
* in correct order.
126
*/
127
device_quiet(dev);
128
rid = 0;
129
if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
130
return ENXIO;
131
if (start == IO_KBD + KBD_STATUS_PORT) {
132
start = IO_KBD;
133
count++;
134
}
135
if (count > 1) /* adjust the count and/or start port */
136
bus_set_resource(dev, SYS_RES_IOPORT, rid, start, 1);
137
port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
138
if (port0 == NULL)
139
return ENXIO;
140
rid = 1;
141
if (bus_get_resource(dev, SYS_RES_IOPORT, rid, NULL, NULL) != 0)
142
bus_set_resource(dev, SYS_RES_IOPORT, 1,
143
start + KBD_STATUS_PORT, 1);
144
port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
145
if (port1 == NULL) {
146
bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
147
return ENXIO;
148
}
149
150
#if defined(__i386__) || defined(__amd64__)
151
/*
152
* Check if we really have AT keyboard controller. Poll status
153
* register until we get "all clear" indication. If no such
154
* indication comes, it probably means that there is no AT
155
* keyboard controller present. Give up in such case. Check relies
156
* on the fact that reading from non-existing in/out port returns
157
* 0xff on i386. May or may not be true on other platforms.
158
*/
159
tag = rman_get_bustag(port0);
160
ioh1 = rman_get_bushandle(port1);
161
flags = intr_disable();
162
for (i = 0; i != 65535; i++) {
163
if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0)
164
break;
165
}
166
intr_restore(flags);
167
if (i == 65535) {
168
bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
169
bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
170
if (bootverbose)
171
device_printf(dev, "AT keyboard controller not found\n");
172
return ENXIO;
173
}
174
#endif
175
176
device_verbose(dev);
177
178
error = atkbdc_probe_unit(device_get_unit(dev), port0, port1);
179
180
bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
181
bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
182
183
return error;
184
}
185
186
static int
187
atkbdc_isa_attach(device_t dev)
188
{
189
atkbdc_softc_t *sc;
190
int unit;
191
int error;
192
int rid;
193
194
unit = device_get_unit(dev);
195
sc = *(atkbdc_softc_t **)device_get_softc(dev);
196
if (sc == NULL) {
197
/*
198
* We have to maintain two copies of the kbdc_softc struct,
199
* as the low-level console needs to have access to the
200
* keyboard controller before kbdc is probed and attached.
201
* kbdc_soft[] contains the default entry for that purpose.
202
* See atkbdc.c. XXX
203
*/
204
sc = atkbdc_get_softc(unit);
205
if (sc == NULL)
206
return ENOMEM;
207
}
208
209
rid = 0;
210
sc->retry = 5000;
211
sc->port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
212
RF_ACTIVE);
213
if (sc->port0 == NULL)
214
return ENXIO;
215
rid = 1;
216
sc->port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
217
RF_ACTIVE);
218
if (sc->port1 == NULL) {
219
bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
220
return ENXIO;
221
}
222
223
/*
224
* If the device is not created by the PnP BIOS or ACPI, then
225
* the hint for the IRQ is on the child atkbd device, not the
226
* keyboard controller, so this can fail.
227
*/
228
rid = 0;
229
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
230
231
error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1);
232
if (error) {
233
bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
234
bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1);
235
if (sc->irq != NULL)
236
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
237
return error;
238
}
239
*(atkbdc_softc_t **)device_get_softc(dev) = sc;
240
241
bus_identify_children(dev);
242
bus_attach_children(dev);
243
244
return 0;
245
}
246
247
static device_t
248
atkbdc_isa_add_child(device_t bus, u_int order, const char *name, int unit)
249
{
250
atkbdc_device_t *ivar;
251
atkbdc_softc_t *sc;
252
device_t child;
253
int t;
254
255
sc = *(atkbdc_softc_t **)device_get_softc(bus);
256
ivar = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV,
257
M_NOWAIT | M_ZERO);
258
if (!ivar)
259
return NULL;
260
261
child = device_add_child_ordered(bus, order, name, unit);
262
if (child == NULL) {
263
free(ivar, M_ATKBDDEV);
264
return child;
265
}
266
267
resource_list_init(&ivar->resources);
268
ivar->rid = order;
269
270
/*
271
* If the device is not created by the PnP BIOS or ACPI, refer
272
* to device hints for IRQ. We always populate the resource
273
* list entry so we can use a standard bus_get_resource()
274
* method.
275
*/
276
if (order == KBDC_RID_KBD) {
277
if (sc->irq == NULL) {
278
if (resource_int_value(name, unit, "irq", &t) != 0)
279
t = -1;
280
} else
281
t = rman_get_start(sc->irq);
282
if (t > 0)
283
resource_list_add(&ivar->resources, SYS_RES_IRQ,
284
ivar->rid, t, t, 1);
285
}
286
287
if (resource_disabled(name, unit))
288
device_disable(child);
289
290
device_set_ivars(child, ivar);
291
292
return child;
293
}
294
295
struct resource *
296
atkbdc_isa_alloc_resource(device_t dev, device_t child, int type, int *rid,
297
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
298
{
299
atkbdc_softc_t *sc;
300
301
sc = *(atkbdc_softc_t **)device_get_softc(dev);
302
if (type == SYS_RES_IRQ && *rid == KBDC_RID_KBD && sc->irq != NULL)
303
return (sc->irq);
304
return (bus_generic_rl_alloc_resource(dev, child, type, rid, start,
305
end, count, flags));
306
}
307
308
static int
309
atkbdc_isa_release_resource(device_t dev, device_t child, struct resource *r)
310
{
311
atkbdc_softc_t *sc;
312
313
sc = *(atkbdc_softc_t **)device_get_softc(dev);
314
if (r == sc->irq)
315
return (0);
316
return (bus_generic_rl_release_resource(dev, child, r));
317
}
318
319
DRIVER_MODULE(atkbdc, isa, atkbdc_isa_driver, 0, 0);
320
DRIVER_MODULE(atkbdc, acpi, atkbdc_isa_driver, 0, 0);
321
ISA_PNP_INFO(atkbdc_ids);
322
323