source: mainline/kernel/genarch/src/drivers/i8259/i8259.c

Last change on this file was c48de91, checked in by Jakub Jermar <jakub@…>, 6 years ago

Hide macros used internally by the i8259 driver

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_genarch
30 * @{
31 */
32/**
33 * @file
34 * @brief i8259 driver.
35 *
36 * Programmable Interrupt Controller for UP systems based on i8259 chip.
37 */
38
39#include <genarch/drivers/i8259/i8259.h>
40#include <typedefs.h>
41#include <stdint.h>
42#include <log.h>
43#include <interrupt.h>
44
45/* ICW1 bits */
46#define I8259_ICW1 (1 << 4)
47#define I8259_ICW1_NEEDICW4 (1 << 0)
48
49/* OCW3 bits */
50#define I8259_OCW3 (1 << 3)
51#define I8259_OCW3_READ_ISR (3 << 0)
52
53/* OCW4 bits */
54#define I8259_OCW4 (0 << 3)
55#define I8259_OCW4_NSEOI (1 << 5)
56
57#define I8259_IRQ_COUNT 8
58
59#define I8259_IRQ_SLAVE 2
60
61static const char *i8259_get_name(void);
62
63pic_ops_t i8259_pic_ops = {
64 .get_name = i8259_get_name,
65 .enable_irqs = i8259_enable_irqs,
66 .disable_irqs = i8259_disable_irqs,
67 .eoi = i8259_eoi,
68 .is_spurious = i8259_is_spurious,
69 .handle_spurious = i8259_handle_spurious
70};
71
72// XXX: need to change pic_* API to get rid of these
73static i8259_t *saved_pic0;
74static i8259_t *saved_pic1;
75
76void i8259_init(i8259_t *pic0, i8259_t *pic1, unsigned int irq0_vec)
77{
78 saved_pic0 = pic0;
79 saved_pic1 = pic1;
80
81 /* ICW1: this is ICW1, ICW4 to follow */
82 pio_write_8(&pic0->port1, I8259_ICW1 | I8259_ICW1_NEEDICW4);
83
84 /* ICW2: IRQ 0 maps to interrupt vector address irq0_vec */
85 pio_write_8(&pic0->port2, irq0_vec);
86
87 /* ICW3: pic1 using IRQ I8259_IRQ_SLAVE */
88 pio_write_8(&pic0->port2, 1 << I8259_IRQ_SLAVE);
89
90 /* ICW4: i8086 mode */
91 pio_write_8(&pic0->port2, 1);
92
93 /* ICW1: ICW1, ICW4 to follow */
94 pio_write_8(&pic1->port1, I8259_ICW1 | I8259_ICW1_NEEDICW4);
95
96 /* ICW2: IRQ 8 maps to interrupt vector address irq0_vec + 8 */
97 pio_write_8(&pic1->port2, irq0_vec + I8259_IRQ_COUNT);
98
99 /* ICW3: pic1 is known as I8259_IRQ_SLAVE */
100 pio_write_8(&pic1->port2, I8259_IRQ_SLAVE);
101
102 /* ICW4: i8086 mode */
103 pio_write_8(&pic1->port2, 1);
104
105 /* disable all irq's */
106 i8259_disable_irqs(0xffff);
107 /* but enable I8259_IRQ_SLAVE */
108 i8259_enable_irqs(1 << I8259_IRQ_SLAVE);
109}
110
111const char *i8259_get_name(void)
112{
113 return "i8259";
114}
115
116void i8259_enable_irqs(uint16_t irqmask)
117{
118 uint8_t x;
119
120 if (irqmask & 0xff) {
121 x = pio_read_8(&saved_pic0->port2);
122 pio_write_8(&saved_pic0->port2,
123 (uint8_t) (x & (~(irqmask & 0xff))));
124 }
125 if (irqmask >> I8259_IRQ_COUNT) {
126 x = pio_read_8(&saved_pic1->port2);
127 pio_write_8(&saved_pic1->port2,
128 (uint8_t) (x & (~(irqmask >> I8259_IRQ_COUNT))));
129 }
130}
131
132void i8259_disable_irqs(uint16_t irqmask)
133{
134 uint8_t x;
135
136 if (irqmask & 0xff) {
137 x = pio_read_8(&saved_pic0->port2);
138 pio_write_8(&saved_pic0->port2,
139 (uint8_t) (x | (irqmask & 0xff)));
140 }
141 if (irqmask >> I8259_IRQ_COUNT) {
142 x = pio_read_8(&saved_pic1->port2);
143 pio_write_8(&saved_pic1->port2,
144 (uint8_t) (x | (irqmask >> I8259_IRQ_COUNT)));
145 }
146}
147
148void i8259_eoi(unsigned int irq)
149{
150 if (irq >= I8259_IRQ_COUNT)
151 pio_write_8(&saved_pic1->port1, I8259_OCW4 | I8259_OCW4_NSEOI);
152 pio_write_8(&saved_pic0->port1, I8259_OCW4 | I8259_OCW4_NSEOI);
153}
154
155bool i8259_is_spurious(unsigned int irq)
156{
157 pio_write_8(&saved_pic0->port1, I8259_OCW3 | I8259_OCW3_READ_ISR);
158 pio_write_8(&saved_pic1->port1, I8259_OCW3 | I8259_OCW3_READ_ISR);
159 uint8_t isr_lo = pio_read_8(&saved_pic0->port1);
160 uint8_t isr_hi = pio_read_8(&saved_pic1->port1);
161 return !(((isr_hi << I8259_IRQ_COUNT) | isr_lo) & (1 << irq));
162}
163
164void i8259_handle_spurious(unsigned int irq)
165{
166 /* For spurious IRQs from pic1, we need to isssue an EOI to pic0 */
167 if (irq >= I8259_IRQ_COUNT)
168 pio_write_8(&saved_pic0->port1, I8259_OCW4 | I8259_OCW4_NSEOI);
169}
170
171/** @}
172 */
Note: See TracBrowser for help on using the repository browser.