Fork me on GitHub

root/kernel/pic.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pic_get_irq_reg
  2. register_irq
  3. unregister_irq
  4. add_bh
  5. enable_irq
  6. disable_irq
  7. irq_handler
  8. do_bh
  9. pic_init

   1 /*
   2  * fiwix/kernel/pic.c
   3  *
   4  * Copyright 2018, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/config.h>
  11 #include <fiwix/limits.h>
  12 #include <fiwix/errno.h>
  13 #include <fiwix/pic.h>
  14 #include <fiwix/stdio.h>
  15 #include <fiwix/string.h>
  16 #include <fiwix/sigcontext.h>
  17 #include <fiwix/sleep.h>
  18 
  19 /* interrupt vector base addresses */
  20 #define IRQ0_ADDR       0x20
  21 #define IRQ8_ADDR       0x28
  22 
  23 struct interrupt *irq_table[NR_IRQS];
  24 static struct bh *bh_table = NULL;
  25 unsigned int intr_count = 0;
  26 
  27 /*
  28  * This sends the command OCW3 to PIC (master or slave) to obtain the register
  29  * values. Slave is chained and represents IRQs 8-15. Master represents IRQs
  30  * 0-7, with IRQ 2 being the chain.
  31  */
  32 static unsigned short int pic_get_irq_reg(int ocw3)
  33 {
  34         outport_b(PIC_MASTER, ocw3);
  35         outport_b(PIC_SLAVE, ocw3);
  36         return (inport_b(PIC_SLAVE) << 8) | inport_b(PIC_MASTER);
  37 }
  38 
  39 int register_irq(int num, struct interrupt *new_irq)
  40 {
  41         struct interrupt **irq;
  42 
  43         if(num < 0  || num >= NR_IRQS) {
  44                 return -EINVAL;
  45         }
  46 
  47         irq = &irq_table[num];
  48         if(*irq) {
  49                 do {
  50                         if(*irq == new_irq) {
  51                                 printk("WARNING: %s(): interrupt %d already registered!\n", __FUNCTION__, num);
  52                                 return -EINVAL;
  53                         }
  54                         irq = &(*irq)->next;
  55                 } while(*irq);
  56         }
  57         *irq = new_irq;
  58         new_irq->ticks = 0;
  59         return 0;
  60 }
  61 
  62 int unregister_irq(int num, struct interrupt *old_irq)
  63 {
  64         struct interrupt **irq, *prev_irq;
  65 
  66         if(num < 0  || num >= NR_IRQS) {
  67                 return -EINVAL;
  68         }
  69 
  70         irq = &irq_table[num];
  71         prev_irq = NULL;
  72 
  73         if(*irq) {
  74                 do {
  75                         if(*irq == old_irq) {
  76                                 if((*irq)->next) {
  77                                         printk("WARNING: %s(): cannot unregister interrupt %d.\n", __FUNCTION__, num);
  78                                         return -EINVAL;
  79                                 }
  80                                 *irq = NULL;
  81                                 if(prev_irq) {
  82                                         prev_irq->next = NULL;
  83                                 }
  84                                 break;
  85                         }
  86                         prev_irq = *irq;
  87                         irq = &(*irq)->next;
  88                 } while(*irq);
  89         }
  90         return 0;
  91 }
  92 
  93 void add_bh(struct bh *new)
  94 {
  95         unsigned long int flags;
  96         struct bh **b;
  97 
  98         SAVE_FLAGS(flags); CLI();
  99 
 100         b = &bh_table;
 101         if(*b) {
 102                 do {
 103                         b = &(*b)->next;
 104                 } while(*b);
 105         }
 106         *b = new;
 107 
 108         RESTORE_FLAGS(flags);
 109 }
 110 
 111 void enable_irq(int irq)
 112 {
 113         int addr;
 114 
 115         addr = (irq > 7) ? PIC_SLAVE + DATA : PIC_MASTER + DATA;
 116         irq &= 0x0007;
 117 
 118         outport_b(addr, inport_b(addr) & ~(1 << irq));
 119 }
 120 
 121 void disable_irq(int irq)
 122 {
 123         int addr;
 124 
 125         addr = (irq > 7) ? PIC_SLAVE + DATA : PIC_MASTER + DATA;
 126         irq &= 0x0007;
 127 
 128         outport_b(addr, inport_b(addr) | (1 << irq));
 129 }
 130 
 131 /* each ISR points to this function */
 132 void irq_handler(int num, struct sigcontext sc)
 133 {
 134         struct interrupt *irq;
 135         int real;
 136 
 137         if(num == -1) {
 138                 printk("Unknown IRQ received!\n");
 139                 return;
 140         }
 141 
 142         irq = irq_table[num];
 143 
 144         /* spurious interrupt treatment */
 145         if(!irq) {
 146                 real = pic_get_irq_reg(PIC_READ_ISR);
 147                 if(!real) {
 148                         /*
 149                          * If IRQ was not real and came from slave, then send
 150                          * an EOI to master because it doesn't know if the IRQ
 151                          * was a spurious interrupt from slave.
 152                          */
 153                         if(num > 7) {
 154                                 outport_b(PIC_MASTER, EOI);
 155                         }
 156                         if(kstat.sirqs < MAX_SPU_NOTICES) {
 157                                 printk("WARNING: spurious interrupt detected (unregistered IRQ %d).\n", num);
 158                         } else if(kstat.sirqs == MAX_SPU_NOTICES) {
 159                                 printk("WARNING: too many spurious interrupts; not logging any more.\n");
 160                         }
 161                         kstat.sirqs++;
 162                         return;
 163                 }
 164                 if(num > 7) {
 165                         outport_b(PIC_SLAVE, EOI);
 166                 }
 167                 outport_b(PIC_MASTER, EOI);
 168                 return;
 169         }
 170 
 171         /* all handlers execute with interrupts disabled */
 172         disable_irq(num);
 173 
 174         if(num > 7) {
 175                 outport_b(PIC_SLAVE, EOI);
 176         }
 177         outport_b(PIC_MASTER, EOI);
 178 
 179         kstat.irqs++;
 180         irq->ticks++;
 181         do {
 182                 irq->handler(num, &sc);
 183                 irq = irq->next;
 184         } while(irq);
 185 
 186         enable_irq(num);
 187 }
 188 
 189 /* do bottom halves (interrupts are (FIXME: not yet) enabled) */
 190 void do_bh(void)
 191 {
 192         struct bh *b;
 193         void (*fn)(void);
 194 
 195         if(!lock_area(AREA_BH)) {
 196                 //FIXME: STI();
 197                 if((b = bh_table)) {
 198                         do {
 199                                 if(b->flags & BH_ACTIVE) {
 200                                         b->flags &= ~BH_ACTIVE;
 201                                         fn = b->fn;
 202                                         (*fn)();
 203                                 }
 204                                 b = b->next;
 205                         } while(b);
 206                 }
 207                 //FIXME: CLI();
 208                 unlock_area(AREA_BH);
 209         }
 210 }
 211 
 212 void pic_init(void)
 213 {
 214         memset_b(irq_table, NULL, sizeof(irq_table));
 215 
 216         /* remap interrupts for PIC1 */
 217         outport_b(PIC_MASTER, ICW1_RESET);
 218         outport_b(PIC_MASTER + DATA, IRQ0_ADDR);        /* ICW2 */
 219         outport_b(PIC_MASTER + DATA, 1 << CASCADE_IRQ); /* ICW3 */
 220         outport_b(PIC_MASTER + DATA, ICW4_8086EOI);
 221 
 222         /* remap interrupts for PIC2 */
 223         outport_b(PIC_SLAVE, ICW1_RESET);
 224         outport_b(PIC_SLAVE + DATA, IRQ8_ADDR);         /* ICW2 */
 225         outport_b(PIC_SLAVE + DATA, CASCADE_IRQ);       /* ICW3 */
 226         outport_b(PIC_SLAVE + DATA, ICW4_8086EOI);
 227 
 228         /* mask all IRQs except cascade */
 229         outport_b(PIC_MASTER + DATA, ~(1 << CASCADE_IRQ));
 230 
 231         /* mask all IRQs */
 232         outport_b(PIC_SLAVE + DATA, OCW1);
 233 }

/* [previous][next][first][last][top][bottom][index][help] */