atpic.c revision 129131
1121985Sjhb/*- 2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121985Sjhb * All rights reserved. 4121985Sjhb * 5121985Sjhb * Redistribution and use in source and binary forms, with or without 6121985Sjhb * modification, are permitted provided that the following conditions 7121985Sjhb * are met: 8121985Sjhb * 1. Redistributions of source code must retain the above copyright 9121985Sjhb * notice, this list of conditions and the following disclaimer. 10121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121985Sjhb * notice, this list of conditions and the following disclaimer in the 12121985Sjhb * documentation and/or other materials provided with the distribution. 13121985Sjhb * 3. Neither the name of the author nor the names of any co-contributors 14121985Sjhb * may be used to endorse or promote products derived from this software 15121985Sjhb * without specific prior written permission. 16121985Sjhb * 17121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121985Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121985Sjhb * SUCH DAMAGE. 28121985Sjhb */ 29121985Sjhb 30121985Sjhb/* 31121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines. 32121985Sjhb */ 33121985Sjhb 34121985Sjhb#include <sys/cdefs.h> 35121985Sjhb__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 129131 2004-05-11 20:23:24Z jhb $"); 36121985Sjhb 37121985Sjhb#include "opt_auto_eoi.h" 38121985Sjhb#include "opt_isa.h" 39121985Sjhb 40121985Sjhb#include <sys/param.h> 41121985Sjhb#include <sys/systm.h> 42121985Sjhb#include <sys/bus.h> 43121985Sjhb#include <sys/interrupt.h> 44121985Sjhb#include <sys/kernel.h> 45121985Sjhb#include <sys/lock.h> 46121985Sjhb#include <sys/mutex.h> 47121985Sjhb 48121985Sjhb#include <machine/cpufunc.h> 49121985Sjhb#include <machine/frame.h> 50121985Sjhb#include <machine/intr_machdep.h> 51121985Sjhb#include <machine/md_var.h> 52121985Sjhb#include <machine/resource.h> 53121985Sjhb#include <machine/segments.h> 54121985Sjhb 55124188Sjhb#include <dev/ic/i8259.h> 56121985Sjhb#include <i386/isa/icu.h> 57122051Snyan#ifdef PC98 58122051Snyan#include <pc98/pc98/pc98.h> 59122051Snyan#else 60121985Sjhb#include <i386/isa/isa.h> 61122051Snyan#endif 62121985Sjhb#include <isa/isavar.h> 63121985Sjhb 64121985Sjhb#define MASTER 0 65121985Sjhb#define SLAVE 1 66121985Sjhb 67124188Sjhb/* 68129131Sjhb * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and 69129131Sjhb * PC-AT machines wire the slave PIC to pin 2 on the master PIC. 70129131Sjhb */ 71129131Sjhb#ifdef PC98 72129131Sjhb#define ICU_SLAVEID 7 73129131Sjhb#else 74129131Sjhb#define ICU_SLAVEID 2 75129131Sjhb#endif 76129131Sjhb 77129131Sjhb/* 78124188Sjhb * Determine the base master and slave modes not including auto EOI support. 79124188Sjhb * All machines that FreeBSD supports use 8086 mode. 80124188Sjhb */ 81121985Sjhb#ifdef PC98 82124188Sjhb/* 83124188Sjhb * PC-98 machines do not support auto EOI on the second PIC. Also, it 84124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC 85124188Sjhb * uses special fully nested mode. 86124188Sjhb */ 87124188Sjhb#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 88124188Sjhb#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 89121985Sjhb#else 90124188Sjhb#define BASE_MASTER_MODE ICW4_8086 91124188Sjhb#define BASE_SLAVE_MODE ICW4_8086 92121985Sjhb#endif 93124188Sjhb 94124188Sjhb/* Enable automatic EOI if requested. */ 95121985Sjhb#ifdef AUTO_EOI_1 96124188Sjhb#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 97121985Sjhb#else 98124188Sjhb#define MASTER_MODE BASE_MASTER_MODE 99121985Sjhb#endif 100121985Sjhb#ifdef AUTO_EOI_2 101124188Sjhb#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 102121985Sjhb#else 103124188Sjhb#define SLAVE_MODE BASE_SLAVE_MODE 104121985Sjhb#endif 105121985Sjhb 106129131Sjhb#define IRQ_MASK(irq) (1 << (irq)) 107129131Sjhb#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 108128875Sjhb 109128875Sjhb#define NUM_ISA_IRQS 16 110128875Sjhb 111121985Sjhbstatic void atpic_init(void *dummy); 112121985Sjhb 113121985Sjhbunsigned int imen; /* XXX */ 114129009Snyan#ifndef PC98 115128929Sjhbstatic int using_elcr; 116129009Snyan#endif 117121985Sjhb 118121985Sjhbinthand_t 119121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 120121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 121121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 122121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 123121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 124121985Sjhb IDTVEC(atpic_intr15); 125121985Sjhb 126121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 127121985Sjhb 128128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 129121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 130121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 131128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 132128931Sjhb IDT_IO_INTS + (base), (imenptr) } 133121985Sjhb 134121985Sjhb#define INTSRC(irq) \ 135128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 136128929Sjhb (irq) % 8 } 137121985Sjhb 138121985Sjhbstruct atpic { 139121985Sjhb struct pic at_pic; 140121985Sjhb int at_ioaddr; 141121985Sjhb int at_irqbase; 142121985Sjhb uint8_t at_intbase; 143121985Sjhb uint8_t *at_imen; 144121985Sjhb}; 145121985Sjhb 146121985Sjhbstruct atpic_intsrc { 147121985Sjhb struct intsrc at_intsrc; 148121985Sjhb inthand_t *at_intr; 149128929Sjhb int at_irq; /* Relative to PIC base. */ 150128929Sjhb enum intr_trigger at_trigger; 151122897Sjhb u_long at_count; 152122897Sjhb u_long at_straycount; 153121985Sjhb}; 154121985Sjhb 155121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 156121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 157121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 158121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 159121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 160121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 161121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 162121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 163128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 164128931Sjhb enum intr_polarity pol); 165121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 166121985Sjhb 167121985Sjhbstatic struct atpic atpics[] = { 168121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 169121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 170121985Sjhb}; 171121985Sjhb 172121985Sjhbstatic struct atpic_intsrc atintrs[] = { 173121985Sjhb INTSRC(0), 174121985Sjhb INTSRC(1), 175121985Sjhb INTSRC(2), 176121985Sjhb INTSRC(3), 177121985Sjhb INTSRC(4), 178121985Sjhb INTSRC(5), 179121985Sjhb INTSRC(6), 180121985Sjhb INTSRC(7), 181121985Sjhb INTSRC(8), 182121985Sjhb INTSRC(9), 183121985Sjhb INTSRC(10), 184121985Sjhb INTSRC(11), 185121985Sjhb INTSRC(12), 186121985Sjhb INTSRC(13), 187121985Sjhb INTSRC(14), 188121985Sjhb INTSRC(15), 189121985Sjhb}; 190121985Sjhb 191129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 192128875Sjhb 193121985Sjhbstatic void 194121985Sjhbatpic_enable_source(struct intsrc *isrc) 195121985Sjhb{ 196121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 197121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 198121985Sjhb 199121985Sjhb mtx_lock_spin(&icu_lock); 200128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 201128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 202128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 203128875Sjhb } 204121985Sjhb mtx_unlock_spin(&icu_lock); 205121985Sjhb} 206121985Sjhb 207121985Sjhbstatic void 208121985Sjhbatpic_disable_source(struct intsrc *isrc) 209121985Sjhb{ 210121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 211121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 212121985Sjhb 213128929Sjhb if (ai->at_trigger == INTR_TRIGGER_EDGE) 214128929Sjhb return; 215121985Sjhb mtx_lock_spin(&icu_lock); 216128875Sjhb *ap->at_imen |= IMEN_MASK(ai); 217121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 218121985Sjhb mtx_unlock_spin(&icu_lock); 219121985Sjhb} 220121985Sjhb 221121985Sjhbstatic void 222121985Sjhbatpic_eoi_master(struct intsrc *isrc) 223121985Sjhb{ 224121985Sjhb 225121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 226121985Sjhb ("%s: mismatched pic", __func__)); 227121985Sjhb#ifndef AUTO_EOI_1 228121985Sjhb mtx_lock_spin(&icu_lock); 229129131Sjhb outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 230121985Sjhb mtx_unlock_spin(&icu_lock); 231121985Sjhb#endif 232121985Sjhb} 233121985Sjhb 234122572Sjhb/* 235122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works. 236122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it. 237122572Sjhb */ 238121985Sjhbstatic void 239121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 240121985Sjhb{ 241121985Sjhb 242121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 243121985Sjhb ("%s: mismatched pic", __func__)); 244121985Sjhb#ifndef AUTO_EOI_2 245121985Sjhb mtx_lock_spin(&icu_lock); 246129131Sjhb outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 247121985Sjhb#ifndef AUTO_EOI_1 248129131Sjhb outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 249121985Sjhb#endif 250121985Sjhb mtx_unlock_spin(&icu_lock); 251121985Sjhb#endif 252121985Sjhb} 253121985Sjhb 254121985Sjhbstatic void 255121985Sjhbatpic_enable_intr(struct intsrc *isrc) 256121985Sjhb{ 257121985Sjhb} 258121985Sjhb 259121985Sjhbstatic int 260121985Sjhbatpic_vector(struct intsrc *isrc) 261121985Sjhb{ 262121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 263121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 264121985Sjhb 265121985Sjhb return (IRQ(ap, ai)); 266121985Sjhb} 267121985Sjhb 268121985Sjhbstatic int 269121985Sjhbatpic_source_pending(struct intsrc *isrc) 270121985Sjhb{ 271121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 272121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 273121985Sjhb 274128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 275121985Sjhb} 276121985Sjhb 277121985Sjhbstatic void 278121985Sjhbatpic_resume(struct intsrc *isrc) 279121985Sjhb{ 280121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 281121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 282121985Sjhb 283128929Sjhb if (ai->at_irq == 0) { 284121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 285129009Snyan#ifndef PC98 286128929Sjhb if (ap == &atpics[SLAVE] && using_elcr) 287128929Sjhb elcr_resume(); 288129009Snyan#endif 289128929Sjhb } 290121985Sjhb} 291121985Sjhb 292128931Sjhbstatic int 293128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 294128931Sjhb enum intr_polarity pol) 295128931Sjhb{ 296128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 297128931Sjhb u_int vector; 298128931Sjhb 299128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 300128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 301128931Sjhb trig = INTR_TRIGGER_EDGE; 302128931Sjhb if (pol == INTR_POLARITY_CONFORM) 303128931Sjhb pol = INTR_POLARITY_HIGH; 304128931Sjhb vector = atpic_vector(isrc); 305128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 306128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 307128931Sjhb printf( 308128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 309128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 310128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 311128931Sjhb return (EINVAL); 312128931Sjhb } 313128931Sjhb 314128931Sjhb /* If there is no change, just return. */ 315128931Sjhb if (ai->at_trigger == trig) 316128931Sjhb return (0); 317128931Sjhb 318129009Snyan#ifdef PC98 319129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 320129009Snyan trig == INTR_TRIGGER_LEVEL) { 321129009Snyan if (bootverbose) 322129009Snyan printf( 323129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 324129009Snyan vector); 325129009Snyan return (EINVAL); 326129009Snyan } 327129009Snyan return (ENXIO); 328129009Snyan#else 329128931Sjhb /* 330128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 331128931Sjhb * that way if asked. At least some ELCR registers ignore setting 332128931Sjhb * these bits as well. 333128931Sjhb */ 334128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 335128931Sjhb trig == INTR_TRIGGER_LEVEL) { 336128931Sjhb if (bootverbose) 337128931Sjhb printf( 338128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 339128931Sjhb vector); 340128931Sjhb return (EINVAL); 341128931Sjhb } 342128931Sjhb if (!using_elcr) { 343128931Sjhb if (bootverbose) 344128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 345128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 346128931Sjhb "level/low"); 347128931Sjhb return (ENXIO); 348128931Sjhb } 349128931Sjhb if (bootverbose) 350128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 351128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 352128931Sjhb mtx_lock_spin(&icu_lock); 353128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 354128931Sjhb ai->at_trigger = trig; 355128931Sjhb mtx_unlock_spin(&icu_lock); 356128931Sjhb return (0); 357129009Snyan#endif /* PC98 */ 358128931Sjhb} 359128931Sjhb 360121985Sjhbstatic void 361121985Sjhbi8259_init(struct atpic *pic, int slave) 362121985Sjhb{ 363121985Sjhb int imr_addr; 364121985Sjhb 365121985Sjhb /* Reset the PIC and program with next four bytes. */ 366121985Sjhb mtx_lock_spin(&icu_lock); 367121985Sjhb#ifdef DEV_MCA 368122692Sjhb /* MCA uses level triggered interrupts. */ 369121985Sjhb if (MCA_system) 370122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 371121985Sjhb else 372121985Sjhb#endif 373122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 374121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 375121985Sjhb 376121985Sjhb /* Start vector. */ 377121985Sjhb outb(imr_addr, pic->at_intbase); 378121985Sjhb 379121985Sjhb /* 380121985Sjhb * Setup slave links. For the master pic, indicate what line 381121985Sjhb * the slave is configured on. For the slave indicate 382121985Sjhb * which line on the master we are connected to. 383121985Sjhb */ 384121985Sjhb if (slave) 385129131Sjhb outb(imr_addr, ICU_SLAVEID); 386121985Sjhb else 387129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 388121985Sjhb 389121985Sjhb /* Set mode. */ 390121985Sjhb if (slave) 391121985Sjhb outb(imr_addr, SLAVE_MODE); 392121985Sjhb else 393121985Sjhb outb(imr_addr, MASTER_MODE); 394121985Sjhb 395121985Sjhb /* Set interrupt enable mask. */ 396121985Sjhb outb(imr_addr, *pic->at_imen); 397121985Sjhb 398121985Sjhb /* Reset is finished, default to IRR on read. */ 399122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 400121985Sjhb 401121985Sjhb#ifndef PC98 402122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 403121985Sjhb if (!slave) 404122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 405121985Sjhb#endif 406121985Sjhb mtx_unlock_spin(&icu_lock); 407121985Sjhb} 408121985Sjhb 409121985Sjhbvoid 410121985Sjhbatpic_startup(void) 411121985Sjhb{ 412122897Sjhb struct atpic_intsrc *ai; 413122897Sjhb int i; 414121985Sjhb 415121985Sjhb /* Start off with all interrupts disabled. */ 416121985Sjhb imen = 0xffff; 417121985Sjhb i8259_init(&atpics[MASTER], 0); 418121985Sjhb i8259_init(&atpics[SLAVE], 1); 419121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 420122897Sjhb 421122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 422128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 423122897Sjhb if (i == ICU_SLAVEID) 424122897Sjhb continue; 425122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 426122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 427122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 428122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 429122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 430122897Sjhb } 431128929Sjhb 432128929Sjhb#ifdef DEV_MCA 433128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 434128929Sjhb if (MCA_system) 435128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 436128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 437128929Sjhb else 438128929Sjhb#endif 439128929Sjhb 440129009Snyan#ifdef PC98 441129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 442129009Snyan switch (i) { 443129009Snyan case 0: 444129009Snyan case 1: 445129009Snyan case 7: 446129009Snyan case 8: 447129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 448129009Snyan break; 449129009Snyan default: 450129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 451129009Snyan break; 452129009Snyan } 453129009Snyan#else 454128929Sjhb /* 455128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 456128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 457128929Sjhb * edge triggered and that everything else is level triggered. 458128929Sjhb * We only use the trigger information to reprogram the ELCR if 459128929Sjhb * we have one and as an optimization to avoid masking edge 460128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 461128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 462129095Sjhb * assume level trigger for any interrupt that we aren't sure is 463129095Sjhb * edge triggered. 464128929Sjhb */ 465128929Sjhb if (elcr_probe() == 0) { 466128929Sjhb using_elcr = 1; 467128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 468128929Sjhb ai->at_trigger = elcr_read_trigger(i); 469128929Sjhb } else { 470128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 471128929Sjhb switch (i) { 472128929Sjhb case 0: 473128929Sjhb case 1: 474128929Sjhb case 2: 475128929Sjhb case 8: 476128929Sjhb case 13: 477128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 478128929Sjhb break; 479128929Sjhb default: 480128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 481128929Sjhb break; 482128929Sjhb } 483128929Sjhb } 484129009Snyan#endif /* PC98 */ 485121985Sjhb} 486121985Sjhb 487121985Sjhbstatic void 488121985Sjhbatpic_init(void *dummy __unused) 489121985Sjhb{ 490128875Sjhb struct atpic_intsrc *ai; 491121985Sjhb int i; 492121985Sjhb 493121985Sjhb /* Loop through all interrupt sources and add them. */ 494128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 495121985Sjhb if (i == ICU_SLAVEID) 496121985Sjhb continue; 497128875Sjhb intr_register_source(&ai->at_intsrc); 498121985Sjhb } 499121985Sjhb} 500121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 501121985Sjhb 502121985Sjhbvoid 503122572Sjhbatpic_handle_intr(struct intrframe iframe) 504121985Sjhb{ 505121985Sjhb struct intsrc *isrc; 506121985Sjhb 507129131Sjhb KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS, 508121985Sjhb ("unknown int %d\n", iframe.if_vec)); 509121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 510122898Sjhb 511122898Sjhb /* 512122898Sjhb * If we don't have an ithread, see if this is a spurious 513122898Sjhb * interrupt. 514122898Sjhb */ 515122898Sjhb if (isrc->is_ithread == NULL && 516122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 517122898Sjhb int port, isr; 518122898Sjhb 519122898Sjhb /* 520122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 521122898Sjhb * pending. Reset read register back to IRR when done. 522122898Sjhb */ 523122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 524122898Sjhb mtx_lock_spin(&icu_lock); 525122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 526122898Sjhb isr = inb(port); 527122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 528122898Sjhb mtx_unlock_spin(&icu_lock); 529129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 530122898Sjhb return; 531122898Sjhb } 532121985Sjhb intr_execute_handlers(isrc, &iframe); 533121985Sjhb} 534121985Sjhb 535121985Sjhb#ifdef DEV_ISA 536121985Sjhb/* 537121985Sjhb * Bus attachment for the ISA PIC. 538121985Sjhb */ 539121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 540121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 541121985Sjhb { 0 } 542121985Sjhb}; 543121985Sjhb 544121985Sjhbstatic int 545121985Sjhbatpic_probe(device_t dev) 546121985Sjhb{ 547121985Sjhb int result; 548121985Sjhb 549121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 550121985Sjhb if (result <= 0) 551121985Sjhb device_quiet(dev); 552121985Sjhb return (result); 553121985Sjhb} 554121985Sjhb 555121985Sjhb/* 556121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 557121985Sjhb * between the two PIC components. If we're using the APIC, however, 558121985Sjhb * this may not be the case, and as such we should free the resource. 559121985Sjhb * (XXX untested) 560121985Sjhb * 561121985Sjhb * The generic ISA attachment code will handle allocating any other resources 562121985Sjhb * that we don't explicitly claim here. 563121985Sjhb */ 564121985Sjhbstatic int 565121985Sjhbatpic_attach(device_t dev) 566121985Sjhb{ 567121985Sjhb struct resource *res; 568121985Sjhb int rid; 569121985Sjhb 570121985Sjhb /* Try to allocate our IRQ and then free it. */ 571121985Sjhb rid = 0; 572127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 573121985Sjhb if (res != NULL) 574121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 575121985Sjhb return (0); 576121985Sjhb} 577121985Sjhb 578121985Sjhbstatic device_method_t atpic_methods[] = { 579121985Sjhb /* Device interface */ 580121985Sjhb DEVMETHOD(device_probe, atpic_probe), 581121985Sjhb DEVMETHOD(device_attach, atpic_attach), 582121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 583121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 584121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 585121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 586121985Sjhb { 0, 0 } 587121985Sjhb}; 588121985Sjhb 589121985Sjhbstatic driver_t atpic_driver = { 590121985Sjhb "atpic", 591121985Sjhb atpic_methods, 592121985Sjhb 1, /* no softc */ 593121985Sjhb}; 594121985Sjhb 595121985Sjhbstatic devclass_t atpic_devclass; 596121985Sjhb 597121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 598122051Snyan#ifndef PC98 599121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 600122051Snyan#endif 601121985Sjhb 602121985Sjhb/* 603121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 604121985Sjhb * and is only suitable for use at probe time. 605121985Sjhb */ 606121985Sjhbintrmask_t 607121985Sjhbisa_irq_pending(void) 608121985Sjhb{ 609121985Sjhb u_char irr1; 610121985Sjhb u_char irr2; 611121985Sjhb 612121985Sjhb irr1 = inb(IO_ICU1); 613121985Sjhb irr2 = inb(IO_ICU2); 614121985Sjhb return ((irr2 << 8) | irr1); 615121985Sjhb} 616121985Sjhb#endif /* DEV_ISA */ 617