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/kernel/i8259.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 /* This file contains routines for initializing the 8259 interrupt controller:
    2  *      put_irq_handler: register an interrupt handler
    3  *      rm_irq_handler: deregister an interrupt handler
    4  *      intr_handle:    handle a hardware interrupt
    5  *      intr_init:      initialize the interrupt controller(s)
    6  */
    7 
    8 #include "kernel.h"
    9 #include "proc.h"
   10 #include <minix/com.h>
   11 
   12 #define ICW1_AT         0x11    /* edge triggered, cascade, need ICW4 */
   13 #define ICW1_PC         0x13    /* edge triggered, no cascade, need ICW4 */
   14 #define ICW1_PS         0x19    /* level triggered, cascade, need ICW4 */
   15 #define ICW4_AT_SLAVE   0x01    /* not SFNM, not buffered, normal EOI, 8086 */
   16 #define ICW4_AT_MASTER  0x05    /* not SFNM, not buffered, normal EOI, 8086 */
   17 #define ICW4_PC_SLAVE   0x09    /* not SFNM, buffered, normal EOI, 8086 */
   18 #define ICW4_PC_MASTER  0x0D    /* not SFNM, buffered, normal EOI, 8086 */
   19 
   20 #if _WORD_SIZE == 2
   21 typedef _PROTOTYPE( void (*vecaddr_t), (void) );
   22 
   23 FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) );
   24 
   25 PRIVATE vecaddr_t int_vec[] = {
   26   int00, int01, int02, int03, int04, int05, int06, int07,
   27 };
   28 
   29 PRIVATE vecaddr_t irq_vec[] = {
   30   hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07,
   31   hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15,
   32 };
   33 #else
   34 #define set_vec(nr, addr)       ((void)0)
   35 #endif
   36 
   37 /*===========================================================================*
   38  *                              intr_init                                    *
   39  *===========================================================================*/
   40 PUBLIC void intr_init(mine)
   41 int mine;
   42 {
   43 /* Initialize the 8259s, finishing with all interrupts disabled.  This is
   44  * only done in protected mode, in real mode we don't touch the 8259s, but
   45  * use the BIOS locations instead.  The flag "mine" is set if the 8259s are
   46  * to be programmed for MINIX, or to be reset to what the BIOS expects.
   47  */
   48   int i;
   49 
   50   intr_disable();
   51 
   52   if (machine.protected) {
   53       /* The AT and newer PS/2 have two interrupt controllers, one master,
   54        * one slaved at IRQ 2.  (We don't have to deal with the PC that
   55        * has just one controller, because it must run in real mode.)
   56        */
   57       outb(INT_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
   58       outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
   59                                                         /* ICW2 for master */
   60       outb(INT_CTLMASK, (1 << CASCADE_IRQ));            /* ICW3 tells slaves */
   61       outb(INT_CTLMASK, ICW4_AT_MASTER);
   62       outb(INT_CTLMASK, ~(1 << CASCADE_IRQ));           /* IRQ 0-7 mask */
   63       outb(INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
   64       outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
   65                                                         /* ICW2 for slave */
   66       outb(INT2_CTLMASK, CASCADE_IRQ);          /* ICW3 is slave nr */
   67       outb(INT2_CTLMASK, ICW4_AT_SLAVE);
   68       outb(INT2_CTLMASK, ~0);                           /* IRQ 8-15 mask */
   69 
   70       /* Copy the BIOS vectors from the BIOS to the Minix location, so we
   71        * can still make BIOS calls without reprogramming the i8259s.
   72        */
   73 #if IRQ0_VECTOR != BIOS_IRQ0_VEC
   74       phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
   75 #endif
   76 #if IRQ8_VECTOR != BIOS_IRQ8_VEC
   77       phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L);
   78 #endif
   79   } else {
   80       /* Use the BIOS interrupt vectors in real mode.  We only reprogram the
   81        * exceptions here, the interrupt vectors are reprogrammed on demand.
   82        * SYS_VECTOR is the Minix system call for message passing.
   83        */
   84       for (i = 0; i < 8; i++) set_vec(i, int_vec[i]);
   85       set_vec(SYS_VECTOR, s_call);
   86   }
   87 }
   88 
   89 /*===========================================================================*
   90  *                              put_irq_handler                              *
   91  *===========================================================================*/
   92 PUBLIC void put_irq_handler(hook, irq, handler)
   93 irq_hook_t *hook;
   94 int irq;
   95 irq_handler_t handler;
   96 {
   97 /* Register an interrupt handler. */
   98   int id;
   99   irq_hook_t **line;
  100 
  101   if (irq < 0 || irq >= NR_IRQ_VECTORS)
  102       panic("invalid call to put_irq_handler", irq);
  103 
  104   line = &irq_handlers[irq];
  105   id = 1;
  106   while (*line != NULL) {
  107       if (hook == *line) return;        /* extra initialization */
  108       line = &(*line)->next;
  109       id <<= 1;
  110   }
  111   if (id == 0) panic("Too many handlers for irq", irq);
  112 
  113   hook->next = NULL;
  114   hook->handler = handler;
  115   hook->irq = irq;
  116   hook->id = id;
  117   *line = hook;
  118 
  119   irq_use |= 1 << irq;
  120 }
  121 
  122 /*===========================================================================*
  123  *                              rm_irq_handler                               *
  124  *===========================================================================*/
  125 PUBLIC void rm_irq_handler(hook)
  126 irq_hook_t *hook;
  127 {
  128 /* Unregister an interrupt handler. */
  129   int irq = hook->irq; 
  130   int id = hook->id;
  131   irq_hook_t **line;
  132 
  133   if (irq < 0 || irq >= NR_IRQ_VECTORS) 
  134       panic("invalid call to rm_irq_handler", irq);
  135 
  136   line = &irq_handlers[irq];
  137   while (*line != NULL) {
  138       if ((*line)->id == id) {
  139           (*line) = (*line)->next;
  140           if (! irq_handlers[irq]) irq_use &= ~(1 << irq);
  141           return;
  142       }
  143       line = &(*line)->next;
  144   }
  145   /* When the handler is not found, normally return here. */
  146 }
  147 
  148 /*===========================================================================*
  149  *                              intr_handle                                  *
  150  *===========================================================================*/
  151 PUBLIC void intr_handle(hook)
  152 irq_hook_t *hook;
  153 {
  154 /* Call the interrupt handlers for an interrupt with the given hook list.
  155  * The assembly part of the handler has already masked the IRQ, reenabled the
  156  * controller(s) and enabled interrupts.
  157  */
  158 
  159   /* Call list of handlers for an IRQ. */
  160   while (hook != NULL) {
  161       /* For each handler in the list, mark it active by setting its ID bit,
  162        * call the function, and unmark it if the function returns true.
  163        */
  164       irq_actids[hook->irq] |= hook->id;
  165       if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id;
  166       hook = hook->next;
  167   }
  168 
  169   /* The assembly code will now disable interrupts, unmask the IRQ if and only
  170    * if all active ID bits are cleared, and restart a process.
  171    */
  172 }
  173 
  174 #if _WORD_SIZE == 2
  175 /*===========================================================================*
  176  *                              set_vec                                      *
  177  *===========================================================================*/
  178 PRIVATE void set_vec(vec_nr, addr)
  179 int vec_nr;                     /* which vector */
  180 vecaddr_t addr;                 /* where to start */
  181 {
  182 /* Set up a real mode interrupt vector. */
  183 
  184   u16_t vec[2];
  185 
  186   /* Build the vector in the array 'vec'. */
  187   vec[0] = (u16_t) addr;
  188   vec[1] = (u16_t) physb_to_hclick(code_base);
  189 
  190   /* Copy the vector into place. */
  191   phys_copy(vir2phys(vec), vec_nr * 4L, 4L);
  192 }
  193 #endif /* _WORD_SIZE == 2 */

Cache object: b09d0426df3e92a0961b5ac9427d6b08


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