atpic.c revision 129876
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 129876 2004-05-30 17:57:46Z phk $");
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>
46129876Sphk#include <sys/module.h>
47121985Sjhb#include <sys/mutex.h>
48121985Sjhb
49121985Sjhb#include <machine/cpufunc.h>
50121985Sjhb#include <machine/frame.h>
51121985Sjhb#include <machine/intr_machdep.h>
52121985Sjhb#include <machine/md_var.h>
53121985Sjhb#include <machine/resource.h>
54121985Sjhb#include <machine/segments.h>
55121985Sjhb
56124188Sjhb#include <dev/ic/i8259.h>
57121985Sjhb#include <i386/isa/icu.h>
58122051Snyan#ifdef PC98
59122051Snyan#include <pc98/pc98/pc98.h>
60122051Snyan#else
61121985Sjhb#include <i386/isa/isa.h>
62122051Snyan#endif
63121985Sjhb#include <isa/isavar.h>
64121985Sjhb
65121985Sjhb#define	MASTER	0
66121985Sjhb#define	SLAVE	1
67121985Sjhb
68124188Sjhb/*
69129131Sjhb * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and
70129131Sjhb * PC-AT machines wire the slave PIC to pin 2 on the master PIC.
71129131Sjhb */
72129131Sjhb#ifdef PC98
73129131Sjhb#define	ICU_SLAVEID	7
74129131Sjhb#else
75129131Sjhb#define	ICU_SLAVEID	2
76129131Sjhb#endif
77129131Sjhb
78129131Sjhb/*
79124188Sjhb * Determine the base master and slave modes not including auto EOI support.
80124188Sjhb * All machines that FreeBSD supports use 8086 mode.
81124188Sjhb */
82121985Sjhb#ifdef PC98
83124188Sjhb/*
84124188Sjhb * PC-98 machines do not support auto EOI on the second PIC.  Also, it
85124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC
86124188Sjhb * uses special fully nested mode.
87124188Sjhb */
88124188Sjhb#define	BASE_MASTER_MODE	(ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086)
89124188Sjhb#define	BASE_SLAVE_MODE		(ICW4_BUF | ICW4_8086)
90121985Sjhb#else
91124188Sjhb#define	BASE_MASTER_MODE	ICW4_8086
92124188Sjhb#define	BASE_SLAVE_MODE		ICW4_8086
93121985Sjhb#endif
94124188Sjhb
95124188Sjhb/* Enable automatic EOI if requested. */
96121985Sjhb#ifdef AUTO_EOI_1
97124188Sjhb#define	MASTER_MODE		(BASE_MASTER_MODE | ICW4_AEOI)
98121985Sjhb#else
99124188Sjhb#define	MASTER_MODE		BASE_MASTER_MODE
100121985Sjhb#endif
101121985Sjhb#ifdef AUTO_EOI_2
102124188Sjhb#define	SLAVE_MODE		(BASE_SLAVE_MODE | ICW4_AEOI)
103121985Sjhb#else
104124188Sjhb#define	SLAVE_MODE		BASE_SLAVE_MODE
105121985Sjhb#endif
106121985Sjhb
107129131Sjhb#define	IRQ_MASK(irq)		(1 << (irq))
108129131Sjhb#define	IMEN_MASK(ai)		(IRQ_MASK((ai)->at_irq))
109128875Sjhb
110128875Sjhb#define	NUM_ISA_IRQS		16
111128875Sjhb
112121985Sjhbstatic void	atpic_init(void *dummy);
113121985Sjhb
114121985Sjhbunsigned int imen;	/* XXX */
115129009Snyan#ifndef PC98
116128929Sjhbstatic int using_elcr;
117129009Snyan#endif
118121985Sjhb
119121985Sjhbinthand_t
120121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
121121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
122121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
123121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
124121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
125121985Sjhb	IDTVEC(atpic_intr15);
126121985Sjhb
127121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
128121985Sjhb
129128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
130121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
131121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
132128931Sjhb	    atpic_resume, atpic_config_intr }, (io), (base),		\
133128931Sjhb	    IDT_IO_INTS + (base), (imenptr) }
134121985Sjhb
135121985Sjhb#define	INTSRC(irq)							\
136128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
137128929Sjhb	    (irq) % 8 }
138121985Sjhb
139121985Sjhbstruct atpic {
140121985Sjhb	struct pic at_pic;
141121985Sjhb	int	at_ioaddr;
142121985Sjhb	int	at_irqbase;
143121985Sjhb	uint8_t	at_intbase;
144121985Sjhb	uint8_t	*at_imen;
145121985Sjhb};
146121985Sjhb
147121985Sjhbstruct atpic_intsrc {
148121985Sjhb	struct intsrc at_intsrc;
149121985Sjhb	inthand_t *at_intr;
150128929Sjhb	int	at_irq;			/* Relative to PIC base. */
151128929Sjhb	enum intr_trigger at_trigger;
152122897Sjhb	u_long	at_count;
153122897Sjhb	u_long	at_straycount;
154121985Sjhb};
155121985Sjhb
156121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
157121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc);
158121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
159121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
160121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
161121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
162121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
163121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
164128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
165128931Sjhb    enum intr_polarity pol);
166121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
167121985Sjhb
168121985Sjhbstatic struct atpic atpics[] = {
169121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
170121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
171121985Sjhb};
172121985Sjhb
173121985Sjhbstatic struct atpic_intsrc atintrs[] = {
174121985Sjhb	INTSRC(0),
175121985Sjhb	INTSRC(1),
176121985Sjhb	INTSRC(2),
177121985Sjhb	INTSRC(3),
178121985Sjhb	INTSRC(4),
179121985Sjhb	INTSRC(5),
180121985Sjhb	INTSRC(6),
181121985Sjhb	INTSRC(7),
182121985Sjhb	INTSRC(8),
183121985Sjhb	INTSRC(9),
184121985Sjhb	INTSRC(10),
185121985Sjhb	INTSRC(11),
186121985Sjhb	INTSRC(12),
187121985Sjhb	INTSRC(13),
188121985Sjhb	INTSRC(14),
189121985Sjhb	INTSRC(15),
190121985Sjhb};
191121985Sjhb
192129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
193128875Sjhb
194121985Sjhbstatic void
195121985Sjhbatpic_enable_source(struct intsrc *isrc)
196121985Sjhb{
197121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
198121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
199121985Sjhb
200121985Sjhb	mtx_lock_spin(&icu_lock);
201128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
202128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
203128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
204128875Sjhb	}
205121985Sjhb	mtx_unlock_spin(&icu_lock);
206121985Sjhb}
207121985Sjhb
208121985Sjhbstatic void
209121985Sjhbatpic_disable_source(struct intsrc *isrc)
210121985Sjhb{
211121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
212121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
213121985Sjhb
214128929Sjhb	if (ai->at_trigger == INTR_TRIGGER_EDGE)
215128929Sjhb		return;
216121985Sjhb	mtx_lock_spin(&icu_lock);
217128875Sjhb	*ap->at_imen |= IMEN_MASK(ai);
218121985Sjhb	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
219121985Sjhb	mtx_unlock_spin(&icu_lock);
220121985Sjhb}
221121985Sjhb
222121985Sjhbstatic void
223121985Sjhbatpic_eoi_master(struct intsrc *isrc)
224121985Sjhb{
225121985Sjhb
226121985Sjhb	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
227121985Sjhb	    ("%s: mismatched pic", __func__));
228121985Sjhb#ifndef AUTO_EOI_1
229121985Sjhb	mtx_lock_spin(&icu_lock);
230129131Sjhb	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
231121985Sjhb	mtx_unlock_spin(&icu_lock);
232121985Sjhb#endif
233121985Sjhb}
234121985Sjhb
235122572Sjhb/*
236122572Sjhb * The data sheet says no auto-EOI on slave, but it sometimes works.
237122572Sjhb * So, if AUTO_EOI_2 is enabled, we use it.
238122572Sjhb */
239121985Sjhbstatic void
240121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
241121985Sjhb{
242121985Sjhb
243121985Sjhb	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
244121985Sjhb	    ("%s: mismatched pic", __func__));
245121985Sjhb#ifndef AUTO_EOI_2
246121985Sjhb	mtx_lock_spin(&icu_lock);
247129131Sjhb	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
248121985Sjhb#ifndef AUTO_EOI_1
249129131Sjhb	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
250121985Sjhb#endif
251121985Sjhb	mtx_unlock_spin(&icu_lock);
252121985Sjhb#endif
253121985Sjhb}
254121985Sjhb
255121985Sjhbstatic void
256121985Sjhbatpic_enable_intr(struct intsrc *isrc)
257121985Sjhb{
258121985Sjhb}
259121985Sjhb
260121985Sjhbstatic int
261121985Sjhbatpic_vector(struct intsrc *isrc)
262121985Sjhb{
263121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
264121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
265121985Sjhb
266121985Sjhb	return (IRQ(ap, ai));
267121985Sjhb}
268121985Sjhb
269121985Sjhbstatic int
270121985Sjhbatpic_source_pending(struct intsrc *isrc)
271121985Sjhb{
272121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
273121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
274121985Sjhb
275128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
276121985Sjhb}
277121985Sjhb
278121985Sjhbstatic void
279121985Sjhbatpic_resume(struct intsrc *isrc)
280121985Sjhb{
281121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
282121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
283121985Sjhb
284128929Sjhb	if (ai->at_irq == 0) {
285121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
286129009Snyan#ifndef PC98
287128929Sjhb		if (ap == &atpics[SLAVE] && using_elcr)
288128929Sjhb			elcr_resume();
289129009Snyan#endif
290128929Sjhb	}
291121985Sjhb}
292121985Sjhb
293128931Sjhbstatic int
294128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
295128931Sjhb    enum intr_polarity pol)
296128931Sjhb{
297128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
298128931Sjhb	u_int vector;
299128931Sjhb
300128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
301128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
302128931Sjhb		trig = INTR_TRIGGER_EDGE;
303128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
304128931Sjhb		pol = INTR_POLARITY_HIGH;
305128931Sjhb	vector = atpic_vector(isrc);
306128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
307128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
308128931Sjhb		printf(
309128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
310128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
311128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
312128931Sjhb		return (EINVAL);
313128931Sjhb	}
314128931Sjhb
315128931Sjhb	/* If there is no change, just return. */
316128931Sjhb	if (ai->at_trigger == trig)
317128931Sjhb		return (0);
318128931Sjhb
319129009Snyan#ifdef PC98
320129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
321129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
322129009Snyan		if (bootverbose)
323129009Snyan			printf(
324129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
325129009Snyan			    vector);
326129009Snyan		return (EINVAL);
327129009Snyan	}
328129009Snyan	return (ENXIO);
329129009Snyan#else
330128931Sjhb	/*
331128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
332128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
333128931Sjhb	 * these bits as well.
334128931Sjhb	 */
335128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
336128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
337128931Sjhb		if (bootverbose)
338128931Sjhb			printf(
339128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
340128931Sjhb			    vector);
341128931Sjhb		return (EINVAL);
342128931Sjhb	}
343128931Sjhb	if (!using_elcr) {
344128931Sjhb		if (bootverbose)
345128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
346128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
347128931Sjhb			    "level/low");
348128931Sjhb		return (ENXIO);
349128931Sjhb	}
350128931Sjhb	if (bootverbose)
351128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
352128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
353128931Sjhb	mtx_lock_spin(&icu_lock);
354128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
355128931Sjhb	ai->at_trigger = trig;
356128931Sjhb	mtx_unlock_spin(&icu_lock);
357128931Sjhb	return (0);
358129009Snyan#endif /* PC98 */
359128931Sjhb}
360128931Sjhb
361121985Sjhbstatic void
362121985Sjhbi8259_init(struct atpic *pic, int slave)
363121985Sjhb{
364121985Sjhb	int imr_addr;
365121985Sjhb
366121985Sjhb	/* Reset the PIC and program with next four bytes. */
367121985Sjhb	mtx_lock_spin(&icu_lock);
368121985Sjhb#ifdef DEV_MCA
369122692Sjhb	/* MCA uses level triggered interrupts. */
370121985Sjhb	if (MCA_system)
371122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
372121985Sjhb	else
373121985Sjhb#endif
374122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
375121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
376121985Sjhb
377121985Sjhb	/* Start vector. */
378121985Sjhb	outb(imr_addr, pic->at_intbase);
379121985Sjhb
380121985Sjhb	/*
381121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
382121985Sjhb	 * the slave is configured on.  For the slave indicate
383121985Sjhb	 * which line on the master we are connected to.
384121985Sjhb	 */
385121985Sjhb	if (slave)
386129131Sjhb		outb(imr_addr, ICU_SLAVEID);
387121985Sjhb	else
388129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
389121985Sjhb
390121985Sjhb	/* Set mode. */
391121985Sjhb	if (slave)
392121985Sjhb		outb(imr_addr, SLAVE_MODE);
393121985Sjhb	else
394121985Sjhb		outb(imr_addr, MASTER_MODE);
395121985Sjhb
396121985Sjhb	/* Set interrupt enable mask. */
397121985Sjhb	outb(imr_addr, *pic->at_imen);
398121985Sjhb
399121985Sjhb	/* Reset is finished, default to IRR on read. */
400122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
401121985Sjhb
402121985Sjhb#ifndef PC98
403122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
404121985Sjhb	if (!slave)
405122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
406121985Sjhb#endif
407121985Sjhb	mtx_unlock_spin(&icu_lock);
408121985Sjhb}
409121985Sjhb
410121985Sjhbvoid
411121985Sjhbatpic_startup(void)
412121985Sjhb{
413122897Sjhb	struct atpic_intsrc *ai;
414122897Sjhb	int i;
415121985Sjhb
416121985Sjhb	/* Start off with all interrupts disabled. */
417121985Sjhb	imen = 0xffff;
418121985Sjhb	i8259_init(&atpics[MASTER], 0);
419121985Sjhb	i8259_init(&atpics[SLAVE], 1);
420121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
421122897Sjhb
422122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
423128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
424122897Sjhb		if (i == ICU_SLAVEID)
425122897Sjhb			continue;
426122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
427122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
428122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
429122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
430122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
431122897Sjhb	}
432128929Sjhb
433128929Sjhb#ifdef DEV_MCA
434128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
435128929Sjhb	if (MCA_system)
436128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
437128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
438128929Sjhb	else
439128929Sjhb#endif
440128929Sjhb
441129009Snyan#ifdef PC98
442129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
443129009Snyan		switch (i) {
444129009Snyan		case 0:
445129009Snyan		case 1:
446129009Snyan		case 7:
447129009Snyan		case 8:
448129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
449129009Snyan			break;
450129009Snyan		default:
451129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
452129009Snyan			break;
453129009Snyan		}
454129009Snyan#else
455128929Sjhb	/*
456128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
457128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
458128929Sjhb	 * edge triggered and that everything else is level triggered.
459128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
460128929Sjhb	 * we have one and as an optimization to avoid masking edge
461128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
462128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
463129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
464129095Sjhb	 * edge triggered.
465128929Sjhb	 */
466128929Sjhb	if (elcr_probe() == 0) {
467128929Sjhb		using_elcr = 1;
468128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
469128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
470128929Sjhb	} else {
471128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
472128929Sjhb			switch (i) {
473128929Sjhb			case 0:
474128929Sjhb			case 1:
475128929Sjhb			case 2:
476128929Sjhb			case 8:
477128929Sjhb			case 13:
478128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
479128929Sjhb				break;
480128929Sjhb			default:
481128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
482128929Sjhb				break;
483128929Sjhb			}
484128929Sjhb	}
485129009Snyan#endif /* PC98 */
486121985Sjhb}
487121985Sjhb
488121985Sjhbstatic void
489121985Sjhbatpic_init(void *dummy __unused)
490121985Sjhb{
491128875Sjhb	struct atpic_intsrc *ai;
492121985Sjhb	int i;
493121985Sjhb
494121985Sjhb	/* Loop through all interrupt sources and add them. */
495128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
496121985Sjhb		if (i == ICU_SLAVEID)
497121985Sjhb			continue;
498128875Sjhb		intr_register_source(&ai->at_intsrc);
499121985Sjhb	}
500121985Sjhb}
501121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
502121985Sjhb
503121985Sjhbvoid
504122572Sjhbatpic_handle_intr(struct intrframe iframe)
505121985Sjhb{
506121985Sjhb	struct intsrc *isrc;
507121985Sjhb
508129131Sjhb	KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS,
509121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
510121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
511122898Sjhb
512122898Sjhb	/*
513122898Sjhb	 * If we don't have an ithread, see if this is a spurious
514122898Sjhb	 * interrupt.
515122898Sjhb	 */
516122898Sjhb	if (isrc->is_ithread == NULL &&
517122898Sjhb	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
518122898Sjhb		int port, isr;
519122898Sjhb
520122898Sjhb		/*
521122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
522122898Sjhb		 * pending.  Reset read register back to IRR when done.
523122898Sjhb		 */
524122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
525122898Sjhb		mtx_lock_spin(&icu_lock);
526122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
527122898Sjhb		isr = inb(port);
528122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
529122898Sjhb		mtx_unlock_spin(&icu_lock);
530129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
531122898Sjhb			return;
532122898Sjhb	}
533121985Sjhb	intr_execute_handlers(isrc, &iframe);
534121985Sjhb}
535121985Sjhb
536121985Sjhb#ifdef DEV_ISA
537121985Sjhb/*
538121985Sjhb * Bus attachment for the ISA PIC.
539121985Sjhb */
540121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
541121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
542121985Sjhb	{ 0 }
543121985Sjhb};
544121985Sjhb
545121985Sjhbstatic int
546121985Sjhbatpic_probe(device_t dev)
547121985Sjhb{
548121985Sjhb	int result;
549121985Sjhb
550121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
551121985Sjhb	if (result <= 0)
552121985Sjhb		device_quiet(dev);
553121985Sjhb	return (result);
554121985Sjhb}
555121985Sjhb
556121985Sjhb/*
557121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
558121985Sjhb * between the two PIC components.  If we're using the APIC, however,
559121985Sjhb * this may not be the case, and as such we should free the resource.
560121985Sjhb * (XXX untested)
561121985Sjhb *
562121985Sjhb * The generic ISA attachment code will handle allocating any other resources
563121985Sjhb * that we don't explicitly claim here.
564121985Sjhb */
565121985Sjhbstatic int
566121985Sjhbatpic_attach(device_t dev)
567121985Sjhb{
568121985Sjhb	struct resource *res;
569121985Sjhb	int rid;
570121985Sjhb
571121985Sjhb	/* Try to allocate our IRQ and then free it. */
572121985Sjhb	rid = 0;
573127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
574121985Sjhb	if (res != NULL)
575121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
576121985Sjhb	return (0);
577121985Sjhb}
578121985Sjhb
579121985Sjhbstatic device_method_t atpic_methods[] = {
580121985Sjhb	/* Device interface */
581121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
582121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
583121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
584121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
585121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
586121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
587121985Sjhb	{ 0, 0 }
588121985Sjhb};
589121985Sjhb
590121985Sjhbstatic driver_t atpic_driver = {
591121985Sjhb	"atpic",
592121985Sjhb	atpic_methods,
593121985Sjhb	1,		/* no softc */
594121985Sjhb};
595121985Sjhb
596121985Sjhbstatic devclass_t atpic_devclass;
597121985Sjhb
598121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
599122051Snyan#ifndef PC98
600121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
601122051Snyan#endif
602121985Sjhb
603121985Sjhb/*
604121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
605121985Sjhb * and is only suitable for use at probe time.
606121985Sjhb */
607121985Sjhbintrmask_t
608121985Sjhbisa_irq_pending(void)
609121985Sjhb{
610121985Sjhb	u_char irr1;
611121985Sjhb	u_char irr2;
612121985Sjhb
613121985Sjhb	irr1 = inb(IO_ICU1);
614121985Sjhb	irr2 = inb(IO_ICU2);
615121985Sjhb	return ((irr2 << 8) | irr1);
616121985Sjhb}
617121985Sjhb#endif /* DEV_ISA */
618