isa.c revision 6512
14Srgrimes/*- 24Srgrimes * Copyright (c) 1991 The Regents of the University of California. 34Srgrimes * All rights reserved. 44Srgrimes * 54Srgrimes * This code is derived from software contributed to Berkeley by 64Srgrimes * William Jolitz. 74Srgrimes * 84Srgrimes * Redistribution and use in source and binary forms, with or without 94Srgrimes * modification, are permitted provided that the following conditions 104Srgrimes * are met: 114Srgrimes * 1. Redistributions of source code must retain the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer. 134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer in the 154Srgrimes * documentation and/or other materials provided with the distribution. 164Srgrimes * 3. All advertising materials mentioning features or use of this software 174Srgrimes * must display the following acknowledgement: 184Srgrimes * This product includes software developed by the University of 194Srgrimes * California, Berkeley and its contributors. 204Srgrimes * 4. Neither the name of the University nor the names of its contributors 214Srgrimes * may be used to endorse or promote products derived from this software 224Srgrimes * without specific prior written permission. 234Srgrimes * 244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 274Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 344Srgrimes * SUCH DAMAGE. 354Srgrimes * 36593Srgrimes * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 376512Sphk * $Id: isa.c,v 1.36 1994/11/03 04:15:03 jkh Exp $ 384Srgrimes */ 394Srgrimes 404Srgrimes/* 414Srgrimes * code to manage AT bus 424Srgrimes * 434Srgrimes * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): 444Srgrimes * Fixed uninitialized variable problem and added code to deal 454Srgrimes * with DMA page boundaries in isa_dmarangecheck(). Fixed word 464Srgrimes * mode DMA count compution and reorganized DMA setup code in 474Srgrimes * isa_dmastart() 484Srgrimes */ 494Srgrimes 502056Swollman#include <sys/param.h> 512056Swollman#include <sys/systm.h> /* isn't it a joy */ 522056Swollman#include <sys/kernel.h> /* to have three of these */ 533871Sphk#include <sys/proc.h> 542056Swollman#include <sys/conf.h> 552056Swollman#include <sys/file.h> 562056Swollman#include <sys/buf.h> 572056Swollman#include <sys/uio.h> 582056Swollman#include <sys/syslog.h> 592056Swollman#include <sys/malloc.h> 602056Swollman#include <sys/rlist.h> 612056Swollman#include <machine/segments.h> 622056Swollman#include <vm/vm.h> 631549Srgrimes#include <machine/spl.h> 642056Swollman#include <i386/isa/isa_device.h> 652056Swollman#include <i386/isa/isa.h> 662056Swollman#include <i386/isa/icu.h> 672056Swollman#include <i386/isa/ic/i8237.h> 682056Swollman#include <i386/isa/ic/i8042.h> 693713Swollman#include <sys/devconf.h> 702103Sdg#include "vector.h" 714Srgrimes 724Srgrimes/* 734Srgrimes** Register definitions for DMA controller 1 (channels 0..3): 744Srgrimes*/ 754Srgrimes#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ 764Srgrimes#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ 774Srgrimes#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ 784Srgrimes#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ 794Srgrimes 804Srgrimes/* 814Srgrimes** Register definitions for DMA controller 2 (channels 4..7): 824Srgrimes*/ 83630Srgrimes#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */ 844Srgrimes#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ 854Srgrimes#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ 864Srgrimes#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ 874Srgrimes 882103Sdg/* 892103Sdg * Bits to specify the type and amount of conflict checking. 902103Sdg */ 912103Sdg#define CC_ATTACH (1 << 0) 922103Sdg#define CC_DRQ (1 << 1) 932103Sdg#define CC_IOADDR (1 << 2) 942103Sdg#define CC_IRQ (1 << 3) 952103Sdg#define CC_MEMADDR (1 << 4) 964Srgrimes 974Srgrimes/* 982103Sdg * XXX these defines should be in a central place. 992103Sdg */ 1002103Sdg#define read_eflags() ({u_long ef; \ 1012103Sdg __asm("pushfl; popl %0" : "=a" (ef)); \ 1022103Sdg ef; }) 1032103Sdg#define write_eflags(ef) __asm("pushl %0; popfl" : : "a" ((u_long)(ef))) 1042103Sdg 1052103Sdgu_long *intr_countp[ICU_LEN]; 1062103Sdginthand2_t *intr_handler[ICU_LEN]; 1072103Sdgu_int intr_mask[ICU_LEN]; 1082103Sdgint intr_unit[ICU_LEN]; 1092103Sdg 1103816Swollmanstruct kern_devconf kdc_isa0 = { 1113816Swollman 0, 0, 0, /* filled in by dev_attach */ 1123816Swollman "isa", 0, { MDDT_BUS, 0 }, 1133816Swollman 0, 0, 0, BUS_EXTERNALLEN, 1143816Swollman 0, /* no parent yet; parent should be CPU */ 1153816Swollman 0, /* no parentdata */ 1163816Swollman DC_BUSY, /* busses are always busy */ 1173816Swollman "ISA or EISA bus" 1183816Swollman}; 1193816Swollman 1202103Sdgstatic inthand_t *fastintr[ICU_LEN] = { 1212103Sdg &IDTVEC(fastintr0), &IDTVEC(fastintr1), 1222103Sdg &IDTVEC(fastintr2), &IDTVEC(fastintr3), 1232103Sdg &IDTVEC(fastintr4), &IDTVEC(fastintr5), 1242103Sdg &IDTVEC(fastintr6), &IDTVEC(fastintr7), 1252103Sdg &IDTVEC(fastintr8), &IDTVEC(fastintr9), 1262103Sdg &IDTVEC(fastintr10), &IDTVEC(fastintr11), 1272103Sdg &IDTVEC(fastintr12), &IDTVEC(fastintr13), 1282103Sdg &IDTVEC(fastintr14), &IDTVEC(fastintr15) 1292103Sdg}; 1302103Sdg 1312103Sdgstatic inthand_t *slowintr[ICU_LEN] = { 1322103Sdg &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), 1332103Sdg &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), 1342103Sdg &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), 1352103Sdg &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) 1362103Sdg}; 1372103Sdg 1382103Sdgstatic void config_isadev __P((struct isa_device *isdp, u_int *mp)); 1392103Sdgstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp, 1402103Sdg int item, char const *whatnot, char const *reason, 1412103Sdg char const *format)); 1422103Sdgstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp, 1432103Sdg u_int checkbits)); 1442103Sdgstatic int haveseen_isadev __P((struct isa_device *dvp, u_int checkbits)); 1452103Sdgstatic inthand2_t isa_strayintr; 1462103Sdgstatic void register_imask __P((struct isa_device *dvp, u_int mask)); 1472103Sdg 1482103Sdg/* 149593Srgrimes * print a conflict message 1504Srgrimes */ 1512103Sdgstatic void 1522103Sdgconflict(dvp, tmpdvp, item, whatnot, reason, format) 1532103Sdg struct isa_device *dvp; 1542103Sdg struct isa_device *tmpdvp; 155593Srgrimes int item; 1562103Sdg char const *whatnot; 1572103Sdg char const *reason; 1582103Sdg char const *format; 159593Srgrimes{ 1602103Sdg printf("%s%d not %sed due to %s conflict with %s%d at ", 1612103Sdg dvp->id_driver->name, dvp->id_unit, whatnot, reason, 162593Srgrimes tmpdvp->id_driver->name, tmpdvp->id_unit); 163593Srgrimes printf(format, item); 164593Srgrimes printf("\n"); 1654Srgrimes} 1664Srgrimes 1674Srgrimes/* 168593Srgrimes * Check to see if things are alread in use, like IRQ's, I/O addresses 169593Srgrimes * and Memory addresses. 1704Srgrimes */ 1712103Sdgstatic int 1722103Sdghaveseen(dvp, tmpdvp, checkbits) 1732103Sdg struct isa_device *dvp; 1742103Sdg struct isa_device *tmpdvp; 1752103Sdg u_int checkbits; 1764Srgrimes{ 177593Srgrimes /* 178593Srgrimes * Only check against devices that have already been found 179593Srgrimes */ 180593Srgrimes if (tmpdvp->id_alive) { 1812103Sdg char const *whatnot; 1822103Sdg 1832466Sats whatnot = checkbits & CC_ATTACH ? "attach" : "prob"; 184593Srgrimes /* 185593Srgrimes * Check for I/O address conflict. We can only check the 186593Srgrimes * starting address of the device against the range of the 187593Srgrimes * device that has already been probed since we do not 188593Srgrimes * know how many I/O addresses this device uses. 189593Srgrimes */ 1902103Sdg if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) { 191593Srgrimes if ((dvp->id_iobase >= tmpdvp->id_iobase) && 192593Srgrimes (dvp->id_iobase <= 193593Srgrimes (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) { 1942103Sdg conflict(dvp, tmpdvp, dvp->id_iobase, whatnot, 195593Srgrimes "I/O address", "0x%x"); 1963670Sphk return 1; 197593Srgrimes } 1984Srgrimes } 199593Srgrimes /* 200593Srgrimes * Check for Memory address conflict. We can check for 201593Srgrimes * range overlap, but it will not catch all cases since the 202593Srgrimes * driver may adjust the msize paramater during probe, for 203593Srgrimes * now we just check that the starting address does not 204593Srgrimes * fall within any allocated region. 205593Srgrimes * XXX could add a second check after the probe for overlap, 206593Srgrimes * since at that time we would know the full range. 207593Srgrimes * XXX KERNBASE is a hack, we should have vaddr in the table! 208593Srgrimes */ 2092103Sdg if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) { 2102103Sdg if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) && 2112103Sdg (KERNBASE + dvp->id_maddr <= 2122103Sdg (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) { 2132103Sdg conflict(dvp, tmpdvp, (int)dvp->id_maddr, 2142103Sdg whatnot, "maddr", "0x%x"); 2153670Sphk return 1; 2164Srgrimes } 217593Srgrimes } 218593Srgrimes /* 219593Srgrimes * Check for IRQ conflicts. 220593Srgrimes */ 2212103Sdg if (checkbits & CC_IRQ && tmpdvp->id_irq) { 222593Srgrimes if (tmpdvp->id_irq == dvp->id_irq) { 223593Srgrimes conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1, 2242103Sdg whatnot, "irq", "%d"); 2253670Sphk return 1; 2264Srgrimes } 227593Srgrimes } 228593Srgrimes /* 229593Srgrimes * Check for DRQ conflicts. 230593Srgrimes */ 2312103Sdg if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) { 232593Srgrimes if (tmpdvp->id_drq == dvp->id_drq) { 2332103Sdg conflict(dvp, tmpdvp, dvp->id_drq, whatnot, 2342103Sdg "drq", "%d"); 2353670Sphk return 1; 2364Srgrimes } 237593Srgrimes } 238593Srgrimes } 2393670Sphk return 0; 240593Srgrimes} 2414Srgrimes 242593Srgrimes/* 243593Srgrimes * Search through all the isa_devtab_* tables looking for anything that 244593Srgrimes * conflicts with the current device. 245593Srgrimes */ 2462103Sdgstatic int 2472103Sdghaveseen_isadev(dvp, checkbits) 248593Srgrimes struct isa_device *dvp; 2492103Sdg u_int checkbits; 250593Srgrimes{ 251593Srgrimes struct isa_device *tmpdvp; 252593Srgrimes int status = 0; 2534Srgrimes 2543670Sphk for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) { 2552103Sdg status |= haveseen(dvp, tmpdvp, checkbits); 2563670Sphk if (status) 2573670Sphk return status; 2583670Sphk } 2593670Sphk for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) { 2602103Sdg status |= haveseen(dvp, tmpdvp, checkbits); 2613670Sphk if (status) 2623670Sphk return status; 2633670Sphk } 2643670Sphk for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) { 2652103Sdg status |= haveseen(dvp, tmpdvp, checkbits); 2663670Sphk if (status) 2673670Sphk return status; 2683670Sphk } 2693670Sphk for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) { 2702103Sdg status |= haveseen(dvp, tmpdvp, checkbits); 2713670Sphk if (status) 2723670Sphk return status; 2733670Sphk } 274593Srgrimes return(status); 2754Srgrimes} 276593Srgrimes 2774Srgrimes/* 2784Srgrimes * Configure all ISA devices 2794Srgrimes */ 280593Srgrimesvoid 2814Srgrimesisa_configure() { 2824Srgrimes struct isa_device *dvp; 2834Srgrimes 2843816Swollman dev_attach(&kdc_isa0); 2853816Swollman 2862103Sdg splhigh(); 2874Srgrimes enable_intr(); 2884Srgrimes INTREN(IRQ_SLAVE); 289593Srgrimes printf("Probing for devices on the ISA bus:\n"); 2903670Sphk /* First probe all the sensitive probes */ 2912103Sdg for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 2923670Sphk if (dvp->id_driver->sensitive_hw) 2933670Sphk config_isadev(dvp, &tty_imask); 2942103Sdg for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 2953670Sphk if (dvp->id_driver->sensitive_hw) 2963670Sphk config_isadev(dvp, &bio_imask); 2972103Sdg for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 2983670Sphk if (dvp->id_driver->sensitive_hw) 2993670Sphk config_isadev(dvp, &net_imask); 3002103Sdg for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 3013670Sphk if (dvp->id_driver->sensitive_hw) 3023670Sphk config_isadev(dvp, (u_int *)NULL); 3033670Sphk 3043670Sphk /* Then all the bad ones */ 3053670Sphk for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 3063670Sphk if (!dvp->id_driver->sensitive_hw) 3073670Sphk config_isadev(dvp, &tty_imask); 3083670Sphk for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 3093670Sphk if (!dvp->id_driver->sensitive_hw) 3103670Sphk config_isadev(dvp, &bio_imask); 3113670Sphk for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 3123670Sphk if (!dvp->id_driver->sensitive_hw) 3133670Sphk config_isadev(dvp, &net_imask); 3143670Sphk for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 3153670Sphk if (!dvp->id_driver->sensitive_hw) 3163670Sphk config_isadev(dvp, (u_int *)NULL); 3173670Sphk 3181321Sdg bio_imask |= SWI_CLOCK_MASK; 3191321Sdg net_imask |= SWI_NET_MASK; 3201321Sdg tty_imask |= SWI_TTY_MASK; 3211321Sdg 322593Srgrimes/* 3231321Sdg * XXX we should really add the tty device to net_imask when the line is 324593Srgrimes * switched to SLIPDISC, and then remove it when it is switched away from 3251321Sdg * SLIPDISC. No need to block out ALL ttys during a splimp when only one 326593Srgrimes * of them is running slip. 3271321Sdg * 3281321Sdg * XXX actually, blocking all ttys during a splimp doesn't matter so much 3291321Sdg * with sio because the serial interrupt layer doesn't use tty_imask. Only 3301321Sdg * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked 3311321Sdg * during spltty. 332593Srgrimes */ 3334Srgrimes#include "sl.h" 3343705Swollman#include "ppp.h" 3353705Swollman 3363705Swollman#if (NSL > 0) || (NPPP > 0) 3371321Sdg net_imask |= tty_imask; 3381321Sdg tty_imask = net_imask; 3394Srgrimes#endif 3401321Sdg /* bio_imask |= tty_imask ; can some tty devices use buffers? */ 3411321Sdg#ifdef DIAGNOSTIC 3421321Sdg printf("bio_imask %x tty_imask %x net_imask %x\n", 3431321Sdg bio_imask, tty_imask, net_imask); 3441321Sdg#endif 3452103Sdg /* 3462103Sdg * Finish initializing intr_mask[]. Note that the partly 3472103Sdg * constructed masks aren't actually used since we're at splhigh. 3482103Sdg * For fully dynamic initialization, register_intr() and 3492103Sdg * unregister_intr() will have to adjust the masks for _all_ 3502103Sdg * interrupts and for tty_imask, etc. 3512103Sdg */ 3522103Sdg for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 3532103Sdg register_imask(dvp, tty_imask); 3542103Sdg for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 3552103Sdg register_imask(dvp, bio_imask); 3562103Sdg for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 3572103Sdg register_imask(dvp, net_imask); 3582103Sdg for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 3592103Sdg register_imask(dvp, SWI_CLOCK_MASK); 3602918Sbde spl0(); 3614Srgrimes} 3624Srgrimes 3634Srgrimes/* 3644Srgrimes * Configure an ISA device. 3654Srgrimes */ 3663258Sdg 3673258Sdg 3683258Sdgstatic void config_isadev_c(); 3693258Sdg 3702103Sdgstatic void 3714Srgrimesconfig_isadev(isdp, mp) 3723258Sdg struct isa_device *isdp; 3733258Sdg u_int *mp; 3743258Sdg{ 3753258Sdg config_isadev_c(isdp, mp, 0); 3763258Sdg} 3773258Sdg 3783258Sdgvoid 3793258Sdgreconfig_isadev(isdp, mp) 3804Srgrimes struct isa_device *isdp; 3814Srgrimes u_int *mp; 3824Srgrimes{ 3833258Sdg config_isadev_c(isdp, mp, 1); 3843258Sdg} 3853258Sdg 3863258Sdgstatic void 3873258Sdgconfig_isadev_c(isdp, mp, reconfig) 3883258Sdg struct isa_device *isdp; 3893258Sdg u_int *mp; 3903258Sdg int reconfig; 3913258Sdg{ 3922103Sdg u_int checkbits; 3932103Sdg int id_alive; 3943258Sdg int last_alive; 395593Srgrimes struct isa_driver *dp = isdp->id_driver; 3964Srgrimes 3972103Sdg checkbits = 0; 3982103Sdg#ifndef ALLOW_CONFLICT_DRQ 3992103Sdg checkbits |= CC_DRQ; 4002103Sdg#endif 4012103Sdg#ifndef ALLOW_CONFLICT_IOADDR 4022103Sdg checkbits |= CC_IOADDR; 4032103Sdg#endif 4042103Sdg#ifndef ALLOW_CONFLICT_MEMADDR 4052103Sdg checkbits |= CC_MEMADDR; 4062103Sdg#endif 4074109Sjkh if (!isdp->id_enabled) { 4084109Sjkh printf("%s%d: disabled, not probed.\n", 4094109Sjkh dp->name, isdp->id_unit); 4104109Sjkh return; 4114109Sjkh } 4123258Sdg if (!reconfig && haveseen_isadev(isdp, checkbits)) 4132103Sdg return; 4143258Sdg if (!reconfig && isdp->id_maddr) { 415593Srgrimes isdp->id_maddr -= 0xa0000; /* XXX should be a define */ 416593Srgrimes isdp->id_maddr += atdevbase; 417593Srgrimes } 4183258Sdg if (reconfig) { 4193258Sdg last_alive = isdp->id_alive; 4206512Sphk isdp->id_reconfig = 1; 4213258Sdg } 4223258Sdg else { 4233258Sdg last_alive = 0; 4246512Sphk isdp->id_reconfig = 0; 4253258Sdg } 4262103Sdg id_alive = (*dp->probe)(isdp); 4272103Sdg if (id_alive) { 428593Srgrimes /* 429593Srgrimes * Only print the I/O address range if id_alive != -1 430593Srgrimes * Right now this is a temporary fix just for the new 431593Srgrimes * NPX code so that if it finds a 486 that can use trap 432593Srgrimes * 16 it will not report I/O addresses. 433593Srgrimes * Rod Grimes 04/26/94 434593Srgrimes */ 4353258Sdg if (!isdp->id_reconfig) { 4363258Sdg printf("%s%d", dp->name, isdp->id_unit); 4373258Sdg if (id_alive != -1) { 4383258Sdg printf(" at 0x%x", isdp->id_iobase); 4393258Sdg if ((isdp->id_iobase + id_alive - 1) != 4403258Sdg isdp->id_iobase) { 4413258Sdg printf("-0x%x", 4423258Sdg isdp->id_iobase + id_alive - 1); 4433258Sdg } 444593Srgrimes } 4453258Sdg if (isdp->id_irq) 4463258Sdg printf(" irq %d", ffs(isdp->id_irq) - 1); 4473258Sdg if (isdp->id_drq != -1) 4483258Sdg printf(" drq %d", isdp->id_drq); 4493258Sdg if (isdp->id_maddr) 4503258Sdg printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); 4513258Sdg if (isdp->id_msize) 4523258Sdg printf(" msize %d", isdp->id_msize); 4533258Sdg if (isdp->id_flags) 4543258Sdg printf(" flags 0x%x", isdp->id_flags); 4553258Sdg if (isdp->id_iobase) { 4563258Sdg if (isdp->id_iobase < 0x100) { 4573258Sdg printf(" on motherboard\n"); 4581002Srgrimes } else { 4593258Sdg if (isdp->id_iobase >= 0x1000) { 4603258Sdg printf (" on eisa\n"); 4613258Sdg } else { 4623258Sdg printf (" on isa\n"); 4633258Sdg } 4641002Srgrimes } 4651002Srgrimes } 4663258Sdg /* 4673258Sdg * Check for conflicts again. The driver may have 4683258Sdg * changed *dvp. We should weaken the early check 4693258Sdg * since the driver may have been able to change 4703258Sdg * *dvp to avoid conflicts if given a chance. We 4713258Sdg * already skip the early check for IRQs and force 4723258Sdg * a check for IRQs in the next group of checks. 4733258Sdg */ 4743224Sswallace#ifndef ALLOW_CONFLICT_IRQ 4753258Sdg checkbits |= CC_IRQ; 4763224Sswallace#endif 4773258Sdg if (haveseen_isadev(isdp, checkbits)) 4783258Sdg return; 4793258Sdg isdp->id_alive = id_alive; 4803258Sdg } 481593Srgrimes (*dp->attach)(isdp); 4822103Sdg if (isdp->id_irq) { 4832103Sdg if (mp) 4842103Sdg INTRMASK(*mp, isdp->id_irq); 4852103Sdg register_intr(ffs(isdp->id_irq) - 1, isdp->id_id, 4862103Sdg isdp->id_ri_flags, isdp->id_intr, 4873869Sse mp, isdp->id_unit); 488593Srgrimes INTREN(isdp->id_irq); 4894Srgrimes } 490593Srgrimes } else { 4913258Sdg if (isdp->id_reconfig) { 4923258Sdg (*dp->attach)(isdp); /* reconfiguration attach */ 493593Srgrimes } 4943258Sdg if (!last_alive) { 4953258Sdg if (!isdp->id_reconfig) { 4963258Sdg printf("%s%d not found", dp->name, isdp->id_unit); 4973258Sdg if (isdp->id_iobase) { 4983258Sdg printf(" at 0x%x", isdp->id_iobase); 4993258Sdg } 5003258Sdg printf("\n"); 5013258Sdg } 5023258Sdg } 5033258Sdg else { 5043258Sdg /* This code has not been tested.... */ 5053258Sdg if (isdp->id_irq) { 5063258Sdg INTRDIS(isdp->id_irq); 5073258Sdg unregister_intr(ffs(isdp->id_irq) - 1, 5083258Sdg isdp->id_intr); 5093258Sdg if (mp) 5103258Sdg INTRUNMASK(*mp, isdp->id_irq); 5113258Sdg } 5123258Sdg } 513593Srgrimes } 5144Srgrimes} 5154Srgrimes 5164Srgrimes/* 5173705Swollman * Provide ISA-specific device information to user programs using the 5183705Swollman * hw.devconf interface. 5193705Swollman */ 5203705Swollmanint 5213705Swollmanisa_externalize(struct isa_device *id, void *userp, size_t *maxlen) 5223705Swollman{ 5233705Swollman if(*maxlen < sizeof *id) { 5243705Swollman return ENOMEM; 5253705Swollman } 5263705Swollman 5273705Swollman *maxlen -= sizeof *id; 5283705Swollman return copyout(id, userp, sizeof *id); 5293705Swollman} 5303705Swollman 5313705Swollman/* 5323705Swollman * Do the same thing for EISA information. EISA information is currently 5333705Swollman * the same as ISA information plus a slot number, but could be extended in 5343705Swollman * the future. 5353705Swollman */ 5363705Swollmanint 5373705Swollmaneisa_externalize(struct isa_device *id, int slot, void *userp, size_t *maxlen) 5383705Swollman{ 5393705Swollman int rv; 5403705Swollman 5413705Swollman if(*maxlen < (sizeof *id) + (sizeof slot)) { 5423705Swollman return ENOMEM; 5433705Swollman } 5443705Swollman *maxlen -= (sizeof *id) + (sizeof slot); 5453705Swollman 5463705Swollman rv = copyout(id, userp, sizeof *id); 5473705Swollman if(rv) return rv; 5483705Swollman 5493705Swollman return copyout(&slot, (char *)userp + sizeof *id, sizeof slot); 5503705Swollman} 5513705Swollman 5523705Swollman/* 5533705Swollman * This is used to forcibly reconfigure an ISA device. It currently just 5543705Swollman * returns an error 'cos you can't do that yet. It is here to demonstrate 5553705Swollman * what the `internalize' routine is supposed to do. 5563705Swollman */ 5573705Swollmanint 5583705Swollmanisa_internalize(struct isa_device *id, void **userpp, size_t *len) 5593705Swollman{ 5603705Swollman struct isa_device myid; 5613705Swollman char *userp = *userpp; 5623705Swollman int rv; 5633705Swollman 5643705Swollman if(*len < sizeof *id) { 5653705Swollman return EINVAL; 5663705Swollman } 5673705Swollman 5683705Swollman rv = copyin(userp, &myid, sizeof myid); 5693705Swollman if(rv) return rv; 5703705Swollman *userpp = userp + sizeof myid; 5713705Swollman *len -= sizeof myid; 5723705Swollman 5733705Swollman rv = EOPNOTSUPP; 5743705Swollman /* code would go here to validate the configuration request */ 5753705Swollman /* code would go here to actually perform the reconfiguration */ 5763705Swollman return rv; 5773705Swollman} 5783705Swollman 5793713Swollmanint 5803713Swollmanisa_generic_externalize(struct proc *p, struct kern_devconf *kdc, 5813713Swollman void *userp, size_t l) 5823713Swollman{ 5833713Swollman return isa_externalize(kdc->kdc_isa, userp, &l); 5843713Swollman} 5853713Swollman 5863713Swollmanint 5873713Swollmaneisa_generic_externalize(struct proc *p, struct kern_devconf *kdc, 5883713Swollman void *userp, size_t l) 5893713Swollman{ 5903713Swollman return eisa_externalize(kdc->kdc_isa, -1, userp, &l); 5913713Swollman} 5923713Swollman 5933705Swollman/* 5944Srgrimes * Fill in default interrupt table (in case of spuruious interrupt 5954Srgrimes * during configuration of kernel, setup interrupt control unit 5964Srgrimes */ 597798Swollmanvoid 598798Swollmanisa_defaultirq() 599798Swollman{ 6004Srgrimes int i; 6014Srgrimes 6024Srgrimes /* icu vectors */ 6031321Sdg for (i = 0; i < ICU_LEN; i++) 6042103Sdg unregister_intr(i, (inthand2_t *)NULL); 6054Srgrimes 6064Srgrimes /* initialize 8259's */ 6074Srgrimes outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 6084Srgrimes outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ 6094Srgrimes outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ 6104Srgrimes#ifdef AUTO_EOI_1 6114Srgrimes outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ 6124Srgrimes#else 6134Srgrimes outb(IO_ICU1+1, 1); /* 8086 mode */ 6144Srgrimes#endif 6154Srgrimes outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 6164Srgrimes outb(IO_ICU1, 0x0a); /* default to IRR on read */ 6174Srgrimes outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 6184Srgrimes 6194Srgrimes outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 6204Srgrimes outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ 6214Srgrimes outb(IO_ICU2+1,2); /* my slave id is 2 */ 6224Srgrimes#ifdef AUTO_EOI_2 6234Srgrimes outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ 6244Srgrimes#else 6254Srgrimes outb(IO_ICU2+1,1); /* 8086 mode */ 6264Srgrimes#endif 6274Srgrimes outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 6284Srgrimes outb(IO_ICU2, 0x0a); /* default to IRR on read */ 6294Srgrimes} 6304Srgrimes 6314Srgrimes/* region of physical memory known to be contiguous */ 6324Srgrimesvm_offset_t isaphysmem; 6334Srgrimesstatic caddr_t dma_bounce[8]; /* XXX */ 6344Srgrimesstatic char bounced[8]; /* XXX */ 6354Srgrimes#define MAXDMASZ 512 /* XXX */ 6364Srgrimes 6374Srgrimes/* high byte of address is stored in this port for i-th dma channel */ 6384Srgrimesstatic short dmapageport[8] = 6394Srgrimes { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 6404Srgrimes 6414Srgrimes/* 6424Srgrimes * isa_dmacascade(): program 8237 DMA controller channel to accept 6434Srgrimes * external dma control by a board. 6444Srgrimes */ 6454Srgrimesvoid isa_dmacascade(unsigned chan) 6464Srgrimes{ 6474Srgrimes if (chan > 7) 6484Srgrimes panic("isa_dmacascade: impossible request"); 6494Srgrimes 6504Srgrimes /* set dma channel mode, and set dma channel mode */ 6514Srgrimes if ((chan & 4) == 0) { 6524Srgrimes outb(DMA1_MODE, DMA37MD_CASCADE | chan); 6534Srgrimes outb(DMA1_SMSK, chan); 6544Srgrimes } else { 6554Srgrimes outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 6564Srgrimes outb(DMA2_SMSK, chan & 3); 6574Srgrimes } 6584Srgrimes} 6594Srgrimes 6602103Sdgstatic int 6612103Sdgisa_dmarangecheck(caddr_t va, unsigned length, unsigned chan); 6622103Sdg 6634Srgrimes/* 6644Srgrimes * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 6654Srgrimes * problems by using a bounce buffer. 6664Srgrimes */ 6674Srgrimesvoid isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) 6684Srgrimes{ vm_offset_t phys; 6694Srgrimes int waport; 6704Srgrimes caddr_t newaddr; 6714Srgrimes 6724Srgrimes if ( chan > 7 6734Srgrimes || (chan < 4 && nbytes > (1<<16)) 6744Srgrimes || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 6754Srgrimes panic("isa_dmastart: impossible request"); 6764Srgrimes 6774Srgrimes if (isa_dmarangecheck(addr, nbytes, chan)) { 6784Srgrimes if (dma_bounce[chan] == 0) 6794Srgrimes dma_bounce[chan] = 6804Srgrimes /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ 6814Srgrimes (caddr_t) isaphysmem + NBPG*chan; 6824Srgrimes bounced[chan] = 1; 6834Srgrimes newaddr = dma_bounce[chan]; 6844Srgrimes *(int *) newaddr = 0; /* XXX */ 6854Srgrimes 6864Srgrimes /* copy bounce buffer on write */ 6874Srgrimes if (!(flags & B_READ)) 6884Srgrimes bcopy(addr, newaddr, nbytes); 6894Srgrimes addr = newaddr; 6904Srgrimes } 6914Srgrimes 6924Srgrimes /* translate to physical */ 6934Srgrimes phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); 6944Srgrimes 6954Srgrimes if ((chan & 4) == 0) { 6964Srgrimes /* 6974Srgrimes * Program one of DMA channels 0..3. These are 6984Srgrimes * byte mode channels. 6994Srgrimes */ 7004Srgrimes /* set dma channel mode, and reset address ff */ 7014051Sache 7024051Sache /* If B_RAW flag is set, then use autoinitialise mode */ 7034051Sache if (flags & B_RAW) { 7044051Sache if (flags & B_READ) 7054051Sache outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); 7064051Sache else 7074051Sache outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); 7084051Sache } 7094051Sache else 7104Srgrimes if (flags & B_READ) 7114Srgrimes outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 7124Srgrimes else 7134Srgrimes outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 7144Srgrimes outb(DMA1_FFC, 0); 7154Srgrimes 7164Srgrimes /* send start address */ 7174Srgrimes waport = DMA1_CHN(chan); 7184Srgrimes outb(waport, phys); 7194Srgrimes outb(waport, phys>>8); 7204Srgrimes outb(dmapageport[chan], phys>>16); 7214Srgrimes 7224Srgrimes /* send count */ 7234Srgrimes outb(waport + 1, --nbytes); 7244Srgrimes outb(waport + 1, nbytes>>8); 7254Srgrimes 7264Srgrimes /* unmask channel */ 7274Srgrimes outb(DMA1_SMSK, chan); 7284Srgrimes } else { 7294Srgrimes /* 7304Srgrimes * Program one of DMA channels 4..7. These are 7314Srgrimes * word mode channels. 7324Srgrimes */ 7334Srgrimes /* set dma channel mode, and reset address ff */ 7344051Sache 7354051Sache /* If B_RAW flag is set, then use autoinitialise mode */ 7364051Sache if (flags & B_RAW) { 7374051Sache if (flags & B_READ) 7384051Sache outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); 7394051Sache else 7404051Sache outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); 7414051Sache } 7424051Sache else 7434Srgrimes if (flags & B_READ) 7444Srgrimes outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 7454Srgrimes else 7464Srgrimes outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 7474Srgrimes outb(DMA2_FFC, 0); 7484Srgrimes 7494Srgrimes /* send start address */ 7504Srgrimes waport = DMA2_CHN(chan - 4); 7514Srgrimes outb(waport, phys>>1); 7524Srgrimes outb(waport, phys>>9); 7534Srgrimes outb(dmapageport[chan], phys>>16); 7544Srgrimes 7554Srgrimes /* send count */ 7564Srgrimes nbytes >>= 1; 7574Srgrimes outb(waport + 2, --nbytes); 7584Srgrimes outb(waport + 2, nbytes>>8); 7594Srgrimes 7604Srgrimes /* unmask channel */ 7614Srgrimes outb(DMA2_SMSK, chan & 3); 7624Srgrimes } 7634Srgrimes} 7644Srgrimes 7654Srgrimesvoid isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 7664Srgrimes{ 7674Srgrimes 7684Srgrimes /* copy bounce buffer on read */ 7694Srgrimes /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ 7704Srgrimes if (bounced[chan]) { 7714Srgrimes bcopy(dma_bounce[chan], addr, nbytes); 7724Srgrimes bounced[chan] = 0; 7734Srgrimes } 7744Srgrimes} 7754Srgrimes 7764Srgrimes/* 7774Srgrimes * Check for problems with the address range of a DMA transfer 7784Srgrimes * (non-contiguous physical pages, outside of bus address space, 7794Srgrimes * crossing DMA page boundaries). 7804Srgrimes * Return true if special handling needed. 7814Srgrimes */ 7824Srgrimes 7832103Sdgstatic int 7844Srgrimesisa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { 7854Srgrimes vm_offset_t phys, priorpage = 0, endva; 7864Srgrimes u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 7874Srgrimes 7884Srgrimes endva = (vm_offset_t)round_page(va + length); 7894Srgrimes for (; va < (caddr_t) endva ; va += NBPG) { 7904Srgrimes phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); 7914Srgrimes#define ISARAM_END RAM_END 7924Srgrimes if (phys == 0) 7934Srgrimes panic("isa_dmacheck: no physical page present"); 7941323Sache if (phys >= ISARAM_END) 7954Srgrimes return (1); 7964Srgrimes if (priorpage) { 7974Srgrimes if (priorpage + NBPG != phys) 7984Srgrimes return (1); 7994Srgrimes /* check if crossing a DMA page boundary */ 8004Srgrimes if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 8014Srgrimes return (1); 8024Srgrimes } 8034Srgrimes priorpage = phys; 8044Srgrimes } 8054Srgrimes return (0); 8064Srgrimes} 8074Srgrimes 8084Srgrimes/* head of queue waiting for physmem to become available */ 8094Srgrimesstruct buf isa_physmemq; 8104Srgrimes 8114Srgrimes/* blocked waiting for resource to become free for exclusive use */ 8124Srgrimesstatic isaphysmemflag; 8134Srgrimes/* if waited for and call requested when free (B_CALL) */ 8144Srgrimesstatic void (*isaphysmemunblock)(); /* needs to be a list */ 8154Srgrimes 8164Srgrimes/* 8174Srgrimes * Allocate contiguous physical memory for transfer, returning 8184Srgrimes * a *virtual* address to region. May block waiting for resource. 8194Srgrimes * (assumed to be called at splbio()) 8204Srgrimes */ 8214Srgrimescaddr_t 8224Srgrimesisa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { 8234Srgrimes 8244Srgrimes isaphysmemunblock = func; 8254Srgrimes while (isaphysmemflag & B_BUSY) { 8264Srgrimes isaphysmemflag |= B_WANTED; 827798Swollman tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0); 8284Srgrimes } 8294Srgrimes isaphysmemflag |= B_BUSY; 8304Srgrimes 8314Srgrimes return((caddr_t)isaphysmem); 8324Srgrimes} 8334Srgrimes 8344Srgrimes/* 8354Srgrimes * Free contiguous physical memory used for transfer. 8364Srgrimes * (assumed to be called at splbio()) 8374Srgrimes */ 8384Srgrimesvoid 8394Srgrimesisa_freephysmem(caddr_t va, unsigned length) { 8404Srgrimes 8414Srgrimes isaphysmemflag &= ~B_BUSY; 8424Srgrimes if (isaphysmemflag & B_WANTED) { 8434Srgrimes isaphysmemflag &= B_WANTED; 844798Swollman wakeup((caddr_t)&isaphysmemflag); 8454Srgrimes if (isaphysmemunblock) 8464Srgrimes (*isaphysmemunblock)(); 8474Srgrimes } 8484Srgrimes} 8494Srgrimes 8502001Swollman#define NMI_PARITY (1 << 7) 8512001Swollman#define NMI_IOCHAN (1 << 6) 8522001Swollman#define ENMI_WATCHDOG (1 << 7) 8532001Swollman#define ENMI_BUSTIMER (1 << 6) 8542001Swollman#define ENMI_IOSTATUS (1 << 5) 8552001Swollman 8564Srgrimes/* 8574Srgrimes * Handle a NMI, possibly a machine check. 8584Srgrimes * return true to panic system, false to ignore. 8594Srgrimes */ 860798Swollmanint 861798Swollmanisa_nmi(cd) 862798Swollman int cd; 863798Swollman{ 8642001Swollman int isa_port = inb(0x61); 8652001Swollman int eisa_port = inb(0x461); 8662001Swollman if(isa_port & NMI_PARITY) { 8672001Swollman panic("RAM parity error, likely hardware failure."); 8682001Swollman } else if(isa_port & NMI_IOCHAN) { 8692001Swollman panic("I/O channel check, likely hardware failure."); 8702001Swollman } else if(eisa_port & ENMI_WATCHDOG) { 8712001Swollman panic("EISA watchdog timer expired, likely hardware failure."); 8722001Swollman } else if(eisa_port & ENMI_BUSTIMER) { 8732001Swollman panic("EISA bus timeout, likely hardware failure."); 8742001Swollman } else if(eisa_port & ENMI_IOSTATUS) { 8752001Swollman panic("EISA I/O port status error."); 8762001Swollman } else { 8772001Swollman printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port); 8782001Swollman return(0); 8792001Swollman } 8804Srgrimes} 8814Srgrimes 8824Srgrimes/* 8834Srgrimes * Caught a stray interrupt, notify 8844Srgrimes */ 8852103Sdgstatic void 886798Swollmanisa_strayintr(d) 887798Swollman int d; 888798Swollman{ 8894Srgrimes 8904Srgrimes /* DON'T BOTHER FOR NOW! */ 8914Srgrimes /* for some reason, we get bursts of intr #7, even if not enabled! */ 8924Srgrimes /* 8934Srgrimes * Well the reason you got bursts of intr #7 is because someone 8944Srgrimes * raised an interrupt line and dropped it before the 8259 could 8954Srgrimes * prioritize it. This is documented in the intel data book. This 8964Srgrimes * means you have BAD hardware! I have changed this so that only 8974Srgrimes * the first 5 get logged, then it quits logging them, and puts 8984Srgrimes * out a special message. rgrimes 3/25/1993 8994Srgrimes */ 9002103Sdg /* 9012103Sdg * XXX TODO print a different message for #7 if it is for a 9022103Sdg * glitch. Glitches can be distinguished from real #7's by 9032103Sdg * testing that the in-service bit is _not_ set. The test 9042103Sdg * must be done before sending an EOI so it can't be done if 9052103Sdg * we are using AUTO_EOI_1. 9062103Sdg */ 9072103Sdg if (intrcnt[NR_DEVICES + d] <= 5) 9082103Sdg log(LOG_ERR, "stray irq %d\n", d); 9092103Sdg if (intrcnt[NR_DEVICES + d] == 5) 9102103Sdg log(LOG_CRIT, 9112103Sdg "too many stray irq %d's; not logging any more\n", d); 9124Srgrimes} 9134Srgrimes 9144Srgrimes/* 9154Srgrimes * find an ISA device in a given isa_devtab_* table, given 9164Srgrimes * the table to search, the expected id_driver entry, and the unit number. 9174Srgrimes * 9184Srgrimes * this function is defined in isa_device.h, and this location is debatable; 9194Srgrimes * i put it there because it's useless w/o, and directly operates on 9204Srgrimes * the other stuff in that file. 9214Srgrimes * 9224Srgrimes */ 9234Srgrimes 9244Srgrimesstruct isa_device *find_isadev(table, driverp, unit) 9254Srgrimes struct isa_device *table; 9264Srgrimes struct isa_driver *driverp; 9274Srgrimes int unit; 9284Srgrimes{ 9294Srgrimes if (driverp == NULL) /* sanity check */ 9304Srgrimes return NULL; 9314Srgrimes 9324Srgrimes while ((table->id_driver != driverp) || (table->id_unit != unit)) { 9334Srgrimes if (table->id_driver == 0) 9344Srgrimes return NULL; 9354Srgrimes 9364Srgrimes table++; 9374Srgrimes } 9384Srgrimes 9394Srgrimes return table; 9404Srgrimes} 9414Srgrimes 9424Srgrimes/* 9434Srgrimes * Return nonzero if a (masked) irq is pending for a given device. 9444Srgrimes */ 9454Srgrimesint 9464Srgrimesisa_irq_pending(dvp) 9474Srgrimes struct isa_device *dvp; 9484Srgrimes{ 9494Srgrimes unsigned id_irq; 9504Srgrimes 9512103Sdg id_irq = dvp->id_irq; 9524Srgrimes if (id_irq & 0xff) 9534Srgrimes return (inb(IO_ICU1) & id_irq); 9544Srgrimes return (inb(IO_ICU2) & (id_irq >> 8)); 9554Srgrimes} 9562103Sdg 9572103Sdgint 9583869Sseregister_intr(intr, device_id, flags, handler, maskptr, unit) 9592103Sdg int intr; 9602103Sdg int device_id; 9612103Sdg u_int flags; 9622103Sdg inthand2_t *handler; 9633869Sse u_int *maskptr; 9642103Sdg int unit; 9652103Sdg{ 9662103Sdg char *cp; 9672103Sdg u_long ef; 9682103Sdg int id; 9693869Sse u_int mask = (maskptr ? *maskptr : 0); 9702103Sdg 9712103Sdg if ((u_int)intr >= ICU_LEN || intr == 2 9722103Sdg || (u_int)device_id >= NR_DEVICES) 9732103Sdg return (EINVAL); 9742103Sdg if (intr_handler[intr] != isa_strayintr) 9752103Sdg return (EBUSY); 9762103Sdg ef = read_eflags(); 9772103Sdg disable_intr(); 9782103Sdg intr_countp[intr] = &intrcnt[device_id]; 9792103Sdg intr_handler[intr] = handler; 9802103Sdg intr_mask[intr] = mask | (1 << intr); 9812103Sdg intr_unit[intr] = unit; 9822103Sdg setidt(ICU_OFFSET + intr, 9832103Sdg flags & RI_FAST ? fastintr[intr] : slowintr[intr], 9842103Sdg SDT_SYS386IGT, SEL_KPL); 9852103Sdg write_eflags(ef); 9862103Sdg for (cp = intrnames, id = 0; id <= device_id; id++) 9872103Sdg while (*cp++ != '\0') 9882103Sdg ; 9892103Sdg if (cp > eintrnames) 9902103Sdg return (0); 9912103Sdg if (intr < 10) { 9922103Sdg cp[-3] = intr + '0'; 9932103Sdg cp[-2] = ' '; 9942103Sdg } else { 9952103Sdg cp[-3] = '1'; 9962103Sdg cp[-2] = intr - 10 + '0'; 9972103Sdg } 9982103Sdg return (0); 9992103Sdg} 10002103Sdg 10012103Sdgstatic void 10022103Sdgregister_imask(dvp, mask) 10032103Sdg struct isa_device *dvp; 10042103Sdg u_int mask; 10052103Sdg{ 10062103Sdg if (dvp->id_alive && dvp->id_irq) { 10072103Sdg int intr; 10082103Sdg 10092103Sdg intr = ffs(dvp->id_irq) - 1; 10102103Sdg intr_mask[intr] = mask | (1 <<intr); 10112103Sdg } 10122103Sdg} 10132103Sdg 10142103Sdgint 10152103Sdgunregister_intr(intr, handler) 10162103Sdg int intr; 10172103Sdg inthand2_t *handler; 10182103Sdg{ 10192103Sdg u_long ef; 10202103Sdg 10212103Sdg if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) 10222103Sdg return (EINVAL); 10232103Sdg ef = read_eflags(); 10242103Sdg disable_intr(); 10252103Sdg intr_countp[intr] = &intrcnt[NR_DEVICES + intr]; 10262103Sdg intr_handler[intr] = isa_strayintr; 10272103Sdg intr_mask[intr] = HWI_MASK | SWI_MASK; 10282103Sdg intr_unit[intr] = intr; 10292103Sdg setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL); 10302103Sdg write_eflags(ef); 10312103Sdg return (0); 10322103Sdg} 1033