DMA.C 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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: DMA.C
  17. author: James R. Dose
  18. date: February 4, 1994
  19. Low level routines to for programming the DMA controller for 8 bit
  20. and 16 bit transfers.
  21. (c) Copyright 1994 James R. Dose. All Rights Reserved.
  22. **********************************************************************/
  23. #include <dos.h>
  24. #include <conio.h>
  25. #include <stdlib.h>
  26. #include "dma.h"
  27. #define DMA_MaxChannel 7
  28. #define VALID ( 1 == 1 )
  29. #define INVALID ( !VALID )
  30. #define BYTE 0
  31. #define WORD 1
  32. typedef struct
  33. {
  34. int Valid;
  35. int Width;
  36. int Mask;
  37. int Mode;
  38. int Clear;
  39. int Page;
  40. int Address;
  41. int Length;
  42. } DMA_PORT;
  43. static const DMA_PORT DMA_PortInfo[ DMA_MaxChannel + 1 ] =
  44. {
  45. { VALID, BYTE, 0xA, 0xB, 0xC, 0x87, 0x0, 0x1 },
  46. { VALID, BYTE, 0xA, 0xB, 0xC, 0x83, 0x2, 0x3 },
  47. { INVALID, BYTE, 0xA, 0xB, 0xC, 0x81, 0x4, 0x5 },
  48. { VALID, BYTE, 0xA, 0xB, 0xC, 0x82, 0x6, 0x7 },
  49. { INVALID, WORD, 0xD4, 0xD6, 0xD8, 0x8F, 0xC0, 0xC2 },
  50. { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8B, 0xC4, 0xC6 },
  51. { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x89, 0xC8, 0xCA },
  52. { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8A, 0xCC, 0xCE },
  53. };
  54. int DMA_ErrorCode = DMA_Ok;
  55. #define DMA_SetErrorCode( status ) \
  56. DMA_ErrorCode = ( status );
  57. /*---------------------------------------------------------------------
  58. Function: DMA_ErrorString
  59. Returns a pointer to the error message associated with an error
  60. number. A -1 returns a pointer the current error.
  61. ---------------------------------------------------------------------*/
  62. char *DMA_ErrorString
  63. (
  64. int ErrorNumber
  65. )
  66. {
  67. char *ErrorString;
  68. switch( ErrorNumber )
  69. {
  70. case DMA_Error :
  71. ErrorString = DMA_ErrorString( DMA_ErrorCode );
  72. break;
  73. case DMA_Ok :
  74. ErrorString = "DMA channel ok.";
  75. break;
  76. case DMA_ChannelOutOfRange :
  77. ErrorString = "DMA channel out of valid range.";
  78. break;
  79. case DMA_InvalidChannel :
  80. ErrorString = "Unsupported DMA channel.";
  81. break;
  82. default :
  83. ErrorString = "Unknown DMA error code.";
  84. break;
  85. }
  86. return( ErrorString );
  87. }
  88. /*---------------------------------------------------------------------
  89. Function: DMA_VerifyChannel
  90. Verifies whether a DMA channel is available to transfer data.
  91. ---------------------------------------------------------------------*/
  92. int DMA_VerifyChannel
  93. (
  94. int channel
  95. )
  96. {
  97. int status;
  98. int Error;
  99. status = DMA_Ok;
  100. Error = DMA_Ok;
  101. if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) )
  102. {
  103. Error = DMA_ChannelOutOfRange;
  104. status = DMA_Error;
  105. }
  106. else if ( DMA_PortInfo[ channel ].Valid == INVALID )
  107. {
  108. Error = DMA_InvalidChannel;
  109. status = DMA_Error;
  110. }
  111. DMA_SetErrorCode( Error );
  112. return( status );
  113. }
  114. /*---------------------------------------------------------------------
  115. Function: DMA_SetupTransfer
  116. Programs the specified DMA channel to transfer data.
  117. ---------------------------------------------------------------------*/
  118. int DMA_SetupTransfer
  119. (
  120. int channel,
  121. char *address,
  122. int length,
  123. int mode
  124. )
  125. {
  126. DMA_PORT *Port;
  127. int addr;
  128. int ChannelSelect;
  129. int Page;
  130. int HiByte;
  131. int LoByte;
  132. int TransferLength;
  133. int status;
  134. status = DMA_VerifyChannel( channel );
  135. if ( status == DMA_Ok )
  136. {
  137. Port = &DMA_PortInfo[ channel ];
  138. ChannelSelect = channel & 0x3;
  139. addr = ( int )address;
  140. if ( Port->Width == WORD )
  141. {
  142. Page = ( addr >> 16 ) & 255;
  143. HiByte = ( addr >> 9 ) & 255;
  144. LoByte = ( addr >> 1 ) & 255;
  145. // Convert the length in bytes to the length in words
  146. TransferLength = ( length + 1 ) >> 1;
  147. // The length is always one less the number of bytes or words
  148. // that we're going to send
  149. TransferLength--;
  150. }
  151. else
  152. {
  153. Page = ( addr >> 16 ) & 255;
  154. HiByte = ( addr >> 8 ) & 255;
  155. LoByte = addr & 255;
  156. // The length is always one less the number of bytes or words
  157. // that we're going to send
  158. TransferLength = length - 1;
  159. }
  160. // Mask off DMA channel
  161. outp( Port->Mask, 4 | ChannelSelect );
  162. // Clear flip-flop to lower byte with any data
  163. outp( Port->Clear, 0 );
  164. // Set DMA mode
  165. switch( mode )
  166. {
  167. case DMA_SingleShotRead :
  168. outp( Port->Mode, 0x48 | ChannelSelect );
  169. break;
  170. case DMA_SingleShotWrite :
  171. outp( Port->Mode, 0x44 | ChannelSelect );
  172. break;
  173. case DMA_AutoInitRead :
  174. outp( Port->Mode, 0x58 | ChannelSelect );
  175. break;
  176. case DMA_AutoInitWrite :
  177. outp( Port->Mode, 0x54 | ChannelSelect );
  178. break;
  179. }
  180. // Send address
  181. outp( Port->Address, LoByte );
  182. outp( Port->Address, HiByte );
  183. // Send page
  184. outp( Port->Page, Page );
  185. // Send length
  186. outp( Port->Length, TransferLength );
  187. outp( Port->Length, TransferLength >> 8 );
  188. // enable DMA channel
  189. outp( Port->Mask, ChannelSelect );
  190. }
  191. return( status );
  192. }
  193. /*---------------------------------------------------------------------
  194. Function: DMA_EndTransfer
  195. Ends use of the specified DMA channel.
  196. ---------------------------------------------------------------------*/
  197. int DMA_EndTransfer
  198. (
  199. int channel
  200. )
  201. {
  202. DMA_PORT *Port;
  203. int ChannelSelect;
  204. int status;
  205. status = DMA_VerifyChannel( channel );
  206. if ( status == DMA_Ok )
  207. {
  208. Port = &DMA_PortInfo[ channel ];
  209. ChannelSelect = channel & 0x3;
  210. // Mask off DMA channel
  211. outp( Port->Mask, 4 | ChannelSelect );
  212. // Clear flip-flop to lower byte with any data
  213. outp( Port->Clear, 0 );
  214. }
  215. return( status );
  216. }
  217. /*---------------------------------------------------------------------
  218. Function: DMA_GetCurrentPos
  219. Returns the position of the specified DMA transfer.
  220. ---------------------------------------------------------------------*/
  221. char *DMA_GetCurrentPos
  222. (
  223. int channel
  224. )
  225. {
  226. DMA_PORT *Port;
  227. unsigned long addr;
  228. int status;
  229. addr = NULL;
  230. status = DMA_VerifyChannel( channel );
  231. if ( status == DMA_Ok )
  232. {
  233. Port = &DMA_PortInfo[ channel ];
  234. if ( Port->Width == WORD )
  235. {
  236. // Get address
  237. addr = inp( Port->Address ) << 1;
  238. addr |= inp( Port->Address ) << 9;
  239. // Get page
  240. addr |= inp( Port->Page ) << 16;
  241. }
  242. else
  243. {
  244. // Get address
  245. addr = inp( Port->Address );
  246. addr |= inp( Port->Address ) << 8;
  247. // Get page
  248. addr |= inp( Port->Page ) << 16;
  249. }
  250. }
  251. return( ( char * )addr );
  252. }
  253. /*---------------------------------------------------------------------
  254. Function: DMA_GetTransferCount
  255. Returns how many bytes are left in the DMA's transfer.
  256. ---------------------------------------------------------------------*/
  257. int DMA_GetTransferCount
  258. (
  259. int channel
  260. )
  261. {
  262. DMA_PORT *Port;
  263. int count;
  264. int status;
  265. status = DMA_Ok;
  266. count = 0;
  267. if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) )
  268. {
  269. status = DMA_ChannelOutOfRange;
  270. }
  271. else if ( DMA_PortInfo[ channel ].Valid == INVALID )
  272. {
  273. status = DMA_InvalidChannel;
  274. }
  275. if ( status == DMA_Ok )
  276. {
  277. Port = &DMA_PortInfo[ channel ];
  278. outp( Port->Clear, 0 );
  279. count = inp( Port->Length );
  280. count += inp( Port->Length ) << 8;
  281. if ( Port->Width == WORD )
  282. {
  283. count <<= 1;
  284. }
  285. }
  286. DMA_SetErrorCode( status );
  287. return( count );
  288. }