1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Interrupt wrapper functions for djgpp. Unlike the libc
12 * _go32_dpmi_* wrapper functions, these can deal with
13 * reentrant interrupts.
14 *
15 * By Shawn Hargreaves.
16 *
17 * See readme.txt for copyright information.
18 */
19
20
21 #include "allegro.h"
22 #include "allegro/internal/aintern.h"
23 #include "allegro/platform/aintdos.h"
24 #include "../i386/asmdefs.inc"
25
26 #ifndef ALLEGRO_DOS
27 #error something is wrong with the makefile
28 #endif
29
30
31
32 #define MAX_IRQS 8 /* timer + keyboard + soundcard + spares */
33 #define STACK_SIZE 8192 /* an 8k stack should be plenty */
34
35 _IRQ_HANDLER _irq_handler[MAX_IRQS];
36
37 unsigned char *_irq_stack[IRQ_STACKS];
38
39 extern void _irq_wrapper_0(void), _irq_wrapper_1(void),
40 _irq_wrapper_2(void), _irq_wrapper_3(void),
41 _irq_wrapper_4(void), _irq_wrapper_5(void),
42 _irq_wrapper_6(void), _irq_wrapper_7(void),
43 _irq_wrapper_0_end(void);
44
45
46
47 /* _dos_irq_init:
48 * Initialises this module.
49 */
_dos_irq_init(void)50 void _dos_irq_init(void)
51 {
52 int c;
53
54 LOCK_VARIABLE(_irq_handler);
55 LOCK_VARIABLE(_irq_stack);
56 LOCK_FUNCTION(_irq_wrapper_0);
57
58 for (c=0; c<MAX_IRQS; c++) {
59 _irq_handler[c].handler = NULL;
60 _irq_handler[c].number = 0;
61 }
62
63 for (c=0; c<IRQ_STACKS; c++) {
64 _irq_stack[c] = _AL_MALLOC(STACK_SIZE);
65 if (_irq_stack[c]) {
66 LOCK_DATA(_irq_stack[c], STACK_SIZE);
67 _irq_stack[c] += STACK_SIZE - 32; /* stacks grow downwards */
68 }
69 }
70 }
71
72
73
74 /* _dos_irq_exit:
75 * Routine for freeing the interrupt handler stacks.
76 */
_dos_irq_exit(void)77 void _dos_irq_exit(void)
78 {
79 int c;
80
81 for (c=0; c<IRQ_STACKS; c++) {
82 if (_irq_stack[c]) {
83 _irq_stack[c] -= STACK_SIZE - 32;
84 _AL_FREE(_irq_stack[c]);
85 _irq_stack[c] = NULL;
86 }
87 }
88 }
89
90
91
92 /* _install_irq:
93 * Installs a hardware interrupt handler for the specified irq, allocating
94 * an asm wrapper function which will save registers and handle the stack
95 * switching. The C function should return zero to exit the interrupt with
96 * an iret instruction, and non-zero to chain to the old handler.
97 */
_install_irq(int num,int (* handler)(void))98 int _install_irq(int num, int (*handler)(void))
99 {
100 __dpmi_paddr addr;
101 int c;
102
103 for (c=0; c<MAX_IRQS; c++) {
104 if (_irq_handler[c].handler == NULL) {
105
106 addr.selector = _my_cs();
107
108 switch (c) {
109 case 0: addr.offset32 = (long)_irq_wrapper_0; break;
110 case 1: addr.offset32 = (long)_irq_wrapper_1; break;
111 case 2: addr.offset32 = (long)_irq_wrapper_2; break;
112 case 3: addr.offset32 = (long)_irq_wrapper_3; break;
113 case 4: addr.offset32 = (long)_irq_wrapper_4; break;
114 case 5: addr.offset32 = (long)_irq_wrapper_5; break;
115 case 6: addr.offset32 = (long)_irq_wrapper_6; break;
116 case 7: addr.offset32 = (long)_irq_wrapper_7; break;
117 default: return -1;
118 }
119
120 _irq_handler[c].handler = handler;
121 _irq_handler[c].number = num;
122
123 __dpmi_get_protected_mode_interrupt_vector(num, &_irq_handler[c].old_vector);
124 __dpmi_set_protected_mode_interrupt_vector(num, &addr);
125
126 return 0;
127 }
128 }
129
130 return -1;
131 }
132
133
134
135 /* _remove_irq:
136 * Removes a hardware interrupt handler, restoring the old vector.
137 */
_remove_irq(int num)138 void _remove_irq(int num)
139 {
140 int c;
141
142 for (c=0; c<MAX_IRQS; c++) {
143 if (_irq_handler[c].number == num) {
144 __dpmi_set_protected_mode_interrupt_vector(num, &_irq_handler[c].old_vector);
145 _irq_handler[c].number = 0;
146 _irq_handler[c].handler = NULL;
147 break;
148 }
149 }
150 }
151
152
153