linux/arch/arm/kernel/dma.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/kernel/dma.c
   3 *
   4 *  Copyright (C) 1995-2000 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  Front-end to the DMA handling.  This handles the allocation/freeing
  11 *  of DMA channels, and provides a unified interface to the machines
  12 *  DMA facilities.
  13 */
  14#include <linux/module.h>
  15#include <linux/init.h>
  16#include <linux/spinlock.h>
  17#include <linux/errno.h>
  18#include <linux/scatterlist.h>
  19#include <linux/seq_file.h>
  20#include <linux/proc_fs.h>
  21
  22#include <asm/dma.h>
  23
  24#include <asm/mach/dma.h>
  25
  26DEFINE_SPINLOCK(dma_spin_lock);
  27EXPORT_SYMBOL(dma_spin_lock);
  28
  29static dma_t *dma_chan[MAX_DMA_CHANNELS];
  30
  31static inline dma_t *dma_channel(unsigned int chan)
  32{
  33        if (chan >= MAX_DMA_CHANNELS)
  34                return NULL;
  35
  36        return dma_chan[chan];
  37}
  38
  39int __init isa_dma_add(unsigned int chan, dma_t *dma)
  40{
  41        if (!dma->d_ops)
  42                return -EINVAL;
  43
  44        sg_init_table(&dma->buf, 1);
  45
  46        if (dma_chan[chan])
  47                return -EBUSY;
  48        dma_chan[chan] = dma;
  49        return 0;
  50}
  51
  52/*
  53 * Request DMA channel
  54 *
  55 * On certain platforms, we have to allocate an interrupt as well...
  56 */
  57int request_dma(unsigned int chan, const char *device_id)
  58{
  59        dma_t *dma = dma_channel(chan);
  60        int ret;
  61
  62        if (!dma)
  63                goto bad_dma;
  64
  65        if (xchg(&dma->lock, 1) != 0)
  66                goto busy;
  67
  68        dma->device_id = device_id;
  69        dma->active    = 0;
  70        dma->invalid   = 1;
  71
  72        ret = 0;
  73        if (dma->d_ops->request)
  74                ret = dma->d_ops->request(chan, dma);
  75
  76        if (ret)
  77                xchg(&dma->lock, 0);
  78
  79        return ret;
  80
  81bad_dma:
  82        printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan);
  83        return -EINVAL;
  84
  85busy:
  86        return -EBUSY;
  87}
  88EXPORT_SYMBOL(request_dma);
  89
  90/*
  91 * Free DMA channel
  92 *
  93 * On certain platforms, we have to free interrupt as well...
  94 */
  95void free_dma(unsigned int chan)
  96{
  97        dma_t *dma = dma_channel(chan);
  98
  99        if (!dma)
 100                goto bad_dma;
 101
 102        if (dma->active) {
 103                printk(KERN_ERR "dma%d: freeing active DMA\n", chan);
 104                dma->d_ops->disable(chan, dma);
 105                dma->active = 0;
 106        }
 107
 108        if (xchg(&dma->lock, 0) != 0) {
 109                if (dma->d_ops->free)
 110                        dma->d_ops->free(chan, dma);
 111                return;
 112        }
 113
 114        printk(KERN_ERR "dma%d: trying to free free DMA\n", chan);
 115        return;
 116
 117bad_dma:
 118        printk(KERN_ERR "dma: trying to free DMA%d\n", chan);
 119}
 120EXPORT_SYMBOL(free_dma);
 121
 122/* Set DMA Scatter-Gather list
 123 */
 124void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg)
 125{
 126        dma_t *dma = dma_channel(chan);
 127
 128        if (dma->active)
 129                printk(KERN_ERR "dma%d: altering DMA SG while "
 130                       "DMA active\n", chan);
 131
 132        dma->sg = sg;
 133        dma->sgcount = nr_sg;
 134        dma->invalid = 1;
 135}
 136EXPORT_SYMBOL(set_dma_sg);
 137
 138/* Set DMA address
 139 *
 140 * Copy address to the structure, and set the invalid bit
 141 */
 142void __set_dma_addr (unsigned int chan, void *addr)
 143{
 144        dma_t *dma = dma_channel(chan);
 145
 146        if (dma->active)
 147                printk(KERN_ERR "dma%d: altering DMA address while "
 148                       "DMA active\n", chan);
 149
 150        dma->sg = NULL;
 151        dma->addr = addr;
 152        dma->invalid = 1;
 153}
 154EXPORT_SYMBOL(__set_dma_addr);
 155
 156/* Set DMA byte count
 157 *
 158 * Copy address to the structure, and set the invalid bit
 159 */
 160void set_dma_count (unsigned int chan, unsigned long count)
 161{
 162        dma_t *dma = dma_channel(chan);
 163
 164        if (dma->active)
 165                printk(KERN_ERR "dma%d: altering DMA count while "
 166                       "DMA active\n", chan);
 167
 168        dma->sg = NULL;
 169        dma->count = count;
 170        dma->invalid = 1;
 171}
 172EXPORT_SYMBOL(set_dma_count);
 173
 174/* Set DMA direction mode
 175 */
 176void set_dma_mode (unsigned int chan, unsigned int mode)
 177{
 178        dma_t *dma = dma_channel(chan);
 179
 180        if (dma->active)
 181                printk(KERN_ERR "dma%d: altering DMA mode while "
 182                       "DMA active\n", chan);
 183
 184        dma->dma_mode = mode;
 185        dma->invalid = 1;
 186}
 187EXPORT_SYMBOL(set_dma_mode);
 188
 189/* Enable DMA channel
 190 */
 191void enable_dma (unsigned int chan)
 192{
 193        dma_t *dma = dma_channel(chan);
 194
 195        if (!dma->lock)
 196                goto free_dma;
 197
 198        if (dma->active == 0) {
 199                dma->active = 1;
 200                dma->d_ops->enable(chan, dma);
 201        }
 202        return;
 203
 204free_dma:
 205        printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
 206        BUG();
 207}
 208EXPORT_SYMBOL(enable_dma);
 209
 210/* Disable DMA channel
 211 */
 212void disable_dma (unsigned int chan)
 213{
 214        dma_t *dma = dma_channel(chan);
 215
 216        if (!dma->lock)
 217                goto free_dma;
 218
 219        if (dma->active == 1) {
 220                dma->active = 0;
 221                dma->d_ops->disable(chan, dma);
 222        }
 223        return;
 224
 225free_dma:
 226        printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan);
 227        BUG();
 228}
 229EXPORT_SYMBOL(disable_dma);
 230
 231/*
 232 * Is the specified DMA channel active?
 233 */
 234int dma_channel_active(unsigned int chan)
 235{
 236        dma_t *dma = dma_channel(chan);
 237        return dma->active;
 238}
 239EXPORT_SYMBOL(dma_channel_active);
 240
 241void set_dma_page(unsigned int chan, char pagenr)
 242{
 243        printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan);
 244}
 245EXPORT_SYMBOL(set_dma_page);
 246
 247void set_dma_speed(unsigned int chan, int cycle_ns)
 248{
 249        dma_t *dma = dma_channel(chan);
 250        int ret = 0;
 251
 252        if (dma->d_ops->setspeed)
 253                ret = dma->d_ops->setspeed(chan, dma, cycle_ns);
 254        dma->speed = ret;
 255}
 256EXPORT_SYMBOL(set_dma_speed);
 257
 258int get_dma_residue(unsigned int chan)
 259{
 260        dma_t *dma = dma_channel(chan);
 261        int ret = 0;
 262
 263        if (dma->d_ops->residue)
 264                ret = dma->d_ops->residue(chan, dma);
 265
 266        return ret;
 267}
 268EXPORT_SYMBOL(get_dma_residue);
 269
 270#ifdef CONFIG_PROC_FS
 271static int proc_dma_show(struct seq_file *m, void *v)
 272{
 273        int i;
 274
 275        for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
 276                dma_t *dma = dma_channel(i);
 277                if (dma && dma->lock)
 278                        seq_printf(m, "%2d: %s\n", i, dma->device_id);
 279        }
 280        return 0;
 281}
 282
 283static int proc_dma_open(struct inode *inode, struct file *file)
 284{
 285        return single_open(file, proc_dma_show, NULL);
 286}
 287
 288static const struct file_operations proc_dma_operations = {
 289        .open           = proc_dma_open,
 290        .read           = seq_read,
 291        .llseek         = seq_lseek,
 292        .release        = single_release,
 293};
 294
 295static int __init proc_dma_init(void)
 296{
 297        proc_create("dma", 0, NULL, &proc_dma_operations);
 298        return 0;
 299}
 300
 301__initcall(proc_dma_init);
 302#endif
 303