home *** CD-ROM | disk | FTP | other *** search
- /*M
- intcomm - implement common code for interrupt handlers that call
- C routines
- */
- #include "interrup.h"
-
- int_handler template =
- {
- #ifndef MPU80186
- { 0x53, /* push bx */
- 0x06, /* push es */ },
- #else
- { 0x60 /* pusha */ },
- #endif
- { 0xBB, 0x0000 /* mov bx, seg svc */ },
- { 0x8E, 0xC3 /* mov es,bx */ },
- { 0xBB,0x0000 /* mov bx,offset svc */ },
- { 0x9A,0x0000,0x0000/* call common far */ },
- #ifndef MPU80186
- { 0x07, /* pop es */
- 0x5B, /* pop bx */ },
- #else
- { 0x61 /* popa */ },
- #endif
- 0xCF, /* iret */
- 0x0000, /* old_offset */
- 0x0000, /* old_segment */
- 0x0000, /* new_offset */
- 0x0000 /* new_segment */
- };
-
- int_handler *
- setup_handler(int_num,handler,chain_int)
- int int_num; /* number of the interrupt to steal */
- void (*handler)(); /* C function to attach to interrupt */
- int chain_int; /* 1 if you're supposed to call old service
- when you're done
- 0 if you're supposed to replace it */
- {
- union
- {
- struct
- {
- unsigned offset,segment;
- } parts;
- long vector;
- } int_vector;
- extern long get_int();
- extern void set_int();
- extern int _dsval, _csval;
- register int_handler *new_handler;
- void *malloc();
- void common(); /* common interrupt handler code */
-
- /* allocate a new handler */
- if (NULL == (new_handler = malloc(sizeof(int_handler))))
- return NULL;
-
- /* copy template via structure assignment */
- *new_handler = template;
-
- /* initialize the mov bx,seg service instruction */
- new_handler->esfix.immed_data =
- #ifdef LONGPTR
- segment(new_handler);
- #else
- _dsval;
- #endif
-
- /* initialize the mov bx, offset service instruction */
- new_handler->svctobx.immed_data = offset(&(new_handler->new_offset));
-
- /* initialize the call far common instruction */
- new_handler->func_call.offset = offset(common);
- new_handler->func_call.segment =
- #ifdef FARPROC
- segment(common);
- #else
- _csval;
- #endif
-
- /* initialize the vector field of new_handler structure */
- new_handler->new_offset = offset(handler);
- new_handler->new_segment =
- #ifdef FARPROC
- segment(handler);
- #else
- _csval;
- #endif
- int_vector.vector = get_int(int_num);
-
- /* save old segment */
- new_handler->old_offset = int_vector.parts.offset;
- new_handler->old_segment = int_vector.parts.segment;
-
- /* if we're supposed to chain to old interrupt call, change iret to
- call far. Since I store old vector right after iret, what could be
- simpler ?
- */
- if (chain_int)
- new_handler->iret = 0xEA; /* jmp inter-segment direct */
-
- /* set up new vector */
- set_int(int_num,offset(new_handler),segment(new_handler));
- return new_handler;
- }
-
- restore_handler(int_num,handler)
- int int_num;
- int_handler *handler;
- {
- extern void set_int();
- set_int(int_num,handler->old_offset,handler->old_segment);
- free(handler);
- }
-
- /*
- * offset and segment used to isolate pointer components
- */
- static offset(ptr)
- #ifdef LONGPTR
- unsigned long ptr;
- {
- return (int)(0x0000FFFF & ptr);
- }
- #else
- unsigned ptr;
- {
- return ptr;
- }
- #endif
-
- static segment(ptr)
- #ifdef LONGPTR
- unsigned long ptr;
- {
- return (int) (0x0000FFFF & (ptr >> 16));
- }
- #else
- {
- extern int _dsval;
- return _dsval;
- }
- #endif
-