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 20 #include <asm/dma.h> 21 22 #include <asm/mach/dma.h> 23 24 DEFINE_SPINLOCK(dma_spin_lock); 25 EXPORT_SYMBOL(dma_spin_lock); 26 27 static dma_t *dma_chan[MAX_DMA_CHANNELS]; 28 29 static inline dma_t *dma_channel(unsigned int chan) 30 { 31 if (chan >= MAX_DMA_CHANNELS) 32 return NULL; 33 34 return dma_chan[chan]; 35 } 36 37 int __init isa_dma_add(unsigned int chan, dma_t *dma) 38 { 39 if (!dma->d_ops) 40 return -EINVAL; 41 42 sg_init_table(&dma->buf, 1); 43 44 if (dma_chan[chan]) 45 return -EBUSY; 46 dma_chan[chan] = dma; 47 return 0; 48 } 49 50 /* 51 * Request DMA channel 52 * 53 * On certain platforms, we have to allocate an interrupt as well... 54 */ 55 int request_dma(unsigned int chan, const char *device_id) 56 { 57 dma_t *dma = dma_channel(chan); 58 int ret; 59 60 if (!dma) 61 goto bad_dma; 62 63 if (xchg(&dma->lock, 1) != 0) 64 goto busy; 65 66 dma->device_id = device_id; 67 dma->active = 0; 68 dma->invalid = 1; 69 70 ret = 0; 71 if (dma->d_ops->request) 72 ret = dma->d_ops->request(chan, dma); 73 74 if (ret) 75 xchg(&dma->lock, 0); 76 77 return ret; 78 79 bad_dma: 80 printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan); 81 return -EINVAL; 82 83 busy: 84 return -EBUSY; 85 } 86 EXPORT_SYMBOL(request_dma); 87 88 /* 89 * Free DMA channel 90 * 91 * On certain platforms, we have to free interrupt as well... 92 */ 93 void free_dma(unsigned int chan) 94 { 95 dma_t *dma = dma_channel(chan); 96 97 if (!dma) 98 goto bad_dma; 99 100 if (dma->active) { 101 printk(KERN_ERR "dma%d: freeing active DMA\n", chan); 102 dma->d_ops->disable(chan, dma); 103 dma->active = 0; 104 } 105 106 if (xchg(&dma->lock, 0) != 0) { 107 if (dma->d_ops->free) 108 dma->d_ops->free(chan, dma); 109 return; 110 } 111 112 printk(KERN_ERR "dma%d: trying to free free DMA\n", chan); 113 return; 114 115 bad_dma: 116 printk(KERN_ERR "dma: trying to free DMA%d\n", chan); 117 } 118 EXPORT_SYMBOL(free_dma); 119 120 /* Set DMA Scatter-Gather list 121 */ 122 void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg) 123 { 124 dma_t *dma = dma_channel(chan); 125 126 if (dma->active) 127 printk(KERN_ERR "dma%d: altering DMA SG while " 128 "DMA active\n", chan); 129 130 dma->sg = sg; 131 dma->sgcount = nr_sg; 132 dma->invalid = 1; 133 } 134 EXPORT_SYMBOL(set_dma_sg); 135 136 /* Set DMA address 137 * 138 * Copy address to the structure, and set the invalid bit 139 */ 140 void __set_dma_addr (unsigned int chan, void *addr) 141 { 142 dma_t *dma = dma_channel(chan); 143 144 if (dma->active) 145 printk(KERN_ERR "dma%d: altering DMA address while " 146 "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 printk(KERN_ERR "dma%d: altering DMA count while " 164 "DMA active\n", chan); 165 166 dma->sg = NULL; 167 dma->count = count; 168 dma->invalid = 1; 169 } 170 EXPORT_SYMBOL(set_dma_count); 171 172 /* Set DMA direction mode 173 */ 174 void set_dma_mode (unsigned int chan, unsigned int mode) 175 { 176 dma_t *dma = dma_channel(chan); 177 178 if (dma->active) 179 printk(KERN_ERR "dma%d: altering DMA mode while " 180 "DMA active\n", chan); 181 182 dma->dma_mode = mode; 183 dma->invalid = 1; 184 } 185 EXPORT_SYMBOL(set_dma_mode); 186 187 /* Enable DMA channel 188 */ 189 void enable_dma (unsigned int chan) 190 { 191 dma_t *dma = dma_channel(chan); 192 193 if (!dma->lock) 194 goto free_dma; 195 196 if (dma->active == 0) { 197 dma->active = 1; 198 dma->d_ops->enable(chan, dma); 199 } 200 return; 201 202 free_dma: 203 printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan); 204 BUG(); 205 } 206 EXPORT_SYMBOL(enable_dma); 207 208 /* Disable DMA channel 209 */ 210 void disable_dma (unsigned int chan) 211 { 212 dma_t *dma = dma_channel(chan); 213 214 if (!dma->lock) 215 goto free_dma; 216 217 if (dma->active == 1) { 218 dma->active = 0; 219 dma->d_ops->disable(chan, dma); 220 } 221 return; 222 223 free_dma: 224 printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan); 225 BUG(); 226 } 227 EXPORT_SYMBOL(disable_dma); 228 229 /* 230 * Is the specified DMA channel active? 231 */ 232 int dma_channel_active(unsigned int chan) 233 { 234 dma_t *dma = dma_channel(chan); 235 return dma->active; 236 } 237 EXPORT_SYMBOL(dma_channel_active); 238 239 void set_dma_page(unsigned int chan, char pagenr) 240 { 241 printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan); 242 } 243 EXPORT_SYMBOL(set_dma_page); 244 245 void set_dma_speed(unsigned int chan, int cycle_ns) 246 { 247 dma_t *dma = dma_channel(chan); 248 int ret = 0; 249 250 if (dma->d_ops->setspeed) 251 ret = dma->d_ops->setspeed(chan, dma, cycle_ns); 252 dma->speed = ret; 253 } 254 EXPORT_SYMBOL(set_dma_speed); 255 256 int get_dma_residue(unsigned int chan) 257 { 258 dma_t *dma = dma_channel(chan); 259 int ret = 0; 260 261 if (dma->d_ops->residue) 262 ret = dma->d_ops->residue(chan, dma); 263 264 return ret; 265 } 266 EXPORT_SYMBOL(get_dma_residue); 267