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