/*         ______   ___    ___ 
 *        /\  _  \ /\_ \  /\_ \ 
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      The djgpp interrupt wrappers used by the stuff in djirq.c.
 *
 *      By Shawn Hargreaves.
 *
 *      Thanks to Marcel de Kogel for identifying the problems Allegro was 
 *      having with reentrant interrupts, and for suggesting this solution.
 *
 *      See readme.txt for copyright information.
 */


#include "../i386/asmdefs.inc"

.text



#define WRAPPER(x)                                                         ; \
FUNC(_irq_wrapper_##x)                                                     ; \
   pushw %ds                              /* save registers */             ; \
   pushw %es                                                               ; \
   pushw %fs                                                               ; \
   pushw %gs                                                               ; \
   pushal                                                                  ; \
									   ; \
   .byte 0x2e                             /* cs: override */               ; \
   movw GLOBL(__djgpp_ds_alias), %ax                                       ; \
   movw %ax, %ds                          /* set up selectors */           ; \
   movw %ax, %es                                                           ; \
   movw %ax, %fs                                                           ; \
   movw %ax, %gs                                                           ; \
									   ; \
   movl $IRQ_STACKS-1, %ecx               /* look for a free stack */      ; \
									   ; \
stack_search_loop_##x:                                                     ; \
   leal GLOBL(_irq_stack)(, %ecx, 4), %ebx                                 ; \
   cmpl $0, (%ebx)                                                         ; \
   jnz found_stack_##x                    /* found one! */                 ; \
									   ; \
   decl %ecx                                                               ; \
   jge stack_search_loop_##x                                               ; \
									   ; \
   jmp get_out_##x                        /* oh shit.. */                  ; \
									   ; \
found_stack_##x:                                                           ; \
   movl %esp, %ecx                        /* old stack in ecx + dx */      ; \
   movw %ss, %dx                                                           ; \
									   ; \
   movl (%ebx), %esp                      /* set up our stack */           ; \
   movw %ax, %ss                                                           ; \
									   ; \
   movl $0, (%ebx)                        /* flag the stack is in use */   ; \
									   ; \
   pushl %edx                             /* push old stack onto new */    ; \
   pushl %ecx                                                              ; \
   pushl %ebx                                                              ; \
									   ; \
   cld                                    /* clear the direction flag */   ; \
									   ; \
   movl GLOBL(_irq_handler) + IRQ_HANDLER + IRQ_SIZE*x, %eax               ; \
   call *%eax                             /* call the C handler */         ; \
									   ; \
   cli                                                                     ; \
									   ; \
   popl %ebx                              /* restore the old stack */      ; \
   popl %ecx                                                               ; \
   popl %edx                                                               ; \
   movl %esp, (%ebx)                                                       ; \
   movw %dx, %ss                                                           ; \
   movl %ecx, %esp                                                         ; \
									   ; \
   orl %eax, %eax                         /* check return value */         ; \
   jz get_out_##x                                                          ; \
									   ; \
   popal                                  /* chain to old handler */       ; \
   popw %gs                                                                ; \
   popw %fs                                                                ; \
   popw %es                                                                ; \
   popw %ds                                                                ; \
   ljmp %cs:GLOBL(_irq_handler) + IRQ_OLDVEC + IRQ_SIZE*x                  ; \
									   ; \
get_out_##x:                                                               ; \
   popal                                  /* iret */                       ; \
   popw %gs                                                                ; \
   popw %fs                                                                ; \
   popw %es                                                                ; \
   popw %ds                                                                ; \
   sti                                                                     ; \
   iret



WRAPPER(0);
WRAPPER(1);
WRAPPER(2);
WRAPPER(3);
WRAPPER(4);
WRAPPER(5);
WRAPPER(6);
WRAPPER(7);


FUNC(_irq_wrapper_0_end)
   ret

