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

Cache object: 6ec104780d009af2ab567e56af1bcc7b


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