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