2 * linux/arch/arm/kernel/dma.c
4 * Copyright (C) 1995-2000 Russell King
6 * Front-end to the DMA handling. This handles the allocation/freeing
7 * of DMA channels, and provides a unified interface to the machines
10 #include <linux/module.h>
11 #include <linux/malloc.h>
12 #include <linux/sched.h>
13 #include <linux/mman.h>
14 #include <linux/init.h>
15 #include <linux/spinlock.h>
21 spinlock_t dma_spin_lock
= SPIN_LOCK_UNLOCKED
;
23 #if MAX_DMA_CHANNELS > 0
25 static dma_t dma_chan
[MAX_DMA_CHANNELS
];
28 * Get dma list for /proc/dma
30 int get_dma_list(char *buf
)
36 for (i
= 0, dma
= dma_chan
; i
< MAX_DMA_CHANNELS
; i
++, dma
++)
38 p
+= sprintf(p
, "%2d: %14s %s\n", i
,
39 dma
->d_ops
->type
, dma
->device_id
);
47 * On certain platforms, we have to allocate an interrupt as well...
49 int request_dma(dmach_t channel
, const char *device_id
)
51 dma_t
*dma
= dma_chan
+ channel
;
54 if (channel
>= MAX_DMA_CHANNELS
|| !dma
->d_ops
)
57 if (xchg(&dma
->lock
, 1) != 0)
60 dma
->device_id
= device_id
;
65 if (dma
->d_ops
->request
)
66 ret
= dma
->d_ops
->request(channel
, dma
);
74 printk(KERN_ERR
"dma: trying to allocate DMA%d\n", channel
);
84 * On certain platforms, we have to free interrupt as well...
86 void free_dma(dmach_t channel
)
88 dma_t
*dma
= dma_chan
+ channel
;
90 if (channel
>= MAX_DMA_CHANNELS
|| !dma
->d_ops
)
94 printk(KERN_ERR
"dma%d: freeing active DMA\n", channel
);
95 dma
->d_ops
->disable(channel
, dma
);
99 if (xchg(&dma
->lock
, 0) != 0) {
100 if (dma
->d_ops
->free
)
101 dma
->d_ops
->free(channel
, dma
);
105 printk(KERN_ERR
"dma%d: trying to free free DMA\n", channel
);
109 printk(KERN_ERR
"dma: trying to free DMA%d\n", channel
);
112 /* Set DMA Scatter-Gather list
114 void set_dma_sg (dmach_t channel
, dmasg_t
*sg
, int nr_sg
)
116 dma_t
*dma
= dma_chan
+ channel
;
119 dma
->sgcount
= nr_sg
;
125 * Copy address to the structure, and set the invalid bit
127 void set_dma_addr (dmach_t channel
, unsigned long physaddr
)
129 dma_t
*dma
= dma_chan
+ channel
;
132 printk(KERN_ERR
"dma%d: altering DMA address while "
133 "DMA active\n", channel
);
137 dma
->buf
.address
= physaddr
;
141 /* Set DMA byte count
143 * Copy address to the structure, and set the invalid bit
145 void set_dma_count (dmach_t channel
, unsigned long count
)
147 dma_t
*dma
= dma_chan
+ channel
;
150 printk(KERN_ERR
"dma%d: altering DMA count while "
151 "DMA active\n", channel
);
155 dma
->buf
.length
= count
;
159 /* Set DMA direction mode
161 void set_dma_mode (dmach_t channel
, dmamode_t mode
)
163 dma_t
*dma
= dma_chan
+ channel
;
166 printk(KERN_ERR
"dma%d: altering DMA mode while "
167 "DMA active\n", channel
);
169 dma
->dma_mode
= mode
;
173 /* Enable DMA channel
175 void enable_dma (dmach_t channel
)
177 dma_t
*dma
= dma_chan
+ channel
;
182 if (dma
->active
== 0) {
184 dma
->d_ops
->enable(channel
, dma
);
189 printk(KERN_ERR
"dma%d: trying to enable free DMA\n", channel
);
193 /* Disable DMA channel
195 void disable_dma (dmach_t channel
)
197 dma_t
*dma
= dma_chan
+ channel
;
202 if (dma
->active
== 1) {
204 dma
->d_ops
->disable(channel
, dma
);
209 printk(KERN_ERR
"dma%d: trying to disable free DMA\n", channel
);
213 void set_dma_page(dmach_t channel
, char pagenr
)
215 printk(KERN_ERR
"dma%d: trying to set_dma_page\n", channel
);
218 void set_dma_speed(dmach_t channel
, int cycle_ns
)
220 dma_t
*dma
= dma_chan
+ channel
;
223 if (dma
->d_ops
->setspeed
)
224 ret
= dma
->d_ops
->setspeed(channel
, dma
, cycle_ns
);
228 int get_dma_residue(dmach_t channel
)
230 dma_t
*dma
= dma_chan
+ channel
;
233 if (dma
->d_ops
->residue
)
234 ret
= dma
->d_ops
->residue(channel
, dma
);
239 void __init
init_dma(void)
241 arch_dma_init(dma_chan
);
246 int request_dma(dmach_t channel
, const char *device_id
)
251 static int no_dma(void)
256 #define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a)
257 GLOBAL_ALIAS(disable_dma
, no_dma
);
258 GLOBAL_ALIAS(enable_dma
, no_dma
);
259 GLOBAL_ALIAS(free_dma
, no_dma
);
260 GLOBAL_ALIAS(get_dma_residue
, no_dma
);
261 GLOBAL_ALIAS(get_dma_list
, no_dma
);
262 GLOBAL_ALIAS(set_dma_mode
, no_dma
);
263 GLOBAL_ALIAS(set_dma_page
, no_dma
);
264 GLOBAL_ALIAS(set_dma_count
, no_dma
);
265 GLOBAL_ALIAS(set_dma_addr
, no_dma
);
266 GLOBAL_ALIAS(set_dma_sg
, no_dma
);
267 GLOBAL_ALIAS(set_dma_speed
, no_dma
);
268 GLOBAL_ALIAS(init_dma
, no_dma
);
272 EXPORT_SYMBOL(enable_dma
);
273 EXPORT_SYMBOL(disable_dma
);
274 EXPORT_SYMBOL(set_dma_addr
);
275 EXPORT_SYMBOL(set_dma_count
);
276 EXPORT_SYMBOL(set_dma_mode
);
277 EXPORT_SYMBOL(set_dma_page
);
278 EXPORT_SYMBOL(get_dma_residue
);
279 EXPORT_SYMBOL(set_dma_sg
);
280 EXPORT_SYMBOL(set_dma_speed
);