atpic.c revision 129876
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 129876 2004-05-30 17:57:46Z phk $"); 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> 46129876Sphk#include <sys/module.h> 47121985Sjhb#include <sys/mutex.h> 48121985Sjhb 49121985Sjhb#include <machine/cpufunc.h> 50121985Sjhb#include <machine/frame.h> 51121985Sjhb#include <machine/intr_machdep.h> 52121985Sjhb#include <machine/md_var.h> 53121985Sjhb#include <machine/resource.h> 54121985Sjhb#include <machine/segments.h> 55121985Sjhb 56124188Sjhb#include <dev/ic/i8259.h> 57121985Sjhb#include <i386/isa/icu.h> 58122051Snyan#ifdef PC98 59122051Snyan#include <pc98/pc98/pc98.h> 60122051Snyan#else 61121985Sjhb#include <i386/isa/isa.h> 62122051Snyan#endif 63121985Sjhb#include <isa/isavar.h> 64121985Sjhb 65121985Sjhb#define MASTER 0 66121985Sjhb#define SLAVE 1 67121985Sjhb 68124188Sjhb/* 69129131Sjhb * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and 70129131Sjhb * PC-AT machines wire the slave PIC to pin 2 on the master PIC. 71129131Sjhb */ 72129131Sjhb#ifdef PC98 73129131Sjhb#define ICU_SLAVEID 7 74129131Sjhb#else 75129131Sjhb#define ICU_SLAVEID 2 76129131Sjhb#endif 77129131Sjhb 78129131Sjhb/* 79124188Sjhb * Determine the base master and slave modes not including auto EOI support. 80124188Sjhb * All machines that FreeBSD supports use 8086 mode. 81124188Sjhb */ 82121985Sjhb#ifdef PC98 83124188Sjhb/* 84124188Sjhb * PC-98 machines do not support auto EOI on the second PIC. Also, it 85124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC 86124188Sjhb * uses special fully nested mode. 87124188Sjhb */ 88124188Sjhb#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 89124188Sjhb#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 90121985Sjhb#else 91124188Sjhb#define BASE_MASTER_MODE ICW4_8086 92124188Sjhb#define BASE_SLAVE_MODE ICW4_8086 93121985Sjhb#endif 94124188Sjhb 95124188Sjhb/* Enable automatic EOI if requested. */ 96121985Sjhb#ifdef AUTO_EOI_1 97124188Sjhb#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 98121985Sjhb#else 99124188Sjhb#define MASTER_MODE BASE_MASTER_MODE 100121985Sjhb#endif 101121985Sjhb#ifdef AUTO_EOI_2 102124188Sjhb#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 103121985Sjhb#else 104124188Sjhb#define SLAVE_MODE BASE_SLAVE_MODE 105121985Sjhb#endif 106121985Sjhb 107129131Sjhb#define IRQ_MASK(irq) (1 << (irq)) 108129131Sjhb#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq)) 109128875Sjhb 110128875Sjhb#define NUM_ISA_IRQS 16 111128875Sjhb 112121985Sjhbstatic void atpic_init(void *dummy); 113121985Sjhb 114121985Sjhbunsigned int imen; /* XXX */ 115129009Snyan#ifndef PC98 116128929Sjhbstatic int using_elcr; 117129009Snyan#endif 118121985Sjhb 119121985Sjhbinthand_t 120121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 121121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 122121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 123121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 124121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 125121985Sjhb IDTVEC(atpic_intr15); 126121985Sjhb 127121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 128121985Sjhb 129128929Sjhb#define ATPIC(io, base, eoi, imenptr) \ 130121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 131121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 132128931Sjhb atpic_resume, atpic_config_intr }, (io), (base), \ 133128931Sjhb IDT_IO_INTS + (base), (imenptr) } 134121985Sjhb 135121985Sjhb#define INTSRC(irq) \ 136128929Sjhb { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \ 137128929Sjhb (irq) % 8 } 138121985Sjhb 139121985Sjhbstruct atpic { 140121985Sjhb struct pic at_pic; 141121985Sjhb int at_ioaddr; 142121985Sjhb int at_irqbase; 143121985Sjhb uint8_t at_intbase; 144121985Sjhb uint8_t *at_imen; 145121985Sjhb}; 146121985Sjhb 147121985Sjhbstruct atpic_intsrc { 148121985Sjhb struct intsrc at_intsrc; 149121985Sjhb inthand_t *at_intr; 150128929Sjhb int at_irq; /* Relative to PIC base. */ 151128929Sjhb enum intr_trigger at_trigger; 152122897Sjhb u_long at_count; 153122897Sjhb u_long at_straycount; 154121985Sjhb}; 155121985Sjhb 156121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 157121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 158121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 159121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 160121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 161121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 162121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 163121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 164128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 165128931Sjhb enum intr_polarity pol); 166121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 167121985Sjhb 168121985Sjhbstatic struct atpic atpics[] = { 169121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 170121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 171121985Sjhb}; 172121985Sjhb 173121985Sjhbstatic struct atpic_intsrc atintrs[] = { 174121985Sjhb INTSRC(0), 175121985Sjhb INTSRC(1), 176121985Sjhb INTSRC(2), 177121985Sjhb INTSRC(3), 178121985Sjhb INTSRC(4), 179121985Sjhb INTSRC(5), 180121985Sjhb INTSRC(6), 181121985Sjhb INTSRC(7), 182121985Sjhb INTSRC(8), 183121985Sjhb INTSRC(9), 184121985Sjhb INTSRC(10), 185121985Sjhb INTSRC(11), 186121985Sjhb INTSRC(12), 187121985Sjhb INTSRC(13), 188121985Sjhb INTSRC(14), 189121985Sjhb INTSRC(15), 190121985Sjhb}; 191121985Sjhb 192129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS); 193128875Sjhb 194121985Sjhbstatic void 195121985Sjhbatpic_enable_source(struct intsrc *isrc) 196121985Sjhb{ 197121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 198121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 199121985Sjhb 200121985Sjhb mtx_lock_spin(&icu_lock); 201128875Sjhb if (*ap->at_imen & IMEN_MASK(ai)) { 202128875Sjhb *ap->at_imen &= ~IMEN_MASK(ai); 203128875Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 204128875Sjhb } 205121985Sjhb mtx_unlock_spin(&icu_lock); 206121985Sjhb} 207121985Sjhb 208121985Sjhbstatic void 209121985Sjhbatpic_disable_source(struct intsrc *isrc) 210121985Sjhb{ 211121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 212121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 213121985Sjhb 214128929Sjhb if (ai->at_trigger == INTR_TRIGGER_EDGE) 215128929Sjhb return; 216121985Sjhb mtx_lock_spin(&icu_lock); 217128875Sjhb *ap->at_imen |= IMEN_MASK(ai); 218121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 219121985Sjhb mtx_unlock_spin(&icu_lock); 220121985Sjhb} 221121985Sjhb 222121985Sjhbstatic void 223121985Sjhbatpic_eoi_master(struct intsrc *isrc) 224121985Sjhb{ 225121985Sjhb 226121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 227121985Sjhb ("%s: mismatched pic", __func__)); 228121985Sjhb#ifndef AUTO_EOI_1 229121985Sjhb mtx_lock_spin(&icu_lock); 230129131Sjhb outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 231121985Sjhb mtx_unlock_spin(&icu_lock); 232121985Sjhb#endif 233121985Sjhb} 234121985Sjhb 235122572Sjhb/* 236122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works. 237122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it. 238122572Sjhb */ 239121985Sjhbstatic void 240121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 241121985Sjhb{ 242121985Sjhb 243121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 244121985Sjhb ("%s: mismatched pic", __func__)); 245121985Sjhb#ifndef AUTO_EOI_2 246121985Sjhb mtx_lock_spin(&icu_lock); 247129131Sjhb outb(atpics[SLAVE].at_ioaddr, OCW2_EOI); 248121985Sjhb#ifndef AUTO_EOI_1 249129131Sjhb outb(atpics[MASTER].at_ioaddr, OCW2_EOI); 250121985Sjhb#endif 251121985Sjhb mtx_unlock_spin(&icu_lock); 252121985Sjhb#endif 253121985Sjhb} 254121985Sjhb 255121985Sjhbstatic void 256121985Sjhbatpic_enable_intr(struct intsrc *isrc) 257121985Sjhb{ 258121985Sjhb} 259121985Sjhb 260121985Sjhbstatic int 261121985Sjhbatpic_vector(struct intsrc *isrc) 262121985Sjhb{ 263121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 264121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 265121985Sjhb 266121985Sjhb return (IRQ(ap, ai)); 267121985Sjhb} 268121985Sjhb 269121985Sjhbstatic int 270121985Sjhbatpic_source_pending(struct intsrc *isrc) 271121985Sjhb{ 272121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 273121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 274121985Sjhb 275128875Sjhb return (inb(ap->at_ioaddr) & IMEN_MASK(ai)); 276121985Sjhb} 277121985Sjhb 278121985Sjhbstatic void 279121985Sjhbatpic_resume(struct intsrc *isrc) 280121985Sjhb{ 281121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 282121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 283121985Sjhb 284128929Sjhb if (ai->at_irq == 0) { 285121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 286129009Snyan#ifndef PC98 287128929Sjhb if (ap == &atpics[SLAVE] && using_elcr) 288128929Sjhb elcr_resume(); 289129009Snyan#endif 290128929Sjhb } 291121985Sjhb} 292121985Sjhb 293128931Sjhbstatic int 294128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 295128931Sjhb enum intr_polarity pol) 296128931Sjhb{ 297128931Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 298128931Sjhb u_int vector; 299128931Sjhb 300128931Sjhb /* Map conforming values to edge/hi and sanity check the values. */ 301128931Sjhb if (trig == INTR_TRIGGER_CONFORM) 302128931Sjhb trig = INTR_TRIGGER_EDGE; 303128931Sjhb if (pol == INTR_POLARITY_CONFORM) 304128931Sjhb pol = INTR_POLARITY_HIGH; 305128931Sjhb vector = atpic_vector(isrc); 306128931Sjhb if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) || 307128931Sjhb (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) { 308128931Sjhb printf( 309128931Sjhb "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n", 310128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level", 311128931Sjhb pol == INTR_POLARITY_HIGH ? "high" : "low"); 312128931Sjhb return (EINVAL); 313128931Sjhb } 314128931Sjhb 315128931Sjhb /* If there is no change, just return. */ 316128931Sjhb if (ai->at_trigger == trig) 317128931Sjhb return (0); 318128931Sjhb 319129009Snyan#ifdef PC98 320129009Snyan if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) && 321129009Snyan trig == INTR_TRIGGER_LEVEL) { 322129009Snyan if (bootverbose) 323129009Snyan printf( 324129009Snyan "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 325129009Snyan vector); 326129009Snyan return (EINVAL); 327129009Snyan } 328129009Snyan return (ENXIO); 329129009Snyan#else 330128931Sjhb /* 331128931Sjhb * Certain IRQs can never be level/lo, so don't try to set them 332128931Sjhb * that way if asked. At least some ELCR registers ignore setting 333128931Sjhb * these bits as well. 334128931Sjhb */ 335128931Sjhb if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) && 336128931Sjhb trig == INTR_TRIGGER_LEVEL) { 337128931Sjhb if (bootverbose) 338128931Sjhb printf( 339128931Sjhb "atpic: Ignoring invalid level/low configuration for IRQ%u\n", 340128931Sjhb vector); 341128931Sjhb return (EINVAL); 342128931Sjhb } 343128931Sjhb if (!using_elcr) { 344128931Sjhb if (bootverbose) 345128931Sjhb printf("atpic: No ELCR to configure IRQ%u as %s\n", 346128931Sjhb vector, trig == INTR_TRIGGER_EDGE ? "edge/high" : 347128931Sjhb "level/low"); 348128931Sjhb return (ENXIO); 349128931Sjhb } 350128931Sjhb if (bootverbose) 351128931Sjhb printf("atpic: Programming IRQ%u as %s\n", vector, 352128931Sjhb trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low"); 353128931Sjhb mtx_lock_spin(&icu_lock); 354128931Sjhb elcr_write_trigger(atpic_vector(isrc), trig); 355128931Sjhb ai->at_trigger = trig; 356128931Sjhb mtx_unlock_spin(&icu_lock); 357128931Sjhb return (0); 358129009Snyan#endif /* PC98 */ 359128931Sjhb} 360128931Sjhb 361121985Sjhbstatic void 362121985Sjhbi8259_init(struct atpic *pic, int slave) 363121985Sjhb{ 364121985Sjhb int imr_addr; 365121985Sjhb 366121985Sjhb /* Reset the PIC and program with next four bytes. */ 367121985Sjhb mtx_lock_spin(&icu_lock); 368121985Sjhb#ifdef DEV_MCA 369122692Sjhb /* MCA uses level triggered interrupts. */ 370121985Sjhb if (MCA_system) 371122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 372121985Sjhb else 373121985Sjhb#endif 374122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 375121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 376121985Sjhb 377121985Sjhb /* Start vector. */ 378121985Sjhb outb(imr_addr, pic->at_intbase); 379121985Sjhb 380121985Sjhb /* 381121985Sjhb * Setup slave links. For the master pic, indicate what line 382121985Sjhb * the slave is configured on. For the slave indicate 383121985Sjhb * which line on the master we are connected to. 384121985Sjhb */ 385121985Sjhb if (slave) 386129131Sjhb outb(imr_addr, ICU_SLAVEID); 387121985Sjhb else 388129131Sjhb outb(imr_addr, IRQ_MASK(ICU_SLAVEID)); 389121985Sjhb 390121985Sjhb /* Set mode. */ 391121985Sjhb if (slave) 392121985Sjhb outb(imr_addr, SLAVE_MODE); 393121985Sjhb else 394121985Sjhb outb(imr_addr, MASTER_MODE); 395121985Sjhb 396121985Sjhb /* Set interrupt enable mask. */ 397121985Sjhb outb(imr_addr, *pic->at_imen); 398121985Sjhb 399121985Sjhb /* Reset is finished, default to IRR on read. */ 400122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 401121985Sjhb 402121985Sjhb#ifndef PC98 403122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 404121985Sjhb if (!slave) 405122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 406121985Sjhb#endif 407121985Sjhb mtx_unlock_spin(&icu_lock); 408121985Sjhb} 409121985Sjhb 410121985Sjhbvoid 411121985Sjhbatpic_startup(void) 412121985Sjhb{ 413122897Sjhb struct atpic_intsrc *ai; 414122897Sjhb int i; 415121985Sjhb 416121985Sjhb /* Start off with all interrupts disabled. */ 417121985Sjhb imen = 0xffff; 418121985Sjhb i8259_init(&atpics[MASTER], 0); 419121985Sjhb i8259_init(&atpics[SLAVE], 1); 420121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 421122897Sjhb 422122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 423128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 424122897Sjhb if (i == ICU_SLAVEID) 425122897Sjhb continue; 426122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 427122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 428122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 429122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 430122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 431122897Sjhb } 432128929Sjhb 433128929Sjhb#ifdef DEV_MCA 434128929Sjhb /* For MCA systems, all interrupts are level triggered. */ 435128929Sjhb if (MCA_system) 436128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 437128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 438128929Sjhb else 439128929Sjhb#endif 440128929Sjhb 441129009Snyan#ifdef PC98 442129009Snyan for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 443129009Snyan switch (i) { 444129009Snyan case 0: 445129009Snyan case 1: 446129009Snyan case 7: 447129009Snyan case 8: 448129009Snyan ai->at_trigger = INTR_TRIGGER_EDGE; 449129009Snyan break; 450129009Snyan default: 451129009Snyan ai->at_trigger = INTR_TRIGGER_LEVEL; 452129009Snyan break; 453129009Snyan } 454129009Snyan#else 455128929Sjhb /* 456128929Sjhb * Look for an ELCR. If we find one, update the trigger modes. 457128929Sjhb * If we don't find one, assume that IRQs 0, 1, 2, and 13 are 458128929Sjhb * edge triggered and that everything else is level triggered. 459128929Sjhb * We only use the trigger information to reprogram the ELCR if 460128929Sjhb * we have one and as an optimization to avoid masking edge 461128929Sjhb * triggered interrupts. For the case that we don't have an ELCR, 462128929Sjhb * it doesn't hurt to mask an edge triggered interrupt, so we 463129095Sjhb * assume level trigger for any interrupt that we aren't sure is 464129095Sjhb * edge triggered. 465128929Sjhb */ 466128929Sjhb if (elcr_probe() == 0) { 467128929Sjhb using_elcr = 1; 468128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 469128929Sjhb ai->at_trigger = elcr_read_trigger(i); 470128929Sjhb } else { 471128929Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) 472128929Sjhb switch (i) { 473128929Sjhb case 0: 474128929Sjhb case 1: 475128929Sjhb case 2: 476128929Sjhb case 8: 477128929Sjhb case 13: 478128929Sjhb ai->at_trigger = INTR_TRIGGER_EDGE; 479128929Sjhb break; 480128929Sjhb default: 481128929Sjhb ai->at_trigger = INTR_TRIGGER_LEVEL; 482128929Sjhb break; 483128929Sjhb } 484128929Sjhb } 485129009Snyan#endif /* PC98 */ 486121985Sjhb} 487121985Sjhb 488121985Sjhbstatic void 489121985Sjhbatpic_init(void *dummy __unused) 490121985Sjhb{ 491128875Sjhb struct atpic_intsrc *ai; 492121985Sjhb int i; 493121985Sjhb 494121985Sjhb /* Loop through all interrupt sources and add them. */ 495128875Sjhb for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { 496121985Sjhb if (i == ICU_SLAVEID) 497121985Sjhb continue; 498128875Sjhb intr_register_source(&ai->at_intsrc); 499121985Sjhb } 500121985Sjhb} 501121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 502121985Sjhb 503121985Sjhbvoid 504122572Sjhbatpic_handle_intr(struct intrframe iframe) 505121985Sjhb{ 506121985Sjhb struct intsrc *isrc; 507121985Sjhb 508129131Sjhb KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS, 509121985Sjhb ("unknown int %d\n", iframe.if_vec)); 510121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 511122898Sjhb 512122898Sjhb /* 513122898Sjhb * If we don't have an ithread, see if this is a spurious 514122898Sjhb * interrupt. 515122898Sjhb */ 516122898Sjhb if (isrc->is_ithread == NULL && 517122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 518122898Sjhb int port, isr; 519122898Sjhb 520122898Sjhb /* 521122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 522122898Sjhb * pending. Reset read register back to IRR when done. 523122898Sjhb */ 524122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 525122898Sjhb mtx_lock_spin(&icu_lock); 526122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 527122898Sjhb isr = inb(port); 528122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 529122898Sjhb mtx_unlock_spin(&icu_lock); 530129131Sjhb if ((isr & IRQ_MASK(7)) == 0) 531122898Sjhb return; 532122898Sjhb } 533121985Sjhb intr_execute_handlers(isrc, &iframe); 534121985Sjhb} 535121985Sjhb 536121985Sjhb#ifdef DEV_ISA 537121985Sjhb/* 538121985Sjhb * Bus attachment for the ISA PIC. 539121985Sjhb */ 540121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 541121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 542121985Sjhb { 0 } 543121985Sjhb}; 544121985Sjhb 545121985Sjhbstatic int 546121985Sjhbatpic_probe(device_t dev) 547121985Sjhb{ 548121985Sjhb int result; 549121985Sjhb 550121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 551121985Sjhb if (result <= 0) 552121985Sjhb device_quiet(dev); 553121985Sjhb return (result); 554121985Sjhb} 555121985Sjhb 556121985Sjhb/* 557121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 558121985Sjhb * between the two PIC components. If we're using the APIC, however, 559121985Sjhb * this may not be the case, and as such we should free the resource. 560121985Sjhb * (XXX untested) 561121985Sjhb * 562121985Sjhb * The generic ISA attachment code will handle allocating any other resources 563121985Sjhb * that we don't explicitly claim here. 564121985Sjhb */ 565121985Sjhbstatic int 566121985Sjhbatpic_attach(device_t dev) 567121985Sjhb{ 568121985Sjhb struct resource *res; 569121985Sjhb int rid; 570121985Sjhb 571121985Sjhb /* Try to allocate our IRQ and then free it. */ 572121985Sjhb rid = 0; 573127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 574121985Sjhb if (res != NULL) 575121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 576121985Sjhb return (0); 577121985Sjhb} 578121985Sjhb 579121985Sjhbstatic device_method_t atpic_methods[] = { 580121985Sjhb /* Device interface */ 581121985Sjhb DEVMETHOD(device_probe, atpic_probe), 582121985Sjhb DEVMETHOD(device_attach, atpic_attach), 583121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 584121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 585121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 586121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 587121985Sjhb { 0, 0 } 588121985Sjhb}; 589121985Sjhb 590121985Sjhbstatic driver_t atpic_driver = { 591121985Sjhb "atpic", 592121985Sjhb atpic_methods, 593121985Sjhb 1, /* no softc */ 594121985Sjhb}; 595121985Sjhb 596121985Sjhbstatic devclass_t atpic_devclass; 597121985Sjhb 598121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 599122051Snyan#ifndef PC98 600121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 601122051Snyan#endif 602121985Sjhb 603121985Sjhb/* 604121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 605121985Sjhb * and is only suitable for use at probe time. 606121985Sjhb */ 607121985Sjhbintrmask_t 608121985Sjhbisa_irq_pending(void) 609121985Sjhb{ 610121985Sjhb u_char irr1; 611121985Sjhb u_char irr2; 612121985Sjhb 613121985Sjhb irr1 = inb(IO_ICU1); 614121985Sjhb irr2 = inb(IO_ICU2); 615121985Sjhb return ((irr2 << 8) | irr1); 616121985Sjhb} 617121985Sjhb#endif /* DEV_ISA */ 618