kmi.cc revision 9049:af47da518149
12131SN/A/* 25268Sksewell@umich.edu * Copyright (c) 2010 ARM Limited 35254Sksewell@umich.edu * All rights reserved 45254Sksewell@umich.edu * 52131SN/A * The license below extends only to copyright in the software and shall 65254Sksewell@umich.edu * not be construed as granting a license to any other intellectual 75254Sksewell@umich.edu * property including but not limited to intellectual property relating 85254Sksewell@umich.edu * to a hardware implementation of the functionality of the software 95254Sksewell@umich.edu * licensed hereunder. You may use the software subject to the license 105254Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated 115254Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software, 125254Sksewell@umich.edu * modified or unmodified, in source code or in binary form. 135254Sksewell@umich.edu * 145254Sksewell@umich.edu * Copyright (c) 2005 The Regents of The University of Michigan 155254Sksewell@umich.edu * All rights reserved. 162131SN/A * 175254Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 185254Sksewell@umich.edu * modification, are permitted provided that the following conditions are 195254Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 205254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 215254Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 225254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 235254Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 245254Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 255254Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 265254Sksewell@umich.edu * this software without specific prior written permission. 275254Sksewell@umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295254Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305254Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328696Sguodeyuan@tsinghua.org.cn * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 338696Sguodeyuan@tsinghua.org.cn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342131SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352131SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362239SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3711793Sbrandon.potter@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 387676Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 397676Snate@binkert.org * 407676Snate@binkert.org * Authors: Ali Saidi 412680Sktlim@umich.edu * William Wang 428232Snate@binkert.org */ 437676Snate@binkert.org 442800Ssaidi@eecs.umich.edu#include "base/vnc/vncserver.hh" 452131SN/A#include "base/trace.hh" 462447SN/A#include "debug/Pl050.hh" 472447SN/A#include "dev/arm/amba_device.hh" 482131SN/A#include "dev/arm/kmi.hh" 498566Sgblack@eecs.umich.edu#include "dev/ps2.hh" 502131SN/A#include "mem/packet.hh" 518578Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 528578Sgblack@eecs.umich.edu 538578Sgblack@eecs.umich.eduPl050::Pl050(const Params *p) 548578Sgblack@eecs.umich.edu : AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0), 558578Sgblack@eecs.umich.edu rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc), 568578Sgblack@eecs.umich.edu driverInitialized(false), intEvent(this) 578578Sgblack@eecs.umich.edu{ 588578Sgblack@eecs.umich.edu pioSize = 0xfff; 598578Sgblack@eecs.umich.edu 608578Sgblack@eecs.umich.edu if (vnc) { 618578Sgblack@eecs.umich.edu if (!p->is_mouse) 628578Sgblack@eecs.umich.edu vnc->setKeyboard(this); 638578Sgblack@eecs.umich.edu else 648578Sgblack@eecs.umich.edu vnc->setMouse(this); 658578Sgblack@eecs.umich.edu } 668578Sgblack@eecs.umich.edu} 678578Sgblack@eecs.umich.edu 688578Sgblack@eecs.umich.eduTick 698578Sgblack@eecs.umich.eduPl050::read(PacketPtr pkt) 708578Sgblack@eecs.umich.edu{ 718578Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 728566Sgblack@eecs.umich.edu 738578Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 742447SN/A pkt->allocate(); 758566Sgblack@eecs.umich.edu 768578Sgblack@eecs.umich.edu 778578Sgblack@eecs.umich.edu uint32_t data = 0; 788578Sgblack@eecs.umich.edu 798578Sgblack@eecs.umich.edu switch (daddr) { 808578Sgblack@eecs.umich.edu case kmiCr: 818578Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); 828578Sgblack@eecs.umich.edu data = control; 838578Sgblack@eecs.umich.edu break; 848578Sgblack@eecs.umich.edu case kmiStat: 858578Sgblack@eecs.umich.edu if (rxQueue.empty()) 868578Sgblack@eecs.umich.edu status.rxfull = 0; 878578Sgblack@eecs.umich.edu else 888578Sgblack@eecs.umich.edu status.rxfull = 1; 892447SN/A 908566Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); 918578Sgblack@eecs.umich.edu data = status; 925222Sksewell@umich.edu break; 938573Sgblack@eecs.umich.edu case kmiData: 948578Sgblack@eecs.umich.edu if (rxQueue.empty()) { 955222Sksewell@umich.edu data = 0; 968573Sgblack@eecs.umich.edu } else { 978578Sgblack@eecs.umich.edu data = rxQueue.front(); 982447SN/A rxQueue.pop_front(); 998737Skoansin.tan@gmail.com } 1008578Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); 1014661Sksewell@umich.edu updateIntStatus(); 1026378Sgblack@eecs.umich.edu break; 1038566Sgblack@eecs.umich.edu case kmiClkDiv: 1045222Sksewell@umich.edu data = clkdiv; 1056378Sgblack@eecs.umich.edu break; 1066383Sgblack@eecs.umich.edu case kmiISR: 1076379Sgblack@eecs.umich.edu data = interrupts; 1086378Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); 1096383Sgblack@eecs.umich.edu break; 1106379Sgblack@eecs.umich.edu default: 1116379Sgblack@eecs.umich.edu if (AmbaDev::readId(pkt, ambaId, pioAddr)) { 1126383Sgblack@eecs.umich.edu // Hack for variable size accesses 1135222Sksewell@umich.edu data = pkt->get<uint32_t>(); 1145222Sksewell@umich.edu break; 1156378Sgblack@eecs.umich.edu } 1166379Sgblack@eecs.umich.edu 1176383Sgblack@eecs.umich.edu warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr); 1185222Sksewell@umich.edu break; 1196378Sgblack@eecs.umich.edu } 1208574Sgblack@eecs.umich.edu 1218574Sgblack@eecs.umich.edu switch(pkt->getSize()) { 1228574Sgblack@eecs.umich.edu case 1: 1238574Sgblack@eecs.umich.edu pkt->set<uint8_t>(data); 1248696Sguodeyuan@tsinghua.org.cn break; 1255222Sksewell@umich.edu case 2: 1266378Sgblack@eecs.umich.edu pkt->set<uint16_t>(data); 1276383Sgblack@eecs.umich.edu break; 1286379Sgblack@eecs.umich.edu case 4: 1298574Sgblack@eecs.umich.edu pkt->set<uint32_t>(data); 1306379Sgblack@eecs.umich.edu break; 1316383Sgblack@eecs.umich.edu default: 1326378Sgblack@eecs.umich.edu panic("KMI read size too big?\n"); 1336378Sgblack@eecs.umich.edu break; 1346378Sgblack@eecs.umich.edu } 13510417Sandreas.hansson@arm.com 1366378Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 1378738Sgblack@eecs.umich.edu return pioDelay; 1388578Sgblack@eecs.umich.edu} 1398578Sgblack@eecs.umich.edu 1408578Sgblack@eecs.umich.eduTick 1416378Sgblack@eecs.umich.eduPl050::write(PacketPtr pkt) 1428578Sgblack@eecs.umich.edu{ 1436378Sgblack@eecs.umich.edu 1446378Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1456378Sgblack@eecs.umich.edu 1466378Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 14710417Sandreas.hansson@arm.com 1484661Sksewell@umich.edu assert(pkt->getSize() == sizeof(uint8_t)); 1498738Sgblack@eecs.umich.edu 1508578Sgblack@eecs.umich.edu 1518578Sgblack@eecs.umich.edu switch (daddr) { 1528578Sgblack@eecs.umich.edu case kmiCr: 1538578Sgblack@eecs.umich.edu DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>()); 1548578Sgblack@eecs.umich.edu control = pkt->get<uint8_t>(); 1558578Sgblack@eecs.umich.edu updateIntStatus(); 1565224Sksewell@umich.edu break; 1576378Sgblack@eecs.umich.edu case kmiData: 1586383Sgblack@eecs.umich.edu DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>()); 1596379Sgblack@eecs.umich.edu processCommand(pkt->get<uint8_t>()); 1606383Sgblack@eecs.umich.edu updateIntStatus(); 1615222Sksewell@umich.edu break; 1625222Sksewell@umich.edu case kmiClkDiv: 1636378Sgblack@eecs.umich.edu clkdiv = pkt->get<uint8_t>(); 16410417Sandreas.hansson@arm.com break; 1655222Sksewell@umich.edu default: 1668578Sgblack@eecs.umich.edu warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); 1675222Sksewell@umich.edu break; 1685222Sksewell@umich.edu } 1696378Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 17010417Sandreas.hansson@arm.com return pioDelay; 1715222Sksewell@umich.edu} 1728578Sgblack@eecs.umich.edu 1734661Sksewell@umich.eduvoid 1744661Sksewell@umich.eduPl050::processCommand(uint8_t byte) 1752447SN/A{ 1762447SN/A using namespace Ps2; 177 178 if (ackNext) { 179 ackNext--; 180 rxQueue.push_back(Ack); 181 updateIntStatus(); 182 return; 183 } 184 185 switch (byte) { 186 case Ps2Reset: 187 rxQueue.push_back(Ack); 188 rxQueue.push_back(SelfTestPass); 189 break; 190 case SetResolution: 191 case SetRate: 192 case SetStatusLed: 193 case SetScaling1_1: 194 case SetScaling1_2: 195 rxQueue.push_back(Ack); 196 ackNext = 1; 197 break; 198 case ReadId: 199 rxQueue.push_back(Ack); 200 if (params()->is_mouse) 201 rxQueue.push_back(MouseId); 202 else 203 rxQueue.push_back(KeyboardId); 204 break; 205 case TpReadId: 206 if (!params()->is_mouse) 207 break; 208 // We're not a trackpoint device, this should make the probe go away 209 rxQueue.push_back(Ack); 210 rxQueue.push_back(0); 211 rxQueue.push_back(0); 212 // fall through 213 case Disable: 214 case Enable: 215 case SetDefaults: 216 rxQueue.push_back(Ack); 217 break; 218 case StatusRequest: 219 rxQueue.push_back(Ack); 220 rxQueue.push_back(0); 221 rxQueue.push_back(2); // default resolution 222 rxQueue.push_back(100); // default sample rate 223 break; 224 case TouchKitId: 225 ackNext = 2; 226 rxQueue.push_back(Ack); 227 rxQueue.push_back(TouchKitId); 228 rxQueue.push_back(1); 229 rxQueue.push_back('A'); 230 231 driverInitialized = true; 232 break; 233 default: 234 panic("Unknown byte received: %d\n", byte); 235 } 236 237 updateIntStatus(); 238} 239 240 241void 242Pl050::updateIntStatus() 243{ 244 if (!rxQueue.empty()) 245 rawInterrupts.rx = 1; 246 else 247 rawInterrupts.rx = 0; 248 249 interrupts.tx = rawInterrupts.tx & control.txint_enable; 250 interrupts.rx = rawInterrupts.rx & control.rxint_enable; 251 252 DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n", 253 (uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts); 254 255 if (interrupts && !intEvent.scheduled()) 256 schedule(intEvent, curTick() + intDelay); 257} 258 259void 260Pl050::generateInterrupt() 261{ 262 263 if (interrupts) { 264 gic->sendInt(intNum); 265 DPRINTF(Pl050, "Generated interrupt\n"); 266 } 267} 268 269void 270Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) 271{ 272 using namespace Ps2; 273 274 // If the driver hasn't initialized the device yet, no need to try and send 275 // it anything. Similarly we can get vnc mouse events orders of maginture 276 // faster than m5 can process them. Only queue up two sets mouse movements 277 // and don't add more until those are processed. 278 if (!driverInitialized || rxQueue.size() > 10) 279 return; 280 281 // We shouldn't be here unless a vnc server called us in which case 282 // we should have a pointer to it 283 assert(vnc); 284 285 // Convert screen coordinates to touchpad coordinates 286 uint16_t _x = (2047.0/vnc->videoWidth()) * x; 287 uint16_t _y = (2047.0/vnc->videoHeight()) * y; 288 289 rxQueue.push_back(buttons); 290 rxQueue.push_back(_x >> 7); 291 rxQueue.push_back(_x & 0x7f); 292 rxQueue.push_back(_y >> 7); 293 rxQueue.push_back(_y & 0x7f); 294 295 updateIntStatus(); 296} 297 298 299void 300Pl050::keyPress(uint32_t key, bool down) 301{ 302 using namespace Ps2; 303 304 std::list<uint8_t> keys; 305 306 // convert the X11 keysym into ps2 codes 307 keySymToPs2(key, down, shiftDown, keys); 308 309 // Insert into our queue of charecters 310 rxQueue.splice(rxQueue.end(), keys); 311 updateIntStatus(); 312} 313 314void 315Pl050::serialize(std::ostream &os) 316{ 317 uint8_t ctrlreg = control; 318 SERIALIZE_SCALAR(ctrlreg); 319 320 uint8_t stsreg = status; 321 SERIALIZE_SCALAR(stsreg); 322 SERIALIZE_SCALAR(clkdiv); 323 324 uint8_t ints = interrupts; 325 SERIALIZE_SCALAR(ints); 326 327 uint8_t raw_ints = rawInterrupts; 328 SERIALIZE_SCALAR(raw_ints); 329 330 SERIALIZE_SCALAR(ackNext); 331 SERIALIZE_SCALAR(shiftDown); 332 SERIALIZE_SCALAR(driverInitialized); 333 334 arrayParamOut(os, "rxQueue", rxQueue); 335} 336 337void 338Pl050::unserialize(Checkpoint *cp, const std::string §ion) 339{ 340 uint8_t ctrlreg; 341 UNSERIALIZE_SCALAR(ctrlreg); 342 control = ctrlreg; 343 344 uint8_t stsreg; 345 UNSERIALIZE_SCALAR(stsreg); 346 status = stsreg; 347 348 UNSERIALIZE_SCALAR(clkdiv); 349 350 uint8_t ints; 351 UNSERIALIZE_SCALAR(ints); 352 interrupts = ints; 353 354 uint8_t raw_ints; 355 UNSERIALIZE_SCALAR(raw_ints); 356 rawInterrupts = raw_ints; 357 358 UNSERIALIZE_SCALAR(ackNext); 359 UNSERIALIZE_SCALAR(shiftDown); 360 UNSERIALIZE_SCALAR(driverInitialized); 361 362 arrayParamIn(cp, section, "rxQueue", rxQueue); 363} 364 365 366 367Pl050 * 368Pl050Params::create() 369{ 370 return new Pl050(this); 371} 372