isa.c revision 15147
118334Speter/*- 290082Sobrien * Copyright (c) 1991 The Regents of the University of California. 3169699Skan * All rights reserved. 418334Speter * 590082Sobrien * This code is derived from software contributed to Berkeley by 618334Speter * William Jolitz. 790082Sobrien * 890082Sobrien * Redistribution and use in source and binary forms, with or without 990082Sobrien * modification, are permitted provided that the following conditions 1090082Sobrien * are met: 1118334Speter * 1. Redistributions of source code must retain the above copyright 1290082Sobrien * notice, this list of conditions and the following disclaimer. 1390082Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1490082Sobrien * notice, this list of conditions and the following disclaimer in the 1590082Sobrien * documentation and/or other materials provided with the distribution. 1618334Speter * 3. All advertising materials mentioning features or use of this software 1718334Speter * must display the following acknowledgement: 1890082Sobrien * This product includes software developed by the University of 19169699Skan * California, Berkeley and its contributors. 20169699Skan * 4. Neither the name of the University nor the names of its contributors 2118334Speter * may be used to endorse or promote products derived from this software 2218334Speter * without specific prior written permission. 2350449Sobrien * 24132728Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25132728Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26132728Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2718334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2818334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2950449Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3052299Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3152299Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3290082Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33132728Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3490082Sobrien * SUCH DAMAGE. 3590082Sobrien * 3690082Sobrien * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 3790082Sobrien * $Id: isa.c,v 1.66 1996/04/07 17:32:13 bde Exp $ 3890082Sobrien */ 3990082Sobrien 4090082Sobrien/* 41117404Skan * code to manage AT bus 42117404Skan * 43117404Skan * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): 44132728Skan * Fixed uninitialized variable problem and added code to deal 45169699Skan * with DMA page boundaries in isa_dmarangecheck(). Fixed word 46169699Skan * mode DMA count compution and reorganized DMA setup code in 47169699Skan * isa_dmastart() 48169699Skan */ 49169699Skan 50169699Skan#include <sys/param.h> 5118334Speter#include <sys/systm.h> 52117404Skan#include <sys/sysctl.h> 5390082Sobrien#include <sys/buf.h> 5490082Sobrien#include <sys/syslog.h> 5590082Sobrien#include <sys/malloc.h> 5690082Sobrien#include <machine/segments.h> 5790082Sobrien#include <vm/vm.h> 5890082Sobrien#include <vm/vm_param.h> 5990082Sobrien#include <vm/pmap.h> 6090082Sobrien#include <i386/isa/isa_device.h> 6190082Sobrien#include <i386/isa/isa.h> 6250449Sobrien#include <i386/isa/icu.h> 6350449Sobrien#include <i386/isa/ic/i8237.h> 64169699Skan#include <sys/devconf.h> 65169699Skan#include "vector.h" 66169699Skan 67169699Skan/* 6890082Sobrien** Register definitions for DMA controller 1 (channels 0..3): 6990082Sobrien*/ 7050449Sobrien#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ 7190082Sobrien#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ 72117404Skan#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ 73117404Skan#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ 74117404Skan 75117404Skan/* 7690082Sobrien** Register definitions for DMA controller 2 (channels 4..7): 7790082Sobrien*/ 7850449Sobrien#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */ 7950449Sobrien#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ 8090082Sobrien#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ 8190082Sobrien#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ 8290082Sobrien 8318334Speteru_long *intr_countp[ICU_LEN]; 8490082Sobrieninthand2_t *intr_handler[ICU_LEN]; 8590082Sobrienu_int intr_mask[ICU_LEN]; 8690082Sobrienu_int* intr_mptr[ICU_LEN]; 8790082Sobrienint intr_unit[ICU_LEN]; 8890082Sobrien 8990082Sobrienextern struct kern_devconf kdc_cpu0; 9090082Sobrien 9190082Sobrienstruct kern_devconf kdc_isa0 = { 9290082Sobrien 0, 0, 0, /* filled in by dev_attach */ 9390082Sobrien "isa", 0, { MDDT_BUS, 0 }, 9490082Sobrien 0, 0, 0, BUS_EXTERNALLEN, 9590082Sobrien &kdc_cpu0, /* parent is the CPU */ 9690082Sobrien 0, /* no parentdata */ 9790082Sobrien DC_BUSY, /* busses are always busy */ 9890082Sobrien "ISA or EISA bus", 9990082Sobrien DC_CLS_BUS /* class */ 10090082Sobrien}; 10190082Sobrien 10290082Sobrienstatic inthand_t *fastintr[ICU_LEN] = { 10390082Sobrien &IDTVEC(fastintr0), &IDTVEC(fastintr1), 10490082Sobrien &IDTVEC(fastintr2), &IDTVEC(fastintr3), 10590082Sobrien &IDTVEC(fastintr4), &IDTVEC(fastintr5), 10690082Sobrien &IDTVEC(fastintr6), &IDTVEC(fastintr7), 10790082Sobrien &IDTVEC(fastintr8), &IDTVEC(fastintr9), 10890082Sobrien &IDTVEC(fastintr10), &IDTVEC(fastintr11), 10990082Sobrien &IDTVEC(fastintr12), &IDTVEC(fastintr13), 11090082Sobrien &IDTVEC(fastintr14), &IDTVEC(fastintr15) 11190082Sobrien}; 11290082Sobrien 113132728Skanstatic inthand_t *slowintr[ICU_LEN] = { 114132728Skan &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), 115132728Skan &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), 11690082Sobrien &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), 11790082Sobrien &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) 11890082Sobrien}; 11990082Sobrien 12090082Sobrienstatic void config_isadev __P((struct isa_device *isdp, u_int *mp)); 12190082Sobrienstatic void config_isadev_c __P((struct isa_device *isdp, u_int *mp, 12290082Sobrien int reconfig)); 12390082Sobrienstatic void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp, 12490082Sobrien int item, char const *whatnot, char const *reason, 12590082Sobrien char const *format)); 12690082Sobrienstatic int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp, 12790082Sobrien u_int checkbits)); 12890082Sobrienstatic int isa_dmarangecheck __P((caddr_t va, u_int length, int chan)); 12990082Sobrienstatic inthand2_t isa_strayintr; 13090082Sobrienstatic void register_imask __P((struct isa_device *dvp, u_int mask)); 13190082Sobrien 13290082Sobrien/* 13390082Sobrien * print a conflict message 134169699Skan */ 135169699Skanstatic void 136169699Skanconflict(dvp, tmpdvp, item, whatnot, reason, format) 137169699Skan struct isa_device *dvp; 13890082Sobrien struct isa_device *tmpdvp; 13990082Sobrien int item; 14090082Sobrien char const *whatnot; 14190082Sobrien char const *reason; 14290082Sobrien char const *format; 14390082Sobrien{ 14490082Sobrien printf("%s%d not %sed due to %s conflict with %s%d at ", 14590082Sobrien dvp->id_driver->name, dvp->id_unit, whatnot, reason, 14690082Sobrien tmpdvp->id_driver->name, tmpdvp->id_unit); 14790082Sobrien printf(format, item); 14890082Sobrien printf("\n"); 14990082Sobrien} 15090082Sobrien 15190082Sobrien/* 15290082Sobrien * Check to see if things are already in use, like IRQ's, I/O addresses 15390082Sobrien * and Memory addresses. 15490082Sobrien */ 15590082Sobrienstatic int 15690082Sobrienhaveseen(dvp, tmpdvp, checkbits) 15790082Sobrien struct isa_device *dvp; 15890082Sobrien struct isa_device *tmpdvp; 15990082Sobrien u_int checkbits; 16090082Sobrien{ 16190082Sobrien /* 16290082Sobrien * Only check against devices that have already been found and are not 16390082Sobrien * unilaterally allowed to conflict anyway. 16490082Sobrien */ 16590082Sobrien if (tmpdvp->id_alive && !dvp->id_conflicts) { 16690082Sobrien char const *whatnot; 16790082Sobrien 16890082Sobrien whatnot = checkbits & CC_ATTACH ? "attach" : "prob"; 16990082Sobrien /* 17090082Sobrien * Check for I/O address conflict. We can only check the 17190082Sobrien * starting address of the device against the range of the 17290082Sobrien * device that has already been probed since we do not 17390082Sobrien * know how many I/O addresses this device uses. 17490082Sobrien */ 17590082Sobrien if (checkbits & CC_IOADDR && tmpdvp->id_alive != -1) { 17690082Sobrien if ((dvp->id_iobase >= tmpdvp->id_iobase) && 17790082Sobrien (dvp->id_iobase <= 17890082Sobrien (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) { 17990082Sobrien conflict(dvp, tmpdvp, dvp->id_iobase, whatnot, 18090082Sobrien "I/O address", "0x%x"); 18190082Sobrien return 1; 18290082Sobrien } 18390082Sobrien } 18490082Sobrien /* 18590082Sobrien * Check for Memory address conflict. We can check for 18690082Sobrien * range overlap, but it will not catch all cases since the 18790082Sobrien * driver may adjust the msize paramater during probe, for 18890082Sobrien * now we just check that the starting address does not 18990082Sobrien * fall within any allocated region. 19090082Sobrien * XXX could add a second check after the probe for overlap, 19190082Sobrien * since at that time we would know the full range. 19290082Sobrien * XXX KERNBASE is a hack, we should have vaddr in the table! 193132728Skan */ 19490082Sobrien if (checkbits & CC_MEMADDR && tmpdvp->id_maddr) { 19590082Sobrien if ((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) && 19690082Sobrien (KERNBASE + dvp->id_maddr <= 19790082Sobrien (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) { 19890082Sobrien conflict(dvp, tmpdvp, (int)dvp->id_maddr, 199132728Skan whatnot, "maddr", "0x%x"); 200117404Skan return 1; 201117404Skan } 202117404Skan } 203132728Skan /* 204117404Skan * Check for IRQ conflicts. 205117404Skan */ 206132728Skan if (checkbits & CC_IRQ && tmpdvp->id_irq) { 207132728Skan if (tmpdvp->id_irq == dvp->id_irq) { 208132728Skan conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1, 209132728Skan whatnot, "irq", "%d"); 210132728Skan return 1; 211132728Skan } 212132728Skan } 213132728Skan /* 214132728Skan * Check for DRQ conflicts. 215132728Skan */ 216132728Skan if (checkbits & CC_DRQ && tmpdvp->id_drq != -1) { 217132728Skan if (tmpdvp->id_drq == dvp->id_drq) { 218132728Skan conflict(dvp, tmpdvp, dvp->id_drq, whatnot, 219132728Skan "drq", "%d"); 220132728Skan return 1; 221132728Skan } 222132728Skan } 223169699Skan } 224169699Skan return 0; 225169699Skan} 226169699Skan 227132728Skan/* 228132728Skan * Search through all the isa_devtab_* tables looking for anything that 229132728Skan * conflicts with the current device. 230132728Skan */ 231132728Skanint 232117404Skanhaveseen_isadev(dvp, checkbits) 233117404Skan struct isa_device *dvp; 234117404Skan u_int checkbits; 235117404Skan{ 236117404Skan struct isa_device *tmpdvp; 237117404Skan int status = 0; 238117404Skan 239117404Skan for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) { 24090082Sobrien status |= haveseen(dvp, tmpdvp, checkbits); 24190082Sobrien if (status) 24290082Sobrien return status; 24390082Sobrien } 24490082Sobrien for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) { 24590082Sobrien status |= haveseen(dvp, tmpdvp, checkbits); 24690082Sobrien if (status) 24790082Sobrien return status; 24890082Sobrien } 24990082Sobrien for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) { 25090082Sobrien status |= haveseen(dvp, tmpdvp, checkbits); 25190082Sobrien if (status) 25290082Sobrien return status; 25390082Sobrien } 25490082Sobrien for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) { 25590082Sobrien status |= haveseen(dvp, tmpdvp, checkbits); 25690082Sobrien if (status) 257259005Spfg return status; 258259005Spfg } 259259005Spfg return(status); 260259005Spfg} 261117404Skan 262117404Skan/* 263117404Skan * Configure all ISA devices 264117404Skan */ 265117404Skanvoid 266117404Skanisa_configure() { 267117404Skan struct isa_device *dvp; 268117404Skan 269117404Skan dev_attach(&kdc_isa0); 270117404Skan 271117404Skan splhigh(); 272132728Skan printf("Probing for devices on the ISA bus:\n"); 273117404Skan /* First probe all the sensitive probes */ 274132728Skan for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 275117404Skan if (dvp->id_driver->sensitive_hw) 276117404Skan config_isadev(dvp, &tty_imask); 277117404Skan for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 278117404Skan if (dvp->id_driver->sensitive_hw) 279117404Skan config_isadev(dvp, &bio_imask); 280117404Skan for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 281169699Skan if (dvp->id_driver->sensitive_hw) 282169699Skan config_isadev(dvp, &net_imask); 283169699Skan for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 284117404Skan if (dvp->id_driver->sensitive_hw) 285169699Skan config_isadev(dvp, (u_int *)NULL); 286117404Skan 287132728Skan /* Then all the bad ones */ 288132728Skan for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 289132728Skan if (!dvp->id_driver->sensitive_hw) 290132728Skan config_isadev(dvp, &tty_imask); 291117404Skan for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 292132728Skan if (!dvp->id_driver->sensitive_hw) 293132728Skan config_isadev(dvp, &bio_imask); 294132728Skan for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 295132728Skan if (!dvp->id_driver->sensitive_hw) 296132728Skan config_isadev(dvp, &net_imask); 297132728Skan for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 298132728Skan if (!dvp->id_driver->sensitive_hw) 299132728Skan config_isadev(dvp, (u_int *)NULL); 300132728Skan 301169699Skan bio_imask |= SWI_CLOCK_MASK; 302117404Skan net_imask |= SWI_NET_MASK; 303117404Skan tty_imask |= SWI_TTY_MASK; 304117404Skan 305117404Skan/* 306117404Skan * XXX we should really add the tty device to net_imask when the line is 307117404Skan * switched to SLIPDISC, and then remove it when it is switched away from 308117404Skan * SLIPDISC. No need to block out ALL ttys during a splimp when only one 309117404Skan * of them is running slip. 310117404Skan * 311117404Skan * XXX actually, blocking all ttys during a splimp doesn't matter so much 312117404Skan * with sio because the serial interrupt layer doesn't use tty_imask. Only 313117404Skan * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked 314117404Skan * during spltty. 315117404Skan */ 316117404Skan#include "sl.h" 317117404Skan#if NSL > 0 318132728Skan net_imask |= tty_imask; 319117404Skan tty_imask = net_imask; 320117404Skan#endif 321117404Skan 322117404Skan /* bio_imask |= tty_imask ; can some tty devices use buffers? */ 323117404Skan 324117404Skan if (bootverbose) 325117404Skan printf("imasks: bio %x, tty %x, net %x\n", 32690082Sobrien bio_imask, tty_imask, net_imask); 327117404Skan 328117404Skan /* 329117404Skan * Finish initializing intr_mask[]. Note that the partly 330117404Skan * constructed masks aren't actually used since we're at splhigh. 331117404Skan * For fully dynamic initialization, register_intr() and 332117404Skan * unregister_intr() will have to adjust the masks for _all_ 333117404Skan * interrupts and for tty_imask, etc. 334117404Skan */ 335117404Skan for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) 336117404Skan register_imask(dvp, tty_imask); 337117404Skan for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) 338117404Skan register_imask(dvp, bio_imask); 339117404Skan for (dvp = isa_devtab_net; dvp->id_driver; dvp++) 340117404Skan register_imask(dvp, net_imask); 341169699Skan for (dvp = isa_devtab_null; dvp->id_driver; dvp++) 342117404Skan register_imask(dvp, SWI_CLOCK_MASK); 343117404Skan spl0(); 344117404Skan} 345117404Skan 346117404Skan/* 347117404Skan * Configure an ISA device. 348117404Skan */ 349117404Skan 350117404Skan 351117404Skanstatic void 352117404Skanconfig_isadev(isdp, mp) 353117404Skan struct isa_device *isdp; 354117404Skan u_int *mp; 355117404Skan{ 356117404Skan config_isadev_c(isdp, mp, 0); 357117404Skan} 358117404Skan 359117404Skanvoid 360117404Skanreconfig_isadev(isdp, mp) 361117404Skan struct isa_device *isdp; 362117404Skan u_int *mp; 363117404Skan{ 364117404Skan config_isadev_c(isdp, mp, 1); 365117404Skan} 366117404Skan 367117404Skanstatic void 368117404Skanconfig_isadev_c(isdp, mp, reconfig) 369117404Skan struct isa_device *isdp; 370117404Skan u_int *mp; 371117404Skan int reconfig; 372117404Skan{ 373117404Skan u_int checkbits; 374117404Skan int id_alive; 375117404Skan int last_alive; 376117404Skan struct isa_driver *dp = isdp->id_driver; 377117404Skan 378117404Skan if (!isdp->id_enabled) { 379117404Skan printf("%s%d: disabled, not probed.\n", 380117404Skan dp->name, isdp->id_unit); 381117404Skan return; 382117404Skan } 383117404Skan checkbits = CC_DRQ | CC_IOADDR | CC_MEMADDR; 384117404Skan if (!reconfig && haveseen_isadev(isdp, checkbits)) 385117404Skan return; 386117404Skan if (!reconfig && isdp->id_maddr) { 387117404Skan isdp->id_maddr -= 0xa0000; /* XXX should be a define */ 388117404Skan isdp->id_maddr += atdevbase; 389117404Skan } 390117404Skan if (reconfig) { 391117404Skan last_alive = isdp->id_alive; 392117404Skan isdp->id_reconfig = 1; 393117404Skan } 394117404Skan else { 395117404Skan last_alive = 0; 396117404Skan isdp->id_reconfig = 0; 397117404Skan } 398117404Skan id_alive = (*dp->probe)(isdp); 399117404Skan if (id_alive) { 400117404Skan /* 401117404Skan * Only print the I/O address range if id_alive != -1 402117404Skan * Right now this is a temporary fix just for the new 403117404Skan * NPX code so that if it finds a 486 that can use trap 404117404Skan * 16 it will not report I/O addresses. 405117404Skan * Rod Grimes 04/26/94 406117404Skan */ 407117404Skan if (!isdp->id_reconfig) { 408117404Skan printf("%s%d", dp->name, isdp->id_unit); 409117404Skan if (id_alive != -1) { 410117404Skan printf(" at 0x%x", isdp->id_iobase); 411117404Skan if (isdp->id_iobase + id_alive - 1 != 412117404Skan isdp->id_iobase) { 413117404Skan printf("-0x%x", 414117404Skan isdp->id_iobase + id_alive - 1); 415117404Skan } 416117404Skan } 417117404Skan if (isdp->id_irq) 418117404Skan printf(" irq %d", ffs(isdp->id_irq) - 1); 419117404Skan if (isdp->id_drq != -1) 420117404Skan printf(" drq %d", isdp->id_drq); 421117404Skan if (isdp->id_maddr) 422117404Skan printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); 423132728Skan if (isdp->id_msize) 424132728Skan printf(" msize %d", isdp->id_msize); 425132728Skan if (isdp->id_flags) 426132728Skan printf(" flags 0x%x", isdp->id_flags); 427132728Skan if (isdp->id_iobase && !(isdp->id_iobase & 0xf300)) { 428132728Skan printf(" on motherboard"); 429132728Skan } else if (isdp->id_iobase >= 0x1000 && 430117404Skan !(isdp->id_iobase & 0x300)) { 431169699Skan printf (" on eisa slot %d", 432169699Skan isdp->id_iobase >> 12); 433117404Skan } else { 434117404Skan printf (" on isa"); 435117404Skan } 436169699Skan printf("\n"); 437169699Skan /* 438169699Skan * Check for conflicts again. The driver may have 439169699Skan * changed *dvp. We should weaken the early check 440169699Skan * since the driver may have been able to change 441117404Skan * *dvp to avoid conflicts if given a chance. We 442117404Skan * already skip the early check for IRQs and force 443117404Skan * a check for IRQs in the next group of checks. 444117404Skan */ 445117404Skan checkbits |= CC_IRQ; 446117404Skan if (haveseen_isadev(isdp, checkbits)) 447117404Skan return; 448117404Skan isdp->id_alive = id_alive; 449117404Skan } 450117404Skan (*dp->attach)(isdp); 451117404Skan if (isdp->id_irq) { 452117404Skan if (mp) 453169699Skan INTRMASK(*mp, isdp->id_irq); 454169699Skan register_intr(ffs(isdp->id_irq) - 1, isdp->id_id, 455117404Skan isdp->id_ri_flags, isdp->id_intr, 456169699Skan mp, isdp->id_unit); 457117404Skan INTREN(isdp->id_irq); 458117404Skan } 459117404Skan } else { 460117404Skan if (isdp->id_reconfig) { 461117404Skan (*dp->attach)(isdp); /* reconfiguration attach */ 462117404Skan } 463117404Skan if (!last_alive) { 464117404Skan if (!isdp->id_reconfig) { 465117404Skan printf("%s%d not found", 466117404Skan dp->name, isdp->id_unit); 467117404Skan if (isdp->id_iobase) { 468117404Skan printf(" at 0x%x", isdp->id_iobase); 469117404Skan } 47090082Sobrien printf("\n"); 47190082Sobrien } 47290082Sobrien } 47390082Sobrien else { 474132728Skan /* This code has not been tested.... */ 47590082Sobrien if (isdp->id_irq) { 47650449Sobrien INTRDIS(isdp->id_irq); 47750449Sobrien unregister_intr(ffs(isdp->id_irq) - 1, 47850449Sobrien isdp->id_intr); 47950449Sobrien if (mp) 48090082Sobrien INTRUNMASK(*mp, isdp->id_irq); 48190082Sobrien } 48290082Sobrien } 48390082Sobrien } 48490082Sobrien} 48590082Sobrien 48690082Sobrien/* 48718334Speter * Provide ISA-specific device information to user programs using the 48890082Sobrien * hw.devconf interface. 48950449Sobrien */ 49090082Sobrienint 49190082Sobrienisa_externalize(struct isa_device *id, struct sysctl_req *req) 49290082Sobrien{ 49390082Sobrien return (SYSCTL_OUT(req, id, sizeof *id)); 49490082Sobrien} 49590082Sobrien 49690082Sobrien/* 49790082Sobrien * This is used to forcibly reconfigure an ISA device. It currently just 49890082Sobrien * returns an error 'cos you can't do that yet. It is here to demonstrate 49990082Sobrien * what the `internalize' routine is supposed to do. 50018334Speter */ 501132728Skanint 502169699Skanisa_internalize(struct isa_device *id, struct sysctl_req *req) 503169699Skan{ 50490082Sobrien struct isa_device myid; 505132728Skan int rv; 506132728Skan 507132728Skan rv = SYSCTL_IN(req, &myid, sizeof *id); 508132728Skan if(rv) 509132728Skan return rv; 510132728Skan 511132728Skan rv = EOPNOTSUPP; 512169699Skan /* code would go here to validate the configuration request */ 513169699Skan /* code would go here to actually perform the reconfiguration */ 514169699Skan return rv; 515132728Skan} 516132728Skan 517169699Skanint 518169699Skanisa_generic_externalize(struct kern_devconf *kdc, struct sysctl_req *req) 519132728Skan{ 520132728Skan return isa_externalize(kdc->kdc_isa, req); 521132728Skan} 522132728Skan 523132728Skan/* 524132728Skan * Fill in default interrupt table (in case of spuruious interrupt 525132728Skan * during configuration of kernel, setup interrupt control unit 526132728Skan */ 527132728Skanvoid 528132728Skanisa_defaultirq() 529169699Skan{ 530132728Skan int i; 531132728Skan 532132728Skan /* icu vectors */ 533132728Skan for (i = 0; i < ICU_LEN; i++) 534132728Skan unregister_intr(i, (inthand2_t *)NULL); 535132728Skan 536132728Skan /* initialize 8259's */ 537169699Skan outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 538132728Skan outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ 539132728Skan outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ 540132728Skan#ifdef AUTO_EOI_1 541169699Skan outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ 542132728Skan#else 543132728Skan outb(IO_ICU1+1, 1); /* 8086 mode */ 544260014Spfg#endif 545260014Spfg outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 546260014Spfg outb(IO_ICU1, 0x0a); /* default to IRR on read */ 547132728Skan outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 548132728Skan 549132728Skan outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 550132728Skan outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ 551132728Skan outb(IO_ICU2+1,2); /* my slave id is 2 */ 552132728Skan#ifdef AUTO_EOI_2 553132728Skan outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ 554169699Skan#else 555260311Spfg outb(IO_ICU2+1,1); /* 8086 mode */ 556260311Spfg#endif 557117404Skan outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 558132728Skan outb(IO_ICU2, 0x0a); /* default to IRR on read */ 559132728Skan} 560132728Skan 561132728Skanstatic caddr_t dma_bouncebuf[8]; 562132728Skanstatic u_int dma_bouncebufsize[8]; 563117404Skanstatic u_int8_t dma_bounced = 0; 564117404Skanstatic u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ 565117404Skanstatic u_int8_t dma_inuse = 0; /* User for acquire/release */ 566117404Skan 567117404Skan#define VALID_DMA_MASK (7) 568117404Skan 569132728Skan/* high byte of address is stored in this port for i-th dma channel */ 570117404Skanstatic short dmapageport[8] = 571117404Skan { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; 572117404Skan 573117404Skan/* 574117404Skan * Setup a DMA channel's bounce buffer. 575117404Skan */ 576117404Skanvoid 577117404Skanisa_dmainit(chan, bouncebufsize) 578117404Skan int chan; 579117404Skan u_int bouncebufsize; 580117404Skan{ 581117404Skan void *buf; 582117404Skan 583117404Skan#ifdef DIAGNOSTIC 584117404Skan if (chan & ~VALID_DMA_MASK) 585117404Skan panic("isa_dmainit: channel out of range"); 586117404Skan 587169699Skan if (dma_bouncebuf[chan] != NULL) 588169699Skan panic("isa_dmainit: impossible request"); 589169699Skan#endif 590169699Skan 591117404Skan dma_bouncebufsize[chan] = bouncebufsize; 592117404Skan 593117404Skan /* Try malloc() first. It works better if it works. */ 594117404Skan buf = malloc(bouncebufsize, M_DEVBUF, M_NOWAIT); 595169699Skan if (buf != NULL) { 596169699Skan if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) { 597117404Skan dma_bouncebuf[chan] = buf; 598117404Skan return; 599117404Skan } 600117404Skan free(buf, M_DEVBUF); 601117404Skan } 602117404Skan buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 603117404Skan 1ul, chan & 4 ? 0x20000ul : 0x10000ul); 604117404Skan if (buf == NULL) 605117404Skan printf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize); 606117404Skan else 607117404Skan dma_bouncebuf[chan] = buf; 608117404Skan} 609117404Skan 610117404Skan/* 611117404Skan * Register a DMA channel's usage. Usually called from a device driver 612260311Spfg * in open() or during it's initialization. 613260311Spfg */ 614117404Skanint 615117404Skanisa_dma_acquire(chan) 616117404Skan int chan; 617169699Skan{ 618169699Skan#ifdef DIAGNOSTIC 619117404Skan if (chan & ~VALID_DMA_MASK) 620117404Skan panic("isa_dma_acquire: channel out of range"); 621117404Skan#endif 622117404Skan 623169699Skan if (dma_inuse & (1 << chan)) { 624169699Skan printf("isa_dma_acquire: channel %d already in use\n", chan); 625117404Skan return (EBUSY); 626117404Skan } 627117404Skan dma_inuse |= (1 << chan); 628117404Skan 629169699Skan return (0); 630169699Skan} 631169699Skan 632169699Skan/* 633117404Skan * Unregister a DMA channel's usage. Usually called from a device driver 634117404Skan * during close() or during it's shutdown. 635260014Spfg */ 636260014Spfgvoid 637260014Spfgisa_dma_release(chan) 638260014Spfg int chan; 639117404Skan{ 640117404Skan#ifdef DIAGNOSTIC 641169699Skan if (chan & ~VALID_DMA_MASK) 642117404Skan panic("isa_dma_release: channel out of range"); 643117404Skan 644117404Skan if (dma_inuse & (1 << chan) == 0) 645117404Skan printf("isa_dma_release: channel %d not in use\n", chan); 646117404Skan#endif 647117404Skan 648117404Skan if (dma_busy & (1 << chan)) { 649117404Skan dma_busy &= ~(1 << chan); 650117404Skan /* 651117404Skan * XXX We should also do "dma_bounced &= (1 << chan);" 652132728Skan * because we are acting on behalf of isa_dmadone() which 653132728Skan * was not called to end the last DMA operation. This does 654169699Skan * not matter now, but it may in the future. 655169699Skan */ 656260311Spfg } 657260311Spfg 658117404Skan dma_inuse &= ~(1 << chan); 659117404Skan} 660117404Skan 661117404Skan/* 662132728Skan * isa_dmacascade(): program 8237 DMA controller channel to accept 663117404Skan * external dma control by a board. 664117404Skan */ 665117404Skanvoid isa_dmacascade(chan) 666117404Skan int chan; 667117404Skan{ 668117404Skan#ifdef DIAGNOSTIC 669117404Skan if (chan & ~VALID_DMA_MASK) 670117404Skan panic("isa_dmacascade: channel out of range"); 671117404Skan#endif 672117404Skan 673117404Skan /* set dma channel mode, and set dma channel mode */ 67490082Sobrien if ((chan & 4) == 0) { 67590082Sobrien outb(DMA1_MODE, DMA37MD_CASCADE | chan); 67690082Sobrien outb(DMA1_SMSK, chan); 677132728Skan } else { 67890082Sobrien outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); 67990082Sobrien outb(DMA2_SMSK, chan & 3); 68090082Sobrien } 681132728Skan} 68290082Sobrien 68318334Speter/* 68490082Sobrien * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 68590082Sobrien * problems by using a bounce buffer. 68690082Sobrien */ 68790082Sobrienvoid isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) 688169699Skan{ 68990082Sobrien vm_offset_t phys; 69090082Sobrien int waport; 69118334Speter caddr_t newaddr; 69290082Sobrien 69390082Sobrien#ifdef DIAGNOSTIC 69490082Sobrien if (chan & ~VALID_DMA_MASK) 69590082Sobrien panic("isa_dmastart: channel out of range"); 69690082Sobrien 69790082Sobrien if ((chan < 4 && nbytes > (1<<16)) 69890082Sobrien || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 699169699Skan panic("isa_dmastart: impossible request"); 700169699Skan 701169699Skan if (dma_inuse & (1 << chan) == 0) 702169699Skan printf("isa_dmastart: channel %d not acquired\n", chan); 70390082Sobrien#endif 70490082Sobrien 705132728Skan if (dma_busy & (1 << chan)) 70690082Sobrien printf("isa_dmastart: channel %d busy\n", chan); 70790082Sobrien 708169699Skan dma_busy |= (1 << chan); 70990082Sobrien 71090082Sobrien if (isa_dmarangecheck(addr, nbytes, chan)) { 71190082Sobrien if (dma_bouncebuf[chan] == NULL 712169699Skan || dma_bouncebufsize[chan] < nbytes) 713132728Skan panic("isa_dmastart: bad bounce buffer"); 714169699Skan dma_bounced |= (1 << chan); 71518334Speter newaddr = dma_bouncebuf[chan]; 716169699Skan 717132728Skan /* copy bounce buffer on write */ 718169699Skan if (!(flags & B_READ)) 719169699Skan bcopy(addr, newaddr, nbytes); 720132728Skan addr = newaddr; 721169699Skan } 722169699Skan 72318334Speter /* translate to physical */ 724132728Skan phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); 72590082Sobrien 72690082Sobrien if ((chan & 4) == 0) { 727132728Skan /* 72890082Sobrien * Program one of DMA channels 0..3. These are 72990082Sobrien * byte mode channels. 73090082Sobrien */ 73190082Sobrien /* set dma channel mode, and reset address ff */ 73218334Speter 73390082Sobrien /* If B_RAW flag is set, then use autoinitialise mode */ 73490082Sobrien if (flags & B_RAW) { 73590082Sobrien if (flags & B_READ) 73690082Sobrien outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); 737132728Skan else 73890082Sobrien outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); 73990082Sobrien } 74090082Sobrien else 74190082Sobrien if (flags & B_READ) 74290082Sobrien outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 74318334Speter else 74418334Speter outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 745132728Skan outb(DMA1_FFC, 0); 746169699Skan 74790082Sobrien /* send start address */ 74890082Sobrien waport = DMA1_CHN(chan); 749132728Skan outb(waport, phys); 75018334Speter outb(waport, phys>>8); 751132728Skan outb(dmapageport[chan], phys>>16); 752169699Skan 753132728Skan /* send count */ 75418334Speter outb(waport + 1, --nbytes); 755169699Skan outb(waport + 1, nbytes>>8); 756132728Skan 757132728Skan /* unmask channel */ 758132728Skan outb(DMA1_SMSK, chan); 759132728Skan } else { 76090082Sobrien /* 761132728Skan * Program one of DMA channels 4..7. These are 762169699Skan * word mode channels. 763132728Skan */ 764169699Skan /* set dma channel mode, and reset address ff */ 765169699Skan 766169699Skan /* If B_RAW flag is set, then use autoinitialise mode */ 767169699Skan if (flags & B_RAW) { 768169699Skan if (flags & B_READ) 769169699Skan outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); 770169699Skan else 771169699Skan outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); 772169699Skan } 773169699Skan else 774169699Skan if (flags & B_READ) 775169699Skan outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); 776169699Skan else 777169699Skan outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); 778169699Skan outb(DMA2_FFC, 0); 779169699Skan 780169699Skan /* send start address */ 781169699Skan waport = DMA2_CHN(chan - 4); 782169699Skan outb(waport, phys>>1); 783169699Skan outb(waport, phys>>9); 78418334Speter outb(dmapageport[chan], phys>>16); 78518334Speter 786169699Skan /* send count */ 787169699Skan nbytes >>= 1; 788169699Skan outb(waport + 2, --nbytes); 789169699Skan outb(waport + 2, nbytes>>8); 790169699Skan 791169699Skan /* unmask channel */ 792169699Skan outb(DMA2_SMSK, chan & 3); 793169699Skan } 794169699Skan} 795169699Skan 796169699Skanvoid isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 797169699Skan{ 798169699Skan#ifdef DIAGNOSTIC 799169699Skan if (chan & ~VALID_DMA_MASK) 800169699Skan panic("isa_dmadone: channel out of range"); 801169699Skan 802169699Skan if (dma_inuse & (1 << chan) == 0) 803169699Skan printf("isa_dmadone: channel %d not acquired\n", chan); 804169699Skan#endif 805169699Skan 806169699Skan#if 0 807169699Skan /* 80890082Sobrien * XXX This should be checked, but drivers like ad1848 only call 80990082Sobrien * isa_dmastart() once because they use Auto DMA mode. If we 81090082Sobrien * leave this in, drivers that do this will print this continuously. 81190082Sobrien */ 81290082Sobrien if (dma_busy & (1 << chan) == 0) 81390082Sobrien printf("isa_dmadone: channel %d not busy\n", chan); 81490082Sobrien#endif 81590082Sobrien 816132728Skan if (dma_bounced & (1 << chan)) { 81790082Sobrien /* copy bounce buffer on read */ 81890082Sobrien if (flags & B_READ) 81990082Sobrien bcopy(dma_bouncebuf[chan], addr, nbytes); 82090082Sobrien 82190082Sobrien dma_bounced &= ~(1 << chan); 82290082Sobrien } 82390082Sobrien dma_busy &= ~(1 << chan); 82490082Sobrien} 82590082Sobrien 82690082Sobrien/* 82790082Sobrien * Check for problems with the address range of a DMA transfer 828117404Skan * (non-contiguous physical pages, outside of bus address space, 829117404Skan * crossing DMA page boundaries). 830117404Skan * Return true if special handling needed. 831117404Skan */ 832117404Skan 833169699Skanstatic int 834169699Skanisa_dmarangecheck(caddr_t va, u_int length, int chan) { 835169699Skan vm_offset_t phys, priorpage = 0, endva; 836169699Skan u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 837169699Skan 838132728Skan endva = (vm_offset_t)round_page(va + length); 839169699Skan for (; va < (caddr_t) endva ; va += NBPG) { 840132728Skan phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); 841169699Skan#define ISARAM_END RAM_END 84290082Sobrien if (phys == 0) 843169699Skan panic("isa_dmacheck: no physical page present"); 844169699Skan if (phys >= ISARAM_END) 845169699Skan return (1); 846169699Skan if (priorpage) { 84790082Sobrien if (priorpage + NBPG != phys) 848169699Skan return (1); 84990082Sobrien /* check if crossing a DMA page boundary */ 85090082Sobrien if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 851169699Skan return (1); 852132728Skan } 85390082Sobrien priorpage = phys; 85490082Sobrien } 85590082Sobrien return (0); 856117404Skan} 85718334Speter 85818334Speter#define NMI_PARITY (1 << 7) 859132728Skan#define NMI_IOCHAN (1 << 6) 860117404Skan#define ENMI_WATCHDOG (1 << 7) 861117404Skan#define ENMI_BUSTIMER (1 << 6) 862117404Skan#define ENMI_IOSTATUS (1 << 5) 863117404Skan 864117404Skan/* 865169699Skan * Handle a NMI, possibly a machine check. 866117404Skan * return true to panic system, false to ignore. 867117404Skan */ 868117404Skanint 869117404Skanisa_nmi(cd) 870169699Skan int cd; 871169699Skan{ 872169699Skan int isa_port = inb(0x61); 873169699Skan int eisa_port = inb(0x461); 874169699Skan if(isa_port & NMI_PARITY) { 875117404Skan panic("RAM parity error, likely hardware failure."); 876169699Skan } else if(isa_port & NMI_IOCHAN) { 877169699Skan panic("I/O channel check, likely hardware failure."); 878169699Skan } else if(eisa_port & ENMI_WATCHDOG) { 879169699Skan panic("EISA watchdog timer expired, likely hardware failure."); 880169699Skan } else if(eisa_port & ENMI_BUSTIMER) { 881169699Skan panic("EISA bus timeout, likely hardware failure."); 882169699Skan } else if(eisa_port & ENMI_IOSTATUS) { 883169699Skan panic("EISA I/O port status error."); 884169699Skan } else { 885169699Skan printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port); 886117404Skan return(0); 887117404Skan } 888169699Skan} 889169699Skan 890169699Skan/* 891169699Skan * Caught a stray interrupt, notify 892169699Skan */ 893169699Skanstatic void 894169699Skanisa_strayintr(d) 895169699Skan int d; 896169699Skan{ 897169699Skan 898169699Skan /* DON'T BOTHER FOR NOW! */ 899169699Skan /* for some reason, we get bursts of intr #7, even if not enabled! */ 900169699Skan /* 901169699Skan * Well the reason you got bursts of intr #7 is because someone 902169699Skan * raised an interrupt line and dropped it before the 8259 could 903169699Skan * prioritize it. This is documented in the intel data book. This 904169699Skan * means you have BAD hardware! I have changed this so that only 905169699Skan * the first 5 get logged, then it quits logging them, and puts 906169699Skan * out a special message. rgrimes 3/25/1993 907169699Skan */ 908169699Skan /* 909169699Skan * XXX TODO print a different message for #7 if it is for a 910117404Skan * glitch. Glitches can be distinguished from real #7's by 911169699Skan * testing that the in-service bit is _not_ set. The test 912169699Skan * must be done before sending an EOI so it can't be done if 913117404Skan * we are using AUTO_EOI_1. 914117404Skan */ 915117404Skan if (intrcnt[NR_DEVICES + d] <= 5) 91618334Speter log(LOG_ERR, "stray irq %d\n", d); 91790082Sobrien if (intrcnt[NR_DEVICES + d] == 5) 91890082Sobrien log(LOG_CRIT, 91990082Sobrien "too many stray irq %d's; not logging any more\n", d); 92090082Sobrien} 92190082Sobrien 92252299Sobrien/* 92390082Sobrien * Find the highest priority enabled display device. Since we can't 924132728Skan * distinguish display devices from ttys, depend on display devices 92552299Sobrien * being sensitive and before sensitive non-display devices (if any) 92690082Sobrien * in isa_devtab_tty. 92796275Sobrien * 92890082Sobrien * XXX we should add capability flags IAMDISPLAY and ISUPPORTCONSOLES. 929169699Skan */ 930169699Skanstruct isa_device * 931169699Skanfind_display() 93290082Sobrien{ 93352299Sobrien struct isa_device *dvp; 93452299Sobrien 935258731Spfg for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++) 936258731Spfg if (dvp->id_driver->sensitive_hw && dvp->id_enabled) 937258731Spfg return (dvp); 93890082Sobrien return (NULL); 93990082Sobrien} 940258731Spfg 94190082Sobrien/* 942258731Spfg * find an ISA device in a given isa_devtab_* table, given 943258731Spfg * the table to search, the expected id_driver entry, and the unit number. 944258731Spfg * 94552299Sobrien * this function is defined in isa_device.h, and this location is debatable; 94618334Speter * i put it there because it's useless w/o, and directly operates on 947132728Skan * the other stuff in that file. 94818334Speter * 949258731Spfg */ 950258731Spfg 951258731Spfgstruct isa_device *find_isadev(table, driverp, unit) 95218334Speter struct isa_device *table; 953258731Spfg struct isa_driver *driverp; 954258731Spfg int unit; 955258731Spfg{ 956258731Spfg if (driverp == NULL) /* sanity check */ 957258731Spfg return NULL; 958258731Spfg 959258731Spfg while ((table->id_driver != driverp) || (table->id_unit != unit)) { 960258731Spfg if (table->id_driver == 0) 961258731Spfg return NULL; 962258731Spfg 963258731Spfg table++; 964258731Spfg } 965258731Spfg 966258731Spfg return table; 967258731Spfg} 968258731Spfg 969258731Spfg/* 970258731Spfg * Return nonzero if a (masked) irq is pending for a given device. 971258731Spfg */ 972258731Spfgint 973258731Spfgisa_irq_pending(dvp) 97418334Speter struct isa_device *dvp; 97518334Speter{ 97650449Sobrien unsigned id_irq; 97790082Sobrien 97890082Sobrien id_irq = dvp->id_irq; 97990082Sobrien if (id_irq & 0xff) 98090082Sobrien return (inb(IO_ICU1) & id_irq); 98150449Sobrien return (inb(IO_ICU2) & (id_irq >> 8)); 982169699Skan} 983132728Skan 98450449Sobrienint 985117404Skanupdate_intr_masks(void) 986117404Skan{ 98790082Sobrien int intr, n=0; 988117404Skan u_int mask,*maskptr; 989169699Skan 99090082Sobrien for (intr=0; intr < ICU_LEN; intr ++) { 991117404Skan if (intr==2) continue; 99250449Sobrien maskptr = intr_mptr[intr]; 993117404Skan if (!maskptr) continue; 99490082Sobrien *maskptr |= 1 << intr; 995169699Skan mask = *maskptr; 996169699Skan if (mask != intr_mask[intr]) { 997169699Skan#if 0 998169699Skan printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n", 999169699Skan intr, intr_mask[intr], mask, maskptr); 100050449Sobrien#endif 100190082Sobrien intr_mask[intr]=mask; 100250449Sobrien n++; 1003169699Skan } 1004169699Skan 1005169699Skan } 1006169699Skan return (n); 1007169699Skan} 1008258501Spfg 1009169699Skanint 1010169699Skanregister_intr(intr, device_id, flags, handler, maskptr, unit) 1011258501Spfg int intr; 1012258501Spfg int device_id; 1013258501Spfg u_int flags; 1014258501Spfg inthand2_t *handler; 1015258501Spfg u_int *maskptr; 1016169699Skan int unit; 1017258501Spfg{ 1018169699Skan char *cp; 1019169699Skan u_long ef; 1020169699Skan int id; 1021258501Spfg u_int mask = (maskptr ? *maskptr : 0); 1022258501Spfg 1023258501Spfg if ((u_int)intr >= ICU_LEN || intr == 2 1024258501Spfg || (u_int)device_id >= NR_DEVICES) 1025258501Spfg return (EINVAL); 1026258501Spfg if (intr_handler[intr] != isa_strayintr) 1027169699Skan return (EBUSY); 1028169699Skan ef = read_eflags(); 1029258501Spfg disable_intr(); 1030258501Spfg intr_countp[intr] = &intrcnt[device_id]; 1031258501Spfg intr_handler[intr] = handler; 1032258501Spfg intr_mptr[intr] = maskptr; 1033169699Skan intr_mask[intr] = mask | (1 << intr); 1034169699Skan intr_unit[intr] = unit; 1035169699Skan setidt(ICU_OFFSET + intr, 1036258501Spfg flags & RI_FAST ? fastintr[intr] : slowintr[intr], 1037258501Spfg SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 1038258501Spfg write_eflags(ef); 1039258501Spfg for (cp = intrnames, id = 0; id <= device_id; id++) 1040258501Spfg while (*cp++ != '\0') 1041258501Spfg ; 1042258501Spfg if (cp > eintrnames) 1043258501Spfg return (0); 1044258501Spfg if (intr < 10) { 1045258501Spfg cp[-3] = intr + '0'; 1046258501Spfg cp[-2] = ' '; 1047258501Spfg } else { 1048258501Spfg cp[-3] = '1'; 1049258501Spfg cp[-2] = intr - 10 + '0'; 1050258501Spfg } 1051258501Spfg return (0); 1052258501Spfg} 1053258501Spfg 1054258501Spfgstatic void 1055258501Spfgregister_imask(dvp, mask) 1056258501Spfg struct isa_device *dvp; 1057258501Spfg u_int mask; 1058258501Spfg{ 1059258501Spfg if (dvp->id_alive && dvp->id_irq) { 1060258501Spfg int intr; 1061258501Spfg 1062169699Skan intr = ffs(dvp->id_irq) - 1; 1063169699Skan intr_mask[intr] = mask | (1 <<intr); 1064258501Spfg } 1065258501Spfg (void) update_intr_masks(); 1066258501Spfg} 1067258501Spfg 1068258501Spfgint 1069169699Skanunregister_intr(intr, handler) 1070169699Skan int intr; 1071169699Skan inthand2_t *handler; 1072169699Skan{ 1073169699Skan u_long ef; 1074169699Skan 1075169699Skan if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) 1076169699Skan return (EINVAL); 1077169699Skan ef = read_eflags(); 1078169699Skan disable_intr(); 1079169699Skan intr_countp[intr] = &intrcnt[NR_DEVICES + intr]; 1080169699Skan intr_handler[intr] = isa_strayintr; 1081169699Skan intr_mptr[intr] = NULL; 1082169699Skan intr_mask[intr] = HWI_MASK | SWI_MASK; 1083169699Skan intr_unit[intr] = intr; 1084169699Skan setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL, 1085169699Skan GSEL(GCODE_SEL, SEL_KPL)); 1086169699Skan write_eflags(ef); 1087169699Skan return (0); 1088169699Skan} 1089169699Skan