diff options
Diffstat (limited to 'arch/arm/kernel/dma-isa.c')
-rw-r--r-- | arch/arm/kernel/dma-isa.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c new file mode 100644 index 000000000..bdf7c6147 --- /dev/null +++ b/arch/arm/kernel/dma-isa.c @@ -0,0 +1,107 @@ +/* + * arch/arm/kernel/dma-isa.c: ISA DMA primitives + * + * Copyright (C) Russell King + * + * Taken from various sources, including: + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen and John Boyd, Nov. 1992. + * arch/arm/kernel/dma-ebsa285.c + * Copyright (C) 1998 Phil Blundell + */ +#include <linux/sched.h> + +#include <asm/dma.h> +#include <asm/io.h> + +#include "dma.h" +#include "dma-isa.h" + +#define ISA_DMA_MASK 0 +#define ISA_DMA_MODE 1 +#define ISA_DMA_CLRFF 2 +#define ISA_DMA_PGHI 3 +#define ISA_DMA_PGLO 4 +#define ISA_DMA_ADDR 5 +#define ISA_DMA_COUNT 6 + +static unsigned int isa_dma_port[8][7] = { + /* MASK MODE CLRFF PAGE_HI PAGE_LO ADDR COUNT */ + { 0x0a, 0x0b, 0x0c, 0x487, 0x087, 0x00, 0x01 }, + { 0x0a, 0x0b, 0x0c, 0x483, 0x083, 0x02, 0x03 }, + { 0x0a, 0x0b, 0x0c, 0x481, 0x081, 0x04, 0x05 }, + { 0x0a, 0x0b, 0x0c, 0x482, 0x082, 0x06, 0x07 }, + { 0xd4, 0xd6, 0xd8, 0x000, 0x000, 0xc0, 0xc2 }, + { 0xd4, 0xd6, 0xd8, 0x48b, 0x08b, 0xc4, 0xc6 }, + { 0xd4, 0xd6, 0xd8, 0x489, 0x089, 0xc8, 0xca }, + { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce } +}; + +int isa_request_dma(int channel, dma_t *dma, const char *dev_name) +{ + if (channel != 4) + return 0; + + return -EINVAL; +} + +void isa_free_dma(int channel, dma_t *dma) +{ + /* nothing to do */ +} + +int isa_get_dma_residue(int channel, dma_t *dma) +{ + unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; + int count; + + count = 1 + inb(io_port) + (inb(io_port) << 8); + + return channel < 4 ? count : (count << 1); +} + +void isa_enable_dma(int channel, dma_t *dma) +{ + unsigned long address, length; + + if (dma->invalid) { + address = dma->buf.address; + length = dma->buf.length - 1; + + outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); + outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); + + if (channel >= 4) { + address >>= 1; + length = (length >> 1) & 0xfe; /* why &0xfe? */ + } + + outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); + + outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); + outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); + + outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); + outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); + + outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]); + + switch (dma->dma_mode) { + case DMA_MODE_READ: + dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length); + break; + + case DMA_MODE_WRITE: + dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length); + break; + } + dma->invalid = 0; + } + outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); +} + +void isa_disable_dma(int channel, dma_t *dma) +{ + outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); +} |