Home | History | Annotate | Line # | Download | only in isa
isabus.c revision 1.15
      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 (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                 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