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