Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/hal/x86/pc/interrupt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. update_mask
  2. interrupt_unmask
  3. interrupt_mask
  4. interrupt_setup
  5. interrupt_handler
  6. interrupt_init

   1 /*-
   2  * Copyright (c) 2005-2007, Kohsuke Ohtani
   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  * interrupt.c - interrupt management routines for intel 8259 chip
  32  */
  33 
  34 #include <sys/ipl.h>
  35 #include <kernel.h>
  36 #include <irq.h>
  37 #include <cpufunc.h>
  38 #include <context.h>
  39 #include <locore.h>
  40 #include <hal.h>
  41 
  42 
  43 /* Number of IRQ lines */
  44 #define NIRQS           16
  45 
  46 /* I/O address for master/slave programmable interrupt controller */
  47 #define PIC_M           0x20
  48 #define PIC_S           0xa0
  49 
  50 /* Edge/level control register */
  51 #define ELCR            0x4d0
  52 
  53 /*
  54  * Interrupt priority level
  55  *
  56  * Each interrupt has its logical priority level, with 0 being
  57  * the highest priority. While some ISR is running, all lower
  58  * priority interrupts are masked off.
  59  */
  60 static volatile int irq_level;
  61 
  62 /*
  63  * Interrupt mapping table
  64  */
  65 static int      ipl_table[NIRQS];       /* Vector -> level */
  66 static u_int    mask_table[NIPLS];      /* Level -> mask */
  67 
  68 /*
  69  * Set mask for current ipl
  70  */
  71 static void
  72 update_mask(void)
  73 {
  74         u_int mask = mask_table[irq_level];
  75 
  76         outb(PIC_M + 1, mask & 0xff);
  77         outb(PIC_S + 1, mask >> 8);
  78 }
  79 
  80 /*
  81  * Unmask interrupt in PIC for specified irq.
  82  * The interrupt mask table is also updated.
  83  * Assumed CPU interrupt is disabled in caller.
  84  */
  85 void
  86 interrupt_unmask(int vector, int level)
  87 {
  88         u_int unmask = (u_int)~(1 << vector);
  89         int i, s;
  90 
  91         s = splhigh();
  92         ipl_table[vector] = level;
  93         /*
  94          * Unmask target interrupt for all
  95          * lower interrupt levels.
  96          */
  97         for (i = 0; i < level; i++)
  98                 mask_table[i] &= unmask;
  99         update_mask();
 100         splx(s);
 101 }
 102 
 103 /*
 104  * Mask interrupt in PIC for specified irq.
 105  * Interrupt must be disabled when this routine is called.
 106  */
 107 void
 108 interrupt_mask(int vector)
 109 {
 110         u_int mask = (u_int)(1 << vector);
 111         int i, level, s;
 112 
 113         s = splhigh();
 114         level = ipl_table[vector];
 115         for (i = 0; i < level; i++)
 116                 mask_table[i] |= mask;
 117         ipl_table[vector] = IPL_NONE;
 118         update_mask();
 119         splx(s);
 120 }
 121 
 122 /*
 123  * Setup interrupt mode.
 124  * Select whether an interrupt trigger is edge or level.
 125  */
 126 void
 127 interrupt_setup(int vector, int mode)
 128 {
 129         int port, s;
 130         u_int bit;
 131         u_char val;
 132 
 133         s = splhigh();
 134         port = vector < 8 ? ELCR : ELCR + 1;
 135         bit = (u_int)(1 << (vector & 7));
 136 
 137         val = inb(port);
 138         if (mode == IMODE_LEVEL)
 139                 val |= bit;
 140         else
 141                 val &= ~bit;
 142         outb(port, val);
 143         splx(s);
 144 }
 145 
 146 /*
 147  * Common interrupt handler.
 148  *
 149  * This routine is called from the low level interrupt routine
 150  * written in assemble code. The interrupt flag is automatically
 151  * disabled by h/w in CPU when the interrupt is occurred. The
 152  * target interrupt will be masked in ICU while the irq handler
 153  * is called.
 154  */
 155 void
 156 interrupt_handler(struct cpu_regs *regs)
 157 {
 158         int vector = (int)regs->trap_no;
 159         int old_ipl, new_ipl;
 160 
 161         /* Adjust interrupt level */
 162         old_ipl = irq_level;
 163         new_ipl = ipl_table[vector];
 164         if (new_ipl > old_ipl)          /* Ignore spurious interrupt */
 165                 irq_level = new_ipl;
 166         update_mask();
 167 
 168         /* Send acknowledge to PIC for specified irq */
 169         if (vector & 8)                 /* Slave ? */
 170                 outb(PIC_S, 0x20);      /* Non specific EOI to slave */
 171         outb(PIC_M, 0x20);              /* Non specific EOI to master */
 172 
 173         /* Dispatch interrupt */
 174         splon();
 175         irq_handler(vector);
 176         sploff();
 177 
 178         /* Restore interrupt level */
 179         irq_level = old_ipl;
 180         update_mask();
 181 }
 182 
 183 /*
 184  * Initialize 8259 interrupt controllers.
 185  * All interrupts will be masked off in ICU.
 186  */
 187 void
 188 interrupt_init(void)
 189 {
 190         int i;
 191 
 192         irq_level = IPL_NONE;
 193 
 194         for (i = 0; i < NIRQS; i++)
 195                 ipl_table[i] = IPL_NONE;
 196 
 197         for (i = 0; i < NIPLS; i++)
 198                 mask_table[i] = 0xfffb;
 199 
 200         outb_p(PIC_M, 0x11);            /* Start initialization edge, master */
 201         outb_p(PIC_M + 1, 0x20);        /* Set h/w vector = 0x20 */
 202         outb_p(PIC_M + 1, 0x04);        /* Chain to slave (IRQ2) */
 203         outb_p(PIC_M + 1, 0x01);        /* 8086 mode */
 204 
 205         outb_p(PIC_S, 0x11);            /* Start initialization edge, master */
 206         outb_p(PIC_S + 1, 0x28);        /* Set h/w vector = 0x28 */
 207         outb_p(PIC_S + 1, 0x02);        /* Slave (cascade) */
 208         outb_p(PIC_S + 1, 0x01);        /* 8086 mode */
 209 
 210         outb(PIC_S + 1, 0xff);          /* Mask all */
 211         outb(PIC_M + 1, 0xfb);          /* Mask all except IRQ2 (cascade) */
 212 }

/* [<][>][^][v][top][bottom][index][help] */