root/kernel/dma.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mutex_atomic_swap
  2. get_dma_list
  3. request_dma
  4. free_dma

   1 /* $Id: dma.c,v 1.5 1992/11/18 02:49:05 root Exp root $
   2  * linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
   3  * Written by Hennus Bergman, 1992. 
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/errno.h>
   8 #include <asm/dma.h>
   9 
  10 
  11 /* A note on resource allocation:
  12  *
  13  * All drivers needing DMA channels, should allocate and release them
  14  * through the public routines `request_dma()' and `free_dma()'.
  15  *
  16  * In order to avoid problems, all processes should allocate resources in
  17  * the same sequence and release them in the reverse order.
  18  * 
  19  * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.
  20  * When releasing them, first release the DMA, then release the IRQ.
  21  * If you don't, you may cause allocation requests to fail unnecessarily.
  22  * This doesn't really matter now, but it will once we get real semaphores
  23  * in the kernel.
  24  */
  25 
  26 
  27 
  28 /* Channel n is busy iff dma_chan_busy[n] != 0.
  29  * DMA0 used to be reserved for DRAM refresh, but apparently not any more...
  30  * DMA4 is reserved for cascading.
  31  */
  32 /*
  33 static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
  34         0, 0, 0, 0, 1, 0, 0, 0
  35 };
  36 */
  37 static volatile char * dma_chan_busy[MAX_DMA_CHANNELS] = {
  38         0,
  39         0,
  40         0,
  41         0,
  42         "cascade",
  43         0,
  44         0,
  45         0
  46 };
  47 
  48 /* Atomically swap memory location [32 bits] with `newval'.
  49  * This avoid the cli()/sti() junk and related problems.
  50  * [And it's faster too :-)]
  51  * Maybe this should be in include/asm/mutex.h and be used for
  52  * implementing kernel-semaphores as well.
  53  */
  54 static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsigned int newval)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         unsigned int semval = newval;
  57 
  58         /* If one of the operands for the XCHG instructions is a memory ref,
  59          * it makes the swap an uninterruptible RMW cycle.
  60          *
  61          * One operand must be in memory, the other in a register, otherwise
  62          * the swap may not be atomic.
  63          */
  64 
  65         asm __volatile__ ("xchgl %2, %0\n"
  66                         : /* outputs: semval   */ "=r" (semval)
  67                         : /* inputs: newval, p */ "0" (semval), "m" (*p)
  68                         );      /* p is a var, containing an address */
  69         return semval;
  70 } /* mutex_atomic_swap */
  71 
  72 
  73 int get_dma_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         int i, len = 0;
  76 
  77         for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
  78                 if (dma_chan_busy[i]) {
  79                     len += sprintf(buf+len, "%2d: %s\n",
  80                                 i,
  81                                 dma_chan_busy[i]);
  82                 }
  83         }
  84         return len;
  85 }
  86 
  87 int request_dma(unsigned int dmanr, char * deviceID)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         if (dmanr >= MAX_DMA_CHANNELS)
  90                 return -EINVAL;
  91 
  92         if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], (unsigned int) deviceID) != 0) 
  93                 return -EBUSY;
  94 
  95         /* old flag was 0, now contains 1 to indicate busy */
  96         return 0;
  97 } /* request_dma */
  98 
  99 
 100 void free_dma(unsigned int dmanr)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         if (dmanr >= MAX_DMA_CHANNELS) {
 103                 printk("Trying to free DMA%d\n", dmanr);
 104                 return;
 105         }
 106 
 107         if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], 0) == 0) {
 108                 printk("Trying to free free DMA%d\n", dmanr);
 109                 return;
 110         }       
 111 
 112 } /* free_dma */
 113 

/* [previous][next][first][last][top][bottom][index][help] */