1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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]);
}
|