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