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_RAW_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 pr_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 pr_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 pr_err("dma%d: trying to free free DMA\n", chan); 115 return; 116 117bad_dma: 118 pr_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 pr_err("dma%d: altering DMA SG while DMA active\n", chan); 130 131 dma->sg = sg; 132 dma->sgcount = nr_sg; 133 dma->invalid = 1; 134} 135EXPORT_SYMBOL(set_dma_sg); 136 137/* Set DMA address 138 * 139 * Copy address to the structure, and set the invalid bit 140 */ 141void __set_dma_addr (unsigned int chan, void *addr) 142{ 143 dma_t *dma = dma_channel(chan); 144 145 if (dma->active) 146 pr_err("dma%d: altering DMA address while DMA active\n", chan); 147 148 dma->sg = NULL; 149 dma->addr = addr; 150 dma->invalid = 1; 151} 152EXPORT_SYMBOL(__set_dma_addr); 153 154/* Set DMA byte count 155 * 156 * Copy address to the structure, and set the invalid bit 157 */ 158void set_dma_count (unsigned int chan, unsigned long count) 159{ 160 dma_t *dma = dma_channel(chan); 161 162 if (dma->active) 163 pr_err("dma%d: altering DMA count while DMA active\n", chan); 164 165 dma->sg = NULL; 166 dma->count = count; 167 dma->invalid = 1; 168} 169EXPORT_SYMBOL(set_dma_count); 170 171/* Set DMA direction mode 172 */ 173void set_dma_mode (unsigned int chan, unsigned int mode) 174{ 175 dma_t *dma = dma_channel(chan); 176 177 if (dma->active) 178 pr_err("dma%d: altering DMA mode while DMA active\n", chan); 179 180 dma->dma_mode = mode; 181 dma->invalid = 1; 182} 183EXPORT_SYMBOL(set_dma_mode); 184 185/* Enable DMA channel 186 */ 187void enable_dma (unsigned int chan) 188{ 189 dma_t *dma = dma_channel(chan); 190 191 if (!dma->lock) 192 goto free_dma; 193 194 if (dma->active == 0) { 195 dma->active = 1; 196 dma->d_ops->enable(chan, dma); 197 } 198 return; 199 200free_dma: 201 pr_err("dma%d: trying to enable free DMA\n", chan); 202 BUG(); 203} 204EXPORT_SYMBOL(enable_dma); 205 206/* Disable DMA channel 207 */ 208void disable_dma (unsigned int chan) 209{ 210 dma_t *dma = dma_channel(chan); 211 212 if (!dma->lock) 213 goto free_dma; 214 215 if (dma->active == 1) { 216 dma->active = 0; 217 dma->d_ops->disable(chan, dma); 218 } 219 return; 220 221free_dma: 222 pr_err("dma%d: trying to disable free DMA\n", chan); 223 BUG(); 224} 225EXPORT_SYMBOL(disable_dma); 226 227/* 228 * Is the specified DMA channel active? 229 */ 230int dma_channel_active(unsigned int chan) 231{ 232 dma_t *dma = dma_channel(chan); 233 return dma->active; 234} 235EXPORT_SYMBOL(dma_channel_active); 236 237void set_dma_page(unsigned int chan, char pagenr) 238{ 239 pr_err("dma%d: trying to set_dma_page\n", chan); 240} 241EXPORT_SYMBOL(set_dma_page); 242 243void set_dma_speed(unsigned int chan, int cycle_ns) 244{ 245 dma_t *dma = dma_channel(chan); 246 int ret = 0; 247 248 if (dma->d_ops->setspeed) 249 ret = dma->d_ops->setspeed(chan, dma, cycle_ns); 250 dma->speed = ret; 251} 252EXPORT_SYMBOL(set_dma_speed); 253 254int get_dma_residue(unsigned int chan) 255{ 256 dma_t *dma = dma_channel(chan); 257 int ret = 0; 258 259 if (dma->d_ops->residue) 260 ret = dma->d_ops->residue(chan, dma); 261 262 return ret; 263} 264EXPORT_SYMBOL(get_dma_residue); 265 266#ifdef CONFIG_PROC_FS 267static int proc_dma_show(struct seq_file *m, void *v) 268{ 269 int i; 270 271 for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) { 272 dma_t *dma = dma_channel(i); 273 if (dma && dma->lock) 274 seq_printf(m, "%2d: %s\n", i, dma->device_id); 275 } 276 return 0; 277} 278 279static int proc_dma_open(struct inode *inode, struct file *file) 280{ 281 return single_open(file, proc_dma_show, NULL); 282} 283 284static const struct file_operations proc_dma_operations = { 285 .open = proc_dma_open, 286 .read = seq_read, 287 .llseek = seq_lseek, 288 .release = single_release, 289}; 290 291static int __init proc_dma_init(void) 292{ 293 proc_create("dma", 0, NULL, &proc_dma_operations); 294 return 0; 295} 296 297__initcall(proc_dma_init); 298#endif 299