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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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/5.4/sys/i386/isa/atpic.c 144124 2005-03-25 21:08:49Z 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/pc98/pc98.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 }, (io), (base),            \
  130             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 i8259_init(struct atpic *pic, int slave);
  164 
  165 static struct atpic atpics[] = {
  166         ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
  167         ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
  168 };
  169 
  170 static struct atpic_intsrc atintrs[] = {
  171         INTSRC(0),
  172         INTSRC(1),
  173         INTSRC(2),
  174         INTSRC(3),
  175         INTSRC(4),
  176         INTSRC(5),
  177         INTSRC(6),
  178         INTSRC(7),
  179         INTSRC(8),
  180         INTSRC(9),
  181         INTSRC(10),
  182         INTSRC(11),
  183         INTSRC(12),
  184         INTSRC(13),
  185         INTSRC(14),
  186         INTSRC(15),
  187 };
  188 
  189 CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
  190 
  191 static __inline void
  192 _atpic_eoi_master(struct intsrc *isrc)
  193 {
  194 
  195         KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
  196             ("%s: mismatched pic", __func__));
  197 #ifndef AUTO_EOI_1
  198         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  199 #endif
  200 }
  201 
  202 /*
  203  * The data sheet says no auto-EOI on slave, but it sometimes works.
  204  * So, if AUTO_EOI_2 is enabled, we use it.
  205  */
  206 static __inline void
  207 _atpic_eoi_slave(struct intsrc *isrc)
  208 {
  209 
  210         KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
  211             ("%s: mismatched pic", __func__));
  212 #ifndef AUTO_EOI_2
  213         outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
  214 #ifndef AUTO_EOI_1
  215         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  216 #endif
  217 #endif
  218 }
  219 
  220 static void
  221 atpic_enable_source(struct intsrc *isrc)
  222 {
  223         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  224         struct atpic *ap = (struct atpic *)isrc->is_pic;
  225 
  226         mtx_lock_spin(&icu_lock);
  227         if (*ap->at_imen & IMEN_MASK(ai)) {
  228                 *ap->at_imen &= ~IMEN_MASK(ai);
  229                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
  230         }
  231         mtx_unlock_spin(&icu_lock);
  232 }
  233 
  234 static void
  235 atpic_disable_source(struct intsrc *isrc, int eoi)
  236 {
  237         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  238         struct atpic *ap = (struct atpic *)isrc->is_pic;
  239 
  240         mtx_lock_spin(&icu_lock);
  241         if (ai->at_trigger != INTR_TRIGGER_EDGE) {
  242                 *ap->at_imen |= IMEN_MASK(ai);
  243                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
  244         }
  245 
  246         /*
  247          * Take care to call these functions directly instead of through
  248          * a function pointer.  All of the referenced variables should
  249          * still be hot in the cache.
  250          */
  251         if (eoi == PIC_EOI) {
  252                 if (isrc->is_pic == &atpics[MASTER].at_pic)
  253                         _atpic_eoi_master(isrc);
  254                 else
  255                         _atpic_eoi_slave(isrc);
  256         }
  257 
  258         mtx_unlock_spin(&icu_lock);
  259 }
  260 
  261 static void
  262 atpic_eoi_master(struct intsrc *isrc)
  263 {
  264 #ifndef AUTO_EOI_1
  265         mtx_lock_spin(&icu_lock);
  266         _atpic_eoi_master(isrc);
  267         mtx_unlock_spin(&icu_lock);
  268 #endif
  269 }
  270 
  271 static void
  272 atpic_eoi_slave(struct intsrc *isrc)
  273 {
  274 #ifndef AUTO_EOI_2
  275         mtx_lock_spin(&icu_lock);
  276         _atpic_eoi_slave(isrc);
  277         mtx_unlock_spin(&icu_lock);
  278 #endif
  279 }
  280 
  281 static void
  282 atpic_enable_intr(struct intsrc *isrc)
  283 {
  284 }
  285 
  286 static int
  287 atpic_vector(struct intsrc *isrc)
  288 {
  289         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  290         struct atpic *ap = (struct atpic *)isrc->is_pic;
  291 
  292         return (IRQ(ap, ai));
  293 }
  294 
  295 static int
  296 atpic_source_pending(struct intsrc *isrc)
  297 {
  298         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  299         struct atpic *ap = (struct atpic *)isrc->is_pic;
  300 
  301         return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
  302 }
  303 
  304 static void
  305 atpic_resume(struct intsrc *isrc)
  306 {
  307         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  308         struct atpic *ap = (struct atpic *)isrc->is_pic;
  309 
  310         if (ai->at_irq == 0) {
  311                 i8259_init(ap, ap == &atpics[SLAVE]);
  312 #ifndef PC98
  313                 if (ap == &atpics[SLAVE] && elcr_found)
  314                         elcr_resume();
  315 #endif
  316         }
  317 }
  318 
  319 static int
  320 atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  321     enum intr_polarity pol)
  322 {
  323         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  324         u_int vector;
  325 
  326         /* Map conforming values to edge/hi and sanity check the values. */
  327         if (trig == INTR_TRIGGER_CONFORM)
  328                 trig = INTR_TRIGGER_EDGE;
  329         if (pol == INTR_POLARITY_CONFORM)
  330                 pol = INTR_POLARITY_HIGH;
  331         vector = atpic_vector(isrc);
  332         if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
  333             (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
  334                 printf(
  335                 "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
  336                     vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
  337                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  338                 return (EINVAL);
  339         }
  340 
  341         /* If there is no change, just return. */
  342         if (ai->at_trigger == trig)
  343                 return (0);
  344 
  345 #ifdef PC98
  346         if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
  347             trig == INTR_TRIGGER_LEVEL) {
  348                 if (bootverbose)
  349                         printf(
  350                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  351                             vector);
  352                 return (EINVAL);
  353         }
  354         return (ENXIO);
  355 #else
  356         /*
  357          * Certain IRQs can never be level/lo, so don't try to set them
  358          * that way if asked.  At least some ELCR registers ignore setting
  359          * these bits as well.
  360          */
  361         if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
  362             trig == INTR_TRIGGER_LEVEL) {
  363                 if (bootverbose)
  364                         printf(
  365                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  366                             vector);
  367                 return (EINVAL);
  368         }
  369         if (!elcr_found) {
  370                 if (bootverbose)
  371                         printf("atpic: No ELCR to configure IRQ%u as %s\n",
  372                             vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
  373                             "level/low");
  374                 return (ENXIO);
  375         }
  376         if (bootverbose)
  377                 printf("atpic: Programming IRQ%u as %s\n", vector,
  378                     trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
  379         mtx_lock_spin(&icu_lock);
  380         elcr_write_trigger(atpic_vector(isrc), trig);
  381         ai->at_trigger = trig;
  382         mtx_unlock_spin(&icu_lock);
  383         return (0);
  384 #endif /* PC98 */
  385 }
  386 
  387 static void
  388 i8259_init(struct atpic *pic, int slave)
  389 {
  390         int imr_addr;
  391 
  392         /* Reset the PIC and program with next four bytes. */
  393         mtx_lock_spin(&icu_lock);
  394 #ifdef DEV_MCA
  395         /* MCA uses level triggered interrupts. */
  396         if (MCA_system)
  397                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
  398         else
  399 #endif
  400                 outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
  401         imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
  402 
  403         /* Start vector. */
  404         outb(imr_addr, pic->at_intbase);
  405 
  406         /*
  407          * Setup slave links.  For the master pic, indicate what line
  408          * the slave is configured on.  For the slave indicate
  409          * which line on the master we are connected to.
  410          */
  411         if (slave)
  412                 outb(imr_addr, ICU_SLAVEID);
  413         else
  414                 outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
  415 
  416         /* Set mode. */
  417         if (slave)
  418                 outb(imr_addr, SLAVE_MODE);
  419         else
  420                 outb(imr_addr, MASTER_MODE);
  421 
  422         /* Set interrupt enable mask. */
  423         outb(imr_addr, *pic->at_imen);
  424 
  425         /* Reset is finished, default to IRR on read. */
  426         outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
  427 
  428 #ifndef PC98
  429         /* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
  430         if (!slave)
  431                 outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
  432 #endif
  433         mtx_unlock_spin(&icu_lock);
  434 }
  435 
  436 void
  437 atpic_startup(void)
  438 {
  439         struct atpic_intsrc *ai;
  440         int i;
  441 
  442         /* Start off with all interrupts disabled. */
  443         imen = 0xffff;
  444         i8259_init(&atpics[MASTER], 0);
  445         i8259_init(&atpics[SLAVE], 1);
  446         atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
  447 
  448         /* Install low-level interrupt handlers for all of our IRQs. */
  449         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  450                 if (i == ICU_SLAVEID)
  451                         continue;
  452                 ai->at_intsrc.is_count = &ai->at_count;
  453                 ai->at_intsrc.is_straycount = &ai->at_straycount;
  454                 setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
  455                     ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
  456                     GSEL(GCODE_SEL, SEL_KPL));
  457         }
  458 
  459 #ifdef DEV_MCA
  460         /* For MCA systems, all interrupts are level triggered. */
  461         if (MCA_system)
  462                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  463                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  464         else
  465 #endif
  466 
  467 #ifdef PC98
  468         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  469                 switch (i) {
  470                 case 0:
  471                 case 1:
  472                 case 7:
  473                 case 8:
  474                         ai->at_trigger = INTR_TRIGGER_EDGE;
  475                         break;
  476                 default:
  477                         ai->at_trigger = INTR_TRIGGER_LEVEL;
  478                         break;
  479                 }
  480 #else
  481         /*
  482          * Look for an ELCR.  If we find one, update the trigger modes.
  483          * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
  484          * edge triggered and that everything else is level triggered.
  485          * We only use the trigger information to reprogram the ELCR if
  486          * we have one and as an optimization to avoid masking edge
  487          * triggered interrupts.  For the case that we don't have an ELCR,
  488          * it doesn't hurt to mask an edge triggered interrupt, so we
  489          * assume level trigger for any interrupt that we aren't sure is
  490          * edge triggered.
  491          */
  492         if (elcr_found) {
  493                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  494                         ai->at_trigger = elcr_read_trigger(i);
  495         } else {
  496                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  497                         switch (i) {
  498                         case 0:
  499                         case 1:
  500                         case 2:
  501                         case 8:
  502                         case 13:
  503                                 ai->at_trigger = INTR_TRIGGER_EDGE;
  504                                 break;
  505                         default:
  506                                 ai->at_trigger = INTR_TRIGGER_LEVEL;
  507                                 break;
  508                         }
  509         }
  510 #endif /* PC98 */
  511 }
  512 
  513 static void
  514 atpic_init(void *dummy __unused)
  515 {
  516         struct atpic_intsrc *ai;
  517         int i;
  518 
  519         /* Loop through all interrupt sources and add them. */
  520         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  521                 if (i == ICU_SLAVEID)
  522                         continue;
  523                 intr_register_source(&ai->at_intsrc);
  524         }
  525 }
  526 SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
  527 
  528 void
  529 atpic_handle_intr(struct intrframe iframe)
  530 {
  531         struct intsrc *isrc;
  532 
  533         KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS,
  534             ("unknown int %d\n", iframe.if_vec));
  535         isrc = &atintrs[iframe.if_vec].at_intsrc;
  536 
  537         /*
  538          * If we don't have an ithread, see if this is a spurious
  539          * interrupt.
  540          */
  541         if (isrc->is_ithread == NULL &&
  542             (iframe.if_vec == 7 || iframe.if_vec == 15)) {
  543                 int port, isr;
  544 
  545                 /*
  546                  * Read the ISR register to see if IRQ 7/15 is really
  547                  * pending.  Reset read register back to IRR when done.
  548                  */
  549                 port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
  550                 mtx_lock_spin(&icu_lock);
  551                 outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
  552                 isr = inb(port);
  553                 outb(port, OCW3_SEL | OCW3_RR);
  554                 mtx_unlock_spin(&icu_lock);
  555                 if ((isr & IRQ_MASK(7)) == 0)
  556                         return;
  557         }
  558         intr_execute_handlers(isrc, &iframe);
  559 }
  560 
  561 #ifdef DEV_ISA
  562 /*
  563  * Bus attachment for the ISA PIC.
  564  */
  565 static struct isa_pnp_id atpic_ids[] = {
  566         { 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
  567         { 0 }
  568 };
  569 
  570 static int
  571 atpic_probe(device_t dev)
  572 {
  573         int result;
  574         
  575         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
  576         if (result <= 0)
  577                 device_quiet(dev);
  578         return (result);
  579 }
  580 
  581 /*
  582  * We might be granted IRQ 2, as this is typically consumed by chaining
  583  * between the two PIC components.  If we're using the APIC, however,
  584  * this may not be the case, and as such we should free the resource.
  585  * (XXX untested)
  586  *
  587  * The generic ISA attachment code will handle allocating any other resources
  588  * that we don't explicitly claim here.
  589  */
  590 static int
  591 atpic_attach(device_t dev)
  592 {
  593         struct resource *res;
  594         int rid;
  595 
  596         /* Try to allocate our IRQ and then free it. */
  597         rid = 0;
  598         res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
  599         if (res != NULL)
  600                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
  601         return (0);
  602 }
  603 
  604 static device_method_t atpic_methods[] = {
  605         /* Device interface */
  606         DEVMETHOD(device_probe,         atpic_probe),
  607         DEVMETHOD(device_attach,        atpic_attach),
  608         DEVMETHOD(device_detach,        bus_generic_detach),
  609         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  610         DEVMETHOD(device_suspend,       bus_generic_suspend),
  611         DEVMETHOD(device_resume,        bus_generic_resume),
  612         { 0, 0 }
  613 };
  614 
  615 static driver_t atpic_driver = {
  616         "atpic",
  617         atpic_methods,
  618         1,              /* no softc */
  619 };
  620 
  621 static devclass_t atpic_devclass;
  622 
  623 DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
  624 #ifndef PC98
  625 DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
  626 #endif
  627 
  628 /*
  629  * Return a bitmap of the current interrupt requests.  This is 8259-specific
  630  * and is only suitable for use at probe time.
  631  */
  632 intrmask_t
  633 isa_irq_pending(void)
  634 {
  635         u_char irr1;
  636         u_char irr2;
  637 
  638         irr1 = inb(IO_ICU1);
  639         irr2 = inb(IO_ICU2);
  640         return ((irr2 << 8) | irr1);
  641 }
  642 #endif /* DEV_ISA */

Cache object: 560cd148cff0d593447243a95ce4a39a


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