dosirq.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:8k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*
  2.     Implementation of IRQ routines on DOS
  3.     Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "dosirq.h"
  17. #include <dpmi.h>
  18. #include <go32.h>
  19. #include <dos.h>
  20. #include <sys/nearptr.h>
  21. #include <malloc.h>
  22. unsigned int __irq_stack_size = 0x4000;
  23. unsigned int __irq_stack_count = 1;
  24. static void __int_stub_template()
  25. {
  26. /* *INDENT-OFF* */
  27. asm(" pushaln"
  28. " pushl %dsn"
  29. " pushl %esn"
  30. " pushl %fsn"
  31. " pushl %gsn"
  32. " movw $0x1234,%axn" /* Get DPMI data selector */
  33. " movw %ax,%dsn" /* Set DS and ES to data selector */
  34. " movw %ax,%esn"
  35. " movl $0x12345678,%ebxn" /* Interrupt stack top */
  36. " movl (%ebx),%ecxn"
  37. " movl %ecx,%edxn"
  38. " subl $0x12345678,%ecxn" /* Subtract irq_stack_count */
  39. " movl %ecx,(%ebx)n"
  40. " movw %ss,%sin" /* Save old SS:ESP */
  41. " movl %esp,%edin"
  42. " movl %edx,%espn" /* Set SS:ESP to interrupt stack */
  43. " movw %ax,%ssn"
  44. " pushl %esin"
  45. " pushl %edin"
  46. " pushl %ebxn"
  47. " pushl %edxn"
  48. " call 1fn" /* Call user interrupt handler */
  49. "1: popl %edxn"
  50. " popl %ebxn"
  51. " movl %edx,(%ebx)n"
  52. " popl %edin"
  53. " popl %esin"
  54. " movl %edi,%espn" /* Restore old SS:ESP */
  55. " movw %si,%ssn"
  56. " popl %gsn"
  57. " popl %fsn"
  58. " popl %esn"
  59. " popl %dsn"
  60. " popaln"
  61. " iretn");
  62. /* *INDENT-ON* */
  63. }
  64. #include <stdio.h>
  65. static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
  66. {
  67. unsigned char *irqtpl = (unsigned char *)__int_stub_template;
  68. unsigned char *irqend, *irqwrapper, *tmp;
  69. __dpmi_meminfo handler_info;
  70. unsigned int wrappersize;
  71. /* First, skip until pushal */
  72. while (*irqtpl != 0x60)
  73. irqtpl++;
  74. /* Now find the iret */
  75. irqend = irqtpl;
  76. while (*irqend++ != 0xcf);
  77. wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
  78.   ((long)irqend - (long)irqtpl);
  79. irqwrapper = malloc(wrappersize);
  80. /* Lock the wrapper */
  81. handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
  82. handler_info.size = wrappersize;
  83. if (__dpmi_lock_linear_region(&handler_info)) {
  84. free(irqwrapper);
  85. return -1;
  86. }
  87. /* First comes the interrupt wrapper size */
  88. *(unsigned long *)irqwrapper = wrappersize;
  89. /* Next comes the interrupt stack */
  90. tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
  91. /* The following dword is interrupt stack pointer */
  92. *((void **)tmp) = tmp;
  93. tmp += 4;
  94. /* Now comes the interrupt wrapper itself */
  95. memcpy(tmp, irqtpl, irqend - irqtpl);
  96. *(unsigned short *)(tmp + 9) = _my_ds();
  97. *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
  98. *(unsigned long *)(tmp + 26) = __irq_stack_size;
  99. *(unsigned long *)(tmp + 46) =
  100.   info->pm_offset - (unsigned long)(tmp + 50);
  101. info->pm_offset = (unsigned long)tmp;
  102. info->pm_selector = _my_cs();
  103. return 0;
  104. }
  105. static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
  106. {
  107. __dpmi_meminfo handler_info;
  108. info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
  109. handler_info.address = __djgpp_base_address + info->pm_offset;
  110. handler_info.size = *(unsigned long *)info->pm_offset;
  111. __dpmi_unlock_linear_region(&handler_info);
  112. free((void *)info->pm_offset);
  113. }
  114. irq_handle *irq_hook(int irqno, void (*handler) (), unsigned long size)
  115. {
  116. int interrupt;
  117. irq_handle *irq;
  118. __dpmi_version_ret version;
  119. __dpmi_meminfo handler_info, struct_info;
  120. _go32_dpmi_seginfo info;
  121. unsigned long old_sel, old_ofs;
  122. __dpmi_get_version(&version);
  123. if (irqno < 8)
  124. interrupt = version.master_pic + irqno;
  125. else
  126. interrupt = version.slave_pic + (irqno - 8);
  127. if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
  128. return NULL;
  129. old_sel = info.pm_selector;
  130. old_ofs = info.pm_offset;
  131. info.pm_offset = (unsigned long)handler;
  132. if (_allocate_iret_wrapper(&info))
  133. return NULL;
  134. /* Lock the interrupt handler in memory */
  135. handler_info.address = __djgpp_base_address + (unsigned long)handler;
  136. handler_info.size = size;
  137. if (__dpmi_lock_linear_region(&handler_info)) {
  138. _free_iret_wrapper(&info);
  139. return NULL;
  140. }
  141. irq = malloc(sizeof(irq_handle));
  142. irq->c_handler = handler;
  143. irq->handler_size = size;
  144. irq->handler = info.pm_offset;
  145. irq->prev_selector = old_sel;
  146. irq->prev_offset = old_ofs;
  147. irq->int_num = interrupt;
  148. irq->irq_num = irqno;
  149. irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
  150. struct_info.address = __djgpp_base_address + (unsigned long)irq;
  151. struct_info.size = sizeof(irq_handle);
  152. if (__dpmi_lock_linear_region(&struct_info)) {
  153. free(irq);
  154. __dpmi_unlock_linear_region(&handler_info);
  155. _free_iret_wrapper(&info);
  156. return NULL;
  157. }
  158. _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
  159. irq->pic_mask = irq_state(irq);
  160. return irq;
  161. }
  162. void irq_unhook(irq_handle * irq)
  163. {
  164. _go32_dpmi_seginfo info;
  165. __dpmi_meminfo mem_info;
  166. if (!irq)
  167. return;
  168. /* Restore the interrupt vector */
  169. irq_disable(irq);
  170. info.pm_offset = irq->prev_offset;
  171. info.pm_selector = irq->prev_selector;
  172. _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
  173. /* Unlock the interrupt handler */
  174. mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
  175. mem_info.size = irq->handler_size;
  176. __dpmi_unlock_linear_region(&mem_info);
  177. /* Unlock the irq_handle structure */
  178. mem_info.address = __djgpp_base_address + (unsigned long)irq;
  179. mem_info.size = sizeof(irq_handle);
  180. __dpmi_unlock_linear_region(&mem_info);
  181. info.pm_offset = irq->handler;
  182. _free_iret_wrapper(&info);
  183. /* If IRQ was enabled before we hooked, restore enabled state */
  184. if (irq->pic_mask)
  185. irq_enable(irq);
  186. else
  187. irq_disable(irq);
  188. free(irq);
  189. }
  190. /*---------------------------------------------- IRQ detection mechanism -----*/
  191. static irq_handle *__irqs[16];
  192. static int (*__irq_confirm) (int irqno);
  193. static volatile unsigned int __irq_mask;
  194. static volatile unsigned int __irq_count[16];
  195. #define DECLARE_IRQ_HANDLER(irqno)
  196. static void __irq##irqno##_handler ()
  197. {
  198.   if (irq_check (__irqs [irqno]) && __irq_confirm (irqno))
  199.   {
  200.     __irq_count [irqno]++;
  201.     __irq_mask |= (1 << irqno);
  202.   }
  203.   irq_ack (__irqs [irqno]);
  204. }
  205. /* *INDENT-OFF* */
  206. DECLARE_IRQ_HANDLER(0)
  207. DECLARE_IRQ_HANDLER(1)
  208. DECLARE_IRQ_HANDLER(2)
  209. DECLARE_IRQ_HANDLER(3)
  210. DECLARE_IRQ_HANDLER(4)
  211. DECLARE_IRQ_HANDLER(5)
  212. DECLARE_IRQ_HANDLER(6)
  213. DECLARE_IRQ_HANDLER(7)
  214. DECLARE_IRQ_HANDLER(8)
  215. DECLARE_IRQ_HANDLER(9)
  216. DECLARE_IRQ_HANDLER(10)
  217. DECLARE_IRQ_HANDLER(11)
  218. DECLARE_IRQ_HANDLER(12)
  219. DECLARE_IRQ_HANDLER(13)
  220. DECLARE_IRQ_HANDLER(14)
  221. DECLARE_IRQ_HANDLER(15)
  222. /* *INDENT-ON* */
  223. static void (*__irq_handlers[16]) () = {
  224. __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
  225.   __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
  226.   __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
  227.   __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
  228. void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
  229. {
  230. int i;
  231. __irq_mask = 0;
  232. __irq_confirm = irq_confirm;
  233. memset(&__irqs, 0, sizeof(__irqs));
  234. memset(&__irq_count, 0, sizeof(__irq_count));
  235. /* Hook all specified IRQs */
  236. for (i = 1; i <= 15; i++)
  237. if (irqs & (1 << i)) {
  238. __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
  239. /* Enable the interrupt */
  240. irq_enable(__irqs[i]);
  241. }
  242. /* Enable IRQ2 if we need at least one IRQ above 7 */
  243. if (irqs & 0xff00)
  244. _irq_enable(2);
  245. }
  246. void irq_detect_end()
  247. {
  248. int i;
  249. for (i = 15; i >= 1; i--)
  250. if (__irqs[i])
  251. irq_unhook(__irqs[i]);
  252. }
  253. int irq_detect_get(int irqno, int *irqmask)
  254. {
  255. int oldirq = disable();
  256. int count = __irq_count[irqno];
  257. *irqmask = __irq_mask;
  258. __irq_mask = 0;
  259. if (oldirq)
  260. enable();
  261. return count;
  262. }
  263. void irq_detect_clear()
  264. {
  265. int oldirq = disable();
  266. memset(&__irq_count, 0, sizeof(__irq_count));
  267. __irq_mask = 0;
  268. if (oldirq)
  269. enable();
  270. }
  271. /* ex:set ts=4: */