atpic.c revision 128931
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 128931 2004-05-04 21:02:56Z 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/*
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
96128875Sjhb#define	IMEN_MASK(ai)		(1 << (ai)->at_irq)
97128875Sjhb
98128875Sjhb#define	NUM_ISA_IRQS		16
99128875Sjhb
100121985Sjhbstatic void	atpic_init(void *dummy);
101121985Sjhb
102121985Sjhbunsigned int imen;	/* XXX */
103128929Sjhbstatic int using_elcr;
104121985Sjhb
105121985Sjhbinthand_t
106121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
107121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
108121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
109121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
110121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
111121985Sjhb	IDTVEC(atpic_intr15);
112121985Sjhb
113121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
114121985Sjhb
115128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
116121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
117121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
118128931Sjhb	    atpic_resume, atpic_config_intr }, (io), (base),		\
119128931Sjhb	    IDT_IO_INTS + (base), (imenptr) }
120121985Sjhb
121121985Sjhb#define	INTSRC(irq)							\
122128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
123128929Sjhb	    (irq) % 8 }
124121985Sjhb
125121985Sjhbstruct atpic {
126121985Sjhb	struct pic at_pic;
127121985Sjhb	int	at_ioaddr;
128121985Sjhb	int	at_irqbase;
129121985Sjhb	uint8_t	at_intbase;
130121985Sjhb	uint8_t	*at_imen;
131121985Sjhb};
132121985Sjhb
133121985Sjhbstruct atpic_intsrc {
134121985Sjhb	struct intsrc at_intsrc;
135121985Sjhb	inthand_t *at_intr;
136128929Sjhb	int	at_irq;			/* Relative to PIC base. */
137128929Sjhb	enum intr_trigger at_trigger;
138122897Sjhb	u_long	at_count;
139122897Sjhb	u_long	at_straycount;
140121985Sjhb};
141121985Sjhb
142121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
143121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc);
144121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
145121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
146121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
147121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
148121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
149121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
150128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
151128931Sjhb    enum intr_polarity pol);
152121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
153121985Sjhb
154121985Sjhbstatic struct atpic atpics[] = {
155121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
156121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
157121985Sjhb};
158121985Sjhb
159121985Sjhbstatic struct atpic_intsrc atintrs[] = {
160121985Sjhb	INTSRC(0),
161121985Sjhb	INTSRC(1),
162121985Sjhb	INTSRC(2),
163121985Sjhb	INTSRC(3),
164121985Sjhb	INTSRC(4),
165121985Sjhb	INTSRC(5),
166121985Sjhb	INTSRC(6),
167121985Sjhb	INTSRC(7),
168121985Sjhb	INTSRC(8),
169121985Sjhb	INTSRC(9),
170121985Sjhb	INTSRC(10),
171121985Sjhb	INTSRC(11),
172121985Sjhb	INTSRC(12),
173121985Sjhb	INTSRC(13),
174121985Sjhb	INTSRC(14),
175121985Sjhb	INTSRC(15),
176121985Sjhb};
177121985Sjhb
178128875SjhbCTASSERT(sizeof(atintrs) / sizeof(struct atpic_intsrc) == NUM_ISA_IRQS);
179128875Sjhb
180121985Sjhbstatic void
181121985Sjhbatpic_enable_source(struct intsrc *isrc)
182121985Sjhb{
183121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
184121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
185121985Sjhb
186121985Sjhb	mtx_lock_spin(&icu_lock);
187128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
188128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
189128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
190128875Sjhb	}
191121985Sjhb	mtx_unlock_spin(&icu_lock);
192121985Sjhb}
193121985Sjhb
194121985Sjhbstatic void
195121985Sjhbatpic_disable_source(struct intsrc *isrc)
196121985Sjhb{
197121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
198121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
199121985Sjhb
200128929Sjhb	if (ai->at_trigger == INTR_TRIGGER_EDGE)
201128929Sjhb		return;
202121985Sjhb	mtx_lock_spin(&icu_lock);
203128875Sjhb	*ap->at_imen |= IMEN_MASK(ai);
204121985Sjhb	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
205121985Sjhb	mtx_unlock_spin(&icu_lock);
206121985Sjhb}
207121985Sjhb
208121985Sjhbstatic void
209121985Sjhbatpic_eoi_master(struct intsrc *isrc)
210121985Sjhb{
211121985Sjhb
212121985Sjhb	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
213121985Sjhb	    ("%s: mismatched pic", __func__));
214121985Sjhb#ifndef AUTO_EOI_1
215121985Sjhb	mtx_lock_spin(&icu_lock);
216121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
217121985Sjhb	mtx_unlock_spin(&icu_lock);
218121985Sjhb#endif
219121985Sjhb}
220121985Sjhb
221122572Sjhb/*
222122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works.
223122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it.
224122572Sjhb */
225121985Sjhbstatic void
226121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
227121985Sjhb{
228121985Sjhb
229121985Sjhb	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
230121985Sjhb	    ("%s: mismatched pic", __func__));
231121985Sjhb#ifndef AUTO_EOI_2
232121985Sjhb	mtx_lock_spin(&icu_lock);
233121985Sjhb	outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
234121985Sjhb#ifndef AUTO_EOI_1
235121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
236121985Sjhb#endif
237121985Sjhb	mtx_unlock_spin(&icu_lock);
238121985Sjhb#endif
239121985Sjhb}
240121985Sjhb
241121985Sjhbstatic void
242121985Sjhbatpic_enable_intr(struct intsrc *isrc)
243121985Sjhb{
244121985Sjhb}
245121985Sjhb
246121985Sjhbstatic int
247121985Sjhbatpic_vector(struct intsrc *isrc)
248121985Sjhb{
249121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
250121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
251121985Sjhb
252121985Sjhb	return (IRQ(ap, ai));
253121985Sjhb}
254121985Sjhb
255121985Sjhbstatic int
256121985Sjhbatpic_source_pending(struct intsrc *isrc)
257121985Sjhb{
258121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
259121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
260121985Sjhb
261128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
262121985Sjhb}
263121985Sjhb
264121985Sjhbstatic void
265121985Sjhbatpic_resume(struct intsrc *isrc)
266121985Sjhb{
267121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
268121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
269121985Sjhb
270128929Sjhb	if (ai->at_irq == 0) {
271121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
272128929Sjhb		if (ap == &atpics[SLAVE] && using_elcr)
273128929Sjhb			elcr_resume();
274128929Sjhb	}
275121985Sjhb}
276121985Sjhb
277128931Sjhbstatic int
278128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
279128931Sjhb    enum intr_polarity pol)
280128931Sjhb{
281128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
282128931Sjhb	u_int vector;
283128931Sjhb
284128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
285128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
286128931Sjhb		trig = INTR_TRIGGER_EDGE;
287128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
288128931Sjhb		pol = INTR_POLARITY_HIGH;
289128931Sjhb	vector = atpic_vector(isrc);
290128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
291128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
292128931Sjhb		printf(
293128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
294128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
295128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
296128931Sjhb		return (EINVAL);
297128931Sjhb	}
298128931Sjhb
299128931Sjhb	/* If there is no change, just return. */
300128931Sjhb	if (ai->at_trigger == trig)
301128931Sjhb		return (0);
302128931Sjhb
303128931Sjhb	/*
304128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
305128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
306128931Sjhb	 * these bits as well.
307128931Sjhb	 */
308128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
309128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
310128931Sjhb		if (bootverbose)
311128931Sjhb			printf(
312128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
313128931Sjhb			    vector);
314128931Sjhb		return (EINVAL);
315128931Sjhb	}
316128931Sjhb	if (!using_elcr) {
317128931Sjhb		if (bootverbose)
318128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
319128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
320128931Sjhb			    "level/low");
321128931Sjhb		return (ENXIO);
322128931Sjhb	}
323128931Sjhb	if (bootverbose)
324128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
325128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
326128931Sjhb	mtx_lock_spin(&icu_lock);
327128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
328128931Sjhb	ai->at_trigger = trig;
329128931Sjhb	mtx_unlock_spin(&icu_lock);
330128931Sjhb	return (0);
331128931Sjhb}
332128931Sjhb
333121985Sjhbstatic void
334121985Sjhbi8259_init(struct atpic *pic, int slave)
335121985Sjhb{
336121985Sjhb	int imr_addr;
337121985Sjhb
338121985Sjhb	/* Reset the PIC and program with next four bytes. */
339121985Sjhb	mtx_lock_spin(&icu_lock);
340121985Sjhb#ifdef DEV_MCA
341122692Sjhb	/* MCA uses level triggered interrupts. */
342121985Sjhb	if (MCA_system)
343122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
344121985Sjhb	else
345121985Sjhb#endif
346122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
347121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
348121985Sjhb
349121985Sjhb	/* Start vector. */
350121985Sjhb	outb(imr_addr, pic->at_intbase);
351121985Sjhb
352121985Sjhb	/*
353121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
354121985Sjhb	 * the slave is configured on.  For the slave indicate
355121985Sjhb	 * which line on the master we are connected to.
356121985Sjhb	 */
357121985Sjhb	if (slave)
358121985Sjhb		outb(imr_addr, ICU_SLAVEID);	/* my slave id is 7 */
359121985Sjhb	else
360121985Sjhb		outb(imr_addr, IRQ_SLAVE);	/* slave on line 7 */
361121985Sjhb
362121985Sjhb	/* Set mode. */
363121985Sjhb	if (slave)
364121985Sjhb		outb(imr_addr, SLAVE_MODE);
365121985Sjhb	else
366121985Sjhb		outb(imr_addr, MASTER_MODE);
367121985Sjhb
368121985Sjhb	/* Set interrupt enable mask. */
369121985Sjhb	outb(imr_addr, *pic->at_imen);
370121985Sjhb
371121985Sjhb	/* Reset is finished, default to IRR on read. */
372122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
373121985Sjhb
374121985Sjhb#ifndef PC98
375122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
376121985Sjhb	if (!slave)
377122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
378121985Sjhb#endif
379121985Sjhb	mtx_unlock_spin(&icu_lock);
380121985Sjhb}
381121985Sjhb
382121985Sjhbvoid
383121985Sjhbatpic_startup(void)
384121985Sjhb{
385122897Sjhb	struct atpic_intsrc *ai;
386122897Sjhb	int i;
387121985Sjhb
388121985Sjhb	/* Start off with all interrupts disabled. */
389121985Sjhb	imen = 0xffff;
390121985Sjhb	i8259_init(&atpics[MASTER], 0);
391121985Sjhb	i8259_init(&atpics[SLAVE], 1);
392121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
393122897Sjhb
394122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
395128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
396122897Sjhb		if (i == ICU_SLAVEID)
397122897Sjhb			continue;
398122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
399122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
400122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
401122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
402122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
403122897Sjhb	}
404128929Sjhb
405128929Sjhb#ifdef DEV_MCA
406128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
407128929Sjhb	if (MCA_system)
408128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
409128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
410128929Sjhb	else
411128929Sjhb#endif
412128929Sjhb
413128929Sjhb	/*
414128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
415128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
416128929Sjhb	 * edge triggered and that everything else is level triggered.
417128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
418128929Sjhb	 * we have one and as an optimization to avoid masking edge
419128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
420128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
421128929Sjhb	 * that is why we assume level trigger for any interrupt that we
422128929Sjhb	 * aren't sure is edge triggered.
423128929Sjhb	 */
424128929Sjhb	if (elcr_probe() == 0) {
425128929Sjhb		using_elcr = 1;
426128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
427128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
428128929Sjhb	} else {
429128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
430128929Sjhb			switch (i) {
431128929Sjhb			case 0:
432128929Sjhb			case 1:
433128929Sjhb			case 2:
434128929Sjhb			case 8:
435128929Sjhb			case 13:
436128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
437128929Sjhb				break;
438128929Sjhb			default:
439128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
440128929Sjhb				break;
441128929Sjhb			}
442128929Sjhb	}
443121985Sjhb}
444121985Sjhb
445121985Sjhbstatic void
446121985Sjhbatpic_init(void *dummy __unused)
447121985Sjhb{
448128875Sjhb	struct atpic_intsrc *ai;
449121985Sjhb	int i;
450121985Sjhb
451121985Sjhb	/* Loop through all interrupt sources and add them. */
452128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
453121985Sjhb		if (i == ICU_SLAVEID)
454121985Sjhb			continue;
455128875Sjhb		intr_register_source(&ai->at_intsrc);
456121985Sjhb	}
457121985Sjhb}
458121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
459121985Sjhb
460121985Sjhbvoid
461122572Sjhbatpic_handle_intr(struct intrframe iframe)
462121985Sjhb{
463121985Sjhb	struct intsrc *isrc;
464121985Sjhb
465128438Sobrien	KASSERT((u_int)iframe.if_vec < ICU_LEN,
466121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
467121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
468122898Sjhb
469122898Sjhb	/*
470122898Sjhb	 * If we don't have an ithread, see if this is a spurious
471122898Sjhb	 * interrupt.
472122898Sjhb	 */
473122898Sjhb	if (isrc->is_ithread == NULL &&
474122898Sjhb	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
475122898Sjhb		int port, isr;
476122898Sjhb
477122898Sjhb		/*
478122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
479122898Sjhb		 * pending.  Reset read register back to IRR when done.
480122898Sjhb		 */
481122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
482122898Sjhb		mtx_lock_spin(&icu_lock);
483122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
484122898Sjhb		isr = inb(port);
485122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
486122898Sjhb		mtx_unlock_spin(&icu_lock);
487122898Sjhb		if ((isr & IRQ7) == 0)
488122898Sjhb			return;
489122898Sjhb	}
490121985Sjhb	intr_execute_handlers(isrc, &iframe);
491121985Sjhb}
492121985Sjhb
493121985Sjhb#ifdef DEV_ISA
494121985Sjhb/*
495121985Sjhb * Bus attachment for the ISA PIC.
496121985Sjhb */
497121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
498121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
499121985Sjhb	{ 0 }
500121985Sjhb};
501121985Sjhb
502121985Sjhbstatic int
503121985Sjhbatpic_probe(device_t dev)
504121985Sjhb{
505121985Sjhb	int result;
506121985Sjhb
507121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
508121985Sjhb	if (result <= 0)
509121985Sjhb		device_quiet(dev);
510121985Sjhb	return (result);
511121985Sjhb}
512121985Sjhb
513121985Sjhb/*
514121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
515121985Sjhb * between the two PIC components.  If we're using the APIC, however,
516121985Sjhb * this may not be the case, and as such we should free the resource.
517121985Sjhb * (XXX untested)
518121985Sjhb *
519121985Sjhb * The generic ISA attachment code will handle allocating any other resources
520121985Sjhb * that we don't explicitly claim here.
521121985Sjhb */
522121985Sjhbstatic int
523121985Sjhbatpic_attach(device_t dev)
524121985Sjhb{
525121985Sjhb	struct resource *res;
526121985Sjhb	int rid;
527121985Sjhb
528121985Sjhb	/* Try to allocate our IRQ and then free it. */
529121985Sjhb	rid = 0;
530127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
531121985Sjhb	if (res != NULL)
532121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
533121985Sjhb	return (0);
534121985Sjhb}
535121985Sjhb
536121985Sjhbstatic device_method_t atpic_methods[] = {
537121985Sjhb	/* Device interface */
538121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
539121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
540121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
541121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
542121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
543121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
544121985Sjhb	{ 0, 0 }
545121985Sjhb};
546121985Sjhb
547121985Sjhbstatic driver_t atpic_driver = {
548121985Sjhb	"atpic",
549121985Sjhb	atpic_methods,
550121985Sjhb	1,		/* no softc */
551121985Sjhb};
552121985Sjhb
553121985Sjhbstatic devclass_t atpic_devclass;
554121985Sjhb
555121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
556122051Snyan#ifndef PC98
557121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
558122051Snyan#endif
559121985Sjhb
560121985Sjhb/*
561121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
562121985Sjhb * and is only suitable for use at probe time.
563121985Sjhb */
564121985Sjhbintrmask_t
565121985Sjhbisa_irq_pending(void)
566121985Sjhb{
567121985Sjhb	u_char irr1;
568121985Sjhb	u_char irr2;
569121985Sjhb
570121985Sjhb	irr1 = inb(IO_ICU1);
571121985Sjhb	irr2 = inb(IO_ICU2);
572121985Sjhb	return ((irr2 << 8) | irr1);
573121985Sjhb}
574121985Sjhb#endif /* DEV_ISA */
575