Home | History | Annotate | Line # | Download | only in isa
      1 /*	$NetBSD: isa.c,v 1.142 2025/10/17 16:56:00 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998, 2001, 2008 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  *
     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.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: isa.c,v 1.142 2025/10/17 16:56:00 thorpej Exp $");
     34 
     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>
     40 
     41 #include <sys/intr.h>
     42 
     43 #include <dev/isa/isareg.h>
     44 #include <dev/isa/isavar.h>
     45 #include <dev/isa/isadmareg.h>
     46 
     47 #include "isadma.h"
     48 
     49 #include "isapnp.h"
     50 #if NISAPNP > 0
     51 #include <dev/isapnp/isapnpreg.h>
     52 #include <dev/isapnp/isapnpvar.h>
     53 #endif
     54 
     55 #include "locators.h"
     56 
     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 int	isaprint(void *, const char *);
     62 
     63 CFATTACH_DECL2_NEW(isa, sizeof(struct isa_softc),
     64     isamatch, isaattach, isadetach, NULL, isarescan, NULL);
     65 
     66 int	isasearch(device_t, cfdata_t, const int *, void *);
     67 
     68 static int	isa_slotcount = -1;	/* -1 == don't know how many */
     69 
     70 int
     71 isamatch(device_t parent, cfdata_t cf, void *aux)
     72 {
     73 	/* XXX check other indicators */
     74 
     75 	return (1);
     76 }
     77 
     78 void
     79 isaattach(device_t parent, device_t self, void *aux)
     80 {
     81 	struct isa_softc *sc = device_private(self);
     82 	struct isabus_attach_args *iba = aux;
     83 	static const int wildcard[ISACF_NLOCS] = {
     84 		[ISACF_PORT]  = ISACF_PORT_DEFAULT,
     85 		[ISACF_SIZE]  = ISACF_SIZE_DEFAULT,
     86 		[ISACF_IOMEM] = ISACF_IOMEM_DEFAULT,
     87 		[ISACF_IOSIZ] = ISACF_IOSIZ_DEFAULT,
     88 		[ISACF_IRQ]   = ISACF_IRQ_DEFAULT,
     89 		[ISACF_DRQ]   = ISACF_DRQ_DEFAULT,
     90 		[ISACF_DRQ2]  = ISACF_DRQ2_DEFAULT,
     91 	};
     92 
     93 	sc->sc_dev = self;
     94 
     95 	isa_attach_hook(parent, self, iba);
     96 	aprint_naive("\n");
     97 	aprint_normal("\n");
     98 
     99 	sc->sc_iot = iba->iba_iot;
    100 	sc->sc_memt = iba->iba_memt;
    101 	sc->sc_dmat = iba->iba_dmat;
    102 	sc->sc_ic = iba->iba_ic;
    103 
    104 #if NISAPNP > 0
    105 	/*
    106 	 * Reset isapnp cards that the bios configured for us
    107 	 */
    108 	isapnp_isa_attach_hook(sc);
    109 #endif
    110 
    111 #if NISADMA > 0
    112 	/*
    113 	 * Initialize our DMA state.
    114 	 */
    115 	isa_dmainit(sc->sc_ic, sc->sc_iot, sc->sc_dmat, self);
    116 #endif
    117 
    118 	/* Attach all indirect-config children. */
    119 	isarescan(self, NULL, wildcard);
    120 
    121 	if (!pmf_device_register(self, NULL, NULL))
    122 		aprint_error_dev(self, "couldn't establish power handler\n");
    123 }
    124 
    125 int
    126 isadetach(device_t self, int flags)
    127 {
    128 	struct isa_softc *sc = device_private(self);
    129 	int rc;
    130 
    131 	if ((rc = config_detach_children(self, flags)) != 0)
    132 		return rc;
    133 
    134 	pmf_device_deregister(self);
    135 
    136 #if NISADMA > 0
    137 	isa_dmadestroy(sc->sc_ic);
    138 #endif
    139 	isa_detach_hook(sc->sc_ic, self);
    140 
    141 	return 0;
    142 }
    143 
    144 int
    145 isarescan(device_t self, const char *ifattr, const int *locators)
    146 {
    147 	int locs[ISACF_NLOCS];
    148 
    149 	if (device_getprop_bool(self, "no-legacy-devices")) {
    150 		aprint_debug_dev(self, "platform reports no legacy devices\n");
    151 		return 0;
    152 	}
    153 
    154 	memcpy(locs, locators, sizeof(locs));
    155 
    156 	/*
    157 	 * XXX Bus independent code calling this function does not
    158 	 * know the locator default values. It assumes "-1" for now.
    159 	 * (should be made available by "config" one day)
    160 	 * So fixup where the "-1" is not correct.
    161 	 */
    162 	if (locs[ISACF_SIZE] == -1)
    163 		locs[ISACF_SIZE] = ISACF_SIZE_DEFAULT;
    164 	if (locs[ISACF_IOSIZ] == -1)
    165 		locs[ISACF_IOSIZ] = ISACF_IOSIZ_DEFAULT;
    166 
    167 	config_search(self, NULL,
    168 	    CFARGS(.search = isasearch,
    169 		   .locators = locs));
    170 	return (0);
    171 }
    172 
    173 static int
    174 checkattachargs(struct isa_attach_args *ia, const int *loc)
    175 {
    176 	int i;
    177 
    178 	if (ia->ia_nio == 0) {
    179 		if (loc[ISACF_PORT] != ISACF_PORT_DEFAULT)
    180 			return (0);
    181 	} else {
    182 		if (loc[ISACF_PORT] != ISACF_PORT_DEFAULT &&
    183 		    loc[ISACF_PORT] != ia->ia_io[0].ir_addr)
    184 			return (0);
    185 	}
    186 
    187 	if (ia->ia_niomem == 0) {
    188 		if (loc[ISACF_IOMEM] != ISACF_IOMEM_DEFAULT)
    189 			return (0);
    190 	} else {
    191 		if (loc[ISACF_IOMEM] != ISACF_IOMEM_DEFAULT &&
    192 		    loc[ISACF_IOMEM] != ia->ia_iomem[0].ir_addr)
    193 			return (0);
    194 	}
    195 
    196 	if (ia->ia_nirq == 0) {
    197 		if (loc[ISACF_IRQ] != ISACF_IRQ_DEFAULT)
    198 			return (0);
    199 	} else {
    200 		if (loc[ISACF_IRQ] != ISACF_IRQ_DEFAULT &&
    201 		    loc[ISACF_IRQ] != ia->ia_irq[0].ir_irq)
    202 			return (0);
    203 	}
    204 
    205 	if (ia->ia_ndrq == 0) {
    206 		if (loc[ISACF_DRQ] != ISACF_DRQ_DEFAULT)
    207 			return (0);
    208 		if (loc[ISACF_DRQ2] != ISACF_DRQ2_DEFAULT)
    209 			return (0);
    210 	} else {
    211 		for (i = 0; i < 2; i++) {
    212 			if (i == ia->ia_ndrq)
    213 				break;
    214 			if (loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT &&
    215 			    loc[ISACF_DRQ + i] != ia->ia_drq[i].ir_drq)
    216 				return (0);
    217 		}
    218 		for (; i < 2; i++) {
    219 			if (loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT)
    220 				return (0);
    221 		}
    222 	}
    223 
    224 	return (1);
    225 }
    226 
    227 int
    228 isaprint(void *aux, const char *isa)
    229 {
    230 	struct isa_attach_args *ia = aux;
    231 	const char *sep;
    232 	int i;
    233 
    234 	/*
    235 	 * This block of code only fires if we have a direct-config'd
    236 	 * device for which there is no driver match.
    237 	 */
    238 	if (isa != NULL) {
    239 		struct isa_pnpname *ipn;
    240 
    241 		if (ia->ia_pnpname != NULL)
    242 			aprint_normal("%s", ia->ia_pnpname);
    243 		if ((ipn = ia->ia_pnpcompatnames) != NULL) {
    244 			aprint_normal(" (");	/* ) */
    245 			for (sep = ""; ipn != NULL;
    246 			     ipn = ipn->ipn_next, sep = " ") {
    247 				aprint_normal("%s%s", sep, ipn->ipn_name);
    248 			}
    249 	/* ( */		aprint_normal(")");
    250 		}
    251 		aprint_normal(" at %s", isa);
    252 	}
    253 
    254 	if (ia->ia_nio) {
    255 		sep = "";
    256 		aprint_normal(" port ");
    257 		for (i = 0; i < ia->ia_nio; i++) {
    258 			if (ia->ia_io[i].ir_size == 0)
    259 				continue;
    260 			aprint_normal("%s0x%x", sep, ia->ia_io[i].ir_addr);
    261 			if (ia->ia_io[i].ir_size > 1)
    262 				aprint_normal("-0x%x", ia->ia_io[i].ir_addr +
    263 				    ia->ia_io[i].ir_size - 1);
    264 			sep = ",";
    265 		}
    266 	}
    267 
    268 	if (ia->ia_niomem) {
    269 		sep = "";
    270 		aprint_normal(" iomem ");
    271 		for (i = 0; i < ia->ia_niomem; i++) {
    272 			if (ia->ia_iomem[i].ir_size == 0)
    273 				continue;
    274 			aprint_normal("%s0x%x", sep, ia->ia_iomem[i].ir_addr);
    275 			if (ia->ia_iomem[i].ir_size > 1)
    276 				aprint_normal("-0x%x", ia->ia_iomem[i].ir_addr +
    277 				    ia->ia_iomem[i].ir_size - 1);
    278 			sep = ",";
    279 		}
    280 	}
    281 
    282 	if (ia->ia_nirq) {
    283 		sep = "";
    284 		aprint_normal(" irq ");
    285 		for (i = 0; i < ia->ia_nirq; i++) {
    286 			if (ia->ia_irq[i].ir_irq == ISACF_IRQ_DEFAULT)
    287 				continue;
    288 			aprint_normal("%s%d", sep, ia->ia_irq[i].ir_irq);
    289 			sep = ",";
    290 		}
    291 	}
    292 
    293 	if (ia->ia_ndrq) {
    294 		sep = "";
    295 		aprint_normal(" drq ");
    296 		for (i = 0; i < ia->ia_ndrq; i++) {
    297 			if (ia->ia_drq[i].ir_drq == ISACF_DRQ_DEFAULT)
    298 				continue;
    299 			aprint_normal("%s%d", sep, ia->ia_drq[i].ir_drq);
    300 			sep = ",";
    301 		}
    302 	}
    303 
    304 	return (UNCONF);
    305 }
    306 
    307 int
    308 isasearch(device_t parent, cfdata_t cf, const int *slocs, void *aux)
    309 {
    310 	struct isa_io res_io[1];
    311 	struct isa_iomem res_mem[1];
    312 	struct isa_irq res_irq[1];
    313 	struct isa_drq res_drq[2];
    314 	struct isa_softc *sc = device_private(parent);
    315 	struct isa_attach_args ia;
    316 	int flocs[ISACF_NLOCS];
    317 	int tryagain;
    318 
    319 	do {
    320 		ia.ia_pnpname = NULL;
    321 		ia.ia_pnpcompatnames = NULL;
    322 
    323 		res_io[0].ir_addr = cf->cf_loc[ISACF_PORT];
    324 		res_io[0].ir_size = 0;
    325 
    326 		res_mem[0].ir_addr = cf->cf_loc[ISACF_IOMEM];
    327 		res_mem[0].ir_size = cf->cf_loc[ISACF_IOSIZ];
    328 
    329 		res_irq[0].ir_irq =
    330 		    cf->cf_loc[ISACF_IRQ] == 2 ? 9 : cf->cf_loc[ISACF_IRQ];
    331 
    332 		res_drq[0].ir_drq = cf->cf_loc[ISACF_DRQ];
    333 		res_drq[1].ir_drq = cf->cf_loc[ISACF_DRQ2];
    334 
    335 		ia.ia_iot = sc->sc_iot;
    336 		ia.ia_memt = sc->sc_memt;
    337 		ia.ia_dmat = sc->sc_dmat;
    338 		ia.ia_ic = sc->sc_ic;
    339 
    340 		ia.ia_io = res_io;
    341 		ia.ia_nio = 1;
    342 
    343 		ia.ia_iomem = res_mem;
    344 		ia.ia_niomem = 1;
    345 
    346 		ia.ia_irq = res_irq;
    347 		ia.ia_nirq = 1;
    348 
    349 		ia.ia_drq = res_drq;
    350 		ia.ia_ndrq = 2;
    351 
    352 		if (!checkattachargs(&ia, slocs))
    353 			return (0);
    354 
    355 		tryagain = 0;
    356 		if (config_probe(parent, cf, &ia)) {
    357 			/*
    358 			 * This is not necessary for detach, but might
    359 			 * still be useful to collect device information.
    360 			 */
    361 			flocs[ISACF_PORT] = ia.ia_io[0].ir_addr;
    362 			flocs[ISACF_SIZE] = ia.ia_io[0].ir_size;
    363 			flocs[ISACF_IOMEM] = ia.ia_iomem[0].ir_addr;
    364 			flocs[ISACF_IOSIZ] = ia.ia_iomem[0].ir_size;
    365 			flocs[ISACF_IRQ] = ia.ia_irq[0].ir_irq;
    366 			flocs[ISACF_DRQ] = ia.ia_drq[0].ir_drq;
    367 			flocs[ISACF_DRQ2] = ia.ia_drq[1].ir_drq;
    368 			config_attach(parent, cf, &ia, isaprint,
    369 			    CFARGS(.locators = flocs));
    370 			tryagain = (cf->cf_fstate == FSTATE_STAR);
    371 		}
    372 	} while (tryagain);
    373 
    374 	return (0);
    375 }
    376 
    377 const char *
    378 isa_intr_typename(int type)
    379 {
    380 
    381 	switch (type) {
    382 	case IST_NONE:
    383 		return ("none");
    384 	case IST_PULSE:
    385 		return ("pulsed");
    386 	case IST_EDGE:
    387 		return ("edge-triggered");
    388 	case IST_LEVEL:
    389 		return ("level-triggered");
    390 	default:
    391 		panic("isa_intr_typename: invalid type %d", type);
    392 	}
    393 }
    394 
    395 int
    396 isa_get_slotcount(void)
    397 {
    398 
    399 	return isa_slotcount;
    400 }
    401 
    402 void
    403 isa_set_slotcount(int arg)
    404 {
    405 
    406 	isa_slotcount = arg;
    407 }
    408