# Node ID a13dc3596e45275bc9dab66bb5d8dc35cdf68ef3 # Parent 5aa6f7e7fcc07f0402c639c41286dec06dcf8e05 diff --git a/src/dev/x86/I8042.py b/src/dev/x86/I8042.py --- a/src/dev/x86/I8042.py +++ b/src/dev/x86/I8042.py @@ -35,6 +35,9 @@ type = 'I8042' cxx_class = 'X86ISA::I8042' cxx_header = "dev/x86/i8042.hh" + + vnc = Param.VncInput(Parent.any, 'Vnc server to receive input from') + # This isn't actually used for anything here. pio_addr = 0x0 data_port = Param.Addr('Data port address') diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh --- a/src/dev/x86/i8042.hh +++ b/src/dev/x86/i8042.hh @@ -1,4 +1,5 @@ /* + * Copyright 2014 Google, Inc. * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * @@ -33,6 +34,7 @@ #include +#include "base/vnc/vncinput.hh" #include "dev/x86/intdev.hh" #include "dev/io_device.hh" #include "params/I8042.hh" @@ -76,7 +78,9 @@ virtual bool processData(uint8_t data) = 0; }; -class PS2Mouse : public PS2Device +class I8042; + +class PS2Mouse : public PS2Device, public VncMouse { protected: static const uint8_t ID[]; @@ -87,6 +91,7 @@ Scale2to1 = 0xE7, SetResolution = 0xE8, GetStatus = 0xE9, + SetStreamMode = 0xEA, ReadData = 0xEB, ResetWrapMode = 0xEC, WrapMode = 0xEE, @@ -111,12 +116,41 @@ Status status; uint8_t resolution; uint8_t sampleRate; + bool reporting; + bool wrapMode; + + struct Sample + { + int32_t x; + int32_t y; + uint8_t buttons; + + Sample() : x(0), y(0), buttons(0) + {} + }; + + Sample last, cur; + + void enableReporting(); + void disableReporting(); + + void reportSample(); + EventWrapper reportEvent; + + I8042 *i8042; + public: - PS2Mouse() : PS2Device(), status(0), resolution(4), sampleRate(100) + PS2Mouse(I8042 *_i8042) : PS2Device(), status(0), resolution(4), + sampleRate(100), reporting(false), + wrapMode(false), reportEvent(this), i8042(_i8042) {} bool processData(uint8_t data); + const std::string name() const; + + void mouseAt(uint16_t x, uint16_t y, uint8_t buttons); + void serialize(const std::string &base, std::ostream &os); void unserialize(const std::string &base, Checkpoint *cp, const std::string §ion); @@ -249,6 +283,8 @@ Tick write(PacketPtr pkt); + void getData(); + virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); }; diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc --- a/src/dev/x86/i8042.cc +++ b/src/dev/x86/i8042.cc @@ -1,4 +1,5 @@ /* + * Copyright 2014 Google, Inc. * Copyright (c) 2008 The Regents of The University of Michigan * All rights reserved. * @@ -49,7 +50,8 @@ latency(p->pio_latency), dataPort(p->data_port), commandPort(p->command_port), statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand), - mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin) + mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin), + mouse(this) { statusReg.passedSelfTest = 1; statusReg.commandLast = 1; @@ -58,6 +60,9 @@ commandByte.convertScanCodes = 1; commandByte.passedSelfTest = 1; commandByte.keyboardFullInt = 1; + + if (p->vnc) + p->vnc->setMouse(&mouse); } @@ -113,17 +118,25 @@ } } +void +X86ISA::I8042::getData() +{ + if (statusReg.outputFull) + return; + if (keyboard.hasData()) { + writeData(keyboard.getData(), false); + } else if (mouse.hasData()) { + writeData(mouse.getData(), true); + } +} + uint8_t X86ISA::I8042::readDataOut() { uint8_t data = dataReg; statusReg.outputFull = 0; statusReg.mouseOutputFull = 0; - if (keyboard.hasData()) { - writeData(keyboard.getData(), false); - } else if (mouse.hasData()) { - writeData(mouse.getData(), true); - } + getData(); return data; } @@ -206,6 +219,82 @@ return hasData(); } +const std::string +X86ISA::PS2Mouse::name() const +{ + return i8042->name() + ".mouse"; +} + +void +X86ISA::PS2Mouse::enableReporting() +{ + if (!reportEvent.scheduled()) + i8042->schedule(reportEvent,SimClock::Int::s / sampleRate + curTick()); + status.enabled = 1; +} + +void +X86ISA::PS2Mouse::disableReporting() +{ + if (reportEvent.scheduled()) + i8042->deschedule(reportEvent); + status.enabled = 0; +} + +void +X86ISA::PS2Mouse::reportSample() +{ + i8042->schedule(reportEvent,SimClock::Int::s / sampleRate + curTick()); + + if (last.x == cur.x && last.y == cur.y && last.buttons == cur.buttons) + return; + + BitUnion8(ReportBits) + Bitfield<0> leftButton; + Bitfield<1> rightButton; + Bitfield<2> middleButton; + Bitfield<3> alwaysOne; + Bitfield<4> xSign; + Bitfield<5> ySign; + Bitfield<6> xOverflow; + Bitfield<7> yOverflow; + EndBitUnion(ReportBits) + + ReportBits reportBits = 0; + reportBits.alwaysOne = 1; + + reportBits.leftButton = bits(cur.buttons, 0); + reportBits.rightButton = bits(cur.buttons, 1); + reportBits.middleButton = bits(cur.buttons, 2); + + int32_t deltaX = cur.x - last.x; + int32_t deltaY = -(cur.y - last.y); + + if (deltaX < 0) + reportBits.xSign = 1; + if (deltaY < 0) + reportBits.ySign = 1; + + // movement is sent as a 9 bit 2's complement delta since the last sample. + if (deltaX > (int64_t)mask(8) || deltaX < -(int64_t)mask(8) - 1) { + reportBits.xOverflow = 1; + deltaX = mask(8); + } + if (deltaY > (int64_t)mask(8) || deltaY < -(int64_t)mask(8) - 1) { + reportBits.yOverflow = 1; + deltaY = mask(8); + } + + uint8_t xByte = deltaX & mask(8); + uint8_t yByte = deltaY & mask(8); + uint8_t bitByte = reportBits; + bufferData(&bitByte, 1); + bufferData(&xByte, 1); + bufferData(&yByte, 1); + last = cur; + i8042->getData(); +} + bool X86ISA::PS2Mouse::processData(uint8_t data) { @@ -252,10 +341,18 @@ bufferData(&resolution, sizeof(resolution)); bufferData(&sampleRate, sizeof(sampleRate)); break; + case SetStreamMode: + DPRINTF(I8042, "Setting stream mode.\n"); + ack(); + break; case ReadData: panic("Reading mouse data unimplemented.\n"); case ResetWrapMode: - panic("Resetting mouse wrap mode unimplemented.\n"); + DPRINTF(I8042, "Resetting wrap mode.\n"); + wrapMode = false; + last = cur; + ack(); + break; case WrapMode: panic("Setting mouse wrap mode unimplemented.\n"); case RemoteMode: @@ -272,12 +369,12 @@ break; case DisableReporting: DPRINTF(I8042, "Disabling data reporting.\n"); - status.enabled = 0; + disableReporting(); ack(); break; case EnableReporting: DPRINTF(I8042, "Enabling data reporting.\n"); - status.enabled = 1; + enableReporting(); ack(); break; case DefaultsAndDisable: @@ -285,7 +382,7 @@ sampleRate = 100; resolution = 4; status.twoToOne = 0; - status.enabled = 0; + disableReporting(); ack(); break; case Resend: @@ -295,7 +392,7 @@ sampleRate = 100; resolution = 4; status.twoToOne = 0; - status.enabled = 0; + disableReporting(); ack(); bufferData(&BatSuccessful, sizeof(BatSuccessful)); bufferData(ID, sizeof(ID)); @@ -308,6 +405,14 @@ return hasData(); } +void +X86ISA::PS2Mouse::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) +{ + cur.x = x; + cur.y = y; + cur.buttons = buttons; +} + Tick X86ISA::I8042::read(PacketPtr pkt) @@ -532,7 +637,6 @@ void X86ISA::PS2Mouse::serialize(const std::string &base, std::ostream &os) { - uint8_t statusData = status.__data; paramOut(os, base + ".lastCommand", lastCommand); int bufferSize = outBuffer.size(); paramOut(os, base + ".outBuffer.size", bufferSize); @@ -544,16 +648,27 @@ arrayParamOut(os, base + ".outBuffer.elts", buffer, bufferSize*sizeof(uint8_t)); delete[] buffer; - paramOut(os, base + ".status", statusData); + uint8_t temp8 = status; + paramOut(os, base + ".status", temp8); paramOut(os, base + ".resolution", resolution); paramOut(os, base + ".sampleRate", sampleRate); + paramOut(os, base + ".reporting", reporting); + paramOut(os, base + ".wrapMode", wrapMode); + paramOut(os, base + ".last.x", last.x); + paramOut(os, base + ".last.y", last.y); + paramOut(os, base + ".last.buttons", last.buttons); + paramOut(os, base + ".cur.x", cur.x); + paramOut(os, base + ".cur.y", cur.y); + paramOut(os, base + ".cur.buttons", cur.buttons); + + Tick reportTick = reportEvent.scheduled() ? reportEvent.when() : 0; + paramOut(os, base + ".reportTick", reportTick); } void X86ISA::PS2Mouse::unserialize(const std::string &base, Checkpoint *cp, const std::string §ion) { - uint8_t statusData; paramIn(cp, section, base + ".lastCommand", lastCommand); int bufferSize; paramIn(cp, section, base + ".outBuffer.size", bufferSize); @@ -564,11 +679,26 @@ outBuffer.push(buffer[i]); } delete[] buffer; - paramIn(cp, section, base + ".status", statusData); + uint8_t temp8; + paramIn(cp, section, base + ".status", temp8); + status = temp8; paramIn(cp, section, base + ".resolution", resolution); paramIn(cp, section, base + ".sampleRate", sampleRate); + paramIn(cp, section, base + ".reporting", reporting); + paramIn(cp, section, base + ".wrapMode", wrapMode); + paramIn(cp, section, base + ".last.x", last.x); + paramIn(cp, section, base + ".last.y", last.y); + paramIn(cp, section, base + ".last.buttons", last.buttons); + paramIn(cp, section, base + ".cur.x", cur.x); + paramIn(cp, section, base + ".cur.y", cur.y); + paramIn(cp, section, base + ".cur.buttons", cur.buttons); - status.__data = statusData; + if (reportEvent.scheduled()) + i8042->deschedule(reportEvent); + Tick reportTick; + paramIn(cp, section, base + ".reportTick", reportTick); + if (reportTick) + i8042->schedule(reportEvent, reportTick); } X86ISA::I8042 *