xref: /netbsd/sys/dev/isa/isa.c (revision bf9ec67e)
1 /*	$NetBSD: isa.c,v 1.110 2002/01/07 21:47:09 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: isa.c,v 1.110 2002/01/07 21:47:09 thorpej Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/device.h>
47 
48 #include <machine/intr.h>
49 
50 #include <dev/isa/isareg.h>
51 #include <dev/isa/isavar.h>
52 #include <dev/isa/isadmareg.h>
53 
54 #include "isadma.h"
55 
56 #include "isapnp.h"
57 #if NISAPNP > 0
58 #include <dev/isapnp/isapnpreg.h>
59 #include <dev/isapnp/isapnpvar.h>
60 #endif
61 
62 int	isamatch(struct device *, struct cfdata *, void *);
63 void	isaattach(struct device *, struct device *, void *);
64 int	isaprint(void *, const char *);
65 
66 struct cfattach isa_ca = {
67 	sizeof(struct isa_softc), isamatch, isaattach
68 };
69 
70 void	isa_attach_knowndevs(struct isa_softc *);
71 void	isa_free_knowndevs(struct isa_softc *);
72 
73 int	isasubmatch(struct device *, struct cfdata *, void *);
74 int	isasearch(struct device *, struct cfdata *, void *);
75 
76 int
77 isamatch(struct device *parent, struct cfdata *cf, void *aux)
78 {
79 	struct isabus_attach_args *iba = aux;
80 
81 	if (strcmp(iba->iba_busname, cf->cf_driver->cd_name))
82 		return (0);
83 
84 	/* XXX check other indicators */
85 
86         return (1);
87 }
88 
89 void
90 isaattach(struct device *parent, struct device *self, void *aux)
91 {
92 	struct isa_softc *sc = (struct isa_softc *)self;
93 	struct isabus_attach_args *iba = aux;
94 
95 	TAILQ_INIT(&sc->sc_knowndevs);
96 	sc->sc_dynamicdevs = 0;
97 
98 	isa_attach_hook(parent, self, iba);
99 	printf("\n");
100 
101 	/* XXX Add code to fetch known-devices. */
102 
103 	sc->sc_iot = iba->iba_iot;
104 	sc->sc_memt = iba->iba_memt;
105 	sc->sc_dmat = iba->iba_dmat;
106 	sc->sc_ic = iba->iba_ic;
107 
108 #if NISAPNP > 0
109 	/*
110 	 * Reset isapnp cards that the bios configured for us
111 	 */
112 	isapnp_isa_attach_hook(sc);
113 #endif
114 
115 #if NISADMA > 0
116 	/*
117 	 * Initialize our DMA state.
118 	 */
119 	isa_dmainit(sc->sc_ic, sc->sc_iot, sc->sc_dmat, self);
120 #endif
121 
122 	/* Attach all direct-config children. */
123 	isa_attach_knowndevs(sc);
124 
125 	/*
126 	 * If we don't support dynamic hello/goodbye of devices,
127 	 * then free the knowndevs info now.
128 	 */
129 	if (sc->sc_dynamicdevs == 0)
130 		isa_free_knowndevs(sc);
131 
132 	/* Attach all indrect-config children. */
133 	config_search(isasearch, self, NULL);
134 }
135 
136 void
137 isa_attach_knowndevs(struct isa_softc *sc)
138 {
139 	struct isa_attach_args ia;
140 	struct isa_knowndev *ik;
141 
142 	if (TAILQ_EMPTY(&sc->sc_knowndevs))
143 		return;
144 
145 	TAILQ_FOREACH(ik, &sc->sc_knowndevs, ik_list) {
146 		if (ik->ik_claimed != NULL)
147 			continue;
148 
149 		ia.ia_iot = sc->sc_iot;
150 		ia.ia_memt = sc->sc_memt;
151 		ia.ia_dmat = sc->sc_dmat;
152 		ia.ia_ic = sc->sc_ic;
153 
154 		ia.ia_pnpname = ik->ik_pnpname;
155 		ia.ia_pnpcompatnames = ik->ik_pnpcompatnames;
156 
157 		ia.ia_io = ik->ik_io;
158 		ia.ia_nio = ik->ik_nio;
159 
160 		ia.ia_iomem = ik->ik_iomem;
161 		ia.ia_niomem = ik->ik_niomem;
162 
163 		ia.ia_irq = ik->ik_irq;
164 		ia.ia_nirq = ik->ik_nirq;
165 
166 		ia.ia_drq = ik->ik_drq;
167 		ia.ia_ndrq = ik->ik_ndrq;
168 
169 		ia.ia_aux = NULL;
170 
171 		ik->ik_claimed = config_found_sm(&sc->sc_dev, &ia,
172 		    isaprint, isasubmatch);
173 	}
174 }
175 
176 void
177 isa_free_knowndevs(struct isa_softc *sc)
178 {
179 	struct isa_knowndev *ik;
180 	struct isa_pnpname *ipn;
181 
182 #define	FREEIT(x)	if (x != NULL) free(x, M_DEVBUF)
183 
184 	while ((ik = TAILQ_FIRST(&sc->sc_knowndevs)) != NULL) {
185 		TAILQ_REMOVE(&sc->sc_knowndevs, ik, ik_list);
186 		FREEIT(ik->ik_pnpname);
187 		while ((ipn = ik->ik_pnpcompatnames) != NULL) {
188 			ik->ik_pnpcompatnames = ipn->ipn_next;
189 			free(ipn->ipn_name, M_DEVBUF);
190 			free(ipn, M_DEVBUF);
191 		}
192 		FREEIT(ik->ik_io);
193 		FREEIT(ik->ik_iomem);
194 		FREEIT(ik->ik_irq);
195 		FREEIT(ik->ik_drq);
196 		free(ik, M_DEVBUF);
197 	}
198 
199 #undef FREEIT
200 }
201 
202 int
203 isasubmatch(struct device *parent, struct cfdata *cf, void *aux)
204 {
205 	struct isa_attach_args *ia = aux;
206 	int i;
207 
208 	if (ia->ia_nio == 0) {
209 		if (cf->cf_iobase != ISACF_PORT_DEFAULT)
210 			return (0);
211 	} else {
212 		if (cf->cf_iobase != ISACF_PORT_DEFAULT &&
213 		    cf->cf_iobase != ia->ia_io[0].ir_addr)
214 			return (0);
215 	}
216 
217 	if (ia->ia_niomem == 0) {
218 		if (cf->cf_maddr != ISACF_IOMEM_DEFAULT)
219 			return (0);
220 	} else {
221 		if (cf->cf_maddr != ISACF_IOMEM_DEFAULT &&
222 		    cf->cf_maddr != ia->ia_iomem[0].ir_addr)
223 			return (0);
224 	}
225 
226 	if (ia->ia_nirq == 0) {
227 		if (cf->cf_irq != ISACF_IRQ_DEFAULT)
228 			return (0);
229 	} else {
230 		if (cf->cf_irq != ISACF_IRQ_DEFAULT &&
231 		    cf->cf_irq != ia->ia_irq[0].ir_irq)
232 			return (0);
233 	}
234 
235 	if (ia->ia_ndrq == 0) {
236 		if (cf->cf_drq != ISACF_DRQ_DEFAULT)
237 			return (0);
238 		if (cf->cf_drq2 != ISACF_DRQ_DEFAULT)
239 			return (0);
240 	} else {
241 		for (i = 0; i < 2; i++) {
242 			if (i == ia->ia_ndrq)
243 				break;
244 			if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT &&
245 			    cf->cf_loc[ISACF_DRQ + i] != ia->ia_drq[i].ir_drq)
246 				return (0);
247 		}
248 		for (; i < 2; i++) {
249 			if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT)
250 				return (0);
251 		}
252 	}
253 
254 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
255 }
256 
257 int
258 isaprint(void *aux, const char *isa)
259 {
260 	struct isa_attach_args *ia = aux;
261 	const char *sep;
262 	int i;
263 
264 	/*
265 	 * This block of code only fires if we have a direct-config'd
266 	 * device for which there is no driver match.
267 	 */
268 	if (isa != NULL) {
269 		struct isa_pnpname *ipn;
270 
271 		if (ia->ia_pnpname != NULL)
272 			printf("%s", ia->ia_pnpname);
273 		if ((ipn = ia->ia_pnpcompatnames) != NULL) {
274 			printf(" (");	/* ) */
275 			for (sep = ""; ipn != NULL;
276 			     ipn = ipn->ipn_next, sep = " ") {
277 				printf("%s%s", sep, ipn->ipn_name);
278 			}
279 	/* ( */		printf(")");
280 		}
281 		printf(" at %s", isa);
282 	}
283 
284 	if (ia->ia_nio) {
285 		sep = "";
286 		printf(" port ");
287 		for (i = 0; i < ia->ia_nio; i++) {
288 			if (ia->ia_io[i].ir_size == 0)
289 				continue;
290 			printf("%s0x%x", sep, ia->ia_io[i].ir_addr);
291 			if (ia->ia_io[i].ir_size > 1)
292 				printf("-0x%x", ia->ia_io[i].ir_addr +
293 				    ia->ia_io[i].ir_size - 1);
294 			sep = ",";
295 		}
296 	}
297 
298 	if (ia->ia_niomem) {
299 		sep = "";
300 		printf(" iomem ");
301 		for (i = 0; i < ia->ia_niomem; i++) {
302 			if (ia->ia_iomem[i].ir_size == 0)
303 				continue;
304 			printf("%s0x%x", sep, ia->ia_iomem[i].ir_addr);
305 			if (ia->ia_iomem[i].ir_size > 1)
306 				printf("-0x%x", ia->ia_iomem[i].ir_addr +
307 				    ia->ia_iomem[i].ir_size - 1);
308 			sep = ",";
309 		}
310 	}
311 
312 	if (ia->ia_nirq) {
313 		sep = "";
314 		printf(" irq ");
315 		for (i = 0; i < ia->ia_nirq; i++) {
316 			if (ia->ia_irq[i].ir_irq == ISACF_IRQ_DEFAULT)
317 				continue;
318 			printf("%s%d", sep, ia->ia_irq[i].ir_irq);
319 			sep = ",";
320 		}
321 	}
322 
323 	if (ia->ia_ndrq) {
324 		sep = "";
325 		printf(" drq ");
326 		for (i = 0; i < ia->ia_ndrq; i++) {
327 			if (ia->ia_drq[i].ir_drq == ISACF_DRQ_DEFAULT)
328 				continue;
329 			printf("%s%d", sep, ia->ia_drq[i].ir_drq);
330 			sep = ",";
331 		}
332 	}
333 
334 	return (UNCONF);
335 }
336 
337 int
338 isasearch(struct device *parent, struct cfdata *cf, void *aux)
339 {
340 	struct isa_io res_io[1];
341 	struct isa_iomem res_mem[1];
342 	struct isa_irq res_irq[1];
343 	struct isa_drq res_drq[2];
344 	struct isa_softc *sc = (struct isa_softc *)parent;
345 	struct isa_attach_args ia;
346 	int tryagain;
347 
348 	do {
349 		ia.ia_pnpname = NULL;
350 		ia.ia_pnpcompatnames = NULL;
351 
352 		res_io[0].ir_addr = cf->cf_loc[ISACF_PORT];
353 		res_io[0].ir_size = 0;
354 
355 		res_mem[0].ir_addr = cf->cf_loc[ISACF_IOMEM];
356 		res_mem[0].ir_size = cf->cf_loc[ISACF_IOSIZ];
357 
358 		res_irq[0].ir_irq =
359 		    cf->cf_loc[ISACF_IRQ] == 2 ? 9 : cf->cf_loc[ISACF_IRQ];
360 
361 		res_drq[0].ir_drq = cf->cf_loc[ISACF_DRQ];
362 		res_drq[1].ir_drq = cf->cf_loc[ISACF_DRQ2];
363 
364 		ia.ia_iot = sc->sc_iot;
365 		ia.ia_memt = sc->sc_memt;
366 		ia.ia_dmat = sc->sc_dmat;
367 		ia.ia_ic = sc->sc_ic;
368 
369 		ia.ia_io = res_io;
370 		ia.ia_nio = 1;
371 
372 		ia.ia_iomem = res_mem;
373 		ia.ia_niomem = 1;
374 
375 		ia.ia_irq = res_irq;
376 		ia.ia_nirq = 1;
377 
378 		ia.ia_drq = res_drq;
379 		ia.ia_ndrq = 2;
380 
381 		tryagain = 0;
382 		if ((*cf->cf_attach->ca_match)(parent, cf, &ia) > 0) {
383 			config_attach(parent, cf, &ia, isaprint);
384 			tryagain = (cf->cf_fstate == FSTATE_STAR);
385 		}
386 	} while (tryagain);
387 
388 	return (0);
389 }
390 
391 char *
392 isa_intr_typename(int type)
393 {
394 
395 	switch (type) {
396         case IST_NONE :
397 		return ("none");
398         case IST_PULSE:
399 		return ("pulsed");
400         case IST_EDGE:
401 		return ("edge-triggered");
402         case IST_LEVEL:
403 		return ("level-triggered");
404 	default:
405 		panic("isa_intr_typename: invalid type %d", type);
406 	}
407 }
408