3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* Just helps in making things look cleaner. :) */
24 typedef unsigned char uchar
;
25 typedef unsigned int uint
;
27 /* Defines for accessing the upper and lower byte of an integer. */
28 #define LOW_BYTE(x) (x & 0x00FF)
29 #define HI_BYTE(x) ((x & 0xFF00) >> 8)
31 /* Quick-access registers and ports for each DMA channel. */
32 uchar MaskReg
[8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };
33 uchar ModeReg
[8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };
34 uchar ClearReg
[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };
36 uchar PagePort
[8] = { 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A };
37 uchar AddrPort
[8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };
38 uchar CountPort
[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };
40 void _dma_xfer(uchar DMA_channel
, unsigned char page
, unsigned int offset
, unsigned int length
, uchar mode
);
42 void dma_xfer(uchar channel
, unsigned long address
, unsigned int length
, unsigned char read
)
44 unsigned char page
=0, mode
=0;
45 unsigned int offset
= 0;
48 mode
= 0x48 + channel
;
50 mode
= 0x44 + channel
;
53 offset
= address
& 0xFFFF;
56 _dma_xfer(channel
, page
, offset
, length
, mode
);
60 void _dma_xfer(uchar DMA_channel
, unsigned char page
, unsigned int offset
, unsigned int length
, uchar mode
)
62 /* Don't let anyone else mess up what we're doing. */
65 /* Set up the DMA channel so we can use it. This tells the DMA */
66 /* that we're going to be using this channel. (It's masked) */
67 outportb(MaskReg
[DMA_channel
], 0x04 | DMA_channel
);
69 /* Clear any data transfers that are currently executing. */
70 outportb(ClearReg
[DMA_channel
], 0x00);
72 /* Send the specified mode to the DMA. */
73 outportb(ModeReg
[DMA_channel
], mode
);
75 /* Send the offset address. The first byte is the low base offset, the */
76 /* second byte is the high offset. */
77 outportb(AddrPort
[DMA_channel
], LOW_BYTE(offset
));
78 outportb(AddrPort
[DMA_channel
], HI_BYTE(offset
));
80 /* Send the physical page that the data lies on. */
81 outportb(PagePort
[DMA_channel
], page
);
83 /* Send the length of the data. Again, low byte first. */
84 outportb(CountPort
[DMA_channel
], LOW_BYTE(length
));
85 outportb(CountPort
[DMA_channel
], HI_BYTE(length
));
87 /* Ok, we're done. Enable the DMA channel (clear the mask). */
88 outportb(MaskReg
[DMA_channel
], DMA_channel
);
90 /* Re-enable interrupts before we leave. */