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