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

Windows CE

开发平台:

C/C++

  1. /*
  2.     Implementation of DMA 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 "dosdma.h"
  17. #include <dos.h>
  18. #include <dpmi.h>
  19. #include <sys/nearptr.h>
  20. #include <malloc.h>
  21. __dma_regs dma[8] = {
  22. /* *INDENT-OFF* */
  23. {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
  24.  DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
  25. {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
  26.  DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
  27. {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
  28.  DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
  29. {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
  30.  DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
  31. {DMA_ADDR_4,          0, DMA_SIZE_4,
  32.  DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
  33. {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
  34.  DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
  35. {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
  36.  DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
  37. {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
  38.  DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
  39. /* *INDENT-ON* */
  40. };
  41. static int __initialized = 0;
  42. static int __buffer_count = 0;
  43. static __dpmi_meminfo __locked_data;
  44. int dma_initialize()
  45. {
  46. if (!__djgpp_nearptr_enable())
  47. return 0;
  48. /* Trick: Avoid re-setting DS selector limit on each memory allocation
  49.    call */
  50. __djgpp_selector_limit = 0xffffffff;
  51. __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
  52. __locked_data.size = sizeof(dma);
  53. if (__dpmi_lock_linear_region(&__locked_data))
  54. return 0;
  55. return (__initialized = 1);
  56. }
  57. void dma_finalize()
  58. {
  59. if (!__initialized)
  60. return;
  61. __dpmi_unlock_linear_region(&__locked_data);
  62. __djgpp_nearptr_disable();
  63. }
  64. dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
  65. {
  66. int parsize = (size + 15) >> 4; /* size in paragraphs */
  67. int par = 0; /* Real-mode paragraph */
  68. int selector = 0; /* Protected-mode selector */
  69. int mask = channel <= 3 ? 0xfff : 0x1fff; /* Alignment mask in para. */
  70. int allocsize = parsize; /* Allocated size in paragraphs */
  71. int count; /* Try count */
  72. int bound = 0; /* Nearest bound address */
  73. int maxsize; /* Maximal possible block size */
  74. dma_buffer *buffer = NULL;
  75. __dpmi_meminfo buff_info, struct_info;
  76. if (!dma_initialize())
  77. return NULL;
  78. /* Loop until we'll get a properly aligned memory block */
  79. for (count = 8; count; count--) {
  80. int resize = (selector != 0);
  81. /* Try first to resize (possibly previously) allocated block */
  82. if (resize) {
  83. maxsize = (bound + parsize) - par;
  84. if (maxsize > parsize * 2)
  85. maxsize = parsize * 2;
  86. if (maxsize == allocsize)
  87. resize = 0;
  88. else {
  89. allocsize = maxsize;
  90. /* BUG WARNING: there is an error in dpmi.h DJGPP 2.01 library:
  91.    the order of "selector" and "alloc size" should be
  92.    reversed */
  93. if (__dpmi_resize_dos_memory(allocsize, selector, &maxsize) !=
  94. 0) resize = 0;
  95. }
  96. }
  97. if (!resize) {
  98. if (selector)
  99. __dpmi_free_dos_memory(selector), selector = 0;
  100. par = __dpmi_allocate_dos_memory(allocsize, &selector);
  101. }
  102. if ((par == 0) || (par == -1))
  103. goto exit;
  104. /* If memory block contains a properly aligned portion, quit loop */
  105. bound = (par + mask + 1) & ~mask;
  106. if (par + parsize <= bound)
  107. break;
  108. if (bound + parsize <= par + allocsize) {
  109. par = bound;
  110. break;
  111. }
  112. }
  113. if (!count) {
  114. __dpmi_free_dos_memory(selector);
  115. goto exit;
  116. }
  117. buffer = malloc(sizeof(dma_buffer));
  118. buffer->linear = (void *)(__djgpp_conventional_base + bound * 16);
  119. buffer->physical = bound * 16;
  120. buffer->size = parsize * 16;
  121. buffer->selector = selector;
  122. buffer->channel = channel;
  123. buff_info.address = buffer->physical;
  124. buff_info.size = buffer->size;
  125. /*
  126.    Don't pay attention to return code since under plain DOS it often
  127.    returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
  128.  */
  129. __dpmi_lock_linear_region(&buff_info);
  130. /* Lock the DMA buffer control structure as well */
  131. struct_info.address = __djgpp_base_address + (unsigned long)buffer;
  132. struct_info.size = sizeof(dma_buffer);
  133. if (__dpmi_lock_linear_region(&struct_info)) {
  134. __dpmi_unlock_linear_region(&buff_info);
  135. __dpmi_free_dos_memory(selector);
  136. free(buffer);
  137. buffer = NULL;
  138. goto exit;
  139. }
  140.   exit:
  141. if (buffer)
  142. __buffer_count++;
  143. else if (--__buffer_count == 0)
  144. dma_finalize();
  145. return buffer;
  146. }
  147. void dma_free(dma_buffer * buffer)
  148. {
  149. __dpmi_meminfo buff_info;
  150. if (!buffer)
  151. return;
  152. buff_info.address = buffer->physical;
  153. buff_info.size = buffer->size;
  154. __dpmi_unlock_linear_region(&buff_info);
  155. __dpmi_free_dos_memory(buffer->selector);
  156. free(buffer);
  157. if (--__buffer_count == 0)
  158. dma_finalize();
  159. }
  160. void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
  161. {
  162. /* Disable interrupts */
  163. int old_ints = disable();
  164. dma_disable(buffer->channel);
  165. dma_set_mode(buffer->channel, mode);
  166. dma_clear_ff(buffer->channel);
  167. dma_set_addr(buffer->channel, buffer->physical);
  168. dma_clear_ff(buffer->channel);
  169. dma_set_count(buffer->channel, count);
  170. dma_enable(buffer->channel);
  171. /* Re-enable interrupts */
  172. if (old_ints)
  173. enable();
  174. }
  175. /* ex:set ts=4: */