/
irqs.c
164 lines (147 loc) · 4.38 KB
/
irqs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <data_types.h>
#include <k_printf.h>
#include <idt.h>
#include <irqs.h>
volatile u_short irq_watching[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#ifdef DEVELOPER_EDITION
u_long irq_keys[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#else
u_long irq_keys[15] = {
0xAAFB39C0, 0x12984C00, 0x502EFB20, 0xB39D82C0, 0xFA29E000,
0xDCAC0210, 0xAD830610, 0x28903000, 0xB33FF000, 0x103422A0,
0xC720A290, 0xFFFFAA30, 0xD729C200, 0x00FCA320, 0x902AAF0 };
#endif
// used for un/mask_irq
u_short irqs=0;
// This function must be called before doing anything with IRQs.
// It remaps the PIC and sets up the ISRs for IRQs 1-15(IRQ 0
// is handled by the task scheduler).
void setup_irqs()
{
k_printf("\nSetting up IRQs...\n");
k_printf("Remapping the PIC... ");
remap_pics(0x40, 0x48);
k_printf("completed\n");
k_printf("Masking all IRQs... ");
mask_irq(0);
mask_irq(1);
mask_irq(2);
mask_irq(3);
mask_irq(4);
mask_irq(5);
mask_irq(6);
mask_irq(7);
mask_irq(8);
mask_irq(9);
mask_irq(10);
mask_irq(11);
mask_irq(12);
mask_irq(13);
mask_irq(14);
mask_irq(15);
k_printf("completed\n");
k_printf("Installing ISRs for IRQs 1-15... ");
modify_gate_address((u_long)&irq_watcher_1, 0x41, 0);
modify_gate_address((u_long)&irq_watcher_2, 0x42, 0);
modify_gate_address((u_long)&irq_watcher_3, 0x43, 0);
modify_gate_address((u_long)&irq_watcher_4, 0x44, 0);
modify_gate_address((u_long)&irq_watcher_5, 0x45, 0);
modify_gate_address((u_long)&irq_watcher_6, 0x46, 0);
modify_gate_address((u_long)&irq_watcher_7, 0x47, 0);
modify_gate_address((u_long)&irq_watcher_8, 0x48, 0);
modify_gate_address((u_long)&irq_watcher_9, 0x49, 0);
modify_gate_address((u_long)&irq_watcher_10, 0x4A, 0);
modify_gate_address((u_long)&irq_watcher_11, 0x4B, 0);
modify_gate_address((u_long)&irq_watcher_12, 0x4C, 0);
modify_gate_address((u_long)&irq_watcher_13, 0x4D, 0);
modify_gate_address((u_long)&irq_watcher_14, 0x4E, 0);
modify_gate_address((u_long)&irq_watcher_15, 0x4F, 0);
k_printf("completed\n");
k_printf("The IRQs have been setup.\n");
};
// Installs a handler if needed to watch an IRQ.
// You must also send the right key for the number.
// this allows making sure that only one driver at
// a time is watching an IRQ and that only certified
// drivers can watch the IRQ.
// Returns the address of to the variable that holds
// the number of times the IRQ has fired, 0 on failure.
//
// NOTE: IRQ 0 cannot be watched this way
u_long watch_irq(u_char irq_number, u_long key)
{
if(irq_keys[irq_number] == key && irq_number != 0)
{
irq_watching[irq_number] = 0;
irq_keys[irq_number] += 1; // the keys table is also used to keep track of what IRQs are being currently watched
enable_gate(irq_number+0x40);
unmask_irq(irq_number);
return(&irq_watching[irq_number]);
} else
{
return(0);
};
};
// Stop watching an IRQ that was watched
// with watch_irq.
void release_irq(u_char irq_number, u_long key)
{
if((irq_keys[irq_number]-1) == key && irq_number != 0)
{
mask_irq(irq_number); // mask the IRQ
disable_gate(irq_number+0x40); // and disable the interrupt
irq_keys[irq_number]--;
};
};
// returns number of times a IRQ has fired
inline u_short num_time_irq_fired(u_char irq_num)
{
irq_num &= 0xF; // asures we the number isn't greater than 15, faster than doing an if/then
return(irq_watching[irq_num]);
};
// called by the IRQ interrupt handlers
void irq_watcher_helper(u_long irq_number)
{
//putc('i');
irq_watching[irq_number]++;
};
// Remaps the PIC, takes the interrupt numbers
// for where to remap PIC1 and PIC2 at.
void remap_pics(u_char pic1, u_char pic2)
{
u_char a1, a2;
a1=inportb(PIC1_DATA);
a2=inportb(PIC2_DATA);
outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);
outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
outportb(PIC1_DATA, pic1);
outportb(PIC2_DATA, pic2);
outportb(PIC1_DATA, 4);
outportb(PIC2_DATA, 2);
outportb(PIC1_DATA, ICW4_8086);
outportb(PIC2_DATA, ICW4_8086);
outportb(PIC1_DATA, a1);
outportb(PIC2_DATA, a2);
};
void unmask_irq(u_char irq)
{
irqs&=~(1<<irq);
if(irq < 8)
{
outportb(PIC1_DATA, irqs&0xFF);
} else
{
outportb(PIC2_DATA, irqs>>8);
};
};
void mask_irq(u_char irq)
{
irqs|=(1<<irq);
if(irq < 8)
{
outportb(PIC1_DATA, irqs&0xFF);
} else
{
outportb(PIC2_DATA, irqs>>8);
};
};