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 26 DEFINE_RAW_SPINLOCK(dma_spin_lock); 27 EXPORT_SYMBOL(dma_spin_lock); 28 29 static dma_t *dma_chan[MAX_DMA_CHANNELS]; 30 31 static 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 39 int __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 */ 57 int 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 81 bad_dma: 82 pr_err("dma: trying to allocate DMA%d\n", chan); 83 return -EINVAL; 84 85 busy: 86 return -EBUSY; 87 } 88 EXPORT_SYMBOL(request_dma); 89 90 /* 91 * Free DMA channel 92 * 93 * On certain platforms, we have to free interrupt as well... 94 */ 95 void 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 117 bad_dma: 118 pr_err("dma: trying to free DMA%d\n", chan); 119 } 120 EXPORT_SYMBOL(free_dma); 121 122 /* Set DMA Scatter-Gather list 123 */ 124 void 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 } 135 EXPORT_SYMBOL(set_dma_sg); 136 137 /* Set DMA address 138 * 139 * Copy address to the structure, and set the invalid bit 140 */ 141 void __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 } 152 EXPORT_SYMBOL(__set_dma_addr); 153 154 /* Set DMA byte count 155 * 156 * Copy address to the structure, and set the invalid bit 157 */ 158 void 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 } 169 EXPORT_SYMBOL(set_dma_count); 170 171 /* Set DMA direction mode 172 */ 173 void 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 } 183 EXPORT_SYMBOL(set_dma_mode); 184 185 /* Enable DMA channel 186 */ 187 void 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 200 free_dma: 201 pr_err("dma%d: trying to enable free DMA\n", chan); 202 BUG(); 203 } 204 EXPORT_SYMBOL(enable_dma); 205 206 /* Disable DMA channel 207 */ 208 void 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 221 free_dma: 222 pr_err("dma%d: trying to disable free DMA\n", chan); 223 BUG(); 224 } 225 EXPORT_SYMBOL(disable_dma); 226 227 /* 228 * Is the specified DMA channel active? 229 */ 230 int dma_channel_active(unsigned int chan) 231 { 232 dma_t *dma = dma_channel(chan); 233 return dma->active; 234 } 235 EXPORT_SYMBOL(dma_channel_active); 236 237 void set_dma_page(unsigned int chan, char pagenr) 238 { 239 pr_err("dma%d: trying to set_dma_page\n", chan); 240 } 241 EXPORT_SYMBOL(set_dma_page); 242 243 void 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 } 252 EXPORT_SYMBOL(set_dma_speed); 253 254 int 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 } 264 EXPORT_SYMBOL(get_dma_residue); 265 266 #ifdef CONFIG_PROC_FS 267 static 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 279 static int __init proc_dma_init(void) 280 { 281 proc_create_single("dma", 0, NULL, proc_dma_show); 282 return 0; 283 } 284 285 __initcall(proc_dma_init); 286 #endif 287