The Pedigree Project  0.1
Ps2Controller.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 "Ps2Controller.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/machine/Controller.h"
23 #include "pedigree/kernel/machine/Device.h"
24 #include "pedigree/kernel/machine/IrqManager.h"
25 #include "pedigree/kernel/machine/Machine.h"
26 #include "pedigree/kernel/machine/Trace.h"
27 #include "pedigree/kernel/processor/IoBase.h"
28 #include "pedigree/kernel/utilities/Vector.h"
29 #include "pedigree/kernel/utilities/assert.h"
30 
31 Ps2Controller::Ps2Controller(Controller *pDev)
32  : Controller(pDev), m_pBase(0), m_bHasSecondPort(false),
33  m_FirstPortBuffer(16384), m_SecondPortBuffer(16384),
34  m_bFirstIrqEnabled(false), m_bSecondIrqEnabled(false), m_ConfigByte(0),
35  m_bDebugStateFirstIrqEnabled(false), m_bDebugStateSecondIrqEnabled(false)
36 {
37 }
38 
39 Ps2Controller::Ps2Controller()
40  : m_FirstPortBuffer(16384), m_SecondPortBuffer(16384)
41 {
42 }
43 
44 void Ps2Controller::initialise()
45 {
46  TRACE("PS2 Controller startup");
47  m_pBase = addresses()[0]->m_Io;
48  assert(m_pBase);
49 
50  TRACE("PS2: disabling devices");
51  sendCommand(0xAD); // disable all devices
52  sendCommand(0xA7);
53  m_pBase->read8(0); // clear output buffer
54 
55  TRACE("PS2: disabling IRQs");
56  m_ConfigByte = sendCommandWithResponse(0x20);
57  m_ConfigByte = (m_ConfigByte & ~0x3) |
58  0x40; // disable IRQs, leave translation enabled
59  sendCommand(0x60, m_ConfigByte);
60 
61  m_bHasSecondPort = (m_ConfigByte & (1 << 5)) != 0;
62 
63  TRACE("PS2: performing self-test");
64  uint8_t selfTestResponse = sendCommandWithResponse(0xAA);
65  NOTICE("PS/2: self-test response: " << Hex << selfTestResponse);
66 
67  // Enable both ports.
68  TRACE("PS2: enabling ports");
69  sendCommand(0xAE);
70  sendCommand(0xA8);
71 
72  // Reset all devices.
73  TRACE("PS2: resetting first device");
74  writeFirstPort(0xFF);
75  uint8_t ack, status;
76  readFirstPort(ack);
77  readFirstPort(status);
78  NOTICE("PS/2: first port reset result: " << Hex << ack << ", " << status);
79 
80  TRACE("PS2: resetting second device");
81  writeSecondPort(0xFF);
82  uint8_t extra = 0;
83  readSecondPort(ack);
84  readSecondPort(status);
85  readSecondPort(extra);
86  NOTICE(
87  "PS/2: second port reset result: " << Hex << ack << ", " << status
88  << ", " << extra);
89 
90  IrqManager &irqManager = *Machine::instance().getIrqManager();
91  m_FirstIrqId = irqManager.registerIsaIrqHandler(1, this, true);
92  if (m_FirstIrqId == 0)
93  {
94  ERROR("PS/2: failed to register first IRQ handler!");
95  }
96 
97  m_SecondIrqId = irqManager.registerIsaIrqHandler(12, this, true);
98  if (m_SecondIrqId == 0)
99  {
100  ERROR("PS/2: failed to register second IRQ handler!");
101  }
102 
103  irqManager.control(1, IrqManager::MitigationThreshold, 100);
104  irqManager.control(12, IrqManager::MitigationThreshold, 100);
105 
106  TRACE("PS2: startup complete");
107 }
108 
109 void Ps2Controller::sendCommand(uint8_t command)
110 {
111  waitForWriting();
112  m_pBase->write8(command, 4);
113 }
114 
115 void Ps2Controller::sendCommand(uint8_t command, uint8_t data)
116 {
117  sendCommand(command);
118 
119  waitForWriting();
120  m_pBase->write8(data, 0);
121 }
122 
124 {
125  sendCommand(command);
126 
128  waitForReading();
129  return m_pBase->read8(0);
130 }
131 
132 uint8_t Ps2Controller::sendCommandWithResponse(uint8_t command, uint8_t data)
133 {
134  sendCommand(command, data);
135 
137  waitForReading();
138  return m_pBase->read8(0);
139 }
140 
142 {
143  waitForWriting();
144  m_pBase->write8(byte, 0);
145 }
146 
148 {
149  sendCommand(0xD4, byte);
150 }
151 
153 {
154  return m_bHasSecondPort;
155 }
156 
157 void Ps2Controller::setIrqEnable(bool firstEnabled, bool secondEnabled)
158 {
159  IrqManager &irqManager = *Machine::instance().getIrqManager();
160 
161  // disable IRQs while we do this - polling
162  m_bFirstIrqEnabled = false;
163  m_bSecondIrqEnabled = false;
164  irqManager.enable(1, false);
165  irqManager.enable(12, false);
166 
167  // Never accidentally remove translation
168  uint8_t flagAdd = 0x40, flagRemove = ~0;
169  if (firstEnabled)
170  {
171  flagAdd |= 1;
172  }
173  else
174  {
175  flagRemove &= ~1;
176  }
177  if (secondEnabled)
178  {
179  flagAdd |= 2;
180  }
181  else
182  {
183  flagRemove &= ~2;
184  }
185 
186  m_ConfigByte = sendCommandWithResponse(0x20);
187  NOTICE("Old config byte: " << Hex << m_ConfigByte);
188  m_ConfigByte |= flagAdd;
189  m_ConfigByte &= flagRemove;
190  NOTICE("New config byte: " << Hex << m_ConfigByte);
191  sendCommand(0x60, m_ConfigByte);
192  NOTICE("completed!");
193 
194  // re-enable now that we're done here
195  m_bFirstIrqEnabled = firstEnabled;
196  irqManager.enable(1, firstEnabled);
197  m_bSecondIrqEnabled = secondEnabled;
198  irqManager.enable(12, secondEnabled);
199 }
200 
202 {
203  waitForReading();
204  return m_pBase->read8();
205 }
206 
207 uint8_t Ps2Controller::readByteNonBlock()
208 {
209  if ((m_pBase->read8(4) & 1) == 0)
210  {
211  return 0;
212  }
213  return m_pBase->read8();
214 }
215 
216 bool Ps2Controller::readFirstPort(uint8_t &byte, bool block)
217 {
218  if (!m_bFirstIrqEnabled)
219  {
220  // fall back to polling
221  byte = readByte();
222  return true;
223  }
224 
225  size_t numRead = m_FirstPortBuffer.read(&byte, 1, block);
226  return numRead > 0;
227 }
228 
229 bool Ps2Controller::readSecondPort(uint8_t &byte, bool block)
230 {
231  if (!m_bSecondIrqEnabled)
232  {
233  // fall back to polling
234  byte = readByte();
235  return true;
236  }
237 
238  size_t numRead = m_SecondPortBuffer.read(&byte, 1, block);
239  return numRead > 0;
240 }
241 
242 void Ps2Controller::setDebugState(bool debugState)
243 {
244  m_bDebugState = debugState;
245 
246  // block IRQs if going into debug state
247  IrqManager &irqManager = *Machine::instance().getIrqManager();
248  if (m_bDebugState)
249  {
250  irqManager.enable(1, false);
251  irqManager.enable(12, false);
252 
253  m_bDebugStateFirstIrqEnabled = m_bFirstIrqEnabled;
254  m_bDebugStateSecondIrqEnabled = m_bSecondIrqEnabled;
255 
256  // force using polling for setIrqEnable
257  m_bFirstIrqEnabled = false;
258  m_bSecondIrqEnabled = false;
259 
260  setIrqEnable(false, false);
261 
262  // disable mouse reports
263  if (m_bDebugStateSecondIrqEnabled)
264  {
265  uint8_t x;
266  writeSecondPort(0xF5);
267  readSecondPort(x);
268  }
269  }
270  else
271  {
272  setIrqEnable(
273  m_bDebugStateFirstIrqEnabled, m_bDebugStateSecondIrqEnabled);
274 
275  // re-enable mouse reports
276  if (m_bDebugStateSecondIrqEnabled)
277  {
278  uint8_t x;
279  writeSecondPort(0xF4);
280  readSecondPort(x);
281  }
282  }
283 }
284 
285 bool Ps2Controller::irq(irq_id_t number, InterruptState &state)
286 {
287  if (m_bDebugState)
288  {
289  return true;
290  }
291 
292  if ((m_pBase->read8(4) & 1) == 0)
293  {
294  ERROR("PS/2: IRQ #" << number << " with no pending data");
295  return true;
296  }
297 
298  uint8_t received = readByte();
299  bool ok = false;
300  size_t numWritten = 0;
301  if (number == 1)
302  {
303  if (m_bFirstIrqEnabled)
304  {
305  m_FirstPortBuffer.write(&received, 1, false);
306  ok = true;
307  }
308  }
309  else
310  {
311  if (m_bSecondIrqEnabled)
312  {
313  m_SecondPortBuffer.write(&received, 1, false);
314  ok = true;
315  }
316  }
317 
318  if (!ok)
319  {
320  ERROR("PS/2: unexpected IRQ #" << number);
321  }
322 
323 #ifdef VERBOSE_KERNEL
324  if (ok && !numWritten)
325  {
326  ERROR(
327  "PS/2: dropping byte " << Hex << received
328  << " from device, not enough buffer space");
329  }
330 #endif
331 
332  return true;
333 }
334 
335 void Ps2Controller::waitForReading()
336 {
337  // wait for controller's output buffer to empty
338  while ((m_pBase->read8(4) & 1) == 0)
339  ;
340 }
341 
342 void Ps2Controller::waitForWriting()
343 {
344  // wait for controller's input buffer to fill
345  while (m_pBase->read8(4) & 2)
346  ;
347 }
virtual bool irq(irq_id_t number, InterruptState &state)
bool hasSecondPort() const
Reports whether this PS/2 controller has two ports.
uint8_t readByte()
Reads a single byte from the PS/2 controller by polling.
uint8_t sendCommandWithResponse(uint8_t command)
Send a command to the PS/2 controller and report its response.
void writeFirstPort(uint8_t byte)
Send a byte to the first port of the PS/2 controller.
EXPORTED_PUBLIC void setIrqEnable(bool firstEnabled, bool secondEnabled)
Enables/disables IRQs for the first or second ports.
void setDebugState(bool debugState)
Sets the debug state (blocks IRQs to allow polling).
EXPORTED_PUBLIC bool readSecondPort(uint8_t &byte, bool block=true)
Reads a single byte from the second port.
bool readFirstPort(uint8_t &byte, bool block=true)
Reads a single byte from the first port.
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
#define assert(x)
Definition: assert.h:37
EXPORTED_PUBLIC void writeSecondPort(uint8_t byte)
Send a byte to the second port of the PS/2 controller.
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, bool bEdge=false)=0
#define ERROR(text)
Definition: Log.h:82
virtual bool control(uint8_t irq, ControlCode code, size_t argument)
Definition: IrqManager.cc:29
void sendCommand(uint8_t command)
Send a command to the PS/2 controller that has no response or data.