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/x86/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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include "opt_auto_eoi.h"
   36 #include "opt_isa.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/asan.h>
   41 #include <sys/bus.h>
   42 #include <sys/interrupt.h>
   43 #include <sys/kernel.h>
   44 #include <sys/lock.h>
   45 #include <sys/module.h>
   46 #include <sys/msan.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 <x86/isa/icu.h>
   57 #include <isa/isareg.h>
   58 #include <isa/isavar.h>
   59 
   60 #ifdef __amd64__
   61 #define SDT_ATPIC       SDT_SYSIGT
   62 #define GSEL_ATPIC      0
   63 #else
   64 #define SDT_ATPIC       SDT_SYS386IGT
   65 #define GSEL_ATPIC      GSEL(GCODE_SEL, SEL_KPL)
   66 #endif
   67 
   68 #define MASTER  0
   69 #define SLAVE   1
   70 
   71 #define IMEN_MASK(ai)           (IRQ_MASK((ai)->at_irq))
   72 
   73 #define NUM_ISA_IRQS            16
   74 
   75 static void     atpic_init(void *dummy);
   76 
   77 inthand_t
   78         IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
   79         IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
   80         IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
   81         IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
   82         IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
   83         IDTVEC(atpic_intr15);
   84 /* XXXKIB i386 uses stubs until pti comes */
   85 inthand_t
   86         IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti),
   87         IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti),
   88         IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti),
   89         IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti),
   90         IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti),
   91         IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti),
   92         IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti),
   93         IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti);
   94 
   95 #define IRQ(ap, ai)     ((ap)->at_irqbase + (ai)->at_irq)
   96 
   97 #define ATPIC(io, base, eoi) {                                          \
   98                 .at_pic = {                                             \
   99                         .pic_register_sources = atpic_register_sources, \
  100                         .pic_enable_source = atpic_enable_source,       \
  101                         .pic_disable_source = atpic_disable_source,     \
  102                         .pic_eoi_source = (eoi),                        \
  103                         .pic_enable_intr = atpic_enable_intr,           \
  104                         .pic_disable_intr = atpic_disable_intr,         \
  105                         .pic_vector = atpic_vector,                     \
  106                         .pic_source_pending = atpic_source_pending,     \
  107                         .pic_resume = atpic_resume,                     \
  108                         .pic_config_intr = atpic_config_intr,           \
  109                         .pic_assign_cpu = atpic_assign_cpu              \
  110                 },                                                      \
  111                 .at_ioaddr = (io),                                      \
  112                 .at_irqbase = (base),                                   \
  113                 .at_intbase = IDT_IO_INTS + (base),                     \
  114                 .at_imen = 0xff,                                        \
  115         }
  116 
  117 #define INTSRC(irq)                                                     \
  118         { { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),    \
  119             IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 }
  120 
  121 struct atpic {
  122         struct pic at_pic;
  123         int     at_ioaddr;
  124         int     at_irqbase;
  125         uint8_t at_intbase;
  126         uint8_t at_imen;
  127 };
  128 
  129 struct atpic_intsrc {
  130         struct intsrc at_intsrc;
  131         inthand_t *at_intr, *at_intr_pti;
  132         int     at_irq;                 /* Relative to PIC base. */
  133         enum intr_trigger at_trigger;
  134         u_long  at_count;
  135         u_long  at_straycount;
  136 };
  137 
  138 static void atpic_register_sources(struct pic *pic);
  139 static void atpic_enable_source(struct intsrc *isrc);
  140 static void atpic_disable_source(struct intsrc *isrc, int eoi);
  141 static void atpic_eoi_master(struct intsrc *isrc);
  142 static void atpic_eoi_slave(struct intsrc *isrc);
  143 static void atpic_enable_intr(struct intsrc *isrc);
  144 static void atpic_disable_intr(struct intsrc *isrc);
  145 static int atpic_vector(struct intsrc *isrc);
  146 static void atpic_resume(struct pic *pic, bool suspend_cancelled);
  147 static int atpic_source_pending(struct intsrc *isrc);
  148 static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  149     enum intr_polarity pol);
  150 static int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
  151 static void i8259_init(struct atpic *pic, int slave);
  152 
  153 static struct atpic atpics[] = {
  154         ATPIC(IO_ICU1, 0, atpic_eoi_master),
  155         ATPIC(IO_ICU2, 8, atpic_eoi_slave)
  156 };
  157 
  158 static struct atpic_intsrc atintrs[] = {
  159         INTSRC(0),
  160         INTSRC(1),
  161         INTSRC(2),
  162         INTSRC(3),
  163         INTSRC(4),
  164         INTSRC(5),
  165         INTSRC(6),
  166         INTSRC(7),
  167         INTSRC(8),
  168         INTSRC(9),
  169         INTSRC(10),
  170         INTSRC(11),
  171         INTSRC(12),
  172         INTSRC(13),
  173         INTSRC(14),
  174         INTSRC(15),
  175 };
  176 
  177 CTASSERT(nitems(atintrs) == NUM_ISA_IRQS);
  178 
  179 static __inline void
  180 _atpic_eoi_master(struct intsrc *isrc)
  181 {
  182 
  183         KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
  184             ("%s: mismatched pic", __func__));
  185 #ifndef AUTO_EOI_1
  186         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  187 #endif
  188 }
  189 
  190 /*
  191  * The data sheet says no auto-EOI on slave, but it sometimes works.
  192  * So, if AUTO_EOI_2 is enabled, we use it.
  193  */
  194 static __inline void
  195 _atpic_eoi_slave(struct intsrc *isrc)
  196 {
  197 
  198         KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
  199             ("%s: mismatched pic", __func__));
  200 #ifndef AUTO_EOI_2
  201         outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
  202 #ifndef AUTO_EOI_1
  203         outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
  204 #endif
  205 #endif
  206 }
  207 
  208 static void
  209 atpic_register_sources(struct pic *pic)
  210 {
  211         struct atpic *ap = (struct atpic *)pic;
  212         struct atpic_intsrc *ai;
  213         int i;
  214 
  215         /*
  216          * If any of the ISA IRQs have an interrupt source already, then
  217          * assume that the I/O APICs are being used and don't register any
  218          * of our interrupt sources.  This makes sure we don't accidentally
  219          * use mixed mode.  The "accidental" use could otherwise occur on
  220          * machines that route the ACPI SCI interrupt to a different ISA
  221          * IRQ (at least one machine routes it to IRQ 13) thus disabling
  222          * that APIC ISA routing and allowing the ATPIC source for that IRQ
  223          * to leak through.  We used to depend on this feature for routing
  224          * IRQ0 via mixed mode, but now we don't use mixed mode at all.
  225          *
  226          * To avoid the slave not register sources after the master
  227          * registers its sources, register all IRQs when this function is
  228          * called on the master.
  229          */
  230         if (ap != &atpics[MASTER])
  231                 return;
  232         for (i = 0; i < NUM_ISA_IRQS; i++)
  233                 if (intr_lookup_source(i) != NULL)
  234                         return;
  235 
  236         /* Loop through all interrupt sources and add them. */
  237         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  238                 if (i == ICU_SLAVEID)
  239                         continue;
  240                 intr_register_source(&ai->at_intsrc);
  241         }
  242 }
  243 
  244 static void
  245 atpic_enable_source(struct intsrc *isrc)
  246 {
  247         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  248         struct atpic *ap = (struct atpic *)isrc->is_pic;
  249 
  250         spinlock_enter();
  251         if (ap->at_imen & IMEN_MASK(ai)) {
  252                 ap->at_imen &= ~IMEN_MASK(ai);
  253                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen);
  254         }
  255         spinlock_exit();
  256 }
  257 
  258 static void
  259 atpic_disable_source(struct intsrc *isrc, int eoi)
  260 {
  261         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  262         struct atpic *ap = (struct atpic *)isrc->is_pic;
  263 
  264         spinlock_enter();
  265         if (ai->at_trigger != INTR_TRIGGER_EDGE) {
  266                 ap->at_imen |= IMEN_MASK(ai);
  267                 outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen);
  268         }
  269 
  270         /*
  271          * Take care to call these functions directly instead of through
  272          * a function pointer.  All of the referenced variables should
  273          * still be hot in the cache.
  274          */
  275         if (eoi == PIC_EOI) {
  276                 if (isrc->is_pic == &atpics[MASTER].at_pic)
  277                         _atpic_eoi_master(isrc);
  278                 else
  279                         _atpic_eoi_slave(isrc);
  280         }
  281 
  282         spinlock_exit();
  283 }
  284 
  285 static void
  286 atpic_eoi_master(struct intsrc *isrc)
  287 {
  288 #ifndef AUTO_EOI_1
  289         spinlock_enter();
  290         _atpic_eoi_master(isrc);
  291         spinlock_exit();
  292 #endif
  293 }
  294 
  295 static void
  296 atpic_eoi_slave(struct intsrc *isrc)
  297 {
  298 #ifndef AUTO_EOI_2
  299         spinlock_enter();
  300         _atpic_eoi_slave(isrc);
  301         spinlock_exit();
  302 #endif
  303 }
  304 
  305 static void
  306 atpic_enable_intr(struct intsrc *isrc)
  307 {
  308 }
  309 
  310 static void
  311 atpic_disable_intr(struct intsrc *isrc)
  312 {
  313 }
  314 
  315 static int
  316 atpic_vector(struct intsrc *isrc)
  317 {
  318         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  319         struct atpic *ap = (struct atpic *)isrc->is_pic;
  320 
  321         return (IRQ(ap, ai));
  322 }
  323 
  324 static int
  325 atpic_source_pending(struct intsrc *isrc)
  326 {
  327         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  328         struct atpic *ap = (struct atpic *)isrc->is_pic;
  329 
  330         return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
  331 }
  332 
  333 static void
  334 atpic_resume(struct pic *pic, bool suspend_cancelled)
  335 {
  336         struct atpic *ap = (struct atpic *)pic;
  337 
  338         i8259_init(ap, ap == &atpics[SLAVE]);
  339         if (ap == &atpics[SLAVE] && elcr_found)
  340                 elcr_resume();
  341 }
  342 
  343 static int
  344 atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  345     enum intr_polarity pol)
  346 {
  347         struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
  348         u_int vector;
  349 
  350         /* Map conforming values to edge/hi and sanity check the values. */
  351         if (trig == INTR_TRIGGER_CONFORM)
  352                 trig = INTR_TRIGGER_EDGE;
  353         if (pol == INTR_POLARITY_CONFORM)
  354                 pol = INTR_POLARITY_HIGH;
  355         vector = atpic_vector(isrc);
  356         if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
  357             (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
  358                 printf(
  359                 "atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
  360                     vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
  361                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  362                 return (EINVAL);
  363         }
  364 
  365         /* If there is no change, just return. */
  366         if (ai->at_trigger == trig)
  367                 return (0);
  368 
  369         /*
  370          * Certain IRQs can never be level/lo, so don't try to set them
  371          * that way if asked.  At least some ELCR registers ignore setting
  372          * these bits as well.
  373          */
  374         if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
  375             trig == INTR_TRIGGER_LEVEL) {
  376                 if (bootverbose)
  377                         printf(
  378                 "atpic: Ignoring invalid level/low configuration for IRQ%u\n",
  379                             vector);
  380                 return (EINVAL);
  381         }
  382         if (!elcr_found) {
  383                 if (bootverbose)
  384                         printf("atpic: No ELCR to configure IRQ%u as %s\n",
  385                             vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
  386                             "level/low");
  387                 return (ENXIO);
  388         }
  389         if (bootverbose)
  390                 printf("atpic: Programming IRQ%u as %s\n", vector,
  391                     trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
  392         spinlock_enter();
  393         elcr_write_trigger(atpic_vector(isrc), trig);
  394         ai->at_trigger = trig;
  395         spinlock_exit();
  396         return (0);
  397 }
  398 
  399 static int
  400 atpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
  401 {
  402 
  403         /*
  404          * 8259A's are only used in UP in which case all interrupts always
  405          * go to the sole CPU and this function shouldn't even be called.
  406          */
  407         panic("%s: bad cookie", __func__);
  408 }
  409 
  410 static void
  411 i8259_init(struct atpic *pic, int slave)
  412 {
  413         int imr_addr;
  414 
  415         /* Reset the PIC and program with next four bytes. */
  416         spinlock_enter();
  417         outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
  418         imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
  419 
  420         /* Start vector. */
  421         outb(imr_addr, pic->at_intbase);
  422 
  423         /*
  424          * Setup slave links.  For the master pic, indicate what line
  425          * the slave is configured on.  For the slave indicate
  426          * which line on the master we are connected to.
  427          */
  428         if (slave)
  429                 outb(imr_addr, ICU_SLAVEID);
  430         else
  431                 outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
  432 
  433         /* Set mode. */
  434         if (slave)
  435                 outb(imr_addr, SLAVE_MODE);
  436         else
  437                 outb(imr_addr, MASTER_MODE);
  438 
  439         /* Set interrupt enable mask. */
  440         outb(imr_addr, pic->at_imen);
  441 
  442         /* Reset is finished, default to IRR on read. */
  443         outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
  444 
  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 
  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         i8259_init(&atpics[MASTER], 0);
  460         i8259_init(&atpics[SLAVE], 1);
  461         atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
  462 
  463         /* Install low-level interrupt handlers for all of our IRQs. */
  464         for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
  465                 if (i == ICU_SLAVEID)
  466                         continue;
  467                 ai->at_intsrc.is_count = &ai->at_count;
  468                 ai->at_intsrc.is_straycount = &ai->at_straycount;
  469                 setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
  470                     ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC,
  471                     SEL_KPL, GSEL_ATPIC);
  472         }
  473 
  474         /*
  475          * Look for an ELCR.  If we find one, update the trigger modes.
  476          * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
  477          * edge triggered and that everything else is level triggered.
  478          * We only use the trigger information to reprogram the ELCR if
  479          * we have one and as an optimization to avoid masking edge
  480          * triggered interrupts.  For the case that we don't have an ELCR,
  481          * it doesn't hurt to mask an edge triggered interrupt, so we
  482          * assume level trigger for any interrupt that we aren't sure is
  483          * edge triggered.
  484          */
  485         if (elcr_found) {
  486                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  487                         ai->at_trigger = elcr_read_trigger(i);
  488         } else {
  489                 for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
  490                         switch (i) {
  491                         case 0:
  492                         case 1:
  493                         case 2:
  494                         case 8:
  495                         case 13:
  496                                 ai->at_trigger = INTR_TRIGGER_EDGE;
  497                                 break;
  498                         default:
  499                                 ai->at_trigger = INTR_TRIGGER_LEVEL;
  500                                 break;
  501                         }
  502         }
  503 }
  504 
  505 static void
  506 atpic_init(void *dummy __unused)
  507 {
  508 
  509         /*
  510          * Register our PICs, even if we aren't going to use any of their
  511          * pins so that they are suspended and resumed.
  512          */
  513         if (intr_register_pic(&atpics[0].at_pic) != 0 ||
  514             intr_register_pic(&atpics[1].at_pic) != 0)
  515                 panic("Unable to register ATPICs");
  516 
  517         if (num_io_irqs == 0)
  518                 num_io_irqs = NUM_ISA_IRQS;
  519 }
  520 SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL);
  521 
  522 void
  523 atpic_handle_intr(u_int vector, struct trapframe *frame)
  524 {
  525         struct intsrc *isrc;
  526 
  527         kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
  528         kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
  529         trap_check_kstack();
  530 
  531         KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
  532         isrc = &atintrs[vector].at_intsrc;
  533 
  534         /*
  535          * If we don't have an event, see if this is a spurious
  536          * interrupt.
  537          */
  538         if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
  539                 int port, isr;
  540 
  541                 /*
  542                  * Read the ISR register to see if IRQ 7/15 is really
  543                  * pending.  Reset read register back to IRR when done.
  544                  */
  545                 port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
  546                 spinlock_enter();
  547                 outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
  548                 isr = inb(port);
  549                 outb(port, OCW3_SEL | OCW3_RR);
  550                 spinlock_exit();
  551                 if ((isr & IRQ_MASK(7)) == 0)
  552                         return;
  553         }
  554         intr_execute_handlers(isrc, frame);
  555 }
  556 
  557 #ifdef DEV_ISA
  558 /*
  559  * Bus attachment for the ISA PIC.
  560  */
  561 static struct isa_pnp_id atpic_ids[] = {
  562         { 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
  563         { 0 }
  564 };
  565 
  566 static int
  567 atpic_probe(device_t dev)
  568 {
  569         int result;
  570 
  571         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
  572         if (result <= 0)
  573                 device_quiet(dev);
  574         return (result);
  575 }
  576 
  577 /*
  578  * We might be granted IRQ 2, as this is typically consumed by chaining
  579  * between the two PIC components.  If we're using the APIC, however,
  580  * this may not be the case, and as such we should free the resource.
  581  * (XXX untested)
  582  *
  583  * The generic ISA attachment code will handle allocating any other resources
  584  * that we don't explicitly claim here.
  585  */
  586 static int
  587 atpic_attach(device_t dev)
  588 {
  589         struct resource *res;
  590         int rid;
  591 
  592         /* Try to allocate our IRQ and then free it. */
  593         rid = 0;
  594         res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
  595         if (res != NULL)
  596                 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
  597         return (0);
  598 }
  599 
  600 static device_method_t atpic_methods[] = {
  601         /* Device interface */
  602         DEVMETHOD(device_probe,         atpic_probe),
  603         DEVMETHOD(device_attach,        atpic_attach),
  604         DEVMETHOD(device_detach,        bus_generic_detach),
  605         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  606         DEVMETHOD(device_suspend,       bus_generic_suspend),
  607         DEVMETHOD(device_resume,        bus_generic_resume),
  608         { 0, 0 }
  609 };
  610 
  611 static driver_t atpic_driver = {
  612         "atpic",
  613         atpic_methods,
  614         1,              /* no softc */
  615 };
  616 
  617 DRIVER_MODULE(atpic, isa, atpic_driver, 0, 0);
  618 DRIVER_MODULE(atpic, acpi, atpic_driver, 0, 0);
  619 ISA_PNP_INFO(atpic_ids);
  620 #endif /* DEV_ISA */

Cache object: fe08880520005ba4f547e249217d5259


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