atpic.c revision 127135
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 127135 2004-03-17 17:50:55Z njl $"); 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/* 68124188Sjhb * Determine the base master and slave modes not including auto EOI support. 69124188Sjhb * All machines that FreeBSD supports use 8086 mode. 70124188Sjhb */ 71121985Sjhb#ifdef PC98 72124188Sjhb/* 73124188Sjhb * PC-98 machines do not support auto EOI on the second PIC. Also, it 74124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC 75124188Sjhb * uses special fully nested mode. 76124188Sjhb */ 77124188Sjhb#define BASE_MASTER_MODE (ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086) 78124188Sjhb#define BASE_SLAVE_MODE (ICW4_BUF | ICW4_8086) 79121985Sjhb#else 80124188Sjhb#define BASE_MASTER_MODE ICW4_8086 81124188Sjhb#define BASE_SLAVE_MODE ICW4_8086 82121985Sjhb#endif 83124188Sjhb 84124188Sjhb/* Enable automatic EOI if requested. */ 85121985Sjhb#ifdef AUTO_EOI_1 86124188Sjhb#define MASTER_MODE (BASE_MASTER_MODE | ICW4_AEOI) 87121985Sjhb#else 88124188Sjhb#define MASTER_MODE BASE_MASTER_MODE 89121985Sjhb#endif 90121985Sjhb#ifdef AUTO_EOI_2 91124188Sjhb#define SLAVE_MODE (BASE_SLAVE_MODE | ICW4_AEOI) 92121985Sjhb#else 93124188Sjhb#define SLAVE_MODE BASE_SLAVE_MODE 94121985Sjhb#endif 95121985Sjhb 96121985Sjhbstatic void atpic_init(void *dummy); 97121985Sjhb 98121985Sjhbunsigned int imen; /* XXX */ 99121985Sjhb 100121985Sjhbinthand_t 101121985Sjhb IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2), 102121985Sjhb IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5), 103121985Sjhb IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8), 104121985Sjhb IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11), 105121985Sjhb IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14), 106121985Sjhb IDTVEC(atpic_intr15); 107121985Sjhb 108121985Sjhb#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq) 109121985Sjhb 110121985Sjhb#define ATPIC(io, base, eoi, imenptr) \ 111121985Sjhb { { atpic_enable_source, atpic_disable_source, (eoi), \ 112121985Sjhb atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \ 113121985Sjhb atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) } 114121985Sjhb 115121985Sjhb#define INTSRC(irq) \ 116121985Sjhb { { &atpics[(irq) / 8].at_pic }, (irq) % 8, \ 117121985Sjhb IDTVEC(atpic_intr ## irq ) } 118121985Sjhb 119121985Sjhbstruct atpic { 120121985Sjhb struct pic at_pic; 121121985Sjhb int at_ioaddr; 122121985Sjhb int at_irqbase; 123121985Sjhb uint8_t at_intbase; 124121985Sjhb uint8_t *at_imen; 125121985Sjhb}; 126121985Sjhb 127121985Sjhbstruct atpic_intsrc { 128121985Sjhb struct intsrc at_intsrc; 129121985Sjhb int at_irq; /* Relative to PIC base. */ 130121985Sjhb inthand_t *at_intr; 131122897Sjhb u_long at_count; 132122897Sjhb u_long at_straycount; 133121985Sjhb}; 134121985Sjhb 135121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc); 136121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc); 137121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc); 138121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc); 139121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc); 140121985Sjhbstatic int atpic_vector(struct intsrc *isrc); 141121985Sjhbstatic void atpic_resume(struct intsrc *isrc); 142121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc); 143121985Sjhbstatic void i8259_init(struct atpic *pic, int slave); 144121985Sjhb 145121985Sjhbstatic struct atpic atpics[] = { 146121985Sjhb ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen), 147121985Sjhb ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1) 148121985Sjhb}; 149121985Sjhb 150121985Sjhbstatic struct atpic_intsrc atintrs[] = { 151121985Sjhb INTSRC(0), 152121985Sjhb INTSRC(1), 153121985Sjhb INTSRC(2), 154121985Sjhb INTSRC(3), 155121985Sjhb INTSRC(4), 156121985Sjhb INTSRC(5), 157121985Sjhb INTSRC(6), 158121985Sjhb INTSRC(7), 159121985Sjhb INTSRC(8), 160121985Sjhb INTSRC(9), 161121985Sjhb INTSRC(10), 162121985Sjhb INTSRC(11), 163121985Sjhb INTSRC(12), 164121985Sjhb INTSRC(13), 165121985Sjhb INTSRC(14), 166121985Sjhb INTSRC(15), 167121985Sjhb}; 168121985Sjhb 169121985Sjhbstatic void 170121985Sjhbatpic_enable_source(struct intsrc *isrc) 171121985Sjhb{ 172121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 173121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 174121985Sjhb 175121985Sjhb mtx_lock_spin(&icu_lock); 176121985Sjhb *ap->at_imen &= ~(1 << ai->at_irq); 177121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 178121985Sjhb mtx_unlock_spin(&icu_lock); 179121985Sjhb} 180121985Sjhb 181121985Sjhbstatic void 182121985Sjhbatpic_disable_source(struct intsrc *isrc) 183121985Sjhb{ 184121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 185121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 186121985Sjhb 187121985Sjhb mtx_lock_spin(&icu_lock); 188121985Sjhb *ap->at_imen |= (1 << ai->at_irq); 189121985Sjhb outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen); 190121985Sjhb mtx_unlock_spin(&icu_lock); 191121985Sjhb} 192121985Sjhb 193121985Sjhbstatic void 194121985Sjhbatpic_eoi_master(struct intsrc *isrc) 195121985Sjhb{ 196121985Sjhb 197121985Sjhb KASSERT(isrc->is_pic == &atpics[MASTER].at_pic, 198121985Sjhb ("%s: mismatched pic", __func__)); 199121985Sjhb#ifndef AUTO_EOI_1 200121985Sjhb mtx_lock_spin(&icu_lock); 201121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 202121985Sjhb mtx_unlock_spin(&icu_lock); 203121985Sjhb#endif 204121985Sjhb} 205121985Sjhb 206122572Sjhb/* 207122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works. 208122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it. 209122572Sjhb */ 210121985Sjhbstatic void 211121985Sjhbatpic_eoi_slave(struct intsrc *isrc) 212121985Sjhb{ 213121985Sjhb 214121985Sjhb KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic, 215121985Sjhb ("%s: mismatched pic", __func__)); 216121985Sjhb#ifndef AUTO_EOI_2 217121985Sjhb mtx_lock_spin(&icu_lock); 218121985Sjhb outb(atpics[SLAVE].at_ioaddr, ICU_EOI); 219121985Sjhb#ifndef AUTO_EOI_1 220121985Sjhb outb(atpics[MASTER].at_ioaddr, ICU_EOI); 221121985Sjhb#endif 222121985Sjhb mtx_unlock_spin(&icu_lock); 223121985Sjhb#endif 224121985Sjhb} 225121985Sjhb 226121985Sjhbstatic void 227121985Sjhbatpic_enable_intr(struct intsrc *isrc) 228121985Sjhb{ 229121985Sjhb} 230121985Sjhb 231121985Sjhbstatic int 232121985Sjhbatpic_vector(struct intsrc *isrc) 233121985Sjhb{ 234121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 235121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 236121985Sjhb 237121985Sjhb return (IRQ(ap, ai)); 238121985Sjhb} 239121985Sjhb 240121985Sjhbstatic int 241121985Sjhbatpic_source_pending(struct intsrc *isrc) 242121985Sjhb{ 243121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 244121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 245121985Sjhb 246121985Sjhb return (inb(ap->at_ioaddr) & (1 << ai->at_irq)); 247121985Sjhb} 248121985Sjhb 249121985Sjhbstatic void 250121985Sjhbatpic_resume(struct intsrc *isrc) 251121985Sjhb{ 252121985Sjhb struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc; 253121985Sjhb struct atpic *ap = (struct atpic *)isrc->is_pic; 254121985Sjhb 255121985Sjhb if (ai->at_irq == 0) 256121985Sjhb i8259_init(ap, ap == &atpics[SLAVE]); 257121985Sjhb} 258121985Sjhb 259121985Sjhbstatic void 260121985Sjhbi8259_init(struct atpic *pic, int slave) 261121985Sjhb{ 262121985Sjhb int imr_addr; 263121985Sjhb 264121985Sjhb /* Reset the PIC and program with next four bytes. */ 265121985Sjhb mtx_lock_spin(&icu_lock); 266121985Sjhb#ifdef DEV_MCA 267122692Sjhb /* MCA uses level triggered interrupts. */ 268121985Sjhb if (MCA_system) 269122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM); 270121985Sjhb else 271121985Sjhb#endif 272122692Sjhb outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4); 273121985Sjhb imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET; 274121985Sjhb 275121985Sjhb /* Start vector. */ 276121985Sjhb outb(imr_addr, pic->at_intbase); 277121985Sjhb 278121985Sjhb /* 279121985Sjhb * Setup slave links. For the master pic, indicate what line 280121985Sjhb * the slave is configured on. For the slave indicate 281121985Sjhb * which line on the master we are connected to. 282121985Sjhb */ 283121985Sjhb if (slave) 284121985Sjhb outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */ 285121985Sjhb else 286121985Sjhb outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */ 287121985Sjhb 288121985Sjhb /* Set mode. */ 289121985Sjhb if (slave) 290121985Sjhb outb(imr_addr, SLAVE_MODE); 291121985Sjhb else 292121985Sjhb outb(imr_addr, MASTER_MODE); 293121985Sjhb 294121985Sjhb /* Set interrupt enable mask. */ 295121985Sjhb outb(imr_addr, *pic->at_imen); 296121985Sjhb 297121985Sjhb /* Reset is finished, default to IRR on read. */ 298122692Sjhb outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR); 299121985Sjhb 300121985Sjhb#ifndef PC98 301122692Sjhb /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */ 302121985Sjhb if (!slave) 303122692Sjhb outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1); 304121985Sjhb#endif 305121985Sjhb mtx_unlock_spin(&icu_lock); 306121985Sjhb} 307121985Sjhb 308121985Sjhbvoid 309121985Sjhbatpic_startup(void) 310121985Sjhb{ 311122897Sjhb struct atpic_intsrc *ai; 312122897Sjhb int i; 313121985Sjhb 314121985Sjhb /* Start off with all interrupts disabled. */ 315121985Sjhb imen = 0xffff; 316121985Sjhb i8259_init(&atpics[MASTER], 0); 317121985Sjhb i8259_init(&atpics[SLAVE], 1); 318121985Sjhb atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]); 319122897Sjhb 320122897Sjhb /* Install low-level interrupt handlers for all of our IRQs. */ 321122897Sjhb for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { 322122897Sjhb if (i == ICU_SLAVEID) 323122897Sjhb continue; 324122897Sjhb ai = &atintrs[i]; 325122897Sjhb ai->at_intsrc.is_count = &ai->at_count; 326122897Sjhb ai->at_intsrc.is_straycount = &ai->at_straycount; 327122897Sjhb setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + 328122897Sjhb ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL, 329122897Sjhb GSEL(GCODE_SEL, SEL_KPL)); 330122897Sjhb } 331121985Sjhb} 332121985Sjhb 333121985Sjhbstatic void 334121985Sjhbatpic_init(void *dummy __unused) 335121985Sjhb{ 336121985Sjhb int i; 337121985Sjhb 338121985Sjhb /* Loop through all interrupt sources and add them. */ 339121985Sjhb for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) { 340121985Sjhb if (i == ICU_SLAVEID) 341121985Sjhb continue; 342122897Sjhb intr_register_source(&atintrs[i].at_intsrc); 343121985Sjhb } 344121985Sjhb} 345121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL) 346121985Sjhb 347121985Sjhbvoid 348122572Sjhbatpic_handle_intr(struct intrframe iframe) 349121985Sjhb{ 350121985Sjhb struct intsrc *isrc; 351121985Sjhb 352121985Sjhb KASSERT((uint)iframe.if_vec < ICU_LEN, 353121985Sjhb ("unknown int %d\n", iframe.if_vec)); 354121985Sjhb isrc = &atintrs[iframe.if_vec].at_intsrc; 355122898Sjhb 356122898Sjhb /* 357122898Sjhb * If we don't have an ithread, see if this is a spurious 358122898Sjhb * interrupt. 359122898Sjhb */ 360122898Sjhb if (isrc->is_ithread == NULL && 361122898Sjhb (iframe.if_vec == 7 || iframe.if_vec == 15)) { 362122898Sjhb int port, isr; 363122898Sjhb 364122898Sjhb /* 365122898Sjhb * Read the ISR register to see if IRQ 7/15 is really 366122898Sjhb * pending. Reset read register back to IRR when done. 367122898Sjhb */ 368122898Sjhb port = ((struct atpic *)isrc->is_pic)->at_ioaddr; 369122898Sjhb mtx_lock_spin(&icu_lock); 370122898Sjhb outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS); 371122898Sjhb isr = inb(port); 372122898Sjhb outb(port, OCW3_SEL | OCW3_RR); 373122898Sjhb mtx_unlock_spin(&icu_lock); 374122898Sjhb if ((isr & IRQ7) == 0) 375122898Sjhb return; 376122898Sjhb } 377121985Sjhb intr_execute_handlers(isrc, &iframe); 378121985Sjhb} 379121985Sjhb 380121985Sjhb#ifdef DEV_ISA 381121985Sjhb/* 382121985Sjhb * Bus attachment for the ISA PIC. 383121985Sjhb */ 384121985Sjhbstatic struct isa_pnp_id atpic_ids[] = { 385121985Sjhb { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 386121985Sjhb { 0 } 387121985Sjhb}; 388121985Sjhb 389121985Sjhbstatic int 390121985Sjhbatpic_probe(device_t dev) 391121985Sjhb{ 392121985Sjhb int result; 393121985Sjhb 394121985Sjhb result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 395121985Sjhb if (result <= 0) 396121985Sjhb device_quiet(dev); 397121985Sjhb return (result); 398121985Sjhb} 399121985Sjhb 400121985Sjhb/* 401121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining 402121985Sjhb * between the two PIC components. If we're using the APIC, however, 403121985Sjhb * this may not be the case, and as such we should free the resource. 404121985Sjhb * (XXX untested) 405121985Sjhb * 406121985Sjhb * The generic ISA attachment code will handle allocating any other resources 407121985Sjhb * that we don't explicitly claim here. 408121985Sjhb */ 409121985Sjhbstatic int 410121985Sjhbatpic_attach(device_t dev) 411121985Sjhb{ 412121985Sjhb struct resource *res; 413121985Sjhb int rid; 414121985Sjhb 415121985Sjhb /* Try to allocate our IRQ and then free it. */ 416121985Sjhb rid = 0; 417127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0); 418121985Sjhb if (res != NULL) 419121985Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, res); 420121985Sjhb return (0); 421121985Sjhb} 422121985Sjhb 423121985Sjhbstatic device_method_t atpic_methods[] = { 424121985Sjhb /* Device interface */ 425121985Sjhb DEVMETHOD(device_probe, atpic_probe), 426121985Sjhb DEVMETHOD(device_attach, atpic_attach), 427121985Sjhb DEVMETHOD(device_detach, bus_generic_detach), 428121985Sjhb DEVMETHOD(device_shutdown, bus_generic_shutdown), 429121985Sjhb DEVMETHOD(device_suspend, bus_generic_suspend), 430121985Sjhb DEVMETHOD(device_resume, bus_generic_resume), 431121985Sjhb { 0, 0 } 432121985Sjhb}; 433121985Sjhb 434121985Sjhbstatic driver_t atpic_driver = { 435121985Sjhb "atpic", 436121985Sjhb atpic_methods, 437121985Sjhb 1, /* no softc */ 438121985Sjhb}; 439121985Sjhb 440121985Sjhbstatic devclass_t atpic_devclass; 441121985Sjhb 442121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0); 443122051Snyan#ifndef PC98 444121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0); 445122051Snyan#endif 446121985Sjhb 447121985Sjhb/* 448121985Sjhb * Return a bitmap of the current interrupt requests. This is 8259-specific 449121985Sjhb * and is only suitable for use at probe time. 450121985Sjhb */ 451121985Sjhbintrmask_t 452121985Sjhbisa_irq_pending(void) 453121985Sjhb{ 454121985Sjhb u_char irr1; 455121985Sjhb u_char irr2; 456121985Sjhb 457121985Sjhb irr1 = inb(IO_ICU1); 458121985Sjhb irr2 = inb(IO_ICU2); 459121985Sjhb return ((irr2 << 8) | irr1); 460121985Sjhb} 461121985Sjhb#endif /* DEV_ISA */ 462