home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_05 / 1005064a < prev    next >
Text File  |  1992-03-19  |  3KB  |  168 lines

  1. /* Listing 4 */
  2.  
  3. /*****************************************************
  4.     DMA.C 
  5.  
  6.     Generic Routines for programming the DMA controller
  7.     8237, on the IBM PC or compatible
  8.  
  9.     Copyright Don Bradley, 1991.
  10.  
  11.     Permission is granted for used of these routines
  12.     in any manner as long as this copyright notice is
  13.     included.
  14.  
  15.     Tested using Quick C 2.5 and MSC 6.0 on a 
  16.     Toshiba T5200.
  17.  
  18.  *****************************************************/
  19.  
  20. #include <conio.h>
  21. #include <malloc.h>
  22. #include <stdio.h>
  23.  
  24. #include "dma.h"
  25.  
  26. #define MASK_REG            0xd4
  27. #define MODE_REG            0xd6
  28. #define COUNT_REG            0xc6
  29. #define MEM_PAGE5_REG        0x8b
  30. #define MEM_PAGE6_REG        0x89
  31. #define MEM_PAGE7_REG        0x8a
  32. #define MEM_OFFSET_REG        0xc4
  33.  
  34. static int far *dma_buffer[10];
  35.  
  36. int dma(int dma_chan, int mode, int far *buffer, 
  37.         unsigned int buffer_len)
  38.     {
  39.     long physaddr;
  40.     int port, page_port;
  41.  
  42.     // values passed OK?
  43.     if (dma_chan < 5 || dma_chan > 7)
  44.         return (FALSE);
  45.  
  46.     if (buffer == 0)
  47.         return (FALSE);
  48.  
  49.     // Initalize 8237 DMA Controller
  50.  
  51.     // Disable DMA Channel first
  52.     disable_dma(dma_chan);
  53.  
  54.     // Setup DMA mode register
  55.     outp(MODE_REG, mode | (dma_chan - 4));
  56.  
  57.     /* Setup page and offset regs */
  58.     switch (dma_chan) {
  59.     case 5:
  60.         page_port = MEM_PAGE5_REG;
  61.         break;
  62.     case 6:
  63.         page_port = MEM_PAGE6_REG;
  64.         break;
  65.     case 7:
  66.         page_port = MEM_PAGE7_REG;
  67.         break;
  68.         }
  69.  
  70.     physaddr = (((long)buffer>>12) & 0xFFFF0L) +
  71.           ((long)buffer & 0xFFFFL);
  72.     
  73.     // output DMA buffer page number.
  74.     outp(page_port, (int) (physaddr >> 16));
  75.  
  76.     // Shift left 1 bit for working with words(ints)
  77.     physaddr /= 2;
  78.  
  79.     // Output DMA buffer offset.
  80.     port = MEM_OFFSET_REG + (dma_chan - 5) * 4;
  81.     outp(port, (int)physaddr & 0xFF);
  82.     outp(port, (int)(physaddr>>8) & 0xFF);
  83.  
  84.     // Transfer Count, low byte first then high byte.
  85.     port = COUNT_REG+(dma_chan-5)*4;
  86.     outp(port, (buffer_len & 0xFF));
  87.     outp(port, ((buffer_len >> 8) & 0xFF));
  88.  
  89.     return (TRUE);
  90.     }
  91.  
  92. void disable_dma(int chan)
  93. /*& Disable DMA channel */
  94.     {
  95.     if (chan < 5 || chan > 7)
  96.         return;
  97.  
  98.     outp(MASK_REG, DMA_DISABLE | (chan - 4));
  99.     }
  100.  
  101. void enable_dma(int chan)
  102. /*& Enable DMA channel */
  103.     {
  104.     if (chan < 5 || chan > 7)
  105.         return;
  106.  
  107.     outp(MASK_REG, DMA_ENABLE | (chan - 4));
  108.     }
  109.  
  110. int far *alloc_dma_buffer(int dma_chn, 
  111.         unsigned int size)
  112. /*& Allocates a DMA buffer containing no page 
  113.      boundary */
  114.     {
  115.     long physaddr, page, offset, extra;
  116.     int far *buffer;
  117.  
  118.     // Values passed OK?
  119.     if (dma_chn < 5 || dma_chn > 7)
  120.         return (NULL);
  121.  
  122.     if(!size)
  123.         return(NULL);
  124.  
  125.     // Create dma buffer
  126.     size *= sizeof(int);
  127.  
  128.     if(!(buffer = (int far *)_fmalloc(size)))
  129.         return (NULL);
  130.  
  131.     physaddr = (((long)buffer & 0xFFFF0000L)>>12) +
  132.         ((long)buffer & 0xFFFFL);
  133.     
  134.     page = (physaddr & 0xFFFF0000L) >> 16;
  135.     offset = physaddr & 0xFFFFL;
  136.  
  137.     if(offset + size > 0xFFFFL) {
  138.         extra = offset + size - 0xFFFFL + 10;
  139.         size += extra;
  140.         
  141.         // can't have a buffer > 64K
  142.         if(size > 0xFFFFL)
  143.             return(NULL);
  144.         
  145.         if(!(buffer = (int far *)_expand(buffer, size)))
  146.             return(NULL);
  147.  
  148.         page++;
  149.         offset = 0;
  150.         }
  151.     
  152.     // save actual buffer address for deallocation
  153.     dma_buffer[dma_chn] = buffer;
  154.  
  155.     // return proper buffer address for DMA usage
  156.     buffer = (int far *)((page<<28) + offset);
  157.     return(buffer);    
  158.     }
  159.  
  160. void free_dma_buffer(int dma_chn)
  161.     {
  162.     // values passed OK?
  163.     if (dma_chn < 5 || dma_chn > 7)
  164.         return;
  165.  
  166.     _ffree(dma_buffer[dma_chn]);
  167.     }
  168.