atpic.c revision 129009
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 129009 2004-05-06 13:48:34Z nyan $");
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 */
103129009Snyan#ifndef PC98
104128929Sjhbstatic int using_elcr;
105129009Snyan#endif
106121985Sjhb
107121985Sjhbinthand_t
108121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
109121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
110121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
111121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
112121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
113121985Sjhb	IDTVEC(atpic_intr15);
114121985Sjhb
115121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
116121985Sjhb
117128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
118121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
119121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
120128931Sjhb	    atpic_resume, atpic_config_intr }, (io), (base),		\
121128931Sjhb	    IDT_IO_INTS + (base), (imenptr) }
122121985Sjhb
123121985Sjhb#define	INTSRC(irq)							\
124128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
125128929Sjhb	    (irq) % 8 }
126121985Sjhb
127121985Sjhbstruct atpic {
128121985Sjhb	struct pic at_pic;
129121985Sjhb	int	at_ioaddr;
130121985Sjhb	int	at_irqbase;
131121985Sjhb	uint8_t	at_intbase;
132121985Sjhb	uint8_t	*at_imen;
133121985Sjhb};
134121985Sjhb
135121985Sjhbstruct atpic_intsrc {
136121985Sjhb	struct intsrc at_intsrc;
137121985Sjhb	inthand_t *at_intr;
138128929Sjhb	int	at_irq;			/* Relative to PIC base. */
139128929Sjhb	enum intr_trigger at_trigger;
140122897Sjhb	u_long	at_count;
141122897Sjhb	u_long	at_straycount;
142121985Sjhb};
143121985Sjhb
144121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
145121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc);
146121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
147121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
148121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
149121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
150121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
151121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
152128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
153128931Sjhb    enum intr_polarity pol);
154121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
155121985Sjhb
156121985Sjhbstatic struct atpic atpics[] = {
157121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
158121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
159121985Sjhb};
160121985Sjhb
161121985Sjhbstatic struct atpic_intsrc atintrs[] = {
162121985Sjhb	INTSRC(0),
163121985Sjhb	INTSRC(1),
164121985Sjhb	INTSRC(2),
165121985Sjhb	INTSRC(3),
166121985Sjhb	INTSRC(4),
167121985Sjhb	INTSRC(5),
168121985Sjhb	INTSRC(6),
169121985Sjhb	INTSRC(7),
170121985Sjhb	INTSRC(8),
171121985Sjhb	INTSRC(9),
172121985Sjhb	INTSRC(10),
173121985Sjhb	INTSRC(11),
174121985Sjhb	INTSRC(12),
175121985Sjhb	INTSRC(13),
176121985Sjhb	INTSRC(14),
177121985Sjhb	INTSRC(15),
178121985Sjhb};
179121985Sjhb
180128875SjhbCTASSERT(sizeof(atintrs) / sizeof(struct atpic_intsrc) == NUM_ISA_IRQS);
181128875Sjhb
182121985Sjhbstatic void
183121985Sjhbatpic_enable_source(struct intsrc *isrc)
184121985Sjhb{
185121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
186121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
187121985Sjhb
188121985Sjhb	mtx_lock_spin(&icu_lock);
189128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
190128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
191128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
192128875Sjhb	}
193121985Sjhb	mtx_unlock_spin(&icu_lock);
194121985Sjhb}
195121985Sjhb
196121985Sjhbstatic void
197121985Sjhbatpic_disable_source(struct intsrc *isrc)
198121985Sjhb{
199121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
200121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
201121985Sjhb
202128929Sjhb	if (ai->at_trigger == INTR_TRIGGER_EDGE)
203128929Sjhb		return;
204121985Sjhb	mtx_lock_spin(&icu_lock);
205128875Sjhb	*ap->at_imen |= IMEN_MASK(ai);
206121985Sjhb	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
207121985Sjhb	mtx_unlock_spin(&icu_lock);
208121985Sjhb}
209121985Sjhb
210121985Sjhbstatic void
211121985Sjhbatpic_eoi_master(struct intsrc *isrc)
212121985Sjhb{
213121985Sjhb
214121985Sjhb	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
215121985Sjhb	    ("%s: mismatched pic", __func__));
216121985Sjhb#ifndef AUTO_EOI_1
217121985Sjhb	mtx_lock_spin(&icu_lock);
218121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
219121985Sjhb	mtx_unlock_spin(&icu_lock);
220121985Sjhb#endif
221121985Sjhb}
222121985Sjhb
223122572Sjhb/*
224122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works.
225122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it.
226122572Sjhb */
227121985Sjhbstatic void
228121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
229121985Sjhb{
230121985Sjhb
231121985Sjhb	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
232121985Sjhb	    ("%s: mismatched pic", __func__));
233121985Sjhb#ifndef AUTO_EOI_2
234121985Sjhb	mtx_lock_spin(&icu_lock);
235121985Sjhb	outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
236121985Sjhb#ifndef AUTO_EOI_1
237121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
238121985Sjhb#endif
239121985Sjhb	mtx_unlock_spin(&icu_lock);
240121985Sjhb#endif
241121985Sjhb}
242121985Sjhb
243121985Sjhbstatic void
244121985Sjhbatpic_enable_intr(struct intsrc *isrc)
245121985Sjhb{
246121985Sjhb}
247121985Sjhb
248121985Sjhbstatic int
249121985Sjhbatpic_vector(struct intsrc *isrc)
250121985Sjhb{
251121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
252121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
253121985Sjhb
254121985Sjhb	return (IRQ(ap, ai));
255121985Sjhb}
256121985Sjhb
257121985Sjhbstatic int
258121985Sjhbatpic_source_pending(struct intsrc *isrc)
259121985Sjhb{
260121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
261121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
262121985Sjhb
263128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
264121985Sjhb}
265121985Sjhb
266121985Sjhbstatic void
267121985Sjhbatpic_resume(struct intsrc *isrc)
268121985Sjhb{
269121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
270121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
271121985Sjhb
272128929Sjhb	if (ai->at_irq == 0) {
273121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
274129009Snyan#ifndef PC98
275128929Sjhb		if (ap == &atpics[SLAVE] && using_elcr)
276128929Sjhb			elcr_resume();
277129009Snyan#endif
278128929Sjhb	}
279121985Sjhb}
280121985Sjhb
281128931Sjhbstatic int
282128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
283128931Sjhb    enum intr_polarity pol)
284128931Sjhb{
285128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
286128931Sjhb	u_int vector;
287128931Sjhb
288128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
289128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
290128931Sjhb		trig = INTR_TRIGGER_EDGE;
291128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
292128931Sjhb		pol = INTR_POLARITY_HIGH;
293128931Sjhb	vector = atpic_vector(isrc);
294128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
295128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
296128931Sjhb		printf(
297128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
298128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
299128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
300128931Sjhb		return (EINVAL);
301128931Sjhb	}
302128931Sjhb
303128931Sjhb	/* If there is no change, just return. */
304128931Sjhb	if (ai->at_trigger == trig)
305128931Sjhb		return (0);
306128931Sjhb
307129009Snyan#ifdef PC98
308129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
309129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
310129009Snyan		if (bootverbose)
311129009Snyan			printf(
312129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
313129009Snyan			    vector);
314129009Snyan		return (EINVAL);
315129009Snyan	}
316129009Snyan	return (ENXIO);
317129009Snyan#else
318128931Sjhb	/*
319128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
320128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
321128931Sjhb	 * these bits as well.
322128931Sjhb	 */
323128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
324128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
325128931Sjhb		if (bootverbose)
326128931Sjhb			printf(
327128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
328128931Sjhb			    vector);
329128931Sjhb		return (EINVAL);
330128931Sjhb	}
331128931Sjhb	if (!using_elcr) {
332128931Sjhb		if (bootverbose)
333128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
334128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
335128931Sjhb			    "level/low");
336128931Sjhb		return (ENXIO);
337128931Sjhb	}
338128931Sjhb	if (bootverbose)
339128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
340128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
341128931Sjhb	mtx_lock_spin(&icu_lock);
342128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
343128931Sjhb	ai->at_trigger = trig;
344128931Sjhb	mtx_unlock_spin(&icu_lock);
345128931Sjhb	return (0);
346129009Snyan#endif /* PC98 */
347128931Sjhb}
348128931Sjhb
349121985Sjhbstatic void
350121985Sjhbi8259_init(struct atpic *pic, int slave)
351121985Sjhb{
352121985Sjhb	int imr_addr;
353121985Sjhb
354121985Sjhb	/* Reset the PIC and program with next four bytes. */
355121985Sjhb	mtx_lock_spin(&icu_lock);
356121985Sjhb#ifdef DEV_MCA
357122692Sjhb	/* MCA uses level triggered interrupts. */
358121985Sjhb	if (MCA_system)
359122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
360121985Sjhb	else
361121985Sjhb#endif
362122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
363121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
364121985Sjhb
365121985Sjhb	/* Start vector. */
366121985Sjhb	outb(imr_addr, pic->at_intbase);
367121985Sjhb
368121985Sjhb	/*
369121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
370121985Sjhb	 * the slave is configured on.  For the slave indicate
371121985Sjhb	 * which line on the master we are connected to.
372121985Sjhb	 */
373121985Sjhb	if (slave)
374121985Sjhb		outb(imr_addr, ICU_SLAVEID);	/* my slave id is 7 */
375121985Sjhb	else
376121985Sjhb		outb(imr_addr, IRQ_SLAVE);	/* slave on line 7 */
377121985Sjhb
378121985Sjhb	/* Set mode. */
379121985Sjhb	if (slave)
380121985Sjhb		outb(imr_addr, SLAVE_MODE);
381121985Sjhb	else
382121985Sjhb		outb(imr_addr, MASTER_MODE);
383121985Sjhb
384121985Sjhb	/* Set interrupt enable mask. */
385121985Sjhb	outb(imr_addr, *pic->at_imen);
386121985Sjhb
387121985Sjhb	/* Reset is finished, default to IRR on read. */
388122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
389121985Sjhb
390121985Sjhb#ifndef PC98
391122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
392121985Sjhb	if (!slave)
393122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
394121985Sjhb#endif
395121985Sjhb	mtx_unlock_spin(&icu_lock);
396121985Sjhb}
397121985Sjhb
398121985Sjhbvoid
399121985Sjhbatpic_startup(void)
400121985Sjhb{
401122897Sjhb	struct atpic_intsrc *ai;
402122897Sjhb	int i;
403121985Sjhb
404121985Sjhb	/* Start off with all interrupts disabled. */
405121985Sjhb	imen = 0xffff;
406121985Sjhb	i8259_init(&atpics[MASTER], 0);
407121985Sjhb	i8259_init(&atpics[SLAVE], 1);
408121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
409122897Sjhb
410122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
411128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
412122897Sjhb		if (i == ICU_SLAVEID)
413122897Sjhb			continue;
414122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
415122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
416122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
417122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
418122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
419122897Sjhb	}
420128929Sjhb
421128929Sjhb#ifdef DEV_MCA
422128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
423128929Sjhb	if (MCA_system)
424128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
425128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
426128929Sjhb	else
427128929Sjhb#endif
428128929Sjhb
429129009Snyan#ifdef PC98
430129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
431129009Snyan		switch (i) {
432129009Snyan		case 0:
433129009Snyan		case 1:
434129009Snyan		case 7:
435129009Snyan		case 8:
436129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
437129009Snyan			break;
438129009Snyan		default:
439129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
440129009Snyan			break;
441129009Snyan		}
442129009Snyan#else
443128929Sjhb	/*
444128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
445128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
446128929Sjhb	 * edge triggered and that everything else is level triggered.
447128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
448128929Sjhb	 * we have one and as an optimization to avoid masking edge
449128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
450128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
451128929Sjhb	 * that is why we assume level trigger for any interrupt that we
452128929Sjhb	 * aren't sure is edge triggered.
453128929Sjhb	 */
454128929Sjhb	if (elcr_probe() == 0) {
455128929Sjhb		using_elcr = 1;
456128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
457128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
458128929Sjhb	} else {
459128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
460128929Sjhb			switch (i) {
461128929Sjhb			case 0:
462128929Sjhb			case 1:
463128929Sjhb			case 2:
464128929Sjhb			case 8:
465128929Sjhb			case 13:
466128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
467128929Sjhb				break;
468128929Sjhb			default:
469128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
470128929Sjhb				break;
471128929Sjhb			}
472128929Sjhb	}
473129009Snyan#endif /* PC98 */
474121985Sjhb}
475121985Sjhb
476121985Sjhbstatic void
477121985Sjhbatpic_init(void *dummy __unused)
478121985Sjhb{
479128875Sjhb	struct atpic_intsrc *ai;
480121985Sjhb	int i;
481121985Sjhb
482121985Sjhb	/* Loop through all interrupt sources and add them. */
483128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
484121985Sjhb		if (i == ICU_SLAVEID)
485121985Sjhb			continue;
486128875Sjhb		intr_register_source(&ai->at_intsrc);
487121985Sjhb	}
488121985Sjhb}
489121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
490121985Sjhb
491121985Sjhbvoid
492122572Sjhbatpic_handle_intr(struct intrframe iframe)
493121985Sjhb{
494121985Sjhb	struct intsrc *isrc;
495121985Sjhb
496128438Sobrien	KASSERT((u_int)iframe.if_vec < ICU_LEN,
497121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
498121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
499122898Sjhb
500122898Sjhb	/*
501122898Sjhb	 * If we don't have an ithread, see if this is a spurious
502122898Sjhb	 * interrupt.
503122898Sjhb	 */
504122898Sjhb	if (isrc->is_ithread == NULL &&
505122898Sjhb	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
506122898Sjhb		int port, isr;
507122898Sjhb
508122898Sjhb		/*
509122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
510122898Sjhb		 * pending.  Reset read register back to IRR when done.
511122898Sjhb		 */
512122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
513122898Sjhb		mtx_lock_spin(&icu_lock);
514122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
515122898Sjhb		isr = inb(port);
516122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
517122898Sjhb		mtx_unlock_spin(&icu_lock);
518122898Sjhb		if ((isr & IRQ7) == 0)
519122898Sjhb			return;
520122898Sjhb	}
521121985Sjhb	intr_execute_handlers(isrc, &iframe);
522121985Sjhb}
523121985Sjhb
524121985Sjhb#ifdef DEV_ISA
525121985Sjhb/*
526121985Sjhb * Bus attachment for the ISA PIC.
527121985Sjhb */
528121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
529121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
530121985Sjhb	{ 0 }
531121985Sjhb};
532121985Sjhb
533121985Sjhbstatic int
534121985Sjhbatpic_probe(device_t dev)
535121985Sjhb{
536121985Sjhb	int result;
537121985Sjhb
538121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
539121985Sjhb	if (result <= 0)
540121985Sjhb		device_quiet(dev);
541121985Sjhb	return (result);
542121985Sjhb}
543121985Sjhb
544121985Sjhb/*
545121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
546121985Sjhb * between the two PIC components.  If we're using the APIC, however,
547121985Sjhb * this may not be the case, and as such we should free the resource.
548121985Sjhb * (XXX untested)
549121985Sjhb *
550121985Sjhb * The generic ISA attachment code will handle allocating any other resources
551121985Sjhb * that we don't explicitly claim here.
552121985Sjhb */
553121985Sjhbstatic int
554121985Sjhbatpic_attach(device_t dev)
555121985Sjhb{
556121985Sjhb	struct resource *res;
557121985Sjhb	int rid;
558121985Sjhb
559121985Sjhb	/* Try to allocate our IRQ and then free it. */
560121985Sjhb	rid = 0;
561127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
562121985Sjhb	if (res != NULL)
563121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
564121985Sjhb	return (0);
565121985Sjhb}
566121985Sjhb
567121985Sjhbstatic device_method_t atpic_methods[] = {
568121985Sjhb	/* Device interface */
569121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
570121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
571121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
572121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
573121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
574121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
575121985Sjhb	{ 0, 0 }
576121985Sjhb};
577121985Sjhb
578121985Sjhbstatic driver_t atpic_driver = {
579121985Sjhb	"atpic",
580121985Sjhb	atpic_methods,
581121985Sjhb	1,		/* no softc */
582121985Sjhb};
583121985Sjhb
584121985Sjhbstatic devclass_t atpic_devclass;
585121985Sjhb
586121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
587122051Snyan#ifndef PC98
588121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
589122051Snyan#endif
590121985Sjhb
591121985Sjhb/*
592121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
593121985Sjhb * and is only suitable for use at probe time.
594121985Sjhb */
595121985Sjhbintrmask_t
596121985Sjhbisa_irq_pending(void)
597121985Sjhb{
598121985Sjhb	u_char irr1;
599121985Sjhb	u_char irr2;
600121985Sjhb
601121985Sjhb	irr1 = inb(IO_ICU1);
602121985Sjhb	irr2 = inb(IO_ICU2);
603121985Sjhb	return ((irr2 << 8) | irr1);
604121985Sjhb}
605121985Sjhb#endif /* DEV_ISA */
606