1 /* $OpenBSD: isa.c,v 1.50 2022/04/06 18:59:28 naddy Exp $ */
2 /* $NetBSD: isa.c,v 1.85 1996/05/14 00:31:04 thorpej Exp $ */
3
4 /*
5 * Copyright (c) 1997, Jason Downs. 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.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*-
30 * Copyright (c) 1993, 1994 Charles Hannum. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by Charles Hannum.
43 * 4. The name of the author may not be used to endorse or promote products
44 * derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/kernel.h>
61 #include <sys/conf.h>
62 #include <sys/malloc.h>
63 #include <sys/device.h>
64 #include <sys/extent.h>
65
66 #include <dev/isa/isareg.h>
67 #include <dev/isa/isavar.h>
68 #include <dev/isa/isadmareg.h>
69
70 int isamatch(struct device *, void *, void *);
71 void isaattach(struct device *, struct device *, void *);
72
73 extern int autoconf_verbose;
74
75 const struct cfattach isa_ca = {
76 sizeof(struct isa_softc), isamatch, isaattach
77 };
78
79 struct cfdriver isa_cd = {
80 NULL, "isa", DV_DULL, CD_INDIRECT
81 };
82
83 int
isamatch(struct device * parent,void * match,void * aux)84 isamatch(struct device *parent, void *match, void *aux)
85 {
86 struct cfdata *cf = match;
87 struct isabus_attach_args *iba = aux;
88
89 if (strcmp(iba->iba_busname, cf->cf_driver->cd_name))
90 return (0);
91
92 /* XXX check other indicators */
93
94 return (1);
95 }
96
97 void
isaattach(struct device * parent,struct device * self,void * aux)98 isaattach(struct device *parent, struct device *self, void *aux)
99 {
100 struct isa_softc *sc = (struct isa_softc *)self;
101 struct isabus_attach_args *iba = aux;
102
103 isa_attach_hook(parent, self, iba);
104 printf("\n");
105
106 sc->sc_iot = iba->iba_iot;
107 sc->sc_memt = iba->iba_memt;
108 #if NISADMA > 0
109 sc->sc_dmat = iba->iba_dmat;
110 #endif /* NISADMA > 0 */
111 sc->sc_ic = iba->iba_ic;
112
113 #if NISAPNP > 0
114 isapnp_isa_attach_hook(sc);
115 #endif
116
117 #if NISADMA > 0
118 /*
119 * Map the registers used by the ISA DMA controller.
120 * XXX Should be done in the isadmaattach routine.. but the delay
121 * XXX port makes it troublesome. Note that these aren't really
122 * XXX valid on ISA busses without DMA.
123 */
124 if (bus_space_map(sc->sc_iot, IO_DMA1, DMA1_IOSIZE, 0, &sc->sc_dma1h))
125 panic("isaattach: can't map DMA controller #1");
126 if (bus_space_map(sc->sc_iot, IO_DMA2, DMA2_IOSIZE, 0, &sc->sc_dma2h))
127 panic("isaattach: can't map DMA controller #2");
128 if (bus_space_map(sc->sc_iot, IO_DMAPG, 0xf, 0, &sc->sc_dmapgh))
129 panic("isaattach: can't map DMA page registers");
130
131 /*
132 * Map port 0x84, which causes a 1.25us delay when read.
133 * We do this now, since several drivers need it.
134 * XXX this port doesn't exist on all ISA busses...
135 */
136 if (bus_space_subregion(sc->sc_iot, sc->sc_dmapgh, 0x04, 1,
137 &sc->sc_delaybah))
138 #else /* NISADMA > 0 */
139 if (bus_space_map(sc->sc_iot, IO_DMAPG + 0x4, 0x1, 0,
140 &sc->sc_delaybah))
141 #endif /* NISADMA > 0 */
142 panic("isaattach: can't map `delay port'"); /* XXX */
143
144 TAILQ_INIT(&sc->sc_subdevs);
145 config_scan(isascan, self);
146 }
147
148 int
isaprint(void * aux,const char * isa)149 isaprint(void *aux, const char *isa)
150 {
151 struct isa_attach_args *ia = aux;
152 int irq, nirq;
153 int dma, ndma;
154
155 if (ia->ia_iosize)
156 printf(" port 0x%x", ia->ia_iobase);
157 if (ia->ia_iosize > 1)
158 printf("/%d", ia->ia_iosize);
159
160 if (ia->ia_msize)
161 printf(" iomem 0x%x", ia->ia_maddr);
162 if (ia->ia_msize > 1)
163 printf("/%d", ia->ia_msize);
164
165 nirq = ia->ipa_nirq;
166 if (nirq < 0 || nirq > nitems(ia->ipa_irq))
167 nirq = 1;
168 for (irq = 0; irq < nirq; irq++)
169 if (ia->ipa_irq[irq].num != IRQUNK)
170 printf(" irq %d", ia->ipa_irq[irq].num);
171
172 ndma = ia->ipa_ndrq;
173 if (ndma < 0 || ndma > nitems(ia->ipa_drq))
174 ndma = 2;
175 for (dma = 0; dma < ndma; dma++)
176 if (ia->ipa_drq[dma].num != DRQUNK) {
177 if (dma == 0)
178 printf(" drq");
179 else
180 printf(" drq%d", dma + 1);
181 printf(" %d", ia->ipa_drq[dma].num);
182 }
183
184 return (UNCONF);
185 }
186
187 void
isascan(struct device * parent,void * match)188 isascan(struct device *parent, void *match)
189 {
190 struct isa_softc *sc = (struct isa_softc *)parent;
191 struct device *dev = match;
192 struct cfdata *cf = dev->dv_cfdata;
193 struct isa_attach_args ia;
194
195 ia.ia_iot = sc->sc_iot;
196 ia.ia_memt = sc->sc_memt;
197 #if NISADMA > 0
198 ia.ia_dmat = sc->sc_dmat;
199 #endif /* NISADMA > 0 */
200 ia.ia_ic = sc->sc_ic;
201 ia.ia_iobase = cf->cf_iobase;
202 ia.ia_iosize = 0x666;
203 ia.ia_maddr = cf->cf_maddr;
204 ia.ia_msize = cf->cf_msize;
205 ia.ia_irq = cf->cf_irq == 2 ? 9 : cf->cf_irq;
206 ia.ipa_nirq = ia.ia_irq == IRQUNK ? 0 : 1;
207 ia.ia_drq = cf->cf_drq;
208 ia.ia_drq2 = cf->cf_drq2;
209 ia.ipa_ndrq = 2;
210 ia.ia_delaybah = sc->sc_delaybah;
211
212 if (cf->cf_fstate == FSTATE_STAR) {
213 struct isa_attach_args ia2 = ia;
214
215 if (autoconf_verbose)
216 printf(">>> probing for %s*\n",
217 cf->cf_driver->cd_name);
218 while ((*cf->cf_attach->ca_match)(parent, dev, &ia2) > 0) {
219 #if !defined(__NO_ISA_INTR_CHECK)
220 if ((ia2.ia_irq != IRQUNK) &&
221 !isa_intr_check(sc->sc_ic, ia2.ia_irq, IST_EDGE)) {
222 printf("%s%d: irq %d already in use\n",
223 cf->cf_driver->cd_name, cf->cf_unit,
224 ia2.ia_irq);
225 ia2 = ia;
226 break;
227 }
228 #endif
229
230 if (autoconf_verbose)
231 printf(">>> probe for %s* clone into %s%d\n",
232 cf->cf_driver->cd_name,
233 cf->cf_driver->cd_name, cf->cf_unit);
234 if (ia2.ia_iosize == 0x666) {
235 printf("%s: iosize not repaired by driver\n",
236 sc->sc_dev.dv_xname);
237 ia2.ia_iosize = 0;
238 }
239 config_attach(parent, dev, &ia2, isaprint);
240 dev = config_make_softc(parent, cf);
241 #if NISADMA > 0
242 if (ia2.ia_drq != DRQUNK)
243 ISA_DRQ_ALLOC((struct device *)sc, ia2.ia_drq);
244 if (ia2.ia_drq2 != DRQUNK)
245 ISA_DRQ_ALLOC((struct device *)sc, ia2.ia_drq2);
246 #endif /* NISAMDA > 0 */
247 ia2 = ia;
248 }
249 if (autoconf_verbose)
250 printf(">>> probing for %s* finished\n",
251 cf->cf_driver->cd_name);
252 free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
253 return;
254 }
255
256 if (autoconf_verbose)
257 printf(">>> probing for %s%d\n", cf->cf_driver->cd_name,
258 cf->cf_unit);
259 if ((*cf->cf_attach->ca_match)(parent, dev, &ia) > 0) {
260 #if !defined(__NO_ISA_INTR_CHECK)
261 if ((ia.ia_irq != IRQUNK) &&
262 !isa_intr_check(sc->sc_ic, ia.ia_irq, IST_EDGE)) {
263 printf("%s%d: irq %d already in use\n",
264 cf->cf_driver->cd_name, cf->cf_unit, ia.ia_irq);
265 free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
266 } else {
267 #endif
268 if (autoconf_verbose)
269 printf(">>> probing for %s%d succeeded\n",
270 cf->cf_driver->cd_name, cf->cf_unit);
271 config_attach(parent, dev, &ia, isaprint);
272
273 #if NISADMA > 0
274 if (ia.ia_drq != DRQUNK)
275 ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq);
276 if (ia.ia_drq2 != DRQUNK)
277 ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq2);
278 #endif /* NISAMDA > 0 */
279 #if !defined(__NO_ISA_INTR_CHECK)
280 }
281 #endif
282 } else {
283 if (autoconf_verbose)
284 printf(">>> probing for %s%d failed\n",
285 cf->cf_driver->cd_name, cf->cf_unit);
286 free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
287 }
288 }
289
290 char *
isa_intr_typename(int type)291 isa_intr_typename(int type)
292 {
293
294 switch (type) {
295 case IST_NONE:
296 return ("none");
297 case IST_PULSE:
298 return ("pulsed");
299 case IST_EDGE:
300 return ("edge-triggered");
301 case IST_LEVEL:
302 return ("level-triggered");
303 default:
304 panic("isa_intr_typename: invalid type %d", type);
305 }
306 }
307