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.2/sys/i386/isa/atpic.c 163803 2006-10-30 18:03:04Z 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 #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 pic *pic);
  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 pic *pic)
  307 {
  308         struct atpic *ap = (struct atpic *)pic;
  309 
  310         i8259_init(ap, ap == &atpics[SLAVE]);
  311 #ifndef PC98
  312         if (ap == &atpics[SLAVE] && elcr_found)
  313                 elcr_resume();
  314 #endif
  315 }
  316 
  317 static int
  318 atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  319     enum intr_polarity pol)
  320 {
  321         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  322         u_int vector;
  323 
  324         /* Map conforming values to edge/hi and sanity check the values. */
  325         if (trig == INTR_TRIGGER_CONFORM)
  326                 trig = INTR_TRIGGER_EDGE;
  327         if (pol == INTR_POLARITY_CONFORM)
  328                 pol = INTR_POLARITY_HIGH;
  329         vector = atpic_vector(isrc);
  330         if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
  331             (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
  332                 printf(
  333                 "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
  334                     vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
  335                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  336                 return (EINVAL);
  337         }
  338 
  339         /* If there is no change, just return. */
  340         if (ai->at_trigger == trig)
  341                 return (0);
  342 
  343 #ifdef PC98
  344         if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
  345             trig == INTR_TRIGGER_LEVEL) {
  346                 if (bootverbose)
  347                         printf(
  348                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  349                             vector);
  350                 return (EINVAL);
  351         }
  352         return (ENXIO);
  353 #else
  354         /*
  355          * Certain IRQs can never be level/lo, so don't try to set them
  356          * that way if asked.  At least some ELCR registers ignore setting
  357          * these bits as well.
  358          */
  359         if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
  360             trig == INTR_TRIGGER_LEVEL) {
  361                 if (bootverbose)
  362                         printf(
  363                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  364                             vector);
  365                 return (EINVAL);
  366         }
  367         if (!elcr_found) {
  368                 if (bootverbose)
  369                         printf("atpic: No ELCR to configure IRQ%u as %s\n",
  370                             vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
  371                             "level/low");
  372                 return (ENXIO);
  373         }
  374         if (bootverbose)
  375                 printf("atpic: Programming IRQ%u as %s\n", vector,
  376                     trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
  377         mtx_lock_spin(&icu_lock);
  378         elcr_write_trigger(atpic_vector(isrc), trig);
  379         ai->at_trigger = trig;
  380         mtx_unlock_spin(&icu_lock);
  381         return (0);
  382 #endif /* PC98 */
  383 }
  384 
  385 static void
  386 atpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
  387 {
  388 
  389         /*
  390          * 8259A's are only used in UP in which case all interrupts always
  391          * go to the sole CPU and this function shouldn't even be called.
  392          */
  393         panic("%s: bad cookie", __func__);
  394 }
  395 
  396 static void
  397 i8259_init(struct atpic *pic, int slave)
  398 {
  399         int imr_addr;
  400 
  401         /* Reset the PIC and program with next four bytes. */
  402         mtx_lock_spin(&icu_lock);
  403 #ifdef DEV_MCA
  404         /* MCA uses level triggered interrupts. */
  405         if (MCA_system)
  406                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
  407         else
  408 #endif
  409                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
  410         imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
  411 
  412         /* Start vector. */
  413         outb(imr_addr, pic->at_intbase);
  414 
  415         /*
  416          * Setup slave links.  For the master pic, indicate what line
  417          * the slave is configured on.  For the slave indicate
  418          * which line on the master we are connected to.
  419          */
  420         if (slave)
  421                 outb(imr_addr, ICU_SLAVEID);
  422         else
  423                 outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
  424 
  425         /* Set mode. */
  426         if (slave)
  427                 outb(imr_addr, SLAVE_MODE);
  428         else
  429                 outb(imr_addr, MASTER_MODE);
  430 
  431         /* Set interrupt enable mask. */
  432         outb(imr_addr, *pic->at_imen);
  433 
  434         /* Reset is finished, default to IRR on read. */
  435         outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
  436 
  437 #ifndef PC98
  438         /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
  439         if (!slave)
  440                 outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
  441 #endif
  442         mtx_unlock_spin(&icu_lock);
  443 }
  444 
  445 void
  446 atpic_startup(void)
  447 {
  448         struct atpic_intsrc *ai;
  449         int i;
  450 
  451         /* Start off with all interrupts disabled. */
  452         imen = 0xffff;
  453         i8259_init(&atpics[MASTER], 0);
  454         i8259_init(&atpics[SLAVE], 1);
  455         atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
  456 
  457         /* Install low-level interrupt handlers for all of our IRQs. */
  458         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  459                 if (i == ICU_SLAVEID)
  460                         continue;
  461                 ai->at_intsrc.is_count = &ai->at_count;
  462                 ai->at_intsrc.is_straycount = &ai->at_straycount;
  463                 setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
  464                     ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
  465                     GSEL(GCODE_SEL, SEL_KPL));
  466         }
  467 
  468 #ifdef DEV_MCA
  469         /* For MCA systems, all interrupts are level triggered. */
  470         if (MCA_system)
  471                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  472                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  473         else
  474 #endif
  475 
  476 #ifdef PC98
  477         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  478                 switch (i) {
  479                 case 0:
  480                 case 1:
  481                 case 7:
  482                 case 8:
  483                         ai->at_trigger = INTR_TRIGGER_EDGE;
  484                         break;
  485                 default:
  486                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  487                         break;
  488                 }
  489 #else
  490         /*
  491          * Look for an ELCR.  If we find one, update the trigger modes.
  492          * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
  493          * edge triggered and that everything else is level triggered.
  494          * We only use the trigger information to reprogram the ELCR if
  495          * we have one and as an optimization to avoid masking edge
  496          * triggered interrupts.  For the case that we don't have an ELCR,
  497          * it doesn't hurt to mask an edge triggered interrupt, so we
  498          * assume level trigger for any interrupt that we aren't sure is
  499          * edge triggered.
  500          */
  501         if (elcr_found) {
  502                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  503                         ai->at_trigger = elcr_read_trigger(i);
  504         } else {
  505                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  506                         switch (i) {
  507                         case 0:
  508                         case 1:
  509                         case 2:
  510                         case 8:
  511                         case 13:
  512                                 ai->at_trigger = INTR_TRIGGER_EDGE;
  513                                 break;
  514                         default:
  515                                 ai->at_trigger = INTR_TRIGGER_LEVEL;
  516                                 break;
  517                         }
  518         }
  519 #endif /* PC98 */
  520 }
  521 
  522 static void
  523 atpic_init(void *dummy __unused)
  524 {
  525         struct atpic_intsrc *ai;
  526         int i;
  527 
  528         /*
  529          * Register our PICs, even if we aren't going to use any of their
  530          * pins so that they are suspended and resumed.
  531          */
  532         if (intr_register_pic(&atpics[0].at_pic) != 0 ||
  533             intr_register_pic(&atpics[1].at_pic) != 0)
  534                 panic("Unable to register ATPICs");
  535 
  536         /*
  537          * If any of the ISA IRQs have an interrupt source already, then
  538          * assume that the APICs are being used and don't register any
  539          * of our interrupt sources.  This makes sure we don't accidentally
  540          * use mixed mode.  The "accidental" use could otherwise occur on
  541          * machines that route the ACPI SCI interrupt to a different ISA
  542          * IRQ (at least one machines routes it to IRQ 13) thus disabling
  543          * that APIC ISA routing and allowing the ATPIC source for that IRQ
  544          * to leak through.  We used to depend on this feature for routing
  545          * IRQ0 via mixed mode, but now we don't use mixed mode at all.
  546          */
  547         for (i = 0; i < NUM_ISA_IRQS; i++)
  548                 if (intr_lookup_source(i) != NULL)
  549                         return;
  550 
  551         /* Loop through all interrupt sources and add them. */
  552         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  553                 if (i == ICU_SLAVEID)
  554                         continue;
  555                 intr_register_source(&ai->at_intsrc);
  556         }
  557 }
  558 SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
  559 
  560 void
  561 atpic_handle_intr(struct intrframe iframe)
  562 {
  563         struct intsrc *isrc;
  564 
  565         KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS,
  566             ("unknown int %d\n", iframe.if_vec));
  567         isrc = &atintrs[iframe.if_vec].at_intsrc;
  568 
  569         /*
  570          * If we don't have an event, see if this is a spurious
  571          * interrupt.
  572          */
  573         if (isrc->is_event == NULL &&
  574             (iframe.if_vec == 7 || iframe.if_vec == 15)) {
  575                 int port, isr;
  576 
  577                 /*
  578                  * Read the ISR register to see if IRQ 7/15 is really
  579                  * pending.  Reset read register back to IRR when done.
  580                  */
  581                 port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
  582                 mtx_lock_spin(&icu_lock);
  583                 outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
  584                 isr = inb(port);
  585                 outb(port, OCW3_SEL | OCW3_RR);
  586                 mtx_unlock_spin(&icu_lock);
  587                 if ((isr & IRQ_MASK(7)) == 0)
  588                         return;
  589         }
  590         intr_execute_handlers(isrc, &iframe);
  591 }
  592 
  593 #ifdef DEV_ISA
  594 /*
  595  * Bus attachment for the ISA PIC.
  596  */
  597 static struct isa_pnp_id atpic_ids[] = {
  598         { 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
  599         { 0 }
  600 };
  601 
  602 static int
  603 atpic_probe(device_t dev)
  604 {
  605         int result;
  606         
  607         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
  608         if (result <= 0)
  609                 device_quiet(dev);
  610         return (result);
  611 }
  612 
  613 /*
  614  * We might be granted IRQ 2, as this is typically consumed by chaining
  615  * between the two PIC components.  If we're using the APIC, however,
  616  * this may not be the case, and as such we should free the resource.
  617  * (XXX untested)
  618  *
  619  * The generic ISA attachment code will handle allocating any other resources
  620  * that we don't explicitly claim here.
  621  */
  622 static int
  623 atpic_attach(device_t dev)
  624 {
  625         struct resource *res;
  626         int rid;
  627 
  628         /* Try to allocate our IRQ and then free it. */
  629         rid = 0;
  630         res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
  631         if (res != NULL)
  632                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
  633         return (0);
  634 }
  635 
  636 static device_method_t atpic_methods[] = {
  637         /* Device interface */
  638         DEVMETHOD(device_probe,         atpic_probe),
  639         DEVMETHOD(device_attach,        atpic_attach),
  640         DEVMETHOD(device_detach,        bus_generic_detach),
  641         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  642         DEVMETHOD(device_suspend,       bus_generic_suspend),
  643         DEVMETHOD(device_resume,        bus_generic_resume),
  644         { 0, 0 }
  645 };
  646 
  647 static driver_t atpic_driver = {
  648         "atpic",
  649         atpic_methods,
  650         1,              /* no softc */
  651 };
  652 
  653 static devclass_t atpic_devclass;
  654 
  655 DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
  656 #ifndef PC98
  657 DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
  658 #endif
  659 
  660 /*
  661  * Return a bitmap of the current interrupt requests.  This is 8259-specific
  662  * and is only suitable for use at probe time.
  663  */
  664 intrmask_t
  665 isa_irq_pending(void)
  666 {
  667         u_char irr1;
  668         u_char irr2;
  669 
  670         irr1 = inb(IO_ICU1);
  671         irr2 = inb(IO_ICU2);
  672         return ((irr2 << 8) | irr1);
  673 }
  674 #endif /* DEV_ISA */

Cache object: 5ec4d8d8945a66e1cb71c23e1e148f13


[ 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.