The Pedigree Project 0.1
X86IsaDma.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "X86IsaDma.h"
21
22X86IsaDma X86IsaDma::m_Instance;
23
24bool X86IsaDma::initTransfer(uint8_t channel, uint8_t mode, size_t length, uintptr_t addr) {
26 // NOTICE("X86IsaDma::initRead(" << channel << ", " << mode << ", " <<
27 // length << ", " << addr << ")");
28
29 // The DMA chip will transfer one extra byte... So compensate.
30 length--;
31
32 // Setup the internal state
33 if (!internalSetup(channel, length, addr)) {
34 NOTICE("Internal setup failed");
35 return false;
36 }
37
38 // Mask our DMA channel
39 size_t port = 0, port2 = 0;
40 if (channel < 4) {
41 port = SlaveChip::ChannelMask;
42 port2 = SlaveChip::Mode;
43 } else {
44 port = MasterChip::ChannelMask;
45 port2 = MasterChip::Mode;
46 }
47 m_Io.write8(0x4 | (channel & 0x3), port);
48
49 // Send the... command?
50 uint8_t modeReg = 0;
51 modeReg |= channel & 0x3;
52 modeReg |= (mode & 0x0C); // Transfer type
53 modeReg |= (mode & 0xC0);
54 m_Io.write8(modeReg, port2);
55
56 // Unmask the channel
57 m_Io.write8(channel & 0x3, port);
58
59 // Successfully set up the transfer
60 return true;
61}
62
63void X86IsaDma::resetFlipFlop(uint8_t chan) {
64 if (chan < 4)
65 m_Io.write8(0xff, SlaveChip::ByteWord);
66 else
67 m_Io.write8(0xff, MasterChip::ByteWord);
68}
69
70void X86IsaDma::resetHard(uint8_t chan) {
71 if (chan < 4)
72 m_Io.write8(0xff, SlaveChip::Intermediate);
73 else
74 m_Io.write8(0xff, MasterChip::Intermediate);
75}
76
77void X86IsaDma::unmaskAll() {
78 m_Io.write8(0xff, 0xdc);
79}
80
81bool X86IsaDma::internalSetup(uint8_t channel, size_t length, uintptr_t addr) {
82 // Some channels are not supposed to be used...
83 if (channel == 0 || channel == 4)
84 return false;
85
86 // May only read up to 64kb of data
87 if (length > 0x10000)
88 return false;
89
90 // Master and slave chips have different registers, as do different
91 // channels. This helps keep things clean.
92 size_t port = 0, port2 = 0;
93
94 // Mask the channel we're going to use
95 if (channel < 4)
96 port = SlaveChip::ChannelMask;
97 else
98 port = MasterChip::ChannelMask;
99 m_Io.write8(0x4 | (channel & 0x3), port);
100
101 // Reset the flip-flop (16-bit transfer coming)
102 resetFlipFlop(channel);
103
104 // Grab the address register port
105 if (channel == 1) {
106 port = SlaveChip::AddressChannel1_5;
107 port2 = SlaveChip::CountChannel1_5;
108 } else if (channel == 2) {
109 port = SlaveChip::AddressChannel2_6;
110 port2 = SlaveChip::CountChannel2_6;
111 } else if (channel == 3) {
112 port = SlaveChip::AddressChannel3_7;
113 port2 = SlaveChip::CountChannel3_7;
114 } else if (channel == 5) {
115 port = MasterChip::AddressChannel1_5;
116 port2 = MasterChip::CountChannel1_5;
117 } else if (channel == 6) {
118 port = MasterChip::AddressChannel2_6;
119 port2 = MasterChip::CountChannel2_6;
120 } else if (channel == 7) {
121 port = MasterChip::AddressChannel3_7;
122 port2 = MasterChip::CountChannel3_7;
123 } else
124 return false;
125
126 // Write first 16 bytes of the address
127 m_Io.write8(addr & 0xFF, port);
128 m_Io.write8((addr >> 8) & 0xFF, port);
129
130 // Reset the flip-flop (another 16-bit transfer coming)
131 resetFlipFlop(channel);
132
133 // Size of the buffer
134 m_Io.write8(length & 0xFF, port2);
135 m_Io.write8((length >> 8) & 0xFF, port2);
136
137 // Page register port
138 if (channel == 1)
139 port = PageRegisters::Channel1;
140 else if (channel == 2)
141 port = PageRegisters::Channel2;
142 else if (channel == 3)
143 port = PageRegisters::Channel3;
144 else if (channel == 5)
145 port = PageRegisters::Channel5;
146 else if (channel == 6)
147 port = PageRegisters::Channel6;
148 else if (channel == 7)
149 port = PageRegisters::Channel7;
150 else
151 FATAL("X86 ISA DMA: Somehow channel is zero or four - impossible!");
152
153 // External page register (nth 64k block)
154 uint8_t extPageReg = addr / 0x10000;
155 m_Io.write8(extPageReg, port);
156
157 // Unmask the channel we've used
158 if (channel < 4)
159 port = SlaveChip::ChannelMask;
160 else
161 port = MasterChip::ChannelMask;
162 m_Io.write8(channel & 0x3, port);
163
164 // Success!
165 return true;
166}
virtual void write8(uint8_t value, size_t offset=0)
virtual bool initTransfer(uint8_t channel, uint8_t mode, size_t length, uintptr_t addr)
Initialises an operation.
Definition X86IsaDma.cc:24