/*1* linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.2*3* Written by Hennus Bergman, 1992.4*5* 1994/12/26: Changes by Alex Nash to fix a minor bug in /proc/dma.6* In the previous version the reported device could end up being wrong,7* if a device requested a DMA channel that was already in use.8* [It also happened to remove the sizeof(char *) == sizeof(int)9* assumption introduced because of those /proc/dma patches. -- Hennus]10*/11#include <linux/module.h>12#include <linux/kernel.h>13#include <linux/errno.h>14#include <linux/spinlock.h>15#include <linux/string.h>16#include <linux/seq_file.h>17#include <linux/proc_fs.h>18#include <linux/init.h>19#include <asm/dma.h>20#include <asm/system.h>21222324/* A note on resource allocation:25*26* All drivers needing DMA channels, should allocate and release them27* through the public routines `request_dma()' and `free_dma()'.28*29* In order to avoid problems, all processes should allocate resources in30* the same sequence and release them in the reverse order.31*32* So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.33* When releasing them, first release the DMA, then release the IRQ.34* If you don't, you may cause allocation requests to fail unnecessarily.35* This doesn't really matter now, but it will once we get real semaphores36* in the kernel.37*/383940DEFINE_SPINLOCK(dma_spin_lock);4142/*43* If our port doesn't define this it has no PC like DMA44*/4546#ifdef MAX_DMA_CHANNELS474849/* Channel n is busy iff dma_chan_busy[n].lock != 0.50* DMA0 used to be reserved for DRAM refresh, but apparently not any more...51* DMA4 is reserved for cascading.52*/5354struct dma_chan {55int lock;56const char *device_id;57};5859static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {60[4] = { 1, "cascade" },61};626364/**65* request_dma - request and reserve a system DMA channel66* @dmanr: DMA channel number67* @device_id: reserving device ID string, used in /proc/dma68*/69int request_dma(unsigned int dmanr, const char * device_id)70{71if (dmanr >= MAX_DMA_CHANNELS)72return -EINVAL;7374if (xchg(&dma_chan_busy[dmanr].lock, 1) != 0)75return -EBUSY;7677dma_chan_busy[dmanr].device_id = device_id;7879/* old flag was 0, now contains 1 to indicate busy */80return 0;81} /* request_dma */8283/**84* free_dma - free a reserved system DMA channel85* @dmanr: DMA channel number86*/87void free_dma(unsigned int dmanr)88{89if (dmanr >= MAX_DMA_CHANNELS) {90printk(KERN_WARNING "Trying to free DMA%d\n", dmanr);91return;92}9394if (xchg(&dma_chan_busy[dmanr].lock, 0) == 0) {95printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr);96return;97}9899} /* free_dma */100101#else102103int request_dma(unsigned int dmanr, const char *device_id)104{105return -EINVAL;106}107108void free_dma(unsigned int dmanr)109{110}111112#endif113114#ifdef CONFIG_PROC_FS115116#ifdef MAX_DMA_CHANNELS117static int proc_dma_show(struct seq_file *m, void *v)118{119int i;120121for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {122if (dma_chan_busy[i].lock) {123seq_printf(m, "%2d: %s\n", i,124dma_chan_busy[i].device_id);125}126}127return 0;128}129#else130static int proc_dma_show(struct seq_file *m, void *v)131{132seq_puts(m, "No DMA\n");133return 0;134}135#endif /* MAX_DMA_CHANNELS */136137static int proc_dma_open(struct inode *inode, struct file *file)138{139return single_open(file, proc_dma_show, NULL);140}141142static const struct file_operations proc_dma_operations = {143.open = proc_dma_open,144.read = seq_read,145.llseek = seq_lseek,146.release = single_release,147};148149static int __init proc_dma_init(void)150{151proc_create("dma", 0, NULL, &proc_dma_operations);152return 0;153}154155__initcall(proc_dma_init);156#endif157158EXPORT_SYMBOL(request_dma);159EXPORT_SYMBOL(free_dma);160EXPORT_SYMBOL(dma_spin_lock);161162163