patch-2.1.96 linux/arch/arm/kernel/dma.c
Next file: linux/arch/arm/kernel/dma.h
Previous file: linux/arch/arm/kernel/dma-rpc.c
Back to the patch index
Back to the overall index
- Lines: 363
- Date:
Sun Apr 12 11:42:15 1998
- Orig file:
v2.1.95/linux/arch/arm/kernel/dma.c
- Orig date:
Tue Jan 20 16:39:41 1998
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c
@@ -1,199 +1,189 @@
/*
* linux/arch/arm/kernel/dma.c
*
- * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 1995-1998 Russell King
+ *
+ * Front-end to the DMA handling. You must provide the following
+ * architecture-specific routines:
+ *
+ * int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id);
+ * void arch_free_dma(dmach_t channel, dma_t *dma);
+ * void arch_enable_dma(dmach_t channel, dma_t *dma);
+ * void arch_disable_dma(dmach_t channel, dma_t *dma);
+ * int arch_get_dma_residue(dmach_t channel, dma_t *dma);
+ *
+ * Moved DMA resource allocation here...
*/
-
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/mman.h>
+#include <linux/init.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
-#define KERNEL_ARCH_DMA
#include <asm/dma.h>
-static unsigned long dma_address[8];
-static unsigned long dma_count[8];
-static char dma_direction[8] = { -1, -1, -1, -1, -1, -1, -1};
-
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
-#define DMA_PCIO
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
-#define DMA_OLD
-#endif
-
-void enable_dma (unsigned int dmanr)
-{
- switch (dmanr) {
-#ifdef DMA_PCIO
- case 2: {
- void *fiqhandler_start;
- unsigned int fiqhandler_length;
- extern void floppy_fiqsetup (unsigned long len, unsigned long addr,
- unsigned long port);
- switch (dma_direction[dmanr]) {
- case 1: {
- extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
- fiqhandler_start = &floppy_fiqin_start;
- fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
- break;
- }
- case 0: {
- extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
- fiqhandler_start = &floppy_fiqout_start;
- fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
- break;
- }
- default:
- printk ("enable_dma: dma%d not initialised\n", dmanr);
- return;
- }
- memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length);
- flush_page_to_ram(0);
- floppy_fiqsetup (dma_count[dmanr], dma_address[dmanr], (int)PCIO_FLOPPYDMABASE);
- enable_irq (64);
- return;
- }
-#endif
-#ifdef DMA_OLD
- case 0: { /* Data DMA */
- switch (dma_direction[dmanr]) {
- case 1: /* read */
- {
- extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
- extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
- unsigned long flags;
-#ifdef DEBUG
- printk("enable_dma fdc1772 data read\n");
-#endif
- save_flags(flags);
- cliIF();
-
- memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
- &fdc1772_dma_read_end - &fdc1772_dma_read);
- fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
- enable_irq (64);
- restore_flags(flags);
- }
- break;
-
- case 0: /* write */
- {
- extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end;
- extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
- unsigned long flags;
-
-#ifdef DEBUG
- printk("enable_dma fdc1772 data write\n");
-#endif
- save_flags(flags);
- cliIF();
- memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
- &fdc1772_dma_write_end - &fdc1772_dma_write);
- fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
- enable_irq (64);
-
- restore_flags(flags);
- }
- break;
- default:
- printk ("enable_dma: dma%d not initialised\n", dmanr);
- return;
- }
- }
- break;
+#include "dma.h"
- case 1: { /* Command end FIQ - actually just sets a flag */
- /* Need to build a branch at the FIQ address */
- extern void fdc1772_comendhandler(void);
- unsigned long flags;
-
- /*printk("enable_dma fdc1772 command end FIQ\n");*/
- save_flags(flags);
- cliIF();
-
- *((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */
+static dma_t dma_chan[MAX_DMA_CHANNELS];
- restore_flags(flags);
- }
- break;
-#endif
- case DMA_0:
- case DMA_1:
- case DMA_2:
- case DMA_3:
- case DMA_S0:
- case DMA_S1:
- arch_enable_dma (dmanr - DMA_0);
- break;
+/* Get dma list
+ * for /proc/dma
+ */
+int get_dma_list(char *buf)
+{
+ int i, len = 0;
- default:
- printk ("enable_dma: dma %d not supported\n", dmanr);
+ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ if (dma_chan[i].lock)
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, dma_chan[i].device_id);
}
+ return len;
}
-void set_dma_mode (unsigned int dmanr, char mode)
+/* Request DMA channel
+ *
+ * On certain platforms, we have to allocate an interrupt as well...
+ */
+int request_dma(dmach_t channel, const char *device_id)
{
- if (dmanr < 8) {
- if (mode == DMA_MODE_READ)
- dma_direction[dmanr] = 1;
- else if (mode == DMA_MODE_WRITE)
- dma_direction[dmanr] = 0;
- else
- printk ("set_dma_mode: dma%d: invalid mode %02X not supported\n",
- dmanr, mode);
- } else if (dmanr < MAX_DMA_CHANNELS)
- arch_set_dma_mode (dmanr - DMA_0, mode);
- else
- printk ("set_dma_mode: dma %d not supported\n", dmanr);
-}
-
-void set_dma_addr (unsigned int dmanr, unsigned int addr)
-{
- if (dmanr < 8)
- dma_address[dmanr] = (unsigned long)addr;
- else if (dmanr < MAX_DMA_CHANNELS)
- arch_set_dma_addr (dmanr - DMA_0, addr);
- else
- printk ("set_dma_addr: dma %d not supported\n", dmanr);
-}
-
-void set_dma_count (unsigned int dmanr, unsigned int count)
-{
- if (dmanr < 8)
- dma_count[dmanr] = (unsigned long)count;
- else if (dmanr < MAX_DMA_CHANNELS)
- arch_set_dma_count (dmanr - DMA_0, count);
- else
- printk ("set_dma_count: dma %d not supported\n", dmanr);
-}
-
-int get_dma_residue (unsigned int dmanr)
-{
- if (dmanr < 8) {
- switch (dmanr) {
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
- case 2: {
- extern int floppy_fiqresidual (void);
- return floppy_fiqresidual ();
+ if (channel < MAX_DMA_CHANNELS) {
+ int ret;
+
+ if (xchg(&dma_chan[channel].lock, 1) != 0)
+ return -EBUSY;
+
+ ret = arch_request_dma(channel, &dma_chan[channel], device_id);
+ if (!ret) {
+ dma_chan[channel].device_id = device_id;
+ dma_chan[channel].active = 0;
+ dma_chan[channel].invalid = 1;
+ } else
+ xchg(&dma_chan[channel].lock, 0);
+
+ return ret;
+ } else {
+ printk (KERN_ERR "Trying to allocate DMA%d\n", channel);
+ return -EINVAL;
+ }
+}
+
+/* Free DMA channel
+ *
+ * On certain platforms, we have to free interrupt as well...
+ */
+void free_dma(dmach_t channel)
+{
+ if (channel >= MAX_DMA_CHANNELS) {
+ printk (KERN_ERR "Trying to free DMA%d\n", channel);
+ return;
+ }
+
+ if (xchg(&dma_chan[channel].lock, 0) == 0) {
+ if (dma_chan[channel].active) {
+ printk (KERN_ERR "Freeing active DMA%d\n", channel);
+ arch_disable_dma(channel, &dma_chan[channel]);
+ dma_chan[channel].active = 0;
}
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
- case 0: {
- extern unsigned int fdc1772_bytestogo;
- return fdc1772_bytestogo;
+
+ printk (KERN_ERR "Trying to free free DMA%d\n", channel);
+ return;
+ }
+ arch_free_dma(channel, &dma_chan[channel]);
+}
+
+/* Set DMA Scatter-Gather list
+ */
+void set_dma_sg (dmach_t channel, dmasg_t *sg, int nr_sg)
+{
+ dma_chan[channel].sg = sg;
+ dma_chan[channel].sgcount = nr_sg;
+ dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA address
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_addr (dmach_t channel, unsigned long physaddr)
+{
+ if (dma_chan[channel].active)
+ printk(KERN_ERR "set_dma_addr: altering DMA%d"
+ " address while DMA active\n",
+ channel);
+
+ dma_chan[channel].sg = &dma_chan[channel].buf;
+ dma_chan[channel].sgcount = 1;
+ dma_chan[channel].buf.address = physaddr;
+ dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA byte count
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_count (dmach_t channel, unsigned long count)
+{
+ if (dma_chan[channel].active)
+ printk(KERN_ERR "set_dma_count: altering DMA%d"
+ " count while DMA active\n",
+ channel);
+
+ dma_chan[channel].sg = &dma_chan[channel].buf;
+ dma_chan[channel].sgcount = 1;
+ dma_chan[channel].buf.length = count;
+ dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA direction mode
+ */
+void set_dma_mode (dmach_t channel, dmamode_t mode)
+{
+ if (dma_chan[channel].active)
+ printk(KERN_ERR "set_dma_mode: altering DMA%d"
+ " mode while DMA active\n",
+ channel);
+
+ dma_chan[channel].dma_mode = mode;
+ dma_chan[channel].invalid = 1;
+}
+
+/* Enable DMA channel
+ */
+void enable_dma (dmach_t channel)
+{
+ if (dma_chan[channel].lock) {
+ if (dma_chan[channel].active == 0) {
+ dma_chan[channel].active = 1;
+ arch_enable_dma(channel, &dma_chan[channel]);
}
-#endif
- default:
- return -1;
+ } else
+ printk (KERN_ERR "Trying to enable free DMA%d\n", channel);
+}
+
+/* Disable DMA channel
+ */
+void disable_dma (dmach_t channel)
+{
+ if (dma_chan[channel].lock) {
+ if (dma_chan[channel].active == 1) {
+ dma_chan[channel].active = 0;
+ arch_disable_dma(channel, &dma_chan[channel]);
}
- } else if (dmanr < MAX_DMA_CHANNELS)
- return arch_dma_count (dmanr - DMA_0);
- return -1;
+ } else
+ printk (KERN_ERR "Trying to disable free DMA%d\n", channel);
+}
+
+int get_dma_residue(dmach_t channel)
+{
+ return arch_get_dma_residue(channel, &dma_chan[channel]);
+}
+
+__initfunc(void init_dma(void))
+{
+ arch_dma_init(dma_chan);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov