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/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


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