Moved input stuff to arch subdirs, as in d1x.
[btb/d2x.git] / arch / dos / comm / irq.c
1 /*
2  * This file is part of DZComm.
3  * Version : 0.6
4  * Minor changes by Dim Zegebart (zager@post.comstar.ru) to run with Palantir
5  */
6
7 /*         ______   ___    ___
8  *        /\  _  \ /\_ \  /\_ \
9  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
10  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
11  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
12  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
13  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
14  *                                           /\____/
15  *                                           \_/__/
16  *      By Shawn Hargreaves,
17  *      1 Salisbury Road,
18  *      Market Drayton,
19  *      Shropshire,
20  *      England, TF9 1AJ.
21  *
22  *      Hardware interrupt wrapper functions. Unlike the _go32_dpmi_*
23  *      functions, these can deal with reentrant interrupts.
24  *
25  *      See readme.txt for copyright information.
26  */
27
28
29 #ifndef DJGPP
30 #error This file should only be used by the djgpp version of Allegro
31 #endif
32
33 #include <stdlib.h>
34 #include <dos.h>
35 #include <go32.h>
36 #include <dpmi.h>
37
38 #include "allegro.h"
39 #include "internal.h"
40 #include "asmdefs.inc"
41
42
43 #define MAX_IRQS     16
44 #define STACK_SIZE   8*1024      /* 8k stack should be plenty */
45
46
47 static int irq_virgin = TRUE;
48
49 _IRQ_HANDLER _irq_handler[MAX_IRQS];
50
51 unsigned char *_irq_stack[IRQ_STACKS];
52
53 extern void _irq_wrapper_0(), _irq_wrapper_1(),
54             _irq_wrapper_2(), _irq_wrapper_3(),
55             _irq_wrapper_4(), _irq_wrapper_5(),
56             _irq_wrapper_6(), _irq_wrapper_7(),
57             _irq_wrapper_8(), _irq_wrapper_9(),
58             _irq_wrapper_10(), _irq_wrapper_11(),
59             _irq_wrapper_12(), _irq_wrapper_13(),
60             _irq_wrapper_14(), _irq_wrapper_15(),
61             _irq_wrapper_0_end();
62
63
64
65 /* _install_irq:
66  *  Installs a hardware interrupt handler for the specified irq, allocating
67  *  an asm wrapper function which will save registers and handle the stack
68  *  switching. The C function should return zero to exit the interrupt with
69  *  an iret instruction, and non-zero to chain to the old handler.
70  */
71 int _install_irq(int num, int (*handler)())
72 {
73    int c;
74    __dpmi_paddr addr;
75
76    if (irq_virgin) {                /* first time we've been called? */
77      LOCK_VARIABLE(_irq_handler);
78       LOCK_VARIABLE(_irq_stack);
79       LOCK_FUNCTION(_irq_wrapper_0);
80
81       for (c=0; c<MAX_IRQS; c++) {
82          _irq_handler[c].handler = NULL;
83          _irq_handler[c].number = 0;
84       }
85
86       for (c=0; c<IRQ_STACKS; c++) {
87          _irq_stack[c] = malloc(STACK_SIZE);
88          if (_irq_stack[c]) {
89             _go32_dpmi_lock_data(_irq_stack[c], STACK_SIZE);
90             _irq_stack[c] += STACK_SIZE - 32;   /* stacks grow downwards */
91          }
92       }
93
94       irq_virgin = FALSE;
95    }
96
97    for (c=0; c<MAX_IRQS; c++) {
98       if (_irq_handler[c].handler == NULL) {
99
100          addr.selector = _my_cs();
101
102          switch (c) {
103             case 0: addr.offset32 = (long)_irq_wrapper_0; break;
104             case 1: addr.offset32 = (long)_irq_wrapper_1; break;
105             case 2: addr.offset32 = (long)_irq_wrapper_2; break;
106             case 3: addr.offset32 = (long)_irq_wrapper_3; break;
107             case 4: addr.offset32 = (long)_irq_wrapper_4; break;
108             case 5: addr.offset32 = (long)_irq_wrapper_5; break;
109             case 6: addr.offset32 = (long)_irq_wrapper_6; break;
110             case 7: addr.offset32 = (long)_irq_wrapper_7; break;
111             case 8: addr.offset32 = (long)_irq_wrapper_8; break;
112             case 9: addr.offset32 = (long)_irq_wrapper_9; break;
113             case 10: addr.offset32 = (long)_irq_wrapper_10; break;
114             case 11: addr.offset32 = (long)_irq_wrapper_11; break;
115             case 12: addr.offset32 = (long)_irq_wrapper_12; break;
116             case 13: addr.offset32 = (long)_irq_wrapper_13; break;
117             case 14: addr.offset32 = (long)_irq_wrapper_14; break;
118             case 15: addr.offset32 = (long)_irq_wrapper_15; break;
119
120             default: return -1;
121          }
122
123          _irq_handler[c].handler = handler;
124          _irq_handler[c].number = num;
125
126          __dpmi_get_protected_mode_interrupt_vector(num,
127                                                 &_irq_handler[c].old_vector);
128
129          __dpmi_set_protected_mode_interrupt_vector(num, &addr);
130
131          return 0;
132       }
133    }
134
135    return -1;
136 }
137
138
139
140 /* _remove_irq:
141  *  Removes a hardware interrupt handler, restoring the old vector.
142  */
143 void _remove_irq(int num)
144 {
145    int c;
146
147    for (c=0; c<MAX_IRQS; c++) {
148       if (_irq_handler[c].number == num) {
149          __dpmi_set_protected_mode_interrupt_vector(num,
150                                                 &_irq_handler[c].old_vector);
151          _irq_handler[c].number = 0;
152          _irq_handler[c].handler = NULL;
153
154          break;
155       }
156    }
157 }