kconfig: use pkg-config for ncurses detection
[akaros.git] / kern / arch / x86 / pic.c
1 /* Copyright (c) 2009, 2014 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * PIC: 8259 interrupt controller */
6
7 #include <arch/pic.h>
8 #include <arch/x86.h>
9 #include <atomic.h>
10 #include <assert.h>
11 #include <stdio.h>
12
13 spinlock_t piclock = SPINLOCK_INITIALIZER_IRQSAVE;
14
15 /* Remaps the Programmable Interrupt Controller to use IRQs 32-47
16  * http://wiki.osdev.org/PIC
17  * Check osdev for a more thorough explanation/implementation.
18  * http://bochs.sourceforge.net/techspec/PORTS.LST  */
19 void pic_remap(void)
20 {
21         spin_lock_irqsave(&piclock);
22         /* start initialization (ICW1) */
23         outb(PIC1_CMD, 0x11);
24         outb(PIC2_CMD, 0x11);
25         /* set new offsets (ICW2) */
26         outb(PIC1_DATA, PIC1_OFFSET);
27         outb(PIC2_DATA, PIC2_OFFSET);
28         /* set up cascading (ICW3) */
29         outb(PIC1_DATA, 0x04);
30         outb(PIC2_DATA, 0x02);
31         /* other stuff (put in 8086/88 mode, or whatever) (ICW4) */
32         outb(PIC1_DATA, 0x01);
33         outb(PIC2_DATA, 0x01);
34         /* Init done, further data R/W access the interrupt mask */
35         /* set masks, defaulting to all masked for now */
36         outb(PIC1_DATA, 0xff);
37         outb(PIC2_DATA, 0xff);
38         spin_unlock_irqsave(&piclock);
39 }
40
41 void pic_mask_irq(struct irq_handler *unused, int trap_nr)
42 {
43         int irq = trap_nr - PIC1_OFFSET;
44
45         spin_lock_irqsave(&piclock);
46         if (irq > 7)
47                 outb(PIC2_DATA, inb(PIC2_DATA) | (1 << (irq - 8)));
48         else
49                 outb(PIC1_DATA, inb(PIC1_DATA) | (1 << irq));
50         spin_unlock_irqsave(&piclock);
51 }
52
53 void pic_unmask_irq(struct irq_handler *unused, int trap_nr)
54 {
55         int irq = trap_nr - PIC1_OFFSET;
56         printd("PIC unmask for TRAP %d, IRQ %d\n", trap_nr, irq);
57         spin_lock_irqsave(&piclock);
58         if (irq > 7) {
59                 outb(PIC2_DATA, inb(PIC2_DATA) & ~(1 << (irq - 8)));
60                 // make sure irq2 is unmasked
61                 outb(PIC1_DATA, inb(PIC1_DATA) & 0xfb);
62         } else
63                 outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
64         spin_unlock_irqsave(&piclock);
65 }
66
67 void pic_mask_all(void)
68 {
69         for (int i = 0 + PIC1_OFFSET; i < 16 + PIC1_OFFSET; i++)
70                 pic_mask_irq(0, i);
71 }
72
73 /* Aka, the IMR.  Simply reading the data port are OCW1s. */
74 uint16_t pic_get_mask(void)
75 {
76         uint16_t ret;
77
78         spin_lock_irqsave(&piclock);
79         ret = (inb(PIC2_DATA) << 8) | inb(PIC1_DATA);
80         spin_unlock_irqsave(&piclock);
81         return ret;
82 }
83
84 static uint16_t __pic_get_irq_reg(int ocw3)
85 {
86         uint16_t ret;
87
88         spin_lock_irqsave(&piclock);
89         /* OCW3 to PIC CMD to get the register values.  PIC2 is chained, and
90          * represents IRQs 8-15.  PIC1 is IRQs 0-7, with 2 being the chain */
91         outb(PIC1_CMD, ocw3);
92         outb(PIC2_CMD, ocw3);
93         ret = (inb(PIC2_CMD) << 8) | inb(PIC1_CMD);
94         spin_unlock_irqsave(&piclock);
95         return ret;
96 }
97
98 /* Returns the combined value of the cascaded PICs irq request register */
99 uint16_t pic_get_irr(void)
100 {
101         return __pic_get_irq_reg(PIC_READ_IRR);
102 }
103
104 /* Returns the combined value of the cascaded PICs irq service register */
105 uint16_t pic_get_isr(void)
106 {
107         return __pic_get_irq_reg(PIC_READ_ISR);
108 }
109
110 /* Takes a raw vector/trap number (32-47), not a device IRQ (0-15) */
111 bool pic_check_spurious(int trap_nr)
112 {
113         /* the PIC may send spurious irqs via one of the chips irq 7.  if the
114          * isr doesn't show that irq, then it was spurious, and we don't send an
115          * eoi.  Check out http://wiki.osdev.org/8259_PIC#Spurious_IRQs */
116         if ((trap_nr == PIC1_SPURIOUS) && !(pic_get_isr() & (1 << 7))) {
117                 /* want to know if this happens */
118                 printd("Spurious PIC1 irq!\n");
119                 return TRUE;
120         }
121         if ((trap_nr == PIC2_SPURIOUS) && !(pic_get_isr() & (1 << 15))) {
122                 /* want to know if this happens */
123                 printd("Spurious PIC2 irq!\n");
124                 /* for the cascaded PIC, we *do* need to send an EOI to the
125                  * master's cascade irq (2). */
126                 pic_send_eoi(2 + PIC1_OFFSET);
127                 return TRUE;
128         }
129         return FALSE;
130 }
131
132 void pic_send_eoi(int trap_nr)
133 {
134         int irq = trap_nr - PIC1_OFFSET;
135
136         spin_lock_irqsave(&piclock);
137         // all irqs beyond the first seven need to be chained to the slave
138         if (irq > 7)
139                 outb(PIC2_CMD, PIC_EOI);
140         outb(PIC1_CMD, PIC_EOI);
141         spin_unlock_irqsave(&piclock);
142 }