Home | History | Annotate | Line # | Download | only in isa
isabus.c revision 1.17
      1 /*	$NetBSD: isabus.c,v 1.17 2003/01/01 00:32:04 thorpej 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 (at) 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                 aprint_normal("%s at %s", ca->ca_name, pnp);
    177         aprint_verbose(" 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