1 /* $NetBSD: isabus.c,v 1.16 2002/03/04 02:19:07 simonb Exp $ */ 2 /* $OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $ */ 3 /* NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp */ 4 5 /*- 6 * Copyright (c) 1995 Per Fogelstrom 7 * Copyright (c) 1993, 1994 Charles M. Hannum. 8 * Copyright (c) 1990 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * William Jolitz and Don Ahn. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * @(#)isa.c 7.2 (Berkeley) 5/12/91 43 */ 44 /* 45 * Mach Operating System 46 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 47 * All Rights Reserved. 48 * 49 * Permission to use, copy, modify and distribute this software and its 50 * documentation is hereby granted, provided that both the copyright 51 * notice and this permission notice appear in all copies of the 52 * software, derivative works or modified versions, and any portions 53 * thereof, and that both notices appear in supporting documentation. 54 * 55 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 56 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 57 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 58 * 59 * Carnegie Mellon requests users of this software to return to 60 * 61 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 62 * School of Computer Science 63 * Carnegie Mellon University 64 * Pittsburgh PA 15213-3890 65 * 66 * any improvements or extensions that they make and grant Carnegie Mellon 67 * the rights to redistribute these changes. 68 */ 69 /* 70 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 71 72 All Rights Reserved 73 74 Permission to use, copy, modify, and distribute this software and 75 its documentation for any purpose and without fee is hereby 76 granted, provided that the above copyright notice appears in all 77 copies and that both the copyright notice and this permission notice 78 appear in supporting documentation, and that the name of Intel 79 not be used in advertising or publicity pertaining to distribution 80 of the software without specific, written prior permission. 81 82 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 83 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 84 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 85 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 86 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 87 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 88 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 89 */ 90 91 #include <sys/param.h> 92 #include <sys/proc.h> 93 #include <sys/user.h> 94 #include <sys/systm.h> 95 #include <sys/callout.h> 96 #include <sys/time.h> 97 #include <sys/kernel.h> 98 #include <sys/device.h> 99 #include <sys/malloc.h> 100 101 #include <uvm/uvm_extern.h> 102 103 #include <machine/cpu.h> 104 #include <machine/pio.h> 105 #include <machine/autoconf.h> 106 #include <machine/intr.h> 107 108 #include <dev/ic/i8253reg.h> 109 #include <dev/isa/isareg.h> 110 #include <dev/isa/isavar.h> 111 #include <arc/isa/isabrvar.h> 112 #include <arc/isa/spkrreg.h> 113 114 static int beeping; 115 static struct callout sysbeep_ch = CALLOUT_INITIALIZER; 116 117 #define IRQ_SLAVE 2 118 119 /* Definition of the driver for autoconfig. */ 120 int isabrprint(void *, const char *); 121 122 extern struct arc_bus_space arc_bus_io, arc_bus_mem; 123 124 void isabr_attach_hook __P((struct device *, struct device *, 125 struct isabus_attach_args *)); 126 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int)); 127 void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int, 128 int (*)(void *), void *)); 129 void isabr_intr_disestablish __P((isa_chipset_tag_t, void*)); 130 int isabr_iointr __P((unsigned int, struct clockframe *)); 131 void isabr_initicu __P((void)); 132 void intr_calculatemasks __P((void)); 133 int fakeintr __P((void *a)); 134 135 struct isabr_config *isabr_conf = NULL; 136 137 void 138 isabrattach(sc) 139 struct isabr_softc *sc; 140 { 141 struct isabus_attach_args iba; 142 143 if (isabr_conf == NULL) 144 panic("isabr_conf isn't initialized"); 145 146 printf("\n"); 147 148 /* Initialize interrupt controller */ 149 isabr_initicu(); 150 151 /*XXX we may remove the abus part of the softc struct... */ 152 sc->sc_bus.ab_dv = (struct device *)sc; 153 sc->sc_bus.ab_type = BUS_ISABR; 154 155 sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook; 156 sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt; 157 sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish; 158 sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish; 159 160 iba.iba_busname = "isa"; 161 iba.iba_iot = &arc_bus_io; 162 iba.iba_memt = &arc_bus_mem; 163 iba.iba_dmat = &sc->sc_dmat; 164 iba.iba_ic = &sc->arc_isa_cs; 165 config_found(&sc->sc_dev, &iba, isabrprint); 166 } 167 168 int 169 isabrprint(aux, pnp) 170 void *aux; 171 const char *pnp; 172 { 173 struct confargs *ca = aux; 174 175 if (pnp) 176 printf("%s at %s", ca->ca_name, pnp); 177 printf(" isa_io_base 0x%lx isa_mem_base 0x%lx", 178 arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase); 179 return (UNCONF); 180 } 181 182 183 /* 184 * Interrupt system driver code 185 * ============================ 186 */ 187 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) 188 189 int imen; 190 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN]; 191 struct intrhand *intrhand[ICU_LEN]; 192 193 int fakeintr(a) 194 void *a; 195 { 196 return 0; 197 } 198 199 /* 200 * Recalculate the interrupt masks from scratch. 201 * We could code special registry and deregistry versions of this function that 202 * would be faster, but the code would be nastier, and we don't expect this to 203 * happen very much anyway. 204 */ 205 void 206 intr_calculatemasks() 207 { 208 int irq, level; 209 struct intrhand *q; 210 211 /* First, figure out which levels each IRQ uses. */ 212 for (irq = 0; irq < ICU_LEN; irq++) { 213 register int levels = 0; 214 for (q = intrhand[irq]; q; q = q->ih_next) 215 levels |= 1 << q->ih_level; 216 intrlevel[irq] = levels; 217 } 218 219 /* Then figure out which IRQs use each level. */ 220 for (level = 0; level < 5; level++) { 221 register int irqs = 0; 222 for (irq = 0; irq < ICU_LEN; irq++) 223 if (intrlevel[irq] & (1 << level)) 224 irqs |= 1 << irq; 225 imask[level] = irqs | SIR_ALLMASK; 226 } 227 228 /* 229 * There are tty, network and disk drivers that use free() at interrupt 230 * time, so imp > (tty | net | bio). 231 */ 232 imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO]; 233 234 /* 235 * Enforce a hierarchy that gives slow devices a better chance at not 236 * dropping data. 237 */ 238 imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO]; 239 imask[IPL_NET] |= imask[IPL_BIO]; 240 241 /* 242 * These are pseudo-levels. 243 */ 244 imask[IPL_NONE] = 0x00000000; 245 imask[IPL_HIGH] = 0xffffffff; 246 247 /* And eventually calculate the complete masks. */ 248 for (irq = 0; irq < ICU_LEN; irq++) { 249 register int irqs = 1 << irq; 250 for (q = intrhand[irq]; q; q = q->ih_next) 251 irqs |= imask[q->ih_level]; 252 intrmask[irq] = irqs | SIR_ALLMASK; 253 } 254 255 /* Lastly, determine which IRQs are actually in use. */ 256 { 257 register int irqs = 0; 258 for (irq = 0; irq < ICU_LEN; irq++) 259 if (intrhand[irq]) 260 irqs |= 1 << irq; 261 if (irqs >= 0x100) /* any IRQs >= 8 in use */ 262 irqs |= 1 << IRQ_SLAVE; 263 imen = ~irqs; 264 isa_outb(IO_ICU1 + 1, imen); 265 isa_outb(IO_ICU2 + 1, imen >> 8); 266 } 267 } 268 269 void 270 isabr_attach_hook(parent, self, iba) 271 struct device *parent, *self; 272 struct isabus_attach_args *iba; 273 { 274 275 /* Nothing to do. */ 276 } 277 278 const struct evcnt * 279 isabr_intr_evcnt(ic, irq) 280 isa_chipset_tag_t ic; 281 int irq; 282 { 283 284 /* XXX for now, no evcnt parent reported */ 285 return NULL; 286 } 287 288 /* 289 * Establish a ISA bus interrupt. 290 */ 291 void * 292 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg) 293 isa_chipset_tag_t ic; 294 int irq; 295 int type; 296 int level; 297 int (*ih_fun) __P((void *)); 298 void *ih_arg; 299 { 300 struct intrhand **p, *q, *ih; 301 static struct intrhand fakehand = {NULL, fakeintr}; 302 303 /* no point in sleeping unless someone can free memory. */ 304 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 305 if (ih == NULL) 306 panic("isa_intr_establish: can't malloc handler info"); 307 308 if (!LEGAL_IRQ(irq) || type == IST_NONE) 309 panic("intr_establish: bogus irq or type"); 310 311 switch (intrtype[irq]) { 312 case IST_EDGE: 313 case IST_LEVEL: 314 if (type == intrtype[irq]) 315 break; 316 case IST_PULSE: 317 if (type != IST_NONE) 318 panic("intr_establish: can't share %s with %s", 319 isa_intr_typename(intrtype[irq]), 320 isa_intr_typename(type)); 321 break; 322 } 323 324 /* 325 * Figure out where to put the handler. 326 * This is O(N^2), but we want to preserve the order, and N is 327 * generally small. 328 */ 329 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) 330 ; 331 332 /* 333 * Actually install a fake handler momentarily, since we might be doing 334 * this with interrupts enabled and don't want the real routine called 335 * until masking is set up. 336 */ 337 fakehand.ih_level = level; 338 *p = &fakehand; 339 340 intr_calculatemasks(); 341 342 /* 343 * Poke the real handler in now. 344 */ 345 ih->ih_fun = ih_fun; 346 ih->ih_arg = ih_arg; 347 ih->ih_count = 0; 348 ih->ih_next = NULL; 349 ih->ih_level = level; 350 ih->ih_irq = irq; 351 ih->ih_what = ""; /* XXX - should be eliminated */ 352 *p = ih; 353 354 return (ih); 355 } 356 357 void 358 isabr_intr_disestablish(ic, arg) 359 isa_chipset_tag_t ic; 360 void *arg; 361 { 362 363 } 364 365 /* 366 * Process an interrupt from the ISA bus. 367 */ 368 int 369 isabr_iointr(mask, cf) 370 unsigned mask; 371 struct clockframe *cf; 372 { 373 struct intrhand *ih; 374 int isa_vector; 375 int o_imen; 376 377 isa_vector = (*isabr_conf->ic_intr_status)(); 378 if (isa_vector < 0) 379 return (~0); 380 381 o_imen = imen; 382 imen |= 1 << (isa_vector & (ICU_LEN - 1)); 383 if(isa_vector & 0x08) { 384 isa_inb(IO_ICU2 + 1); 385 isa_outb(IO_ICU2 + 1, imen >> 8); 386 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7)); 387 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE); 388 } 389 else { 390 isa_inb(IO_ICU1 + 1); 391 isa_outb(IO_ICU1 + 1, imen); 392 isa_outb(IO_ICU1, 0x60 + isa_vector); 393 } 394 ih = intrhand[isa_vector]; 395 if(isa_vector == 0) { /* Clock */ /*XXX*/ 396 (*ih->ih_fun)(cf); 397 ih = ih->ih_next; 398 } 399 while(ih) { 400 (*ih->ih_fun)(ih->ih_arg); 401 ih = ih->ih_next; 402 } 403 imen = o_imen; 404 isa_inb(IO_ICU1 + 1); 405 isa_inb(IO_ICU2 + 1); 406 isa_outb(IO_ICU1 + 1, imen); 407 isa_outb(IO_ICU2 + 1, imen >> 8); 408 409 return(~0); /* Dont reenable */ 410 } 411 412 413 /* 414 * Initialize the Interrupt controller logic. 415 */ 416 void 417 isabr_initicu() 418 { 419 420 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 421 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */ 422 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ 423 isa_outb(IO_ICU1+1, 1); /* 8086 mode */ 424 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 425 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */ 426 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */ 427 #ifdef REORDER_IRQ 428 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 429 #endif 430 431 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 432 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */ 433 isa_outb(IO_ICU2+1, IRQ_SLAVE); 434 isa_outb(IO_ICU2+1, 1); /* 8086 mode */ 435 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 436 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */ 437 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */ 438 } 439 440 441 /* 442 * SPEAKER BEEPER... 443 */ 444 void 445 sysbeepstop(arg) 446 void *arg; 447 { 448 int s; 449 450 /* disable counter 2 */ 451 s = splhigh(); 452 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR); 453 splx(s); 454 beeping = 0; 455 } 456 457 void 458 sysbeep(pitch, period) 459 int pitch, period; 460 { 461 static int last_pitch, last_period; 462 int s; 463 464 if (cold) 465 return; /* Can't beep yet. */ 466 467 if (beeping) 468 callout_stop(&sysbeep_ch); 469 if (!beeping || last_pitch != pitch) { 470 s = splhigh(); 471 isa_outb(IO_TIMER1 + TIMER_MODE, 472 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); 473 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256); 474 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256); 475 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR); 476 splx(s); 477 } 478 last_pitch = pitch; 479 beeping = last_period = period; 480 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL); 481 } 482