Home | History | Annotate | Line # | Download | only in isa
isa.c revision 1.112
      1 /*	$NetBSD: isa.c,v 1.112 2002/09/27 03:18:14 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.112 2002/09/27 03:18:14 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_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 (config_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 (config_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