1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Helper functions to make things work with Watcom. This file
12  *      emulates the DPMI support functions from the djgpp libc, and
13  *      provides interrupt wrapper routines using the same API as the
14  *      stuff in djirq.c.
15  *
16  *      By Shawn Hargreaves.
17  *
18  *      See readme.txt for copyright information.
19  */
20 
21 
22 #ifndef SCAN_DEPEND
23    #include <dos.h>
24 #endif
25 
26 #include "allegro.h"
27 #include "allegro/internal/aintern.h"
28 #include "allegro/platform/aintdos.h"
29 #include "../i386/asmdefs.inc"
30 
31 
32 
33 /* some useful globals */
34 static int out_eax, out_ebx, out_ecx, out_edx, out_esi, out_edi;
35 
36 #define MAX_IRQS        8
37 #define STACK_SIZE      8192
38 
39 static _IRQ_HANDLER irq_handler[MAX_IRQS];
40 
41 static unsigned char *irq_stack[IRQ_STACKS];
42 
43 static unsigned char *rmcb_stack;
44 
45 static void (__interrupt __far *old_int24)() = NULL;
46 
47 unsigned long __tb = 0;
48 
49 static int tb_sel = 0;
50 
51 int __djgpp_ds_alias = 0;
52 
53 
54 
55 /* my_int24:
56  *  Stop those stupid "abort, retry, fail" messages from popping up all
57  *  over the place.
58  */
59 #if __WATCOMC__ >= 1200
60 
my_int24(void)61 static void __interrupt __far my_int24(void)
62 {}
63 
64 #else
65 
my_int24(void)66 static int __interrupt __far my_int24(void)
67 {
68    return 3;
69 }
70 
71 #endif
72 
73 
74 
75 /* _dos_irq_init:
76  *  Initialises this module.
77  */
_dos_irq_init(void)78 void _dos_irq_init(void)
79 {
80    int c;
81 
82    old_int24 = _dos_getvect(0x24);
83    _dos_setvect(0x24, my_int24);
84 
85    __tb = __dpmi_allocate_dos_memory(16384/16, &tb_sel) * 16;
86 
87    __djgpp_ds_alias = _default_ds();
88 
89    for (c=0; c<MAX_IRQS; c++) {
90       irq_handler[c].handler = NULL;
91       irq_handler[c].number = 0;
92    }
93 
94    for (c=0; c<IRQ_STACKS; c++) {
95       irq_stack[c] = _AL_MALLOC(STACK_SIZE);
96       if (irq_stack[c]) {
97 	 LOCK_DATA(irq_stack[c], STACK_SIZE);
98 	 irq_stack[c] += STACK_SIZE - 32;
99       }
100    }
101 
102    rmcb_stack = _AL_MALLOC(STACK_SIZE);
103    if (rmcb_stack) {
104       LOCK_DATA(rmcb_stack, STACK_SIZE);
105       rmcb_stack += STACK_SIZE - 32;
106    }
107 
108    LOCK_VARIABLE(out_eax);
109    LOCK_VARIABLE(out_ebx);
110    LOCK_VARIABLE(out_ecx);
111    LOCK_VARIABLE(out_edx);
112    LOCK_VARIABLE(out_esi);
113    LOCK_VARIABLE(out_edi);
114    LOCK_VARIABLE(irq_handler);
115    LOCK_VARIABLE(irq_stack);
116    LOCK_VARIABLE(rmcb_stack);
117    LOCK_VARIABLE(__tb);
118    LOCK_VARIABLE(__djgpp_ds_alias);
119 }
120 
121 
122 
123 /* _dos_irq_exit:
124  *  Shuts down this module.
125  */
_dos_irq_exit(void)126 void _dos_irq_exit(void)
127 {
128    int c;
129 
130    for (c=0; c<IRQ_STACKS; c++) {
131       if (irq_stack[c]) {
132 	 irq_stack[c] -= STACK_SIZE - 32;
133 	 _AL_FREE(irq_stack[c]);
134 	 irq_stack[c] = NULL;
135       }
136    }
137 
138    if (rmcb_stack) {
139       rmcb_stack -= STACK_SIZE - 32;
140       _AL_FREE(rmcb_stack);
141       rmcb_stack = NULL;
142    }
143 
144    __dpmi_free_dos_memory(tb_sel);
145 
146    tb_sel = 0;
147    __tb = 0;
148 
149    _dos_setvect(0x24, old_int24);
150 }
151 
152 
153 
154 /* wrapper for calling DPMI interrupts */
155 int DPMI(int ax, int bx, int cx, int dx, int si, int di);
156 
157 #pragma aux DPMI =                              \
158    "  int 0x31 "                                \
159    "  jnc dpmi_ok "                             \
160    "  mov eax, -1 "                             \
161    "  jmp dpmi_done "                           \
162    " dpmi_ok: "                                 \
163    "  mov eax, 0 "                              \
164    " dpmi_done: "                               \
165 						\
166    parm [eax] [ebx] [ecx] [edx] [esi] [edi]     \
167    value [eax];
168 
169 
170 
171 /* wrapper for calling DPMI interrupts with output values */
172 int DPMI_OUT(int ax, int bx, int cx, int dx, int si, int di);
173 
174 #pragma aux DPMI_OUT =                          \
175    "  int 0x31 "                                \
176    "  jnc dpmi_ok "                             \
177    "  mov eax, -1 "                             \
178    "  jmp dpmi_done "                           \
179    " dpmi_ok: "                                 \
180    "  mov out_eax, eax "                        \
181    "  mov out_ebx, ebx "                        \
182    "  mov out_ecx, ecx "                        \
183    "  mov out_edx, edx "                        \
184    "  mov out_esi, esi "                        \
185    "  mov out_edi, edi "                        \
186    "  mov eax, 0 "                              \
187    " dpmi_done: "                               \
188 						\
189    parm [eax] [ebx] [ecx] [edx] [esi] [edi]     \
190    value [eax];
191 
192 
193 
194 /* __dpmi_int:
195  *  Watcom implementation of the djgpp library routine.
196  */
__dpmi_int(int vector,__dpmi_regs * regs)197 int __dpmi_int(int vector, __dpmi_regs *regs)
198 {
199    regs->x.flags = 0;
200    regs->x.sp = 0;
201    regs->x.ss = 0;
202 
203    return DPMI(0x300, vector, 0, 0, 0, (int)regs);
204 }
205 
206 
207 
208 /* __dpmi_simulate_real_mode_interrupt:
209  *  Watcom implementation of the djgpp library routine.
210  */
__dpmi_simulate_real_mode_interrupt(int vector,__dpmi_regs * regs)211 int __dpmi_simulate_real_mode_interrupt(int vector, __dpmi_regs *regs)
212 {
213    return DPMI(0x300, vector, 0, 0, 0, (int)regs);
214 }
215 
216 
217 
218 /* __dpmi_simulate_real_mode_procedure_retf:
219  *  Watcom implementation of the djgpp library routine.
220  */
__dpmi_simulate_real_mode_procedure_retf(__dpmi_regs * regs)221 int __dpmi_simulate_real_mode_procedure_retf(__dpmi_regs *regs)
222 {
223    return DPMI(0x301, 0, 0, 0, 0, (int)regs);
224 }
225 
226 
227 
228 /* __dpmi_allocate_dos_memory:
229  *  Watcom implementation of the djgpp library routine.
230  */
__dpmi_allocate_dos_memory(int paragraphs,int * ret)231 int __dpmi_allocate_dos_memory(int paragraphs, int *ret)
232 {
233    if (DPMI_OUT(0x100, paragraphs, 0, 0, 0, 0) != 0)
234       return -1;
235 
236    *ret = (out_edx & 0xFFFF);
237 
238    return (out_eax & 0xFFFF);
239 }
240 
241 
242 
243 /* __dpmi_free_dos_memory:
244  *  Watcom implementation of the djgpp library routine.
245  */
__dpmi_free_dos_memory(int selector)246 int __dpmi_free_dos_memory(int selector)
247 {
248    return DPMI(0x101, 0, 0, selector, 0, 0);
249 }
250 
251 
252 
253 /* __dpmi_physical_address_mapping:
254  *  Watcom implementation of the djgpp library routine.
255  */
__dpmi_physical_address_mapping(__dpmi_meminfo * info)256 int __dpmi_physical_address_mapping(__dpmi_meminfo *info)
257 {
258    if (DPMI_OUT(0x800, (info->address >> 16), (info->address & 0xFFFF), 0,
259 		       (info->size >> 16), (info->size & 0xFFFF)) != 0)
260       return -1;
261 
262    info->address = (out_ebx << 16) | (out_ecx & 0xFFFF);
263 
264    return 0;
265 }
266 
267 
268 
269 /* __dpmi_free_physical_address_mapping:
270  *  Watcom implementation of the djgpp library routine.
271  */
__dpmi_free_physical_address_mapping(__dpmi_meminfo * info)272 int __dpmi_free_physical_address_mapping(__dpmi_meminfo *info)
273 {
274    return DPMI(0x801, (info->address >> 16), (info->address & 0xFFFF), 0, 0, 0);
275 }
276 
277 
278 
279 /* __dpmi_lock_linear_region:
280  *  Watcom implementation of the djgpp library routine.
281  */
__dpmi_lock_linear_region(__dpmi_meminfo * info)282 int __dpmi_lock_linear_region(__dpmi_meminfo *info)
283 {
284    return DPMI(0x600, (info->address >> 16), (info->address & 0xFFFF), 0,
285 		      (info->size >> 16), (info->size & 0xFFFF));
286 }
287 
288 
289 
290 /* __dpmi_unlock_linear_region:
291  *  Watcom implementation of the djgpp library routine.
292  */
__dpmi_unlock_linear_region(__dpmi_meminfo * info)293 int __dpmi_unlock_linear_region(__dpmi_meminfo *info)
294 {
295    return DPMI(0x601, (info->address >> 16), (info->address & 0xFFFF), 0,
296 		      (info->size >> 16), (info->size & 0xFFFF));
297 }
298 
299 
300 
301 /* _go32_dpmi_lock_data:
302  *  Watcom implementation of the djgpp library routine.
303  */
_go32_dpmi_lock_data(void * lockaddr,unsigned long locksize)304 int _go32_dpmi_lock_data(void *lockaddr, unsigned long locksize)
305 {
306    unsigned long baseaddr;
307    __dpmi_meminfo meminfo;
308 
309    if (__dpmi_get_segment_base_address(_default_ds(), &baseaddr) != 0)
310       return -1;
311 
312    meminfo.handle = 0;
313    meminfo.size = locksize;
314    meminfo.address = baseaddr + (unsigned long)lockaddr;
315 
316    return __dpmi_lock_linear_region(&meminfo);
317 }
318 
319 
320 
321 /* _go32_dpmi_lock_code:
322  *  Watcom implementation of the djgpp library routine.
323  */
_go32_dpmi_lock_code(void * lockaddr,unsigned long locksize)324 int _go32_dpmi_lock_code(void *lockaddr, unsigned long locksize)
325 {
326    unsigned long baseaddr;
327    __dpmi_meminfo meminfo;
328 
329    if (__dpmi_get_segment_base_address(_my_cs(), &baseaddr) != 0)
330       return -1;
331 
332    meminfo.handle = 0;
333    meminfo.size = locksize;
334    meminfo.address = baseaddr + (unsigned long)lockaddr;
335 
336    return __dpmi_lock_linear_region(&meminfo);
337 }
338 
339 
340 
341 /* __dpmi_allocate_ldt_descriptors:
342  *  Watcom implementation of the djgpp library routine.
343  */
__dpmi_allocate_ldt_descriptors(int count)344 int __dpmi_allocate_ldt_descriptors(int count)
345 {
346    if (DPMI_OUT(0x000, 0, count, 0, 0, 0) != 0)
347       return -1;
348 
349    return (out_eax & 0xFFFF);
350 }
351 
352 
353 
354 /* __dpmi_free_ldt_descriptor:
355  *  Watcom implementation of the djgpp library routine.
356  */
__dpmi_free_ldt_descriptor(int descriptor)357 int __dpmi_free_ldt_descriptor(int descriptor)
358 {
359    return DPMI(0x001, descriptor, 0, 0, 0, 0);
360 }
361 
362 
363 
364 /* __dpmi_get_segment_base_address:
365  *  Watcom implementation of the djgpp library routine.
366  */
__dpmi_get_segment_base_address(int selector,unsigned long * addr)367 int __dpmi_get_segment_base_address(int selector, unsigned long *addr)
368 {
369    if (DPMI_OUT(0x006, selector, 0, 0, 0, 0) != 0)
370       return -1;
371 
372    *addr = (out_ecx << 16) | (out_edx & 0xFFFF);
373    return 0;
374 }
375 
376 
377 
378 /* __dpmi_set_segment_base_address:
379  *  Watcom implementation of the djgpp library routine.
380  */
__dpmi_set_segment_base_address(int selector,unsigned long address)381 int __dpmi_set_segment_base_address(int selector, unsigned long address)
382 {
383    return DPMI(0x007, selector, (address >> 16), (address & 0xFFFF), 0, 0);
384 }
385 
386 
387 
388 /* __dpmi_set_segment_limit:
389  *  Watcom implementation of the djgpp library routine.
390  */
__dpmi_set_segment_limit(int selector,unsigned long limit)391 int __dpmi_set_segment_limit(int selector, unsigned long limit)
392 {
393    return DPMI(0x008, selector, (limit >> 16), (limit & 0xFFFF), 0, 0);
394 }
395 
396 
397 
398 /* __dpmi_get_free_memory_information:
399  *  Watcom implementation of the djgpp library routine.
400  */
__dpmi_get_free_memory_information(__dpmi_free_mem_info * info)401 int __dpmi_get_free_memory_information(__dpmi_free_mem_info *info)
402 {
403    return DPMI(0x500, 0, 0, 0, 0, (int)info);
404 }
405 
406 
407 
408 /* switches to a custom stack when running interrupt code */
409 int CALL_HANDLER(int (*func)(void), int max_stack);
410 
411 #pragma aux CALL_HANDLER =                                                 \
412    "  push ds "                                                            \
413    "  pop es "                                                             \
414 									   \
415    " stack_search_loop: "              /* look for a free stack */         \
416    "  lea ebx, irq_stack[ecx*4] "                                          \
417    "  cmp [ebx], 0 "                                                       \
418    "  jnz found_stack "                /* found one! */                    \
419 									   \
420    "  dec ecx "                                                            \
421    "  jge stack_search_loop "                                              \
422 									   \
423    "  mov eax, 0 "                     /* oh shit.. */                     \
424    "  jmp get_out "                                                        \
425 									   \
426    " found_stack: "                                                        \
427    "  mov ecx, esp "                   /* old stack in ecx + dx */         \
428    "  mov dx, ss "                                                         \
429 									   \
430    "  mov ax, ds "                     /* set up our stack */              \
431    "  mov ss, ax "                                                         \
432    "  mov esp, [ebx] "                                                     \
433 									   \
434    "  mov dword ptr [ebx], 0 "         /* flag the stack is in use */      \
435 									   \
436    "  push edx "                       /* push old stack onto new */       \
437    "  push ecx "                                                           \
438    "  push ebx "                                                           \
439 									   \
440    "  cld "                            /* call the handler */              \
441    "  cli "                                                                \
442    "  call esi "                                                           \
443 									   \
444    "  pop ebx "                        /* restore the old stack */         \
445    "  pop ecx "                                                            \
446    "  pop edx "                                                            \
447    "  mov [ebx], esp "                                                     \
448    "  mov ss, dx "                                                         \
449    "  mov esp, ecx "                                                       \
450    "  get_out:     "                                                       \
451 									   \
452    parm [esi] [ecx]                                                        \
453    modify [ebx edx edi]                                                    \
454    value [eax];
455 
456 
457 
458 /* interrupt wrapper */
459 #define WRAPPER(num)                                                       \
460 									   \
461    static void __interrupt __far irq_wrapper_##num()                       \
462    {                                                                       \
463       if (CALL_HANDLER(irq_handler[num].handler, IRQ_STACKS-1))            \
464 	 _chain_intr(irq_handler[num].old_vector);                         \
465    }
466 
467 
468 WRAPPER(0);
469 WRAPPER(1);
470 WRAPPER(2);
471 WRAPPER(3);
472 WRAPPER(4);
473 WRAPPER(5);
474 WRAPPER(6);
475 WRAPPER(7);
476 
477 END_OF_STATIC_FUNCTION(irq_wrapper_0);
478 
479 
480 
481 /* _install_irq:
482  *  Installs a custom IRQ handler.
483  */
_install_irq(int num,int (* handler)(void))484 int _install_irq(int num, int (*handler)(void))
485 {
486    int c;
487 
488    LOCK_FUNCTION(irq_wrapper_0);
489 
490    for (c=0; c<MAX_IRQS; c++) {
491       if (!irq_handler[c].handler) {
492 	 irq_handler[c].handler = handler;
493 	 irq_handler[c].number = num;
494 	 irq_handler[c].old_vector = _dos_getvect(num);
495 
496 	 switch (c) {
497 	    case 0: _dos_setvect(num, irq_wrapper_0); break;
498 	    case 1: _dos_setvect(num, irq_wrapper_1); break;
499 	    case 2: _dos_setvect(num, irq_wrapper_2); break;
500 	    case 3: _dos_setvect(num, irq_wrapper_3); break;
501 	    case 4: _dos_setvect(num, irq_wrapper_4); break;
502 	    case 5: _dos_setvect(num, irq_wrapper_5); break;
503 	    case 6: _dos_setvect(num, irq_wrapper_6); break;
504 	    case 7: _dos_setvect(num, irq_wrapper_7); break;
505 	 }
506 
507 	 return 0;
508       }
509    }
510 
511    return -1;
512 }
513 
514 
515 
516 /* _remove_irq:
517  *  Returns to the default IRQ handler.
518  */
_remove_irq(int num)519 void _remove_irq(int num)
520 {
521    int c;
522 
523    for (c=0; c<MAX_IRQS; c++) {
524       if (irq_handler[c].number == num) {
525 	 _dos_setvect(num, irq_handler[c].old_vector);
526 	 irq_handler[c].number = 0;
527 	 irq_handler[c].handler = NULL;
528 	 break;
529       }
530    }
531 }
532 
533 
534 
535 /* real mode callback for the mouse driver */
536 static void (*rmcb_handler)(__dpmi_regs *) = NULL;
537 
538 static __dpmi_regs *rmcb_regs = NULL;
539 
540 static short rmcb_saved_ss = 0;
541 static int rmcb_saved_esp = 0;
542 
543 
544 
545 /* has to be done in two parts because Watcom can't handle the pragma size */
546 void CALL_RMCB_PART1(void);
547 void CALL_RMCB_PART2(void);
548 
549 
550 
551 #pragma aux CALL_RMCB_PART1 =                                              \
552    "  push eax "                       /* save registers */                \
553    "  push ecx "                                                           \
554    "  push edx "                                                           \
555    "  push ds "                                                            \
556    "  push es "                                                            \
557 									   \
558    "  mov eax, cs:__djgpp_ds_alias "   /* set up our data selector */      \
559    "  mov ds, ax "                                                         \
560    "  mov es, ax "                                                         \
561 									   \
562    "  mov ax, ss "                     /* switch to our own stack */       \
563    "  mov rmcb_saved_ss, ax "                                              \
564    "  mov rmcb_saved_esp, esp "                                            \
565    "  mov ax, ds "                                                         \
566    "  mov ss, ax "                                                         \
567    "  mov esp, rmcb_stack "
568 
569 
570 
571 #pragma aux CALL_RMCB_PART2 =                                              \
572    "  mov eax, rmcb_regs "             /* fill register structure */       \
573    "  mov 0[eax], edi"                                                     \
574    "  mov 4[eax], esi"                                                     \
575    "  mov 16[eax], ebx"                                                    \
576    "  mov 20[eax], edx"                                                    \
577    "  mov 24[eax], ecx "                                                   \
578 									   \
579    "  cld "                            /* call the handler */              \
580    "  mov esi, rmcb_handler "                                              \
581    "  push eax "                                                           \
582    "  call esi "                                                           \
583 									   \
584    "  mov esp, rmcb_saved_esp "        /* restore the original stack */    \
585    "  mov ax, rmcb_saved_ss "                                              \
586    "  mov ss, ax "                                                         \
587 									   \
588    "  pop es "                         /* restore registers */             \
589    "  pop ds "                                                             \
590    "  pop edx "                                                            \
591    "  pop ecx "                                                            \
592    "  pop eax "
593 
594 
595 
rmcb_callback(void)596 static void far rmcb_callback(void)
597 {
598    CALL_RMCB_PART1();
599    CALL_RMCB_PART2();
600 }
601 
602 END_OF_STATIC_FUNCTION(rmcb_callback);
603 
604 
605 
606 /* _allocate_real_mode_callback:
607  *  Sets up a realmode callback for the mouse driver.
608  */
_allocate_real_mode_callback(void (* handler)(__dpmi_regs *),__dpmi_regs * regs)609 long _allocate_real_mode_callback(void (*handler)(__dpmi_regs *), __dpmi_regs *regs)
610 {
611    LOCK_VARIABLE(rmcb_handler);
612    LOCK_VARIABLE(rmcb_regs);
613    LOCK_VARIABLE(rmcb_saved_ss);
614    LOCK_VARIABLE(rmcb_saved_esp);
615    LOCK_FUNCTION(rmcb_callback);
616 
617    rmcb_handler = handler;
618    rmcb_regs = regs;
619 
620    return (long)rmcb_callback;
621 }
622 
623