Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Implementing Direct Memory Access (DMA) in C


May 1992/Implementing Direct Memory Access (DMA) in C/Listing 4

Listing 4 (dma.c) Generic Routines for Programming the DMA Controller 8237 on the IBM PC or Compatible

/*******************************************************

       Generic Routines for programming the DMA controller
       8237, on the IBM PC or compatible

       Copyright Don Bradley, 1991.

       Permission is granted for used of these routines
       in any manner as long as this copyright notice is 
       included.

       Tested using Quick C 2.5 and MSC 6.0 on a
       Toshiba T5200.

*******************************************************/

#include <conio.h>
#include <malloc.h>
#include <stdio.h>

#include "dma.h"

#define MASK_REG                      0xd4
#define MODE_REG                      0xd6
#define COUNT_REG                     0xc6
#define MEM_PAGE5_REG          0x8b
#define MEM_PAGE6_REG          0x89
#define MEM_PAGE7_REG          0x8a
#define MEM_OFFSET_REG         0xc4

static int far *dma_buffer[10];

int dma(int dma_chan, int mode, int far *buffer,
              unsigned int buffer_len)
       {
       long physaddr;
       int port, page_port;

       // values passed OK?
       if (dma_chan < 5 || dma_chan > 7)
              return (FALSE);

       if (buffer == 0)
              return (FALSE);

       // Initalize 8237 DMA Controller

       // Disable DMA Channel first
       disable_dma(dma_chan);

       // Setup DMA mode register
       outp(MODE_REG, mode | (dma_chan - 4));

       /* Setup page and offset regs */
       switch (dma_chan) {
       case 5:
              page_port = MEM_PAGE5_REG;
              break;
       case 6:
              page_port = MEM_PAGE6_REG;
              break;
       case 7:
              page_port = MEM_PAGE7_REG;
              break;
              }

       physaddr = (((long)buffer>>12) & 0xFFFF0L) + ((long) buffer & 0xFFFFL);

       // output DMA buffer page number.
       outp(page_port, (int) (physaddr >> 16));

       // Shift left 1 bit for working with words (ints)
       physaddr /= 2;

       // Output DMA buffer offset.
       port = MEM_OFFSET_REG + (dma_chan - 5) * 4;
       outp(port, (int)physaddr & 0xFF);
       outp(port, (int)(physaddr>>8) & 0xFF);

       // Transfer Count, low byte first then high byte.
       port = COUNT_REG+(dma_chan-5)*4;
       outp(port, (buffer_len & 0xFF));
       outp(port, ((buffer_len >> 8) & 0xFF));

       return (TRUE);
       }

void disable_dma(int chan)
/*& Disable DMA channel */
       {
       if (chan < 5 || chan > 7)
              return;

       outp(MASK_REG, DMA_DISABLE | (chan - 4));
       }

void enable_dma(int chan)
/*& Enable DMA channel */
       {
       if (chan < 5 || chan > 7)
              return;

       outp(MASK_REG, DMA_ENABLE | (chan - 4));
       }

int far *alloc_dma_buffer(int dma_chn,
              unsigned int size)
/*& Allocates a DMA buffer containing no page
        boundary */
       {
       long physaddr, page, offset, extra;
       int far *buffer;

       // Values passed OK?
       if (dma_chn < 5 || dma_chn > 7)
              return (NULL);

       if(!size)
              return(NULL);

       // Create dma buffer
       size *= sizeof(int);

       if(!(buffer = (int far *)_fmalloc(size)))
              return (NULL);

       physaddr = (((long)buffer & 0xFFFF0000L)>>12) +
              ((long)buffer & 0xFFFFL);

       page = (physaddr & 0xFFFF0000L) >> 16;
       offset = physaddr & 0xFFFFL;

       if(offset + size > 0xFFFFL) {
              extra = offset + size -0xFFFFL + 10;
              size += extra;

              // can't have a buffer > 64K
              if(size > 0xFFFFL)
                    return(NULL);

              if(!(buffer = (int far *)_expand(buffer,
                                               size)))
                    return(NULL);

              page++;
              offset = 0;
              }

       // save actual buffer address for deallocation
       dma_buffer[dma_chn] = buffer;

       // return proper buffer address for DMA usage
       buffer = (int far *)((page<<28) + offset);
       return(buffer);
       }

void free_dma_buffer(int dma_chn)
       {
       // values passed OK?
       if (dma_chn < 5 || dma_chn > 7)
              return;

       _ffree(dma_buffer[dma_chn]);
       }
/* End of File */

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.