gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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 
38 // The 8042 has a whopping 32 bytes of internal RAM.
39 const uint8_t RamSize = 32;
40 const uint8_t NumOutputBits = 14;
41 const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83};
42 const uint8_t X86ISA::PS2Mouse::ID[] = {0x00};
43 const uint8_t CommandAck = 0xfa;
44 const uint8_t CommandNack = 0xfe;
45 const uint8_t BatSuccessful = 0xaa;
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  mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin)
54 {
55  statusReg.passedSelfTest = 1;
56  statusReg.commandLast = 1;
57  statusReg.keyboardUnlocked = 1;
58 
59  commandByte.convertScanCodes = 1;
60  commandByte.passedSelfTest = 1;
61  commandByte.keyboardFullInt = 1;
62 }
63 
64 
67 {
68  AddrRangeList ranges;
69  // TODO: Are these really supposed to be a single byte and not 4?
70  ranges.push_back(RangeSize(dataPort, 1));
71  ranges.push_back(RangeSize(commandPort, 1));
72  return ranges;
73 }
74 
75 void
76 X86ISA::I8042::writeData(uint8_t newData, bool mouse)
77 {
78  DPRINTF(I8042, "Set data %#02x.\n", newData);
79  dataReg = newData;
80  statusReg.outputFull = 1;
81  statusReg.mouseOutputFull = (mouse ? 1 : 0);
82  if (!mouse && commandByte.keyboardFullInt) {
83  DPRINTF(I8042, "Sending keyboard interrupt.\n");
84  keyboardIntPin->raise();
85  //This is a hack
86  keyboardIntPin->lower();
87  } else if (mouse && commandByte.mouseFullInt) {
88  DPRINTF(I8042, "Sending mouse interrupt.\n");
89  mouseIntPin->raise();
90  //This is a hack
91  mouseIntPin->lower();
92  }
93 }
94 
95 void
96 X86ISA::PS2Device::serialize(const std::string &base, CheckpointOut &cp) const
97 {
98  paramOut(cp, base + ".lastCommand", lastCommand);
99 
100  std::vector<uint8_t> buffer(outBuffer.size());
101  std::copy(outBuffer.begin(), outBuffer.end(), buffer.begin());
102  arrayParamOut(cp, base + ".outBuffer.elts", buffer);
103 }
104 
105 void
107 {
108  paramIn(cp, base + ".lastCommand", lastCommand);
109 
110  std::vector<uint8_t> buffer;
111  arrayParamIn(cp, base + ".outBuffer.elts", buffer);
112  assert(outBuffer.empty());
113  for (auto c : buffer)
114  outBuffer.push_back(c);
115 }
116 
117 
118 void
120 {
121  bufferData(&CommandAck, sizeof(CommandAck));
122 }
123 
124 void
126 {
127  bufferData(&CommandNack, sizeof(CommandNack));
128 }
129 
130 void
132 {
133  assert(data || size == 0);
134  while (size) {
135  outBuffer.push_back(*(data++));
136  size--;
137  }
138 }
139 
140 uint8_t
142 {
143  uint8_t data = dataReg;
144  statusReg.outputFull = 0;
145  statusReg.mouseOutputFull = 0;
146  if (keyboard.hasData()) {
147  writeData(keyboard.getData(), false);
148  } else if (mouse.hasData()) {
149  writeData(mouse.getData(), true);
150  }
151  return data;
152 }
153 
154 bool
156 {
157  if (lastCommand != NoCommand) {
158  switch (lastCommand) {
159  case LEDWrite:
160  DPRINTF(I8042, "Setting LEDs: "
161  "caps lock %s, num lock %s, scroll lock %s\n",
162  bits(data, 2) ? "on" : "off",
163  bits(data, 1) ? "on" : "off",
164  bits(data, 0) ? "on" : "off");
165  ack();
166  lastCommand = NoCommand;
167  break;
168  case TypematicInfo:
169  DPRINTF(I8042, "Setting typematic info to %#02x.\n", data);
170  ack();
171  lastCommand = NoCommand;
172  break;
173  }
174  return hasData();
175  }
176  switch (data) {
177  case LEDWrite:
178  DPRINTF(I8042, "Got LED write command.\n");
179  ack();
180  lastCommand = LEDWrite;
181  break;
182  case DiagnosticEcho:
183  panic("Keyboard diagnostic echo unimplemented.\n");
184  case AlternateScanCodes:
185  panic("Accessing alternate scan codes unimplemented.\n");
186  case ReadID:
187  DPRINTF(I8042, "Got keyboard read ID command.\n");
188  ack();
189  bufferData((uint8_t *)&ID, sizeof(ID));
190  break;
191  case TypematicInfo:
192  DPRINTF(I8042, "Setting typematic info.\n");
193  ack();
194  lastCommand = TypematicInfo;
195  break;
196  case Enable:
197  DPRINTF(I8042, "Enabling the keyboard.\n");
198  ack();
199  break;
200  case Disable:
201  DPRINTF(I8042, "Disabling the keyboard.\n");
202  ack();
203  break;
204  case DefaultsAndDisable:
205  DPRINTF(I8042, "Disabling and resetting the keyboard.\n");
206  ack();
207  break;
208  case AllKeysToTypematic:
209  panic("Setting all keys to typemantic unimplemented.\n");
210  case AllKeysToMakeRelease:
211  panic("Setting all keys to make/release unimplemented.\n");
212  case AllKeysToMake:
213  panic("Setting all keys to make unimplemented.\n");
214  case AllKeysToTypematicMakeRelease:
215  panic("Setting all keys to "
216  "typematic/make/release unimplemented.\n");
217  case KeyToTypematic:
218  panic("Setting a key to typematic unimplemented.\n");
219  case KeyToMakeRelease:
220  panic("Setting a key to make/release unimplemented.\n");
221  case KeyToMakeOnly:
222  panic("Setting key to make only unimplemented.\n");
223  case Resend:
224  panic("Keyboard resend unimplemented.\n");
225  case Reset:
226  panic("Keyboard reset unimplemented.\n");
227  default:
228  panic("Unknown keyboard command %#02x.\n", data);
229  }
230  return hasData();
231 }
232 
233 bool
235 {
236  if (lastCommand != NoCommand) {
237  switch(lastCommand) {
238  case SetResolution:
239  DPRINTF(I8042, "Mouse resolution set to %d.\n", data);
240  resolution = data;
241  ack();
242  lastCommand = NoCommand;
243  break;
244  case SampleRate:
245  DPRINTF(I8042, "Mouse sample rate %d samples "
246  "per second.\n", data);
247  sampleRate = data;
248  ack();
249  lastCommand = NoCommand;
250  break;
251  default:
252  panic("Not expecting data for a mouse command.\n");
253  }
254  return hasData();
255  }
256  switch (data) {
257  case Scale1to1:
258  DPRINTF(I8042, "Setting mouse scale to 1:1.\n");
259  status.twoToOne = 0;
260  ack();
261  break;
262  case Scale2to1:
263  DPRINTF(I8042, "Setting mouse scale to 2:1.\n");
264  status.twoToOne = 1;
265  ack();
266  break;
267  case SetResolution:
268  DPRINTF(I8042, "Setting mouse resolution.\n");
269  lastCommand = SetResolution;
270  ack();
271  break;
272  case GetStatus:
273  DPRINTF(I8042, "Getting mouse status.\n");
274  ack();
275  bufferData((uint8_t *)&(status), 1);
276  bufferData(&resolution, sizeof(resolution));
277  bufferData(&sampleRate, sizeof(sampleRate));
278  break;
279  case ReadData:
280  panic("Reading mouse data unimplemented.\n");
281  case ResetWrapMode:
282  panic("Resetting mouse wrap mode unimplemented.\n");
283  case WrapMode:
284  panic("Setting mouse wrap mode unimplemented.\n");
285  case RemoteMode:
286  panic("Setting mouse remote mode unimplemented.\n");
287  case ReadID:
288  DPRINTF(I8042, "Mouse ID requested.\n");
289  ack();
290  bufferData(ID, sizeof(ID));
291  break;
292  case SampleRate:
293  DPRINTF(I8042, "Setting mouse sample rate.\n");
294  lastCommand = SampleRate;
295  ack();
296  break;
297  case DisableReporting:
298  DPRINTF(I8042, "Disabling data reporting.\n");
299  status.enabled = 0;
300  ack();
301  break;
302  case EnableReporting:
303  DPRINTF(I8042, "Enabling data reporting.\n");
304  status.enabled = 1;
305  ack();
306  break;
307  case DefaultsAndDisable:
308  DPRINTF(I8042, "Disabling and resetting mouse.\n");
309  sampleRate = 100;
310  resolution = 4;
311  status.twoToOne = 0;
312  status.enabled = 0;
313  ack();
314  break;
315  case Resend:
316  panic("Mouse resend unimplemented.\n");
317  case Reset:
318  DPRINTF(I8042, "Resetting the mouse.\n");
319  sampleRate = 100;
320  resolution = 4;
321  status.twoToOne = 0;
322  status.enabled = 0;
323  ack();
324  bufferData(&BatSuccessful, sizeof(BatSuccessful));
325  bufferData(ID, sizeof(ID));
326  break;
327  default:
328  warn("Unknown mouse command %#02x.\n", data);
329  nack();
330  break;
331  }
332  return hasData();
333 }
334 
335 
336 Tick
338 {
339  assert(pkt->getSize() == 1);
340  Addr addr = pkt->getAddr();
341  if (addr == dataPort) {
342  uint8_t data = readDataOut();
343  //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
344  pkt->set<uint8_t>(data);
345  } else if (addr == commandPort) {
346  //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
347  pkt->set<uint8_t>((uint8_t)statusReg);
348  } else {
349  panic("Read from unrecognized port %#x.\n", addr);
350  }
351  pkt->makeAtomicResponse();
352  return latency;
353 }
354 
355 Tick
357 {
358  assert(pkt->getSize() == 1);
359  Addr addr = pkt->getAddr();
360  uint8_t data = pkt->get<uint8_t>();
361  if (addr == dataPort) {
362  statusReg.commandLast = 0;
363  switch (lastCommand) {
364  case NoCommand:
365  if (keyboard.processData(data)) {
366  writeData(keyboard.getData(), false);
367  }
368  break;
369  case WriteToMouse:
370  if (mouse.processData(data)) {
371  writeData(mouse.getData(), true);
372  }
373  break;
374  case WriteCommandByte:
375  commandByte = data;
376  DPRINTF(I8042, "Got data %#02x for \"Write "
377  "command byte\" command.\n", data);
378  statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
379  break;
380  case WriteMouseOutputBuff:
381  DPRINTF(I8042, "Got data %#02x for \"Write "
382  "mouse output buffer\" command.\n", data);
383  writeData(data, true);
384  break;
385  default:
386  panic("Data written for unrecognized "
387  "command %#02x\n", lastCommand);
388  }
389  lastCommand = NoCommand;
390  } else if (addr == commandPort) {
391  DPRINTF(I8042, "Got command %#02x.\n", data);
392  statusReg.commandLast = 1;
393  // These purposefully leave off the first byte of the controller RAM
394  // so it can be handled specially.
395  if (data > ReadControllerRamBase &&
396  data < ReadControllerRamBase + RamSize) {
397  panic("Attempted to use i8042 read controller RAM command to "
398  "get byte %d.\n", data - ReadControllerRamBase);
399  } else if (data > WriteControllerRamBase &&
400  data < WriteControllerRamBase + RamSize) {
401  panic("Attempted to use i8042 read controller RAM command to "
402  "get byte %d.\n", data - ReadControllerRamBase);
403  } else if (data >= PulseOutputBitBase &&
404  data < PulseOutputBitBase + NumOutputBits) {
405  panic("Attempted to use i8042 pulse output bit command to "
406  "to pulse bit %d.\n", data - PulseOutputBitBase);
407  }
408  switch (data) {
409  case GetCommandByte:
410  DPRINTF(I8042, "Getting command byte.\n");
411  writeData(commandByte);
412  break;
413  case WriteCommandByte:
414  DPRINTF(I8042, "Setting command byte.\n");
415  lastCommand = WriteCommandByte;
416  break;
417  case CheckForPassword:
418  panic("i8042 \"Check for password\" command not implemented.\n");
419  case LoadPassword:
420  panic("i8042 \"Load password\" command not implemented.\n");
421  case CheckPassword:
422  panic("i8042 \"Check password\" command not implemented.\n");
423  case DisableMouse:
424  DPRINTF(I8042, "Disabling mouse at controller.\n");
425  commandByte.disableMouse = 1;
426  break;
427  case EnableMouse:
428  DPRINTF(I8042, "Enabling mouse at controller.\n");
429  commandByte.disableMouse = 0;
430  break;
431  case TestMouse:
432  panic("i8042 \"Test mouse\" command not implemented.\n");
433  case SelfTest:
434  panic("i8042 \"Self test\" command not implemented.\n");
435  case InterfaceTest:
436  panic("i8042 \"Interface test\" command not implemented.\n");
437  case DiagnosticDump:
438  panic("i8042 \"Diagnostic dump\" command not implemented.\n");
439  case DisableKeyboard:
440  DPRINTF(I8042, "Disabling keyboard at controller.\n");
441  commandByte.disableKeyboard = 1;
442  break;
443  case EnableKeyboard:
444  DPRINTF(I8042, "Enabling keyboard at controller.\n");
445  commandByte.disableKeyboard = 0;
446  break;
447  case ReadInputPort:
448  panic("i8042 \"Read input port\" command not implemented.\n");
449  case ContinuousPollLow:
450  panic("i8042 \"Continuous poll low\" command not implemented.\n");
451  case ContinuousPollHigh:
452  panic("i8042 \"Continuous poll high\" command not implemented.\n");
453  case ReadOutputPort:
454  panic("i8042 \"Read output port\" command not implemented.\n");
455  case WriteOutputPort:
456  warn("i8042 \"Write output port\" command not implemented.\n");
457  lastCommand = WriteOutputPort;
458  case WriteKeyboardOutputBuff:
459  warn("i8042 \"Write keyboard output buffer\" "
460  "command not implemented.\n");
461  lastCommand = WriteKeyboardOutputBuff;
462  case WriteMouseOutputBuff:
463  DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
464  lastCommand = WriteMouseOutputBuff;
465  break;
466  case WriteToMouse:
467  DPRINTF(I8042, "Expecting mouse command.\n");
468  lastCommand = WriteToMouse;
469  break;
470  case DisableA20:
471  panic("i8042 \"Disable A20\" command not implemented.\n");
472  case EnableA20:
473  panic("i8042 \"Enable A20\" command not implemented.\n");
474  case ReadTestInputs:
475  panic("i8042 \"Read test inputs\" command not implemented.\n");
476  case SystemReset:
477  panic("i8042 \"System reset\" command not implemented.\n");
478  default:
479  warn("Write to unknown i8042 "
480  "(keyboard controller) command port.\n");
481  }
482  } else {
483  panic("Write to unrecognized port %#x.\n", addr);
484  }
485  pkt->makeAtomicResponse();
486  return latency;
487 }
488 
489 void
491 {
492  uint8_t statusRegData = statusReg.__data;
493  uint8_t commandByteData = commandByte.__data;
494 
495  SERIALIZE_SCALAR(dataPort);
496  SERIALIZE_SCALAR(commandPort);
497  SERIALIZE_SCALAR(statusRegData);
498  SERIALIZE_SCALAR(commandByteData);
499  SERIALIZE_SCALAR(dataReg);
500  SERIALIZE_SCALAR(lastCommand);
501  mouse.serialize("mouse", cp);
502  keyboard.serialize("keyboard", cp);
503 }
504 
505 void
507 {
508  uint8_t statusRegData;
509  uint8_t commandByteData;
510 
511  UNSERIALIZE_SCALAR(dataPort);
512  UNSERIALIZE_SCALAR(commandPort);
513  UNSERIALIZE_SCALAR(statusRegData);
514  UNSERIALIZE_SCALAR(commandByteData);
515  UNSERIALIZE_SCALAR(dataReg);
516  UNSERIALIZE_SCALAR(lastCommand);
517  mouse.unserialize("mouse", cp);
518  keyboard.unserialize("keyboard", cp);
519 
520  statusReg.__data = statusRegData;
521  commandByte.__data = commandByteData;
522 }
523 
524 void
525 X86ISA::PS2Mouse::serialize(const std::string &base, CheckpointOut &cp) const
526 {
527  PS2Device::serialize(base, cp);
528 
529  paramOut(cp, base + ".status", status);
530  paramOut(cp, base + ".resolution", resolution);
531  paramOut(cp, base + ".sampleRate", sampleRate);
532 }
533 
534 void
536 {
537  PS2Device::unserialize(base, cp);
538 
539  paramIn(cp, base + ".status", status);
540  paramIn(cp, base + ".resolution", resolution);
541  paramIn(cp, base + ".sampleRate", sampleRate);
542 }
543 
545 I8042Params::create()
546 {
547  return new X86ISA::I8042(this);
548 }
#define DPRINTF(x,...)
Definition: trace.hh:212
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:398
void set(T v, ByteOrder endian)
Set the value in the data pointer to v using the specified endianness.
const uint8_t BatSuccessful
Definition: i8042.cc:45
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8042.cc:506
#define panic(...)
Definition: misc.hh:153
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8042.cc:490
bool processData(uint8_t data) override
Definition: i8042.cc:155
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: i8042.cc:66
PioDeviceParams Params
Definition: io_device.hh:116
void serialize(const std::string &base, CheckpointOut &cp) const override
Definition: i8042.cc:525
Bitfield< 42 > c
Definition: misc.hh:888
StatusReg statusReg
Definition: i8042.hh:216
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
const char data[]
Definition: circlebuf.cc:43
#define warn(...)
Definition: misc.hh:219
Bitfield< 5, 0 > status
Definition: miscregs.hh:1604
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
I8042(Params *p)
Definition: i8042.cc:48
void bufferData(const uint8_t *data, int size)
Definition: i8042.cc:131
uint8_t readDataOut()
Definition: i8042.cc:141
CommandByte commandByte
Definition: i8042.hh:217
void makeAtomicResponse()
Definition: packet.hh:857
uint64_t Tick
Tick count type.
Definition: types.hh:63
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:40
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:356
Bitfield< 51, 12 > base
Definition: pagetable.hh:85
void writeData(uint8_t newData, bool mouse=false)
Definition: i8042.cc:76
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > &param)
Definition: circlebuf.hh:251
const uint8_t CommandAck
Definition: i8042.cc:43
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
static const uint8_t ID[]
Definition: i8042.hh:130
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:337
virtual void serialize(const std::string &base, CheckpointOut &cp) const
Definition: i8042.cc:96
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
int size()
Definition: pagetable.hh:146
virtual void unserialize(const std::string &base, CheckpointIn &cp)
Definition: i8042.cc:106
Declaration of the Packet class.
std::ostream CheckpointOut
Definition: serialize.hh:67
const uint8_t RamSize
Definition: i8042.cc:39
void unserialize(const std::string &base, CheckpointIn &cp) override
Definition: i8042.cc:535
const uint8_t CommandNack
Definition: i8042.cc:44
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:71
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > &param)
Definition: circlebuf.hh:261
static const uint8_t ID[]
Definition: i8042.hh:85
const uint8_t NumOutputBits
Definition: i8042.cc:40
unsigned getSize() const
Definition: packet.hh:649
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:67
bool processData(uint8_t data) override
Definition: i8042.cc:234
Bitfield< 0 > p
Bitfield< 3 > addr
Definition: types.hh:81
Addr getAddr() const
Definition: packet.hh:639

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6