Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

dma.c File Reference

DMA (Direct Memory Access) driver. More...

#include <const.h>
#include <arch/i386.h>
#include <arch/mem.h>
#include <arch/paging.h>
#include <kernel/kernel_map.h>
#include <kernel/kmalloc.h>
#include <kernel/task.h>
#include <kernel/dma.h>

Go to the source code of this file.

Defines

#define DMA_MEMORY_DIM   (DMA_MEMORY_END-DMA_MEMORY_START)
 The size of the DMA memory area.

#define DMA_FREE_FRAME   0
 The DMA-memory frame is marked as free.

#define DMA_BUSY_FRAME   1
 The DMA-memory frame is marked as busy.


Functions

void dma_xfer (unsigned channel, addr_t physaddr, size_t length, bool read)
 Set up a DMA transfer between a device and memory.
Parameters:
channel  The 8-bit channel number (0..3).
physaddr  The physical address of the buffer.
length  The size of the buffer.
read  If it is TRUE the transfer will be from memory to device, otherwise will be from device to memory.


void dma_alloc_init ()
 Initialize the DMA memory allocator.

void * dma_phys_alloc (size_t len)
 Return a pointer of len contiguous bytes into the DMA address space.
Parameters:
len  The size of the buffer we want to allocate.
Returns:
A pointer to the allocated buffer.
Note:
The pointer is the physical address of the buffer and not the virtual address!!!
Exceptions:
NULL  Out of DMA memory area!


bool dma_phys_free (size_t dma_start, size_t len)
 Free the DMA memory area from dma_start to dma_start+len address.
Parameters:
dma_start  The beginning of the area to free.
len  The size of the buffer to free.
Returns:
Note:
The dma_start address is the physical address of the buffer to free and not the virtual address!!!



Variables

dma_channel_t dmainfo []
 Definition of DMA channels.

bytedma_free_frames
 DMA free frames vector. It maps every frame into the DMA memory area. On i386 we have to reserve the first 16MB of physical memory to the DMA, because on the bus we have a 24-bit register dedicated to the addressing (2^24=16MB).


Detailed Description

DMA (Direct Memory Access) driver.

Author:
Andrea Righi <drizzt@inwind.it>
Date:
Last update: 2003-11-08
This driver is based on the Fabian Nunez DMA driver. The author can be reached by email at: <fabian@cs.uct.ac.za>.

Definition in file dma.c.


Function Documentation

void dma_alloc_init  
 

Initialize the DMA memory allocator.

Definition at line 116 of file dma.c.

00117 {
00118         uint32_t i;
00119         extern dword *K_VIR_END;
00120 
00121         // Initialize the DMA free frames vector                        //
00122         dma_free_frames = kmalloc(DMA_MEMORY_DIM/PAGE_SIZE);
00123         memset(dma_free_frames, DMA_FREE_FRAME, DMA_MEMORY_DIM/PAGE_SIZE);
00124 
00125         // Set the kernel physical space busy                           //
00126         for (i=0; i<=(uint32_t)K_VIR_END-K_VIR_START; i+=PAGE_SIZE)
00127                 dma_free_frames[K_PHYS_ADDR+i] = DMA_BUSY_FRAME;
00128 }

void* dma_phys_alloc size_t    len
 

Return a pointer of len contiguous bytes into the DMA address space.

Parameters:
len  The size of the buffer we want to allocate.
Returns:
A pointer to the allocated buffer.
Note:
The pointer is the physical address of the buffer and not the virtual address!!!
Exceptions:
NULL  Out of DMA memory area!

Definition at line 141 of file dma.c.

00142 {
00143         dword i, j, ret;
00144         char flag=0;
00145 
00146         // len must be not null!                                        //
00147         if (!len) return(NULL);
00148 
00149         // Round up len to frames boundary                              //
00150         len = PAGE_ALIGN_UP(len);
00151 
00152         sched_enter_critical_region();
00153 
00154         // Search for a free dma page                                   //
00155         for(i=0; i<(DMA_MEMORY_DIM/PAGE_SIZE); i++)
00156         {
00157                 if (dma_free_frames[i] == DMA_FREE_FRAME)
00158                 {
00159                         // Found a free frame!                          //
00160                         // OK, now I require (len/PAGE_SIZE-1)          //
00161                         // others free frames                           //
00162                         for(j=1, flag=0; j<len/PAGE_SIZE; j++)
00163                         {
00164                                 if (dma_free_frames[i+j] == DMA_BUSY_FRAME)
00165                                 {
00166                                         // Nooo! Found a busy frame!    //
00167                                         flag = 1;
00168                                         break;
00169                                 }
00170                         }
00171                         if (flag == 1)
00172                         {
00173                                 // Not a valid contiguous free space.   //
00174                                 // Continue after j position...         //
00175                                 i += j;
00176                         }
00177                         else
00178                         {
00179                                 // Found a valid contiguous free        //
00180                                 // space, so mark it                    //
00181                                 for(j=0; j<len/PAGE_SIZE; j++)
00182                                         dma_free_frames[i+j] = DMA_BUSY_FRAME;
00183                                 break;
00184                         }
00185                 }
00186         }
00187         // Check if we have found the free DMA location                 //
00188         if (flag == 0)
00189                 // We found it!!!                                       //
00190                 ret = (i * PAGE_SIZE + DMA_MEMORY_START);
00191         else
00192                 // Not found!!!                                         //
00193                 ret = NULL;
00194 
00195         sched_leave_critical_region();
00196         return((void *)ret);
00197 }

bool dma_phys_free size_t    dma_start,
size_t    len
 

Free the DMA memory area from dma_start to dma_start+len address.

Parameters:
dma_start  The beginning of the area to free.
len  The size of the buffer to free.
Returns:
Note:
The dma_start address is the physical address of the buffer to free and not the virtual address!!!

Definition at line 210 of file dma.c.

00211 {
00212         int i;
00213 
00214         if (!len) return(FALSE);
00215 
00216         // Round up len to frames boundary                              //
00217         len = PAGE_ALIGN_UP(len);
00218 
00219         if (
00220                 (dma_start >= DMA_MEMORY_START) && (dma_start < DMA_MEMORY_END) &&
00221                 ((dma_start + len) < DMA_MEMORY_END)
00222         )
00223         {
00224                 sched_enter_critical_region();
00225 
00226                 // Mark the DMA region as free                          //
00227                 for(i=(dma_start-DMA_MEMORY_START)/PAGE_SIZE; i<DMA_MEMORY_DIM/PAGE_SIZE; i++)
00228                         dma_free_frames[i] = DMA_FREE_FRAME;
00229 
00230                 sched_leave_critical_region();
00231 
00232                 return(TRUE);
00233         }
00234         else
00235                 // Invalid DMA memory range                             //
00236                 return(FALSE);
00237 }

void dma_xfer unsigned    channel,
addr_t    physaddr,
size_t    length,
bool    read
 

Set up a DMA transfer between a device and memory.

Parameters:
channel  The 8-bit channel number (0..3).
physaddr  The physical address of the buffer.
length  The size of the buffer.
read  If it is TRUE the transfer will be from memory to device, otherwise will be from device to memory.

Definition at line 47 of file dma.c.

00048 {
00049         int page, offset;
00050 
00051         if (channel > 3) return;
00052 
00053         // calculate dma page and offset //
00054         page = physaddr >> 16;
00055         offset = physaddr & 0xFFFF;
00056         length -= 1;  // with dma, if you want k bytes, you ask for k-1 //
00057 
00058         disable();
00059 
00060         // set the mask bit for the channel //
00061         outportb(0x0A, channel | 0x04);
00062 
00063         // clear flipflop //
00064         outportb(0x0C, 0x00);
00065 
00066         // set DMA mode (write+single+r/w) //
00067         outportb(0x0B, (read ? 0x48 : 0x44) + channel);
00068 
00069         // set DMA page //
00070         outportb(dmainfo[channel].page, page);
00071 
00072         // set DMA offset //
00073         outportb(dmainfo[channel].offset, offset & 0xFF);  // low byte //
00074         outportb(dmainfo[channel].offset, offset >> 8);    // high byte //
00075 
00076         // set DMA length //
00077         outportb(dmainfo[channel].length, length & 0xFF);  // low byte //
00078         outportb(dmainfo[channel].length, length >> 8);    // high byte //
00079 
00080         // clear DMA mask bit //
00081         outportb(0x0A, channel);
00082 
00083         enable();
00084 }


Generated on Fri Feb 20 15:32:17 2004 for Minirighi by doxygen1.2.18