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