gem5  v20.1.0.0
i8042.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "dev/x86/i8042.hh"
30 
31 #include "base/bitunion.hh"
32 #include "base/trace.hh"
33 #include "debug/I8042.hh"
34 #include "mem/packet.hh"
35 #include "mem/packet_access.hh"
36 
42 // The 8042 has a whopping 32 bytes of internal RAM.
43 const uint8_t RamSize = 32;
44 const uint8_t NumOutputBits = 14;
45 
46 
48  : BasicPioDevice(p, 0), // pioSize arg is dummy value... not used
49  latency(p->pio_latency),
50  dataPort(p->data_port), commandPort(p->command_port),
51  statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand),
52  mouse(p->mouse), keyboard(p->keyboard)
53 {
54  fatal_if(!mouse, "The i8042 model requires a mouse instance");
55  fatal_if(!keyboard, "The i8042 model requires a keyboard instance");
56 
57  statusReg.passedSelfTest = 1;
58  statusReg.commandLast = 1;
59  statusReg.keyboardUnlocked = 1;
60 
61  commandByte.convertScanCodes = 1;
62  commandByte.passedSelfTest = 1;
63  commandByte.keyboardFullInt = 1;
64 
65  for (int i = 0; i < p->port_keyboard_int_pin_connection_count; i++) {
66  keyboardIntPin.push_back(new IntSourcePin<I8042>(
67  csprintf("%s.keyboard_int_pin[%d]", name(), i), i, this));
68  }
69  for (int i = 0; i < p->port_mouse_int_pin_connection_count; i++) {
70  mouseIntPin.push_back(new IntSourcePin<I8042>(
71  csprintf("%s.mouse_int_pin[%d]", name(), i), i, this));
72  }
73 }
74 
75 
78 {
79  AddrRangeList ranges;
80  // TODO: Are these really supposed to be a single byte and not 4?
81  ranges.push_back(RangeSize(dataPort, 1));
82  ranges.push_back(RangeSize(commandPort, 1));
83  return ranges;
84 }
85 
86 void
87 X86ISA::I8042::writeData(uint8_t newData, bool mouse)
88 {
89  DPRINTF(I8042, "Set data %#02x.\n", newData);
90  dataReg = newData;
91  statusReg.outputFull = 1;
92  statusReg.mouseOutputFull = (mouse ? 1 : 0);
93  if (!mouse && commandByte.keyboardFullInt) {
94  DPRINTF(I8042, "Sending keyboard interrupt.\n");
95  for (auto *wire: keyboardIntPin) {
96  wire->raise();
97  //This is a hack
98  wire->lower();
99  }
100  } else if (mouse && commandByte.mouseFullInt) {
101  DPRINTF(I8042, "Sending mouse interrupt.\n");
102  for (auto *wire: mouseIntPin) {
103  wire->raise();
104  //This is a hack
105  wire->lower();
106  }
107  }
108 }
109 
110 uint8_t
112 {
113  uint8_t data = dataReg;
114  statusReg.outputFull = 0;
115  statusReg.mouseOutputFull = 0;
116  if (keyboard->hostDataAvailable()) {
117  writeData(keyboard->hostRead(), false);
118  } else if (mouse->hostDataAvailable()) {
119  writeData(mouse->hostRead(), true);
120  }
121  return data;
122 }
123 
124 Tick
126 {
127  assert(pkt->getSize() == 1);
128  Addr addr = pkt->getAddr();
129  if (addr == dataPort) {
130  uint8_t data = readDataOut();
131  //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
132  pkt->setLE<uint8_t>(data);
133  } else if (addr == commandPort) {
134  //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
135  pkt->setLE<uint8_t>((uint8_t)statusReg);
136  } else {
137  panic("Read from unrecognized port %#x.\n", addr);
138  }
139  pkt->makeAtomicResponse();
140  return latency;
141 }
142 
143 Tick
145 {
146  assert(pkt->getSize() == 1);
147  Addr addr = pkt->getAddr();
148  uint8_t data = pkt->getLE<uint8_t>();
149  if (addr == dataPort) {
150  statusReg.commandLast = 0;
151  switch (lastCommand) {
152  case NoCommand:
153  keyboard->hostWrite(data);
154  if (keyboard->hostDataAvailable())
155  writeData(keyboard->hostRead(), false);
156  break;
157  case WriteToMouse:
158  mouse->hostWrite(data);
159  if (mouse->hostDataAvailable())
160  writeData(mouse->hostRead(), true);
161  break;
162  case WriteCommandByte:
163  commandByte = data;
164  DPRINTF(I8042, "Got data %#02x for \"Write "
165  "command byte\" command.\n", data);
166  statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
167  break;
168  case WriteMouseOutputBuff:
169  DPRINTF(I8042, "Got data %#02x for \"Write "
170  "mouse output buffer\" command.\n", data);
171  writeData(data, true);
172  break;
173  case WriteKeyboardOutputBuff:
174  DPRINTF(I8042, "Got data %#02x for \"Write "
175  "keyboad output buffer\" command.\n", data);
176  writeData(data, false);
177  break;
178  case WriteOutputPort:
179  DPRINTF(I8042, "Got data %#02x for \"Write "
180  "output port\" command.\n", data);
181  panic_if(bits(data, 0) != 1, "Reset bit should be 1");
182  // Safe to ignore otherwise
183  break;
184  default:
185  panic("Data written for unrecognized "
186  "command %#02x\n", lastCommand);
187  }
188  lastCommand = NoCommand;
189  } else if (addr == commandPort) {
190  DPRINTF(I8042, "Got command %#02x.\n", data);
191  statusReg.commandLast = 1;
192  // These purposefully leave off the first byte of the controller RAM
193  // so it can be handled specially.
194  if (data > ReadControllerRamBase &&
195  data < ReadControllerRamBase + RamSize) {
196  panic("Attempted to use i8042 read controller RAM command to "
197  "get byte %d.\n", data - ReadControllerRamBase);
198  } else if (data > WriteControllerRamBase &&
199  data < WriteControllerRamBase + RamSize) {
200  panic("Attempted to use i8042 read controller RAM command to "
201  "get byte %d.\n", data - ReadControllerRamBase);
202  } else if (data >= PulseOutputBitBase &&
203  data < PulseOutputBitBase + NumOutputBits) {
204  panic("Attempted to use i8042 pulse output bit command to "
205  "to pulse bit %d.\n", data - PulseOutputBitBase);
206  }
207  switch (data) {
208  case GetCommandByte:
209  DPRINTF(I8042, "Getting command byte.\n");
210  writeData(commandByte);
211  break;
212  case WriteCommandByte:
213  DPRINTF(I8042, "Setting command byte.\n");
214  lastCommand = WriteCommandByte;
215  break;
216  case CheckForPassword:
217  panic("i8042 \"Check for password\" command not implemented.\n");
218  case LoadPassword:
219  panic("i8042 \"Load password\" command not implemented.\n");
220  case CheckPassword:
221  panic("i8042 \"Check password\" command not implemented.\n");
222  case DisableMouse:
223  DPRINTF(I8042, "Disabling mouse at controller.\n");
224  commandByte.disableMouse = 1;
225  break;
226  case EnableMouse:
227  DPRINTF(I8042, "Enabling mouse at controller.\n");
228  commandByte.disableMouse = 0;
229  break;
230  case TestMouse:
231  panic("i8042 \"Test mouse\" command not implemented.\n");
232  case SelfTest:
233  panic("i8042 \"Self test\" command not implemented.\n");
234  case InterfaceTest:
235  panic("i8042 \"Interface test\" command not implemented.\n");
236  case DiagnosticDump:
237  panic("i8042 \"Diagnostic dump\" command not implemented.\n");
238  case DisableKeyboard:
239  DPRINTF(I8042, "Disabling keyboard at controller.\n");
240  commandByte.disableKeyboard = 1;
241  break;
242  case EnableKeyboard:
243  DPRINTF(I8042, "Enabling keyboard at controller.\n");
244  commandByte.disableKeyboard = 0;
245  break;
246  case ReadInputPort:
247  panic("i8042 \"Read input port\" command not implemented.\n");
248  case ContinuousPollLow:
249  panic("i8042 \"Continuous poll low\" command not implemented.\n");
250  case ContinuousPollHigh:
251  panic("i8042 \"Continuous poll high\" command not implemented.\n");
252  case ReadOutputPort:
253  panic("i8042 \"Read output port\" command not implemented.\n");
254  case WriteOutputPort:
255  lastCommand = WriteOutputPort;
256  break;
257  case WriteKeyboardOutputBuff:
258  lastCommand = WriteKeyboardOutputBuff;
259  break;
260  case WriteMouseOutputBuff:
261  DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
262  lastCommand = WriteMouseOutputBuff;
263  break;
264  case WriteToMouse:
265  DPRINTF(I8042, "Expecting mouse command.\n");
266  lastCommand = WriteToMouse;
267  break;
268  case DisableA20:
269  panic("i8042 \"Disable A20\" command not implemented.\n");
270  case EnableA20:
271  panic("i8042 \"Enable A20\" command not implemented.\n");
272  case ReadTestInputs:
273  panic("i8042 \"Read test inputs\" command not implemented.\n");
274  case SystemReset:
275  panic("i8042 \"System reset\" command not implemented.\n");
276  default:
277  warn("Write to unknown i8042 "
278  "(keyboard controller) command port.\n");
279  }
280  } else {
281  panic("Write to unrecognized port %#x.\n", addr);
282  }
283  pkt->makeAtomicResponse();
284  return latency;
285 }
286 
287 void
289 {
290  SERIALIZE_SCALAR(dataPort);
291  SERIALIZE_SCALAR(commandPort);
292  SERIALIZE_SCALAR(statusReg);
293  SERIALIZE_SCALAR(commandByte);
294  SERIALIZE_SCALAR(dataReg);
295  SERIALIZE_SCALAR(lastCommand);
296 }
297 
298 void
300 {
301  UNSERIALIZE_SCALAR(dataPort);
302  UNSERIALIZE_SCALAR(commandPort);
303  UNSERIALIZE_SCALAR(statusReg);
304  UNSERIALIZE_SCALAR(commandByte);
305  UNSERIALIZE_SCALAR(dataReg);
306  UNSERIALIZE_SCALAR(lastCommand);
307 }
308 
310 I8042Params::create()
311 {
312  return new X86ISA::I8042(this);
313 }
Packet::makeAtomicResponse
void makeAtomicResponse()
Definition: packet.hh:1016
warn
#define warn(...)
Definition: logging.hh:239
data
const char data[]
Definition: circlebuf.test.cc:42
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:754
X86ISA::I8042::I8042
I8042(Params *p)
Definition: i8042.cc:47
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
IntSourcePin
Definition: intpin.hh:109
X86ISA::I8042::readDataOut
uint8_t readDataOut()
Definition: i8042.cc:111
X86ISA::I8042::keyboardIntPin
std::vector< IntSourcePin< I8042 > * > keyboardIntPin
Definition: i8042.hh:110
X86ISA::I8042::statusReg
StatusReg statusReg
Definition: i8042.hh:101
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
X86ISA::I8042::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8042.cc:288
Packet::getSize
unsigned getSize() const
Definition: packet.hh:764
i8042.hh
packet.hh
X86ISA::I8042::keyboard
PS2Device * keyboard
Definition: i8042.hh:113
X86ISA::I8042::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8042.cc:299
cp
Definition: cprintf.cc:40
X86ISA::I8042::write
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:144
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
X86ISA::I8042::getAddrRanges
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: i8042.cc:77
X86ISA::I8042::writeData
void writeData(uint8_t newData, bool mouse=false)
Definition: i8042.cc:87
X86ISA::I8042
Definition: i8042.hh:42
bitunion.hh
RangeSize
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:638
PioDevice::Params
PioDeviceParams Params
Definition: io_device.hh:131
X86ISA::I8042::mouse
PS2Device * mouse
Definition: i8042.hh:112
X86ISA::I8042::read
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:125
X86ISA::I8042::commandByte
CommandByte commandByte
Definition: i8042.hh:102
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
packet_access.hh
X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:79
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:133
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:197
Packet::getLE
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Definition: packet_access.hh:75
X86ISA::p
Bitfield< 0 > p
Definition: pagetable.hh:151
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:257
BasicPioDevice
Definition: io_device.hh:150
X86ISA::I8042::mouseIntPin
std::vector< IntSourcePin< I8042 > * > mouseIntPin
Definition: i8042.hh:109
Packet::setLE
void setLE(T v)
Set the value in the data pointer to v as little endian.
Definition: packet_access.hh:105
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
trace.hh
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
std::list< AddrRange >
fatal_if
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:219
RamSize
const uint8_t RamSize
Note: For details on the implementation see https://wiki.osdev.org/%228042%22_PS/2_Controller.
Definition: i8042.cc:43
CheckpointIn
Definition: serialize.hh:67
csprintf
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
NumOutputBits
const uint8_t NumOutputBits
Definition: i8042.cc:44
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
bits
T bits(T val, int first, int last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:75

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17