home *** CD-ROM | disk | FTP | other *** search
/ PC Loisirs 18 / cd.iso / sharewar / mikm202 / source / mdma.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-18  |  9.5 KB  |  347 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <dos.h>
  4. #include <malloc.h>
  5. #include <conio.h>
  6. #include "mtypes.h"
  7. #include "mdma.h"
  8.  
  9.  
  10. /* DMA Controler #1 (8-bit controller) */
  11. #define DMA1_STAT       0x08            /* read status register */
  12. #define DMA1_WCMD       0x08            /* write command register */
  13. #define DMA1_WREQ       0x09            /* write request register */
  14. #define DMA1_SNGL       0x0A            /* write single bit register */
  15. #define DMA1_MODE       0x0B            /* write mode register */
  16. #define DMA1_CLRFF      0x0C            /* clear byte ptr flip/flop */
  17. #define DMA1_MCLR       0x0D            /* master clear register */
  18. #define DMA1_CLRM       0x0E            /* clear mask register */
  19. #define DMA1_WRTALL     0x0F            /* write all mask register */
  20.  
  21. /* DMA Controler #2 (16-bit controller) */
  22. #define DMA2_STAT       0xD0            /* read status register */
  23. #define DMA2_WCMD       0xD0            /* write command register */
  24. #define DMA2_WREQ       0xD2            /* write request register */
  25. #define DMA2_SNGL       0xD4            /* write single bit register */
  26. #define DMA2_MODE       0xD6            /* write mode register */
  27. #define DMA2_CLRFF      0xD8            /* clear byte ptr flip/flop */
  28. #define DMA2_MCLR       0xDA            /* master clear register */
  29. #define DMA2_CLRM       0xDC            /* clear mask register */
  30. #define DMA2_WRTALL     0xDE            /* write all mask register */
  31.  
  32. #define DMA0_ADDR       0x00            /* chan 0 base adddress */
  33. #define DMA0_CNT        0x01            /* chan 0 base count */
  34. #define DMA1_ADDR       0x02            /* chan 1 base adddress */
  35. #define DMA1_CNT        0x03            /* chan 1 base count */
  36. #define DMA2_ADDR       0x04            /* chan 2 base adddress */
  37. #define DMA2_CNT        0x05            /* chan 2 base count */
  38. #define DMA3_ADDR       0x06            /* chan 3 base adddress */
  39. #define DMA3_CNT        0x07            /* chan 3 base count */
  40. #define DMA4_ADDR       0xC0            /* chan 4 base adddress */
  41. #define DMA4_CNT        0xC2            /* chan 4 base count */
  42. #define DMA5_ADDR       0xC4            /* chan 5 base adddress */
  43. #define DMA5_CNT        0xC6            /* chan 5 base count */
  44. #define DMA6_ADDR       0xC8            /* chan 6 base adddress */
  45. #define DMA6_CNT        0xCA            /* chan 6 base count */
  46. #define DMA7_ADDR       0xCC            /* chan 7 base adddress */
  47. #define DMA7_CNT        0xCE            /* chan 7 base count */
  48.  
  49. #define DMA0_PAGE       0x87            /* chan 0 page register (refresh)*/
  50. #define DMA1_PAGE       0x83            /* chan 1 page register */
  51. #define DMA2_PAGE       0x81            /* chan 2 page register */
  52. #define DMA3_PAGE       0x82            /* chan 3 page register */
  53. #define DMA4_PAGE       0x8F            /* chan 4 page register (unuseable)*/
  54. #define DMA5_PAGE       0x8B            /* chan 5 page register */
  55. #define DMA6_PAGE       0x89            /* chan 6 page register */
  56. #define DMA7_PAGE       0x8A            /* chan 7 page register */
  57.  
  58. #define MAX_DMA         8
  59.  
  60. #define DMA_DECREMENT   0x20    /* mask to make DMA hardware go backwards */
  61.  
  62. typedef struct {
  63.     UBYTE dma_disable;      /* bits to disable dma channel */
  64.     UBYTE dma_enable;       /* bits to enable dma channel */
  65.     UWORD page;                     /* page port location */
  66.     UWORD addr;                     /* addr port location */
  67.     UWORD count;            /* count port location */
  68.     UWORD single;           /* single mode port location */
  69.     UWORD mode;                     /* mode port location */
  70.     UWORD clear_ff;         /* clear flip-flop port location */
  71.     UBYTE write;            /* bits for write transfer */
  72.     UBYTE read;                     /* bits for read transfer */
  73. } DMA_ENTRY;
  74.  
  75. #ifdef __WATCOMC__
  76.  
  77. #define ENTER_CRITICAL IRQ_PUSH_OFF()
  78. extern void IRQ_PUSH_OFF (void);
  79. #pragma aux IRQ_PUSH_OFF =      \
  80.     "pushfd",                   \
  81.     "cli";
  82.  
  83. #define ENTER_CRITICAL_ON IRQ_PUSH_ON()
  84. extern void IRQ_PUSH_ON (void);
  85. #pragma aux IRQ_PUSH_ON =       \
  86.     "pushfd",                   \
  87.     "sti";
  88.  
  89. #define LEAVE_CRITICAL IRQ_POP()
  90. extern void IRQ_POP (void);
  91. #pragma aux IRQ_POP =   \
  92.     "popfd";
  93. #define LEAVE_CRITICAL_ON LEAVE_CRITICAL
  94.  
  95. #else
  96.  
  97. #define ENTER_CRITICAL asm{ pushf; cli }
  98. #define LEAVE_CRITICAL asm{ popf }
  99.  
  100. #endif
  101.  
  102. /* Variables needed ... */
  103.  
  104. static DMA_ENTRY mydma[MAX_DMA] = {
  105.  
  106. /* DMA channel 0 */
  107.             {0x04,0x00,DMA0_PAGE,DMA0_ADDR,DMA0_CNT,
  108.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x48,0x44},
  109.  
  110. /* DMA channel 1 */
  111.             {0x05,0x01,DMA1_PAGE,DMA1_ADDR,DMA1_CNT,
  112.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45},
  113.  
  114. /* DMA channel 2 */
  115.             {0x06,0x02,DMA2_PAGE,DMA2_ADDR,DMA2_CNT,
  116.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4A,0x46},
  117.  
  118. /* DMA channel 3 */
  119.             {0x07,0x03,DMA3_PAGE,DMA3_ADDR,DMA3_CNT,
  120.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4B,0x47},
  121.  
  122. /* DMA channel 4 */
  123.             {0x04,0x00,DMA4_PAGE,DMA4_ADDR,DMA4_CNT,
  124.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x48,0x44},
  125.  
  126. /* DMA channel 5 */
  127.             {0x05,0x01,DMA5_PAGE,DMA5_ADDR,DMA5_CNT,
  128.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x49,0x45},
  129.  
  130. /* DMA channel 6 */
  131.             {0x06,0x02,DMA6_PAGE,DMA6_ADDR,DMA6_CNT,
  132.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4A,0x46},
  133.  
  134. /* DMA channel 7 */
  135.             {0x07,0x03,DMA7_PAGE,DMA7_ADDR,DMA7_CNT,
  136.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4B,0x47},
  137. };
  138.  
  139.  
  140. #define LPTR(ptr) (((ULONG)FP_SEG(ptr)<<4)+FP_OFF(ptr))
  141.  
  142.  
  143. #ifdef __WATCOMC__
  144.  
  145.  
  146. static UWORD dma_selector;
  147.  
  148. void *Dma_AllocMem(UWORD size)
  149. /*
  150.     Allocates a dma buffer of 'size' bytes. 
  151.     this watcom dma memory allocation doesn't check if it's 
  152.     page-continuous, and can only be used to allocate exactly 1 block
  153.  
  154.     returns NULL if failed.
  155. */
  156. {
  157.     union REGS r;
  158.  
  159.     r.x.eax = 0x0100;           /* DPMI allocate DOS memory */
  160.     r.x.ebx = (size + 15) >> 4; /* Number of paragraphs requested */
  161.  
  162.     int386 (0x31, &r, &r);
  163.  
  164.     if( r.x.cflag )  /* Failed */
  165.         return ((ULONG) 0);
  166.  
  167.     dma_selector=r.x.edx;
  168.  
  169.     return (void *) ((r.x.eax & 0xFFFF) << 4);
  170. }
  171.  
  172.  
  173. void Dma_FreeMem(void *p)
  174. {
  175.     union REGS r;
  176.     r.x.eax = 0x0101;           /* DPMI free DOS memory */
  177.     r.x.edx = dma_selector;     /* base selector */
  178.     int386 (0x31, &r, &r);
  179. }
  180.  
  181.  
  182. #else
  183.  
  184.  
  185. void *Dma_AllocMem(UWORD size)
  186. /*
  187.     Allocates a dma buffer of 'size' bytes.
  188.     
  189.     returns NULL if failed.
  190. */
  191. {
  192.     char huge *p1;
  193.     char huge *p2;
  194.     ULONG s1;
  195.  
  196.     // Alloceer size bytes van de far heap
  197.  
  198.     if((p1=malloc((ULONG)size))==NULL) return NULL;
  199.  
  200.     s1=LPTR(p1);
  201.  
  202.     /* Controleer of de gehele buffer
  203.       zich in hetzelfde 64k gebied bevindt */
  204.  
  205.     if( (s1>>16) != ( (s1+size-1) >> 16 ) ){
  206.  
  207.         /* Als dit niet het geval is, p1 kleiner maken
  208.            zodat het precies tot die 64k grens loopt */
  209.  
  210.         realloc(p1,0x10000L-(s1&0xffff));
  211.  
  212.         /* en opnieuw proberen een buffer te alloceren */
  213.  
  214.         p2=Dma_AllocMem(size);
  215.  
  216.         /* en de oude vrijgeven */
  217.  
  218.         free(p1);
  219.  
  220.         /* return met nieuw gevonden pointer */
  221.  
  222.         p1=p2;
  223.     }
  224.     return(p1);
  225. }
  226.  
  227.  
  228. void Dma_FreeMem(void *p)
  229. {
  230.     free(p);
  231. }
  232. #endif
  233.  
  234.  
  235. int Dma_Start(int channel,void *pc_ptr,UWORD size,int type)
  236. {
  237.     DMA_ENTRY *tdma;
  238.     ULONG s_20bit,e_20bit;
  239.     UWORD spage,saddr,tcount;
  240.     UWORD epage,eaddr;
  241.     UBYTE cur_mode;
  242.  
  243.     tdma=&mydma[channel];           /* point to this dma data */
  244.  
  245.     /* Convert the pc address to a 20 bit physical
  246.        address that the DMA controller needs */
  247.  
  248. #ifdef __WATCOMC__
  249.     s_20bit = pc_ptr;
  250. #else
  251.     s_20bit = LPTR(pc_ptr);
  252. #endif
  253.  
  254.     e_20bit = s_20bit + size - 1;
  255.     spage = s_20bit>>16;
  256.     epage = e_20bit>>16;
  257.  
  258.     if(spage != epage) return 0;
  259.  
  260.     if(channel>=4){
  261.         /* if 16-bit xfer, then addr,count & size are divided by 2 */
  262.         s_20bit = s_20bit >> 1;
  263.         e_20bit = e_20bit >> 1;
  264.         size = size >> 1;
  265.     }
  266.  
  267.     saddr=s_20bit&0xffff;
  268.  
  269.     tcount = size-1;
  270.  
  271.     switch (type){
  272.  
  273.         case READ_DMA:
  274.             cur_mode = tdma->read;
  275.             break;
  276.  
  277.         case WRITE_DMA:
  278.             cur_mode = tdma->write;
  279.             break;
  280.  
  281.         case INDEF_READ:
  282.             cur_mode = tdma->read | 0x10;   /* turn on auto init */
  283.             break;
  284.  
  285.         case INDEF_WRITE:
  286.             cur_mode = tdma->write | 0x10;  /* turn on auto init */
  287.             break;
  288.     }
  289.  
  290. //        ENTER_CRITICAL;
  291.     outportb(tdma->single,tdma->dma_disable);               /* disable channel */
  292.     outportb(tdma->mode,cur_mode);                                  /* set mode */
  293.     outportb(tdma->clear_ff,0);                                             /* clear f/f */
  294.     outportb(tdma->addr,saddr&0xff);                                /* LSB */
  295.     outportb(tdma->addr,saddr>>8);                                  /* MSB */
  296.     outportb(tdma->page,spage);                                             /* page # */
  297.     outportb(tdma->clear_ff,0);                                             /* clear f/f */
  298.     outportb(tdma->count,tcount&0x0ff);                             /* LSB count */
  299.     outportb(tdma->count,tcount>>8);                                /* MSB count */
  300.     outportb(tdma->single,tdma->dma_enable);                /* enable */
  301. //        LEAVE_CRITICAL;
  302.  
  303.     return 1;
  304. }
  305.  
  306.  
  307. void Dma_Stop(int channel)
  308. {
  309.     DMA_ENTRY *tdma;
  310.     tdma=&mydma[channel];                                                   /* point to this dma data */
  311.     outportb(tdma->single,tdma->dma_disable);               /* disable chan */
  312. }
  313.  
  314.  
  315.  
  316. UWORD Dma_Todo(int channel)
  317. {
  318.     UWORD creg;
  319.     UWORD val1,val2;
  320.  
  321.     DMA_ENTRY *tdma=&mydma[channel];
  322.  
  323.     creg=tdma->count;
  324.  
  325.     ENTER_CRITICAL;
  326.  
  327. //        outportb(tdma->clear_ff,0xff);
  328.  
  329.     redo:
  330.     val1=inportb(creg);
  331.     val1|=inportb(creg)<<8;
  332.     val2=inportb(creg);
  333.     val2|=inportb(creg)<<8;
  334.  
  335.     val1-=val2;
  336.     if(val1>0x40) goto redo;
  337.  
  338.     LEAVE_CRITICAL;
  339.  
  340. //      if(val1<0xffc0) goto redo;
  341.  
  342.     if(channel>3) val2<<=1;
  343.  
  344.     return val2;
  345. }
  346.  
  347.