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