IRQ.C 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. Copyright (C) 1994-1995 Apogee Software, Ltd.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. /**********************************************************************
  16. module: IRQ.C
  17. author: James R. Dose
  18. date: August 26, 1994
  19. Low level routines to set and restore IRQ's through DPMI.
  20. (c) Copyright 1994 James R. Dose. All Rights Reserved.
  21. **********************************************************************/
  22. #include <dos.h>
  23. #include <stdlib.h>
  24. #include "irq.h"
  25. #define D32RealSeg(P) ( ( ( ( unsigned long )( P ) ) >> 4 ) & 0xFFFF )
  26. #define D32RealOff(P) ( ( ( unsigned long )( P ) ) & 0xF )
  27. typedef struct
  28. {
  29. unsigned long drdi;
  30. unsigned long drsi;
  31. unsigned long drbp;
  32. unsigned long drxx;
  33. unsigned long drbx;
  34. unsigned long drdx;
  35. unsigned long drcx;
  36. unsigned long drax;
  37. unsigned short drflags;
  38. unsigned short dres;
  39. unsigned short drds;
  40. unsigned short drfs;
  41. unsigned short drgs;
  42. unsigned short drip;
  43. unsigned short drcs;
  44. unsigned short drsp;
  45. unsigned short drss;
  46. } DPMI_REGS;
  47. static DPMI_REGS rmregs = { 0 };
  48. static void ( __interrupt __far *IRQ_Callback )( void ) = NULL;
  49. static char *IRQ_RealModeCode = NULL;
  50. static unsigned short IRQ_CallBackSegment;
  51. static unsigned short IRQ_CallBackOffset;
  52. static unsigned short IRQ_RealModeSegment;
  53. static unsigned short IRQ_RealModeOffset;
  54. static unsigned long IRQ_ProtectedModeOffset;
  55. static unsigned short IRQ_ProtectedModeSelector;
  56. static union REGS Regs;
  57. static struct SREGS SegRegs;
  58. static void *D32DosMemAlloc
  59. (
  60. unsigned long size
  61. )
  62. {
  63. // DPMI allocate DOS memory
  64. Regs.x.eax = 0x0100;
  65. // Number of paragraphs requested
  66. Regs.x.ebx = ( size + 15 ) >> 4;
  67. int386( 0x31, &Regs, &Regs );
  68. if ( Regs.x.cflag != 0 )
  69. {
  70. // Failed
  71. return ( ( unsigned long )0 );
  72. }
  73. return( ( void * )( ( Regs.x.eax & 0xFFFF ) << 4 ) );
  74. }
  75. // Intermediary function: DPMI calls this, making it
  76. // easier to write in C
  77. // handle 16-bit incoming stack
  78. void fixebp
  79. (
  80. void
  81. );
  82. #pragma aux fixebp = \
  83. "mov bx, ss" \
  84. "lar ebx, ebx" \
  85. "bt ebx, 22" \
  86. "jc bigstk" \
  87. "movzx esp, sp" \
  88. "mov ebp, esp" \
  89. "bigstk:" \
  90. modify exact [ ebx ];
  91. #pragma aux rmcallback parm [];
  92. void rmcallback
  93. (
  94. unsigned short _far *stkp
  95. )
  96. {
  97. // "Pop" the real mode return frame so we
  98. // can resume where we left off
  99. rmregs.drip = *stkp++;
  100. rmregs.drcs = *stkp++;
  101. rmregs.drsp = FP_OFF(stkp);
  102. // Call protected-mode handler
  103. IRQ_Callback();
  104. }
  105. static void _interrupt _cdecl callback_x
  106. (
  107. // regs pushed in this order by prologue
  108. int rgs,
  109. int rfs,
  110. int res,
  111. int rds,
  112. int rdi,
  113. int rsi,
  114. int rbp,
  115. int rsp,
  116. int rbx,
  117. int rdx,
  118. int rcx,
  119. int rax
  120. )
  121. {
  122. // unsigned short _far *stkp;
  123. // return;
  124. fixebp();
  125. rmcallback (MK_FP(rds, rsi));
  126. }
  127. /*
  128. static void _interrupt _cdecl callback_x
  129. (
  130. // regs pushed in this order by prologue
  131. int rgs,
  132. int rfs,
  133. int res,
  134. int rds,
  135. int rdi,
  136. int rsi,
  137. int rbp,
  138. int rsp,
  139. int rbx,
  140. int rdx,
  141. int rcx,
  142. int rax
  143. )
  144. {
  145. unsigned short _far *stkp;
  146. fixebp();
  147. stkp = MK_FP(rds, rsi);
  148. // "Pop" the real mode return frame so we
  149. // can resume where we left off
  150. rmregs.drip = *stkp++;
  151. rmregs.drcs = *stkp++;
  152. rmregs.drsp = FP_OFF(stkp);
  153. // Call protected-mode handler
  154. IRQ_Callback();
  155. }
  156. */
  157. int IRQ_SetVector
  158. (
  159. int vector,
  160. void ( __interrupt __far *function )( void )
  161. )
  162. {
  163. void far *fp;
  164. IRQ_Callback = function;
  165. // Save the starting real-mode and protected-mode handler addresses
  166. // DPMI get protected mode vector */
  167. Regs.w.ax = 0x0204;
  168. Regs.w.bx = vector;
  169. int386( 0x31, &Regs, &Regs );
  170. IRQ_ProtectedModeSelector = Regs.w.cx;
  171. IRQ_ProtectedModeOffset = Regs.x.edx;
  172. // DPMI get real mode vector
  173. Regs.w.ax = 0x0200;
  174. Regs.w.bx = vector;
  175. int386( 0x31, &Regs, &Regs );
  176. IRQ_RealModeSegment = Regs.w.cx;
  177. IRQ_RealModeOffset = Regs.w.dx;
  178. // Set up callback
  179. // DPMI allocate real mode callback
  180. Regs.w.ax = 0x0303;
  181. fp = ( void far * )callback_x;
  182. SegRegs.ds = FP_SEG( fp );
  183. Regs.x.esi = FP_OFF( fp );
  184. fp = ( void _far * )&rmregs;
  185. SegRegs.es = FP_SEG( fp );
  186. Regs.x.edi = FP_OFF( fp );
  187. int386x( 0x31, &Regs, &Regs, &SegRegs );
  188. IRQ_CallBackSegment = Regs.w.cx;
  189. IRQ_CallBackOffset = Regs.w.dx;
  190. if ( Regs.x.cflag != 0 )
  191. {
  192. return( IRQ_Error );
  193. }
  194. if ( IRQ_RealModeCode == NULL )
  195. {
  196. // Allocate 6 bytes of low memory for real mode interrupt handler
  197. IRQ_RealModeCode = D32DosMemAlloc( 6 );
  198. if ( IRQ_RealModeCode == NULL )
  199. {
  200. // Free callback
  201. Regs.w.ax = 0x304;
  202. Regs.w.cx = IRQ_CallBackSegment;
  203. Regs.w.dx = IRQ_CallBackOffset;
  204. int386x( 0x31, &Regs, &Regs, &SegRegs );
  205. return( IRQ_Error );
  206. }
  207. }
  208. // Poke code (to call callback) into real mode handler
  209. // CALL FAR PTR (callback)
  210. IRQ_RealModeCode[ 0 ] = '\x9A';
  211. *( ( unsigned short * )&IRQ_RealModeCode[ 1 ] ) = IRQ_CallBackOffset;
  212. *( ( unsigned short * )&IRQ_RealModeCode[ 3 ] ) = IRQ_CallBackSegment;
  213. // IRET
  214. IRQ_RealModeCode[ 5 ] = '\xCF';
  215. // Install protected mode handler
  216. // DPMI set protected mode vector
  217. Regs.w.ax = 0x0205;
  218. Regs.w.bx = vector;
  219. fp = function;
  220. Regs.w.cx = FP_SEG( fp );
  221. Regs.x.edx = FP_OFF( fp );
  222. int386( 0x31, &Regs, &Regs );
  223. // Install callback address as real mode handler
  224. // DPMI set real mode vector
  225. Regs.w.ax = 0x0201;
  226. Regs.w.bx = vector;
  227. Regs.w.cx = D32RealSeg( IRQ_RealModeCode );
  228. Regs.w.dx = D32RealOff( IRQ_RealModeCode );
  229. int386( 0x31, &Regs, &Regs );
  230. return( IRQ_Ok );
  231. }
  232. int IRQ_RestoreVector
  233. (
  234. int vector
  235. )
  236. {
  237. // Restore original interrupt handlers
  238. // DPMI set real mode vector
  239. Regs.w.ax = 0x0201;
  240. Regs.w.bx = vector;
  241. Regs.w.cx = IRQ_RealModeSegment;
  242. Regs.w.dx = IRQ_RealModeOffset;
  243. int386( 0x31, &Regs, &Regs );
  244. Regs.w.ax = 0x0205;
  245. Regs.w.bx = vector;
  246. Regs.w.cx = IRQ_ProtectedModeSelector;
  247. Regs.x.edx = IRQ_ProtectedModeOffset;
  248. int386( 0x31, &Regs, &Regs );
  249. // Free callback
  250. Regs.w.ax = 0x304;
  251. Regs.w.cx = IRQ_CallBackSegment;
  252. Regs.w.dx = IRQ_CallBackOffset;
  253. int386x( 0x31, &Regs, &Regs, &SegRegs );
  254. if ( Regs.x.cflag )
  255. {
  256. return( IRQ_Error );
  257. }
  258. return( IRQ_Ok );
  259. }