The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/atpic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7f44d4ee2df5d6cf1976150777f3de58


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.