gem5  v20.0.0.2
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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);
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;
169  DPRINTF(I8042, "Got data %#02x for \"Write "
170  "mouse output buffer\" command.\n", data);
171  writeData(data, true);
172  break;
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  }
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 &&
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");
211  break;
212  case WriteCommandByte:
213  DPRINTF(I8042, "Setting command byte.\n");
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:
256  break;
259  break;
261  DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
263  break;
264  case WriteToMouse:
265  DPRINTF(I8042, "Expecting mouse command.\n");
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 {
296 }
297 
298 void
300 {
307 }
308 
310 I8042Params::create()
311 {
312  return new X86ISA::I8042(this);
313 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
#define DPRINTF(x,...)
Definition: trace.hh:222
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:580
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8042.cc:299
std::vector< IntSourcePin< I8042 > * > mouseIntPin
Definition: i8042.hh:109
Bitfield< 7 > i
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8042.cc:288
Addr commandPort
Definition: i8042.hh:99
void hostWrite(uint8_t c)
Transmit a character from the host interface to the device.
Definition: device.cc:95
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: i8042.cc:77
uint16_t lastCommand
Definition: i8042.hh:107
PioDeviceParams Params
Definition: io_device.hh:131
PS2Device * mouse
Definition: i8042.hh:112
Definition: cprintf.cc:40
uint8_t dataReg
Definition: i8042.hh:104
StatusReg statusReg
Definition: i8042.hh:101
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition: packet.hh:730
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:770
I8042(Params *p)
Definition: i8042.cc:47
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
uint8_t readDataOut()
Definition: i8042.cc:111
CommandByte commandByte
Definition: i8042.hh:102
Addr dataPort
Definition: i8042.hh:98
void makeAtomicResponse()
Definition: packet.hh:943
uint64_t Tick
Tick count type.
Definition: types.hh:61
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:144
Addr getAddr() const
Definition: packet.hh:720
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:199
void writeData(uint8_t newData, bool mouse=false)
Definition: i8042.cc:87
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:140
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:249
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:125
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:763
virtual const std::string name() const
Definition: sim_object.hh:128
Declaration of the Packet class.
std::ostream CheckpointOut
Definition: serialize.hh:63
const uint8_t RamSize
Note: For details on the implementation see https://wiki.osdev.org/%228042%22_PS/2_Controller.
Definition: i8042.cc:43
PS2Device * keyboard
Definition: i8042.hh:113
static const uint16_t NoCommand
Definition: i8042.hh:106
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
#define warn(...)
Definition: logging.hh:208
const uint8_t NumOutputBits
Definition: i8042.cc:44
T bits(T val, int first, int last)
Extract the bitfield from position &#39;first&#39; to &#39;last&#39; (inclusive) from &#39;val&#39; and right justify it...
Definition: bitfield.hh:71
Bitfield< 0 > p
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:181
bool hostDataAvailable() const
Check if there is pending data from the PS/2 device.
Definition: device.hh:73
const char data[]
Bitfield< 3 > addr
Definition: types.hh:79
std::vector< IntSourcePin< I8042 > * > keyboardIntPin
Definition: i8042.hh:110
uint8_t hostRead()
Read a character from the device.
Definition: device.cc:87

Generated on Mon Jun 8 2020 15:45:11 for gem5 by doxygen 1.8.13