gem5  v19.0.0.0
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  * Authors: Gabe Black
29  */
30 
31 #include "dev/x86/i8042.hh"
32 
33 #include "base/bitunion.hh"
34 #include "debug/I8042.hh"
35 #include "mem/packet.hh"
36 #include "mem/packet_access.hh"
37 
43 // The 8042 has a whopping 32 bytes of internal RAM.
44 const uint8_t RamSize = 32;
45 const uint8_t NumOutputBits = 14;
46 
47 
49  : BasicPioDevice(p, 0), // pioSize arg is dummy value... not used
50  latency(p->pio_latency),
51  dataPort(p->data_port), commandPort(p->command_port),
52  statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand),
53  mouse(p->mouse), keyboard(p->keyboard)
54 {
55  fatal_if(!mouse, "The i8042 model requires a mouse instance");
56  fatal_if(!keyboard, "The i8042 model requires a keyboard instance");
57 
58  statusReg.passedSelfTest = 1;
59  statusReg.commandLast = 1;
60  statusReg.keyboardUnlocked = 1;
61 
62  commandByte.convertScanCodes = 1;
63  commandByte.passedSelfTest = 1;
64  commandByte.keyboardFullInt = 1;
65 
66  for (int i = 0; i < p->port_keyboard_int_pin_connection_count; i++) {
67  keyboardIntPin.push_back(new IntSourcePin<I8042>(
68  csprintf("%s.keyboard_int_pin[%d]", name(), i), i, this));
69  }
70  for (int i = 0; i < p->port_mouse_int_pin_connection_count; i++) {
71  mouseIntPin.push_back(new IntSourcePin<I8042>(
72  csprintf("%s.mouse_int_pin[%d]", name(), i), i, this));
73  }
74 }
75 
76 
79 {
80  AddrRangeList ranges;
81  // TODO: Are these really supposed to be a single byte and not 4?
82  ranges.push_back(RangeSize(dataPort, 1));
83  ranges.push_back(RangeSize(commandPort, 1));
84  return ranges;
85 }
86 
87 void
88 X86ISA::I8042::writeData(uint8_t newData, bool mouse)
89 {
90  DPRINTF(I8042, "Set data %#02x.\n", newData);
91  dataReg = newData;
92  statusReg.outputFull = 1;
93  statusReg.mouseOutputFull = (mouse ? 1 : 0);
94  if (!mouse && commandByte.keyboardFullInt) {
95  DPRINTF(I8042, "Sending keyboard interrupt.\n");
96  for (auto *wire: keyboardIntPin) {
97  wire->raise();
98  //This is a hack
99  wire->lower();
100  }
101  } else if (mouse && commandByte.mouseFullInt) {
102  DPRINTF(I8042, "Sending mouse interrupt.\n");
103  for (auto *wire: mouseIntPin) {
104  wire->raise();
105  //This is a hack
106  wire->lower();
107  }
108  }
109 }
110 
111 uint8_t
113 {
114  uint8_t data = dataReg;
115  statusReg.outputFull = 0;
116  statusReg.mouseOutputFull = 0;
117  if (keyboard->hostDataAvailable()) {
118  writeData(keyboard->hostRead(), false);
119  } else if (mouse->hostDataAvailable()) {
120  writeData(mouse->hostRead(), true);
121  }
122  return data;
123 }
124 
125 Tick
127 {
128  assert(pkt->getSize() == 1);
129  Addr addr = pkt->getAddr();
130  if (addr == dataPort) {
131  uint8_t data = readDataOut();
132  //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
133  pkt->setLE<uint8_t>(data);
134  } else if (addr == commandPort) {
135  //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
136  pkt->setLE<uint8_t>((uint8_t)statusReg);
137  } else {
138  panic("Read from unrecognized port %#x.\n", addr);
139  }
140  pkt->makeAtomicResponse();
141  return latency;
142 }
143 
144 Tick
146 {
147  assert(pkt->getSize() == 1);
148  Addr addr = pkt->getAddr();
149  uint8_t data = pkt->getLE<uint8_t>();
150  if (addr == dataPort) {
151  statusReg.commandLast = 0;
152  switch (lastCommand) {
153  case NoCommand:
154  keyboard->hostWrite(data);
156  writeData(keyboard->hostRead(), false);
157  break;
158  case WriteToMouse:
159  mouse->hostWrite(data);
160  if (mouse->hostDataAvailable())
161  writeData(mouse->hostRead(), true);
162  break;
163  case WriteCommandByte:
164  commandByte = data;
165  DPRINTF(I8042, "Got data %#02x for \"Write "
166  "command byte\" command.\n", data);
167  statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
168  break;
170  DPRINTF(I8042, "Got data %#02x for \"Write "
171  "mouse output buffer\" command.\n", data);
172  writeData(data, true);
173  break;
175  DPRINTF(I8042, "Got data %#02x for \"Write "
176  "keyboad output buffer\" command.\n", data);
177  writeData(data, false);
178  break;
179  case WriteOutputPort:
180  DPRINTF(I8042, "Got data %#02x for \"Write "
181  "output port\" command.\n", data);
182  panic_if(bits(data, 0) != 1, "Reset bit should be 1");
183  // Safe to ignore otherwise
184  break;
185  default:
186  panic("Data written for unrecognized "
187  "command %#02x\n", lastCommand);
188  }
190  } else if (addr == commandPort) {
191  DPRINTF(I8042, "Got command %#02x.\n", data);
192  statusReg.commandLast = 1;
193  // These purposefully leave off the first byte of the controller RAM
194  // so it can be handled specially.
195  if (data > ReadControllerRamBase &&
196  data < ReadControllerRamBase + RamSize) {
197  panic("Attempted to use i8042 read controller RAM command to "
198  "get byte %d.\n", data - ReadControllerRamBase);
199  } else if (data > WriteControllerRamBase &&
200  data < WriteControllerRamBase + RamSize) {
201  panic("Attempted to use i8042 read controller RAM command to "
202  "get byte %d.\n", data - ReadControllerRamBase);
203  } else if (data >= PulseOutputBitBase &&
205  panic("Attempted to use i8042 pulse output bit command to "
206  "to pulse bit %d.\n", data - PulseOutputBitBase);
207  }
208  switch (data) {
209  case GetCommandByte:
210  DPRINTF(I8042, "Getting command byte.\n");
212  break;
213  case WriteCommandByte:
214  DPRINTF(I8042, "Setting command byte.\n");
216  break;
217  case CheckForPassword:
218  panic("i8042 \"Check for password\" command not implemented.\n");
219  case LoadPassword:
220  panic("i8042 \"Load password\" command not implemented.\n");
221  case CheckPassword:
222  panic("i8042 \"Check password\" command not implemented.\n");
223  case DisableMouse:
224  DPRINTF(I8042, "Disabling mouse at controller.\n");
225  commandByte.disableMouse = 1;
226  break;
227  case EnableMouse:
228  DPRINTF(I8042, "Enabling mouse at controller.\n");
229  commandByte.disableMouse = 0;
230  break;
231  case TestMouse:
232  panic("i8042 \"Test mouse\" command not implemented.\n");
233  case SelfTest:
234  panic("i8042 \"Self test\" command not implemented.\n");
235  case InterfaceTest:
236  panic("i8042 \"Interface test\" command not implemented.\n");
237  case DiagnosticDump:
238  panic("i8042 \"Diagnostic dump\" command not implemented.\n");
239  case DisableKeyboard:
240  DPRINTF(I8042, "Disabling keyboard at controller.\n");
241  commandByte.disableKeyboard = 1;
242  break;
243  case EnableKeyboard:
244  DPRINTF(I8042, "Enabling keyboard at controller.\n");
245  commandByte.disableKeyboard = 0;
246  break;
247  case ReadInputPort:
248  panic("i8042 \"Read input port\" command not implemented.\n");
249  case ContinuousPollLow:
250  panic("i8042 \"Continuous poll low\" command not implemented.\n");
251  case ContinuousPollHigh:
252  panic("i8042 \"Continuous poll high\" command not implemented.\n");
253  case ReadOutputPort:
254  panic("i8042 \"Read output port\" command not implemented.\n");
255  case WriteOutputPort:
257  break;
260  break;
262  DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
264  break;
265  case WriteToMouse:
266  DPRINTF(I8042, "Expecting mouse command.\n");
268  break;
269  case DisableA20:
270  panic("i8042 \"Disable A20\" command not implemented.\n");
271  case EnableA20:
272  panic("i8042 \"Enable A20\" command not implemented.\n");
273  case ReadTestInputs:
274  panic("i8042 \"Read test inputs\" command not implemented.\n");
275  case SystemReset:
276  panic("i8042 \"System reset\" command not implemented.\n");
277  default:
278  warn("Write to unknown i8042 "
279  "(keyboard controller) command port.\n");
280  }
281  } else {
282  panic("Write to unrecognized port %#x.\n", addr);
283  }
284  pkt->makeAtomicResponse();
285  return latency;
286 }
287 
288 void
290 {
297 }
298 
299 void
301 {
308 }
309 
311 I8042Params::create()
312 {
313  return new X86ISA::I8042(this);
314 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
#define DPRINTF(x,...)
Definition: trace.hh:229
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:584
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8042.cc:300
std::vector< IntSourcePin< I8042 > * > mouseIntPin
Definition: i8042.hh:111
Bitfield< 7 > i
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8042.cc:289
Addr commandPort
Definition: i8042.hh:101
void hostWrite(uint8_t c)
Transmit a character from the host interface to the device.
Definition: device.cc:97
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: i8042.cc:78
uint16_t lastCommand
Definition: i8042.hh:109
PioDeviceParams Params
Definition: io_device.hh:134
PS2Device * mouse
Definition: i8042.hh:114
Definition: cprintf.cc:42
uint8_t dataReg
Definition: i8042.hh:106
StatusReg statusReg
Definition: i8042.hh:103
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition: packet.hh:736
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:645
I8042(Params *p)
Definition: i8042.cc:48
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:162
uint8_t readDataOut()
Definition: i8042.cc:112
CommandByte commandByte
Definition: i8042.hh:104
Addr dataPort
Definition: i8042.hh:100
void makeAtomicResponse()
Definition: packet.hh:949
uint64_t Tick
Tick count type.
Definition: types.hh:63
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:145
Addr getAddr() const
Definition: packet.hh:726
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:203
void writeData(uint8_t newData, bool mouse=false)
Definition: i8042.cc:88
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
virtual const std::string name() const
Definition: sim_object.hh:120
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:255
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:126
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:643
Declaration of the Packet class.
std::ostream CheckpointOut
Definition: serialize.hh:68
const uint8_t RamSize
Note: For details on the implementation see https://wiki.osdev.org/%228042%22_PS/2_Controller.
Definition: i8042.cc:44
PS2Device * keyboard
Definition: i8042.hh:115
static const uint16_t NoCommand
Definition: i8042.hh:108
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
#define warn(...)
Definition: logging.hh:212
const uint8_t NumOutputBits
Definition: i8042.cc:45
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:72
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:185
bool hostDataAvailable() const
Check if there is pending data from the PS/2 device.
Definition: device.hh:76
const char data[]
Bitfield< 3 > addr
Definition: types.hh:81
std::vector< IntSourcePin< I8042 > * > keyboardIntPin
Definition: i8042.hh:112
uint8_t hostRead()
Read a character from the device.
Definition: device.cc:89

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13