1 /* $NetBSD: isa.c,v 1.136 2009/08/18 16:52:42 dyoung Exp $ */
4 * Copyright (c) 1998, 2001, 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum; by Jason R. Thorpe of Wasabi Systems, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: isa.c,v 1.136 2009/08/18 16:52:42 dyoung Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/device.h>
43 #include <dev/isa/isareg.h>
44 #include <dev/isa/isavar.h>
45 #include <dev/isa/isadmareg.h>
51 #include <dev/isapnp/isapnpreg.h>
52 #include <dev/isapnp/isapnpvar.h>
57 int isamatch(device_t
, cfdata_t
, void *);
58 void isaattach(device_t
, device_t
, void *);
59 int isadetach(device_t
, int);
60 int isarescan(device_t
, const char *, const int *);
61 void isachilddetached(device_t
, device_t
);
62 int isaprint(void *, const char *);
64 CFATTACH_DECL2_NEW(isa
, sizeof(struct isa_softc
),
65 isamatch
, isaattach
, isadetach
, NULL
, isarescan
, isachilddetached
);
67 void isa_attach_knowndevs(struct isa_softc
*);
68 void isa_free_knowndevs(struct isa_softc
*);
70 int isasubmatch(device_t
, cfdata_t
, const int *, void *);
71 int isasearch(device_t
, cfdata_t
, const int *, void *);
73 static int isa_slotcount
= -1; /* -1 == don't know how many */
76 isamatch(device_t parent
, cfdata_t cf
, void *aux
)
78 /* XXX check other indicators */
84 isaattach(device_t parent
, device_t self
, void *aux
)
86 struct isa_softc
*sc
= device_private(self
);
87 struct isabus_attach_args
*iba
= aux
;
88 static const int wildcard
[ISACF_NLOCS
] = {
89 ISACF_PORT_DEFAULT
, ISACF_SIZE_DEFAULT
,
90 ISACF_IOMEM_DEFAULT
, ISACF_IOSIZ_DEFAULT
,
91 ISACF_IRQ_DEFAULT
, ISACF_DRQ_DEFAULT
, ISACF_DRQ2_DEFAULT
94 TAILQ_INIT(&sc
->sc_knowndevs
);
95 sc
->sc_dynamicdevs
= 0;
99 isa_attach_hook(parent
, self
, iba
);
103 /* XXX Add code to fetch known-devices. */
105 sc
->sc_iot
= iba
->iba_iot
;
106 sc
->sc_memt
= iba
->iba_memt
;
107 sc
->sc_dmat
= iba
->iba_dmat
;
108 sc
->sc_ic
= iba
->iba_ic
;
112 * Reset isapnp cards that the bios configured for us
114 isapnp_isa_attach_hook(sc
);
119 * Initialize our DMA state.
121 isa_dmainit(sc
->sc_ic
, sc
->sc_iot
, sc
->sc_dmat
, self
);
124 /* Attach all direct-config children. */
125 isa_attach_knowndevs(sc
);
128 * If we don't support dynamic hello/goodbye of devices,
129 * then free the knowndevs info now.
131 if (sc
->sc_dynamicdevs
== 0)
132 isa_free_knowndevs(sc
);
134 /* Attach all indirect-config children. */
135 isarescan(self
, "isa", wildcard
);
137 if (!pmf_device_register(self
, NULL
, NULL
))
138 aprint_error_dev(self
, "couldn't establish power handler\n");
142 isadetach(device_t self
, int flags
)
144 struct isa_softc
*sc
= device_private(self
);
147 if ((rc
= config_detach_children(self
, flags
)) != 0)
150 pmf_device_deregister(self
);
152 isa_free_knowndevs(sc
);
155 isa_dmadestroy(sc
->sc_ic
);
157 isa_detach_hook(sc
->sc_ic
, self
);
163 isarescan(device_t self
, const char *ifattr
, const int *locators
)
165 int locs
[ISACF_NLOCS
];
167 memcpy(locs
, locators
, sizeof(locs
));
170 * XXX Bus independent code calling this function does not
171 * know the locator default values. It assumes "-1" for now.
172 * (should be made available by "config" one day)
173 * So fixup where the "-1" is not correct.
175 if (locs
[ISACF_SIZE
] == -1)
176 locs
[ISACF_SIZE
] = ISACF_SIZE_DEFAULT
;
177 if (locs
[ISACF_IOSIZ
] == -1)
178 locs
[ISACF_IOSIZ
] = ISACF_IOSIZ_DEFAULT
;
180 config_search_loc(isasearch
, self
, ifattr
, locs
, NULL
);
185 isachilddetached(device_t self
, device_t child
)
187 struct isa_knowndev
*ik
;
188 struct isa_softc
*sc
= device_private(self
);
190 TAILQ_FOREACH(ik
, &sc
->sc_knowndevs
, ik_list
) {
191 if (ik
->ik_claimed
== child
)
192 ik
->ik_claimed
= NULL
;
197 isa_attach_knowndevs(struct isa_softc
*sc
)
199 struct isa_attach_args ia
;
200 struct isa_knowndev
*ik
;
202 if (TAILQ_EMPTY(&sc
->sc_knowndevs
))
205 TAILQ_FOREACH(ik
, &sc
->sc_knowndevs
, ik_list
) {
206 if (ik
->ik_claimed
!= NULL
)
209 ia
.ia_iot
= sc
->sc_iot
;
210 ia
.ia_memt
= sc
->sc_memt
;
211 ia
.ia_dmat
= sc
->sc_dmat
;
212 ia
.ia_ic
= sc
->sc_ic
;
214 ia
.ia_pnpname
= ik
->ik_pnpname
;
215 ia
.ia_pnpcompatnames
= ik
->ik_pnpcompatnames
;
217 ia
.ia_io
= ik
->ik_io
;
218 ia
.ia_nio
= ik
->ik_nio
;
220 ia
.ia_iomem
= ik
->ik_iomem
;
221 ia
.ia_niomem
= ik
->ik_niomem
;
223 ia
.ia_irq
= ik
->ik_irq
;
224 ia
.ia_nirq
= ik
->ik_nirq
;
226 ia
.ia_drq
= ik
->ik_drq
;
227 ia
.ia_ndrq
= ik
->ik_ndrq
;
231 /* XXX should setup locator array */
233 ik
->ik_claimed
= config_found_sm_loc(sc
->sc_dev
,
234 "isa", 0, &ia
, isaprint
, isasubmatch
);
239 isa_free_knowndevs(struct isa_softc
*sc
)
241 struct isa_knowndev
*ik
;
242 struct isa_pnpname
*ipn
;
244 #define FREEIT(x) if (x != NULL) free(x, M_DEVBUF)
246 while ((ik
= TAILQ_FIRST(&sc
->sc_knowndevs
)) != NULL
) {
247 TAILQ_REMOVE(&sc
->sc_knowndevs
, ik
, ik_list
);
248 FREEIT(ik
->ik_pnpname
);
249 while ((ipn
= ik
->ik_pnpcompatnames
) != NULL
) {
250 ik
->ik_pnpcompatnames
= ipn
->ipn_next
;
251 free(ipn
->ipn_name
, M_DEVBUF
);
255 FREEIT(ik
->ik_iomem
);
265 checkattachargs(struct isa_attach_args
*ia
, const int *loc
)
269 if (ia
->ia_nio
== 0) {
270 if (loc
[ISACF_PORT
] != ISACF_PORT_DEFAULT
)
273 if (loc
[ISACF_PORT
] != ISACF_PORT_DEFAULT
&&
274 loc
[ISACF_PORT
] != ia
->ia_io
[0].ir_addr
)
278 if (ia
->ia_niomem
== 0) {
279 if (loc
[ISACF_IOMEM
] != ISACF_IOMEM_DEFAULT
)
282 if (loc
[ISACF_IOMEM
] != ISACF_IOMEM_DEFAULT
&&
283 loc
[ISACF_IOMEM
] != ia
->ia_iomem
[0].ir_addr
)
287 if (ia
->ia_nirq
== 0) {
288 if (loc
[ISACF_IRQ
] != ISACF_IRQ_DEFAULT
)
291 if (loc
[ISACF_IRQ
] != ISACF_IRQ_DEFAULT
&&
292 loc
[ISACF_IRQ
] != ia
->ia_irq
[0].ir_irq
)
296 if (ia
->ia_ndrq
== 0) {
297 if (loc
[ISACF_DRQ
] != ISACF_DRQ_DEFAULT
)
299 if (loc
[ISACF_DRQ2
] != ISACF_DRQ2_DEFAULT
)
302 for (i
= 0; i
< 2; i
++) {
303 if (i
== ia
->ia_ndrq
)
305 if (loc
[ISACF_DRQ
+ i
] != ISACF_DRQ_DEFAULT
&&
306 loc
[ISACF_DRQ
+ i
] != ia
->ia_drq
[i
].ir_drq
)
310 if (loc
[ISACF_DRQ
+ i
] != ISACF_DRQ_DEFAULT
)
319 isasubmatch(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
321 struct isa_attach_args
*ia
= aux
;
323 if (!checkattachargs(ia
, cf
->cf_loc
))
326 return (config_match(parent
, cf
, aux
));
330 isaprint(void *aux
, const char *isa
)
332 struct isa_attach_args
*ia
= aux
;
337 * This block of code only fires if we have a direct-config'd
338 * device for which there is no driver match.
341 struct isa_pnpname
*ipn
;
343 if (ia
->ia_pnpname
!= NULL
)
344 aprint_normal("%s", ia
->ia_pnpname
);
345 if ((ipn
= ia
->ia_pnpcompatnames
) != NULL
) {
346 aprint_normal(" ("); /* ) */
347 for (sep
= ""; ipn
!= NULL
;
348 ipn
= ipn
->ipn_next
, sep
= " ") {
349 aprint_normal("%s%s", sep
, ipn
->ipn_name
);
351 /* ( */ aprint_normal(")");
353 aprint_normal(" at %s", isa
);
358 aprint_normal(" port ");
359 for (i
= 0; i
< ia
->ia_nio
; i
++) {
360 if (ia
->ia_io
[i
].ir_size
== 0)
362 aprint_normal("%s0x%x", sep
, ia
->ia_io
[i
].ir_addr
);
363 if (ia
->ia_io
[i
].ir_size
> 1)
364 aprint_normal("-0x%x", ia
->ia_io
[i
].ir_addr
+
365 ia
->ia_io
[i
].ir_size
- 1);
372 aprint_normal(" iomem ");
373 for (i
= 0; i
< ia
->ia_niomem
; i
++) {
374 if (ia
->ia_iomem
[i
].ir_size
== 0)
376 aprint_normal("%s0x%x", sep
, ia
->ia_iomem
[i
].ir_addr
);
377 if (ia
->ia_iomem
[i
].ir_size
> 1)
378 aprint_normal("-0x%x", ia
->ia_iomem
[i
].ir_addr
+
379 ia
->ia_iomem
[i
].ir_size
- 1);
386 aprint_normal(" irq ");
387 for (i
= 0; i
< ia
->ia_nirq
; i
++) {
388 if (ia
->ia_irq
[i
].ir_irq
== ISACF_IRQ_DEFAULT
)
390 aprint_normal("%s%d", sep
, ia
->ia_irq
[i
].ir_irq
);
397 aprint_normal(" drq ");
398 for (i
= 0; i
< ia
->ia_ndrq
; i
++) {
399 if (ia
->ia_drq
[i
].ir_drq
== ISACF_DRQ_DEFAULT
)
401 aprint_normal("%s%d", sep
, ia
->ia_drq
[i
].ir_drq
);
410 isasearch(device_t parent
, cfdata_t cf
, const int *slocs
, void *aux
)
412 struct isa_io res_io
[1];
413 struct isa_iomem res_mem
[1];
414 struct isa_irq res_irq
[1];
415 struct isa_drq res_drq
[2];
416 struct isa_softc
*sc
= device_private(parent
);
417 struct isa_attach_args ia
;
418 int flocs
[ISACF_NLOCS
];
422 ia
.ia_pnpname
= NULL
;
423 ia
.ia_pnpcompatnames
= NULL
;
425 res_io
[0].ir_addr
= cf
->cf_loc
[ISACF_PORT
];
426 res_io
[0].ir_size
= 0;
428 res_mem
[0].ir_addr
= cf
->cf_loc
[ISACF_IOMEM
];
429 res_mem
[0].ir_size
= cf
->cf_loc
[ISACF_IOSIZ
];
432 cf
->cf_loc
[ISACF_IRQ
] == 2 ? 9 : cf
->cf_loc
[ISACF_IRQ
];
434 res_drq
[0].ir_drq
= cf
->cf_loc
[ISACF_DRQ
];
435 res_drq
[1].ir_drq
= cf
->cf_loc
[ISACF_DRQ2
];
437 ia
.ia_iot
= sc
->sc_iot
;
438 ia
.ia_memt
= sc
->sc_memt
;
439 ia
.ia_dmat
= sc
->sc_dmat
;
440 ia
.ia_ic
= sc
->sc_ic
;
445 ia
.ia_iomem
= res_mem
;
454 if (!checkattachargs(&ia
, slocs
))
458 if (config_match(parent
, cf
, &ia
) > 0) {
460 * This is not necessary for detach, but might
461 * still be useful to collect device information.
463 flocs
[ISACF_PORT
] = ia
.ia_io
[0].ir_addr
;
464 flocs
[ISACF_SIZE
] = ia
.ia_io
[0].ir_size
;
465 flocs
[ISACF_IOMEM
] = ia
.ia_iomem
[0].ir_addr
;
466 flocs
[ISACF_IOSIZ
] = ia
.ia_iomem
[0].ir_size
;
467 flocs
[ISACF_IRQ
] = ia
.ia_irq
[0].ir_irq
;
468 flocs
[ISACF_DRQ
] = ia
.ia_drq
[0].ir_drq
;
469 flocs
[ISACF_DRQ2
] = ia
.ia_drq
[1].ir_drq
;
470 config_attach_loc(parent
, cf
, flocs
, &ia
, isaprint
);
471 tryagain
= (cf
->cf_fstate
== FSTATE_STAR
);
479 isa_intr_typename(int type
)
488 return ("edge-triggered");
490 return ("level-triggered");
492 panic("isa_intr_typename: invalid type %d", type
);
497 isa_get_slotcount(void)
500 return isa_slotcount
;
504 isa_set_slotcount(int arg
)