1 /* $NetBSD: isabus.c,v 1.15 2001/06/13 15:03:25 soda 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 extern int cold; 303 304 /* no point in sleeping unless someone can free memory. */ 305 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 306 if (ih == NULL) 307 panic("isa_intr_establish: can't malloc handler info"); 308 309 if (!LEGAL_IRQ(irq) || type == IST_NONE) 310 panic("intr_establish: bogus irq or type"); 311 312 switch (intrtype[irq]) { 313 case IST_EDGE: 314 case IST_LEVEL: 315 if (type == intrtype[irq]) 316 break; 317 case IST_PULSE: 318 if (type != IST_NONE) 319 panic("intr_establish: can't share %s with %s", 320 isa_intr_typename(intrtype[irq]), 321 isa_intr_typename(type)); 322 break; 323 } 324 325 /* 326 * Figure out where to put the handler. 327 * This is O(N^2), but we want to preserve the order, and N is 328 * generally small. 329 */ 330 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) 331 ; 332 333 /* 334 * Actually install a fake handler momentarily, since we might be doing 335 * this with interrupts enabled and don't want the real routine called 336 * until masking is set up. 337 */ 338 fakehand.ih_level = level; 339 *p = &fakehand; 340 341 intr_calculatemasks(); 342 343 /* 344 * Poke the real handler in now. 345 */ 346 ih->ih_fun = ih_fun; 347 ih->ih_arg = ih_arg; 348 ih->ih_count = 0; 349 ih->ih_next = NULL; 350 ih->ih_level = level; 351 ih->ih_irq = irq; 352 ih->ih_what = ""; /* XXX - should be eliminated */ 353 *p = ih; 354 355 return (ih); 356 } 357 358 void 359 isabr_intr_disestablish(ic, arg) 360 isa_chipset_tag_t ic; 361 void *arg; 362 { 363 364 } 365 366 /* 367 * Process an interrupt from the ISA bus. 368 */ 369 int 370 isabr_iointr(mask, cf) 371 unsigned mask; 372 struct clockframe *cf; 373 { 374 struct intrhand *ih; 375 int isa_vector; 376 int o_imen; 377 378 isa_vector = (*isabr_conf->ic_intr_status)(); 379 if (isa_vector < 0) 380 return (~0); 381 382 o_imen = imen; 383 imen |= 1 << (isa_vector & (ICU_LEN - 1)); 384 if(isa_vector & 0x08) { 385 isa_inb(IO_ICU2 + 1); 386 isa_outb(IO_ICU2 + 1, imen >> 8); 387 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7)); 388 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE); 389 } 390 else { 391 isa_inb(IO_ICU1 + 1); 392 isa_outb(IO_ICU1 + 1, imen); 393 isa_outb(IO_ICU1, 0x60 + isa_vector); 394 } 395 ih = intrhand[isa_vector]; 396 if(isa_vector == 0) { /* Clock */ /*XXX*/ 397 (*ih->ih_fun)(cf); 398 ih = ih->ih_next; 399 } 400 while(ih) { 401 (*ih->ih_fun)(ih->ih_arg); 402 ih = ih->ih_next; 403 } 404 imen = o_imen; 405 isa_inb(IO_ICU1 + 1); 406 isa_inb(IO_ICU2 + 1); 407 isa_outb(IO_ICU1 + 1, imen); 408 isa_outb(IO_ICU2 + 1, imen >> 8); 409 410 return(~0); /* Dont reenable */ 411 } 412 413 414 /* 415 * Initialize the Interrupt controller logic. 416 */ 417 void 418 isabr_initicu() 419 { 420 421 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 422 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */ 423 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ 424 isa_outb(IO_ICU1+1, 1); /* 8086 mode */ 425 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 426 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */ 427 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */ 428 #ifdef REORDER_IRQ 429 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 430 #endif 431 432 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 433 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */ 434 isa_outb(IO_ICU2+1, IRQ_SLAVE); 435 isa_outb(IO_ICU2+1, 1); /* 8086 mode */ 436 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 437 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */ 438 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */ 439 } 440 441 442 /* 443 * SPEAKER BEEPER... 444 */ 445 void 446 sysbeepstop(arg) 447 void *arg; 448 { 449 int s; 450 451 /* disable counter 2 */ 452 s = splhigh(); 453 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR); 454 splx(s); 455 beeping = 0; 456 } 457 458 void 459 sysbeep(pitch, period) 460 int pitch, period; 461 { 462 static int last_pitch, last_period; 463 int s; 464 extern int cold; 465 466 if (cold) 467 return; /* Can't beep yet. */ 468 469 if (beeping) 470 callout_stop(&sysbeep_ch); 471 if (!beeping || last_pitch != pitch) { 472 s = splhigh(); 473 isa_outb(IO_TIMER1 + TIMER_MODE, 474 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); 475 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256); 476 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256); 477 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR); 478 splx(s); 479 } 480 last_pitch = pitch; 481 beeping = last_period = period; 482 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL); 483 } 484