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 
22 X86IsaDma X86IsaDma::m_Instance;
23 
25  uint8_t channel, uint8_t mode, size_t length, uintptr_t addr)
26 {
28  // NOTICE("X86IsaDma::initRead(" << channel << ", " << mode << ", " <<
29  // length << ", " << addr << ")");
30 
31  // The DMA chip will transfer one extra byte... So compensate.
32  length--;
33 
34  // Setup the internal state
35  if (!internalSetup(channel, length, addr))
36  {
37  NOTICE("Internal setup failed");
38  return false;
39  }
40 
41  // Mask our DMA channel
42  size_t port = 0, port2 = 0;
43  if (channel < 4)
44  {
45  port = SlaveChip::ChannelMask;
46  port2 = SlaveChip::Mode;
47  }
48  else
49  {
50  port = MasterChip::ChannelMask;
51  port2 = MasterChip::Mode;
52  }
53  m_Io.write8(0x4 | (channel & 0x3), port);
54 
55  // Send the... command?
56  uint8_t modeReg = 0;
57  modeReg |= channel & 0x3;
58  modeReg |= (mode & 0x0C); // Transfer type
59  modeReg |= (mode & 0xC0);
60  m_Io.write8(modeReg, port2);
61 
62  // Unmask the channel
63  m_Io.write8(channel & 0x3, port);
64 
65  // Successfully set up the transfer
66  return true;
67 }
68 
69 void X86IsaDma::resetFlipFlop(uint8_t chan)
70 {
71  if (chan < 4)
72  m_Io.write8(0xff, SlaveChip::ByteWord);
73  else
74  m_Io.write8(0xff, MasterChip::ByteWord);
75 }
76 
77 void X86IsaDma::resetHard(uint8_t chan)
78 {
79  if (chan < 4)
80  m_Io.write8(0xff, SlaveChip::Intermediate);
81  else
82  m_Io.write8(0xff, MasterChip::Intermediate);
83 }
84 
85 void X86IsaDma::unmaskAll()
86 {
87  m_Io.write8(0xff, 0xdc);
88 }
89 
90 bool X86IsaDma::internalSetup(uint8_t channel, size_t length, uintptr_t addr)
91 {
92  // Some channels are not supposed to be used...
93  if (channel == 0 || channel == 4)
94  return false;
95 
96  // May only read up to 64kb of data
97  if (length > 0x10000)
98  return false;
99 
100  // Master and slave chips have different registers, as do different
101  // channels. This helps keep things clean.
102  size_t port = 0, port2 = 0;
103 
104  // Mask the channel we're going to use
105  if (channel < 4)
106  port = SlaveChip::ChannelMask;
107  else
108  port = MasterChip::ChannelMask;
109  m_Io.write8(0x4 | (channel & 0x3), port);
110 
111  // Reset the flip-flop (16-bit transfer coming)
112  resetFlipFlop(channel);
113 
114  // Grab the address register port
115  if (channel == 1)
116  {
117  port = SlaveChip::AddressChannel1_5;
118  port2 = SlaveChip::CountChannel1_5;
119  }
120  else if (channel == 2)
121  {
122  port = SlaveChip::AddressChannel2_6;
123  port2 = SlaveChip::CountChannel2_6;
124  }
125  else if (channel == 3)
126  {
127  port = SlaveChip::AddressChannel3_7;
128  port2 = SlaveChip::CountChannel3_7;
129  }
130  else if (channel == 5)
131  {
132  port = MasterChip::AddressChannel1_5;
133  port2 = MasterChip::CountChannel1_5;
134  }
135  else if (channel == 6)
136  {
137  port = MasterChip::AddressChannel2_6;
138  port2 = MasterChip::CountChannel2_6;
139  }
140  else if (channel == 7)
141  {
142  port = MasterChip::AddressChannel3_7;
143  port2 = MasterChip::CountChannel3_7;
144  }
145  else
146  return false;
147 
148  // Write first 16 bytes of the address
149  m_Io.write8(addr & 0xFF, port);
150  m_Io.write8((addr >> 8) & 0xFF, port);
151 
152  // Reset the flip-flop (another 16-bit transfer coming)
153  resetFlipFlop(channel);
154 
155  // Size of the buffer
156  m_Io.write8(length & 0xFF, port2);
157  m_Io.write8((length >> 8) & 0xFF, port2);
158 
159  // Page register port
160  if (channel == 1)
161  port = PageRegisters::Channel1;
162  else if (channel == 2)
163  port = PageRegisters::Channel2;
164  else if (channel == 3)
165  port = PageRegisters::Channel3;
166  else if (channel == 5)
167  port = PageRegisters::Channel5;
168  else if (channel == 6)
169  port = PageRegisters::Channel6;
170  else if (channel == 7)
171  port = PageRegisters::Channel7;
172  else
173  FATAL("X86 ISA DMA: Somehow channel is zero or four - impossible!");
174 
175  // External page register (nth 64k block)
176  uint8_t extPageReg = addr / 0x10000;
177  m_Io.write8(extPageReg, port);
178 
179  // Unmask the channel we've used
180  if (channel < 4)
181  port = SlaveChip::ChannelMask;
182  else
183  port = MasterChip::ChannelMask;
184  m_Io.write8(channel & 0x3, port);
185 
186  // Success!
187  return true;
188 }
virtual bool initTransfer(uint8_t channel, uint8_t mode, size_t length, uintptr_t addr)
Initialises an operation.
Definition: X86IsaDma.cc:24
#define NOTICE(text)
Definition: Log.h:74
#define FATAL(text)
Definition: Log.h:89
virtual void write8(uint8_t value, size_t offset=0)