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

Cache object: dd0b9d42fe9a9f4bb33e618ff4cb683d


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