atpic.c revision 156124
1/*-
2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 156124 2006-02-28 22:24:55Z jhb $");
36
37#include "opt_auto_eoi.h"
38#include "opt_isa.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>
43#include <sys/interrupt.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/module.h>
47#include <sys/mutex.h>
48
49#include <machine/cpufunc.h>
50#include <machine/frame.h>
51#include <machine/intr_machdep.h>
52#include <machine/md_var.h>
53#include <machine/resource.h>
54#include <machine/segments.h>
55
56#include <dev/ic/i8259.h>
57#include <i386/isa/icu.h>
58#ifdef PC98
59#include <pc98/cbus/cbus.h>
60#else
61#include <i386/isa/isa.h>
62#endif
63#include <isa/isavar.h>
64
65#define	MASTER	0
66#define	SLAVE	1
67
68/*
69 * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and
70 * PC-AT machines wire the slave PIC to pin 2 on the master PIC.
71 */
72#ifdef PC98
73#define	ICU_SLAVEID	7
74#else
75#define	ICU_SLAVEID	2
76#endif
77
78/*
79 * Determine the base master and slave modes not including auto EOI support.
80 * All machines that FreeBSD supports use 8086 mode.
81 */
82#ifdef PC98
83/*
84 * PC-98 machines do not support auto EOI on the second PIC.  Also, it
85 * seems that PC-98 machine PICs use buffered mode, and the master PIC
86 * uses special fully nested mode.
87 */
88#define	BASE_MASTER_MODE	(ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086)
89#define	BASE_SLAVE_MODE		(ICW4_BUF | ICW4_8086)
90#else
91#define	BASE_MASTER_MODE	ICW4_8086
92#define	BASE_SLAVE_MODE		ICW4_8086
93#endif
94
95/* Enable automatic EOI if requested. */
96#ifdef AUTO_EOI_1
97#define	MASTER_MODE		(BASE_MASTER_MODE | ICW4_AEOI)
98#else
99#define	MASTER_MODE		BASE_MASTER_MODE
100#endif
101#ifdef AUTO_EOI_2
102#define	SLAVE_MODE		(BASE_SLAVE_MODE | ICW4_AEOI)
103#else
104#define	SLAVE_MODE		BASE_SLAVE_MODE
105#endif
106
107#define	IRQ_MASK(irq)		(1 << (irq))
108#define	IMEN_MASK(ai)		(IRQ_MASK((ai)->at_irq))
109
110#define	NUM_ISA_IRQS		16
111
112static void	atpic_init(void *dummy);
113
114unsigned int imen;	/* XXX */
115
116inthand_t
117	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
118	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
119	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
120	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
121	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
122	IDTVEC(atpic_intr15);
123
124#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
125
126#define	ATPIC(io, base, eoi, imenptr)					\
127     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
128	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
129	    atpic_resume, atpic_config_intr, atpic_assign_cpu }, (io),  \
130	    (base), IDT_IO_INTS + (base), (imenptr) }
131
132#define	INTSRC(irq)							\
133	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
134	    (irq) % 8 }
135
136struct atpic {
137	struct pic at_pic;
138	int	at_ioaddr;
139	int	at_irqbase;
140	uint8_t	at_intbase;
141	uint8_t	*at_imen;
142};
143
144struct atpic_intsrc {
145	struct intsrc at_intsrc;
146	inthand_t *at_intr;
147	int	at_irq;			/* Relative to PIC base. */
148	enum intr_trigger at_trigger;
149	u_long	at_count;
150	u_long	at_straycount;
151};
152
153static void atpic_enable_source(struct intsrc *isrc);
154static void atpic_disable_source(struct intsrc *isrc, int eoi);
155static void atpic_eoi_master(struct intsrc *isrc);
156static void atpic_eoi_slave(struct intsrc *isrc);
157static void atpic_enable_intr(struct intsrc *isrc);
158static int atpic_vector(struct intsrc *isrc);
159static void atpic_resume(struct intsrc *isrc);
160static int atpic_source_pending(struct intsrc *isrc);
161static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
162    enum intr_polarity pol);
163static void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
164static void i8259_init(struct atpic *pic, int slave);
165
166static struct atpic atpics[] = {
167	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
168	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
169};
170
171static struct atpic_intsrc atintrs[] = {
172	INTSRC(0),
173	INTSRC(1),
174	INTSRC(2),
175	INTSRC(3),
176	INTSRC(4),
177	INTSRC(5),
178	INTSRC(6),
179	INTSRC(7),
180	INTSRC(8),
181	INTSRC(9),
182	INTSRC(10),
183	INTSRC(11),
184	INTSRC(12),
185	INTSRC(13),
186	INTSRC(14),
187	INTSRC(15),
188};
189
190CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
191
192static __inline void
193_atpic_eoi_master(struct intsrc *isrc)
194{
195
196	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
197	    ("%s: mismatched pic", __func__));
198#ifndef AUTO_EOI_1
199	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
200#endif
201}
202
203/*
204 * The data sheet says no auto-EOI on slave, but it sometimes works.
205 * So, if AUTO_EOI_2 is enabled, we use it.
206 */
207static __inline void
208_atpic_eoi_slave(struct intsrc *isrc)
209{
210
211	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
212	    ("%s: mismatched pic", __func__));
213#ifndef AUTO_EOI_2
214	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
215#ifndef AUTO_EOI_1
216	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
217#endif
218#endif
219}
220
221static void
222atpic_enable_source(struct intsrc *isrc)
223{
224	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
225	struct atpic *ap = (struct atpic *)isrc->is_pic;
226
227	mtx_lock_spin(&icu_lock);
228	if (*ap->at_imen & IMEN_MASK(ai)) {
229		*ap->at_imen &= ~IMEN_MASK(ai);
230		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
231	}
232	mtx_unlock_spin(&icu_lock);
233}
234
235static void
236atpic_disable_source(struct intsrc *isrc, int eoi)
237{
238	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
239	struct atpic *ap = (struct atpic *)isrc->is_pic;
240
241	mtx_lock_spin(&icu_lock);
242	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
243		*ap->at_imen |= IMEN_MASK(ai);
244		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
245	}
246
247	/*
248	 * Take care to call these functions directly instead of through
249	 * a function pointer.  All of the referenced variables should
250	 * still be hot in the cache.
251	 */
252	if (eoi == PIC_EOI) {
253		if (isrc->is_pic == &atpics[MASTER].at_pic)
254			_atpic_eoi_master(isrc);
255		else
256			_atpic_eoi_slave(isrc);
257	}
258
259	mtx_unlock_spin(&icu_lock);
260}
261
262static void
263atpic_eoi_master(struct intsrc *isrc)
264{
265#ifndef AUTO_EOI_1
266	mtx_lock_spin(&icu_lock);
267	_atpic_eoi_master(isrc);
268	mtx_unlock_spin(&icu_lock);
269#endif
270}
271
272static void
273atpic_eoi_slave(struct intsrc *isrc)
274{
275#ifndef AUTO_EOI_2
276	mtx_lock_spin(&icu_lock);
277	_atpic_eoi_slave(isrc);
278	mtx_unlock_spin(&icu_lock);
279#endif
280}
281
282static void
283atpic_enable_intr(struct intsrc *isrc)
284{
285}
286
287static int
288atpic_vector(struct intsrc *isrc)
289{
290	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
291	struct atpic *ap = (struct atpic *)isrc->is_pic;
292
293	return (IRQ(ap, ai));
294}
295
296static int
297atpic_source_pending(struct intsrc *isrc)
298{
299	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
300	struct atpic *ap = (struct atpic *)isrc->is_pic;
301
302	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
303}
304
305static void
306atpic_resume(struct intsrc *isrc)
307{
308	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
309	struct atpic *ap = (struct atpic *)isrc->is_pic;
310
311	if (ai->at_irq == 0) {
312		i8259_init(ap, ap == &atpics[SLAVE]);
313#ifndef PC98
314		if (ap == &atpics[SLAVE] && elcr_found)
315			elcr_resume();
316#endif
317	}
318}
319
320static int
321atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
322    enum intr_polarity pol)
323{
324	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
325	u_int vector;
326
327	/* Map conforming values to edge/hi and sanity check the values. */
328	if (trig == INTR_TRIGGER_CONFORM)
329		trig = INTR_TRIGGER_EDGE;
330	if (pol == INTR_POLARITY_CONFORM)
331		pol = INTR_POLARITY_HIGH;
332	vector = atpic_vector(isrc);
333	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
334	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
335		printf(
336		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
337		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
338		    pol == INTR_POLARITY_HIGH ? "high" : "low");
339		return (EINVAL);
340	}
341
342	/* If there is no change, just return. */
343	if (ai->at_trigger == trig)
344		return (0);
345
346#ifdef PC98
347	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
348	    trig == INTR_TRIGGER_LEVEL) {
349		if (bootverbose)
350			printf(
351		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
352			    vector);
353		return (EINVAL);
354	}
355	return (ENXIO);
356#else
357	/*
358	 * Certain IRQs can never be level/lo, so don't try to set them
359	 * that way if asked.  At least some ELCR registers ignore setting
360	 * these bits as well.
361	 */
362	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
363	    trig == INTR_TRIGGER_LEVEL) {
364		if (bootverbose)
365			printf(
366		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
367			    vector);
368		return (EINVAL);
369	}
370	if (!elcr_found) {
371		if (bootverbose)
372			printf("atpic: No ELCR to configure IRQ%u as %s\n",
373			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
374			    "level/low");
375		return (ENXIO);
376	}
377	if (bootverbose)
378		printf("atpic: Programming IRQ%u as %s\n", vector,
379		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
380	mtx_lock_spin(&icu_lock);
381	elcr_write_trigger(atpic_vector(isrc), trig);
382	ai->at_trigger = trig;
383	mtx_unlock_spin(&icu_lock);
384	return (0);
385#endif /* PC98 */
386}
387
388static void
389atpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
390{
391
392	/*
393	 * 8259A's are only used in UP in which case all interrupts always
394	 * go to the sole CPU and this function shouldn't even be called.
395	 */
396	panic("%s: bad cookie", __func__);
397}
398
399static void
400i8259_init(struct atpic *pic, int slave)
401{
402	int imr_addr;
403
404	/* Reset the PIC and program with next four bytes. */
405	mtx_lock_spin(&icu_lock);
406#ifdef DEV_MCA
407	/* MCA uses level triggered interrupts. */
408	if (MCA_system)
409		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
410	else
411#endif
412		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
413	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
414
415	/* Start vector. */
416	outb(imr_addr, pic->at_intbase);
417
418	/*
419	 * Setup slave links.  For the master pic, indicate what line
420	 * the slave is configured on.  For the slave indicate
421	 * which line on the master we are connected to.
422	 */
423	if (slave)
424		outb(imr_addr, ICU_SLAVEID);
425	else
426		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
427
428	/* Set mode. */
429	if (slave)
430		outb(imr_addr, SLAVE_MODE);
431	else
432		outb(imr_addr, MASTER_MODE);
433
434	/* Set interrupt enable mask. */
435	outb(imr_addr, *pic->at_imen);
436
437	/* Reset is finished, default to IRR on read. */
438	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
439
440#ifndef PC98
441	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
442	if (!slave)
443		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
444#endif
445	mtx_unlock_spin(&icu_lock);
446}
447
448void
449atpic_startup(void)
450{
451	struct atpic_intsrc *ai;
452	int i;
453
454	/* Start off with all interrupts disabled. */
455	imen = 0xffff;
456	i8259_init(&atpics[MASTER], 0);
457	i8259_init(&atpics[SLAVE], 1);
458	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
459
460	/* Install low-level interrupt handlers for all of our IRQs. */
461	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
462		if (i == ICU_SLAVEID)
463			continue;
464		ai->at_intsrc.is_count = &ai->at_count;
465		ai->at_intsrc.is_straycount = &ai->at_straycount;
466		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
467		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
468		    GSEL(GCODE_SEL, SEL_KPL));
469	}
470
471#ifdef DEV_MCA
472	/* For MCA systems, all interrupts are level triggered. */
473	if (MCA_system)
474		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
475			ai->at_trigger = INTR_TRIGGER_LEVEL;
476	else
477#endif
478
479#ifdef PC98
480	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
481		switch (i) {
482		case 0:
483		case 1:
484		case 7:
485		case 8:
486			ai->at_trigger = INTR_TRIGGER_EDGE;
487			break;
488		default:
489			ai->at_trigger = INTR_TRIGGER_LEVEL;
490			break;
491		}
492#else
493	/*
494	 * Look for an ELCR.  If we find one, update the trigger modes.
495	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
496	 * edge triggered and that everything else is level triggered.
497	 * We only use the trigger information to reprogram the ELCR if
498	 * we have one and as an optimization to avoid masking edge
499	 * triggered interrupts.  For the case that we don't have an ELCR,
500	 * it doesn't hurt to mask an edge triggered interrupt, so we
501	 * assume level trigger for any interrupt that we aren't sure is
502	 * edge triggered.
503	 */
504	if (elcr_found) {
505		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
506			ai->at_trigger = elcr_read_trigger(i);
507	} else {
508		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
509			switch (i) {
510			case 0:
511			case 1:
512			case 2:
513			case 8:
514			case 13:
515				ai->at_trigger = INTR_TRIGGER_EDGE;
516				break;
517			default:
518				ai->at_trigger = INTR_TRIGGER_LEVEL;
519				break;
520			}
521	}
522#endif /* PC98 */
523}
524
525static void
526atpic_init(void *dummy __unused)
527{
528	struct atpic_intsrc *ai;
529	int i;
530
531	/*
532	 * If any of the ISA IRQs have an interrupt source already, then
533	 * assume that the APICs are being used and don't register any
534	 * of our interrupt sources.  This makes sure we don't accidentally
535	 * use mixed mode.  The "accidental" use could otherwise occur on
536	 * machines that route the ACPI SCI interrupt to a different ISA
537	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
538	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
539	 * to leak through.  We used to depend on this feature for routing
540	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
541	 */
542	for (i = 0; i < NUM_ISA_IRQS; i++)
543		if (intr_lookup_source(i) != NULL)
544			return;
545
546	/* Loop through all interrupt sources and add them. */
547	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
548		if (i == ICU_SLAVEID)
549			continue;
550		intr_register_source(&ai->at_intsrc);
551	}
552}
553SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
554
555void
556atpic_handle_intr(u_int vector, struct trapframe frame)
557{
558	struct intsrc *isrc;
559
560	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
561	isrc = &atintrs[vector].at_intsrc;
562
563	/*
564	 * If we don't have an event, see if this is a spurious
565	 * interrupt.
566	 */
567	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
568		int port, isr;
569
570		/*
571		 * Read the ISR register to see if IRQ 7/15 is really
572		 * pending.  Reset read register back to IRR when done.
573		 */
574		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
575		mtx_lock_spin(&icu_lock);
576		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
577		isr = inb(port);
578		outb(port, OCW3_SEL | OCW3_RR);
579		mtx_unlock_spin(&icu_lock);
580		if ((isr & IRQ_MASK(7)) == 0)
581			return;
582	}
583	intr_execute_handlers(isrc, &frame);
584}
585
586#ifdef DEV_ISA
587/*
588 * Bus attachment for the ISA PIC.
589 */
590static struct isa_pnp_id atpic_ids[] = {
591	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
592	{ 0 }
593};
594
595static int
596atpic_probe(device_t dev)
597{
598	int result;
599
600	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
601	if (result <= 0)
602		device_quiet(dev);
603	return (result);
604}
605
606/*
607 * We might be granted IRQ 2, as this is typically consumed by chaining
608 * between the two PIC components.  If we're using the APIC, however,
609 * this may not be the case, and as such we should free the resource.
610 * (XXX untested)
611 *
612 * The generic ISA attachment code will handle allocating any other resources
613 * that we don't explicitly claim here.
614 */
615static int
616atpic_attach(device_t dev)
617{
618	struct resource *res;
619	int rid;
620
621	/* Try to allocate our IRQ and then free it. */
622	rid = 0;
623	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
624	if (res != NULL)
625		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
626	return (0);
627}
628
629static device_method_t atpic_methods[] = {
630	/* Device interface */
631	DEVMETHOD(device_probe,		atpic_probe),
632	DEVMETHOD(device_attach,	atpic_attach),
633	DEVMETHOD(device_detach,	bus_generic_detach),
634	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
635	DEVMETHOD(device_suspend,	bus_generic_suspend),
636	DEVMETHOD(device_resume,	bus_generic_resume),
637	{ 0, 0 }
638};
639
640static driver_t atpic_driver = {
641	"atpic",
642	atpic_methods,
643	1,		/* no softc */
644};
645
646static devclass_t atpic_devclass;
647
648DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
649#ifndef PC98
650DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
651#endif
652
653/*
654 * Return a bitmap of the current interrupt requests.  This is 8259-specific
655 * and is only suitable for use at probe time.
656 */
657intrmask_t
658isa_irq_pending(void)
659{
660	u_char irr1;
661	u_char irr2;
662
663	irr1 = inb(IO_ICU1);
664	irr2 = inb(IO_ICU2);
665	return ((irr2 << 8) | irr1);
666}
667#endif /* DEV_ISA */
668