kmi.cc revision 9806:3f262c18ad5d
17191Sgblack@eecs.umich.edu/* 27191Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited 37191Sgblack@eecs.umich.edu * All rights reserved 47191Sgblack@eecs.umich.edu * 57191Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67191Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77191Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87191Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97191Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107191Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117191Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127191Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137191Sgblack@eecs.umich.edu * 147191Sgblack@eecs.umich.edu * Copyright (c) 2005 The Regents of The University of Michigan 157191Sgblack@eecs.umich.edu * All rights reserved. 167191Sgblack@eecs.umich.edu * 177191Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 187191Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 197191Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 207191Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 217191Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 227191Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 237191Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 247191Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 257191Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 267191Sgblack@eecs.umich.edu * this software without specific prior written permission. 277191Sgblack@eecs.umich.edu * 287191Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 297191Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307191Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 317191Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 327191Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337191Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 347191Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 357191Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 367191Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 377191Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 387191Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 397191Sgblack@eecs.umich.edu * 407191Sgblack@eecs.umich.edu * Authors: Ali Saidi 417191Sgblack@eecs.umich.edu * William Wang 427191Sgblack@eecs.umich.edu */ 437191Sgblack@eecs.umich.edu 447191Sgblack@eecs.umich.edu#include "base/vnc/vncinput.hh" 457191Sgblack@eecs.umich.edu#include "base/trace.hh" 467191Sgblack@eecs.umich.edu#include "debug/Pl050.hh" 477308Sgblack@eecs.umich.edu#include "dev/arm/amba_device.hh" 487191Sgblack@eecs.umich.edu#include "dev/arm/kmi.hh" 497191Sgblack@eecs.umich.edu#include "dev/ps2.hh" 507191Sgblack@eecs.umich.edu#include "mem/packet.hh" 517191Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 527191Sgblack@eecs.umich.edu 537191Sgblack@eecs.umich.eduPl050::Pl050(const Params *p) 547191Sgblack@eecs.umich.edu : AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0), 557191Sgblack@eecs.umich.edu rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc), 567191Sgblack@eecs.umich.edu driverInitialized(false), intEvent(this) 577191Sgblack@eecs.umich.edu{ 587191Sgblack@eecs.umich.edu pioSize = 0xfff; 597191Sgblack@eecs.umich.edu 607191Sgblack@eecs.umich.edu if (vnc) { 617248Sgblack@eecs.umich.edu if (!p->is_mouse) 627191Sgblack@eecs.umich.edu vnc->setKeyboard(this); 637192Sgblack@eecs.umich.edu else 647192Sgblack@eecs.umich.edu vnc->setMouse(this); 657192Sgblack@eecs.umich.edu } 667192Sgblack@eecs.umich.edu} 677192Sgblack@eecs.umich.edu 687192Sgblack@eecs.umich.eduTick 697192Sgblack@eecs.umich.eduPl050::read(PacketPtr pkt) 707192Sgblack@eecs.umich.edu{ 717192Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 727191Sgblack@eecs.umich.edu 737191Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 747191Sgblack@eecs.umich.edu pkt->allocate(); 757192Sgblack@eecs.umich.edu 767192Sgblack@eecs.umich.edu 777192Sgblack@eecs.umich.edu uint32_t data = 0; 787192Sgblack@eecs.umich.edu 797192Sgblack@eecs.umich.edu switch (daddr) { 807192Sgblack@eecs.umich.edu case kmiCr: 817192Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); 827192Sgblack@eecs.umich.edu data = control; 837192Sgblack@eecs.umich.edu break; 847192Sgblack@eecs.umich.edu case kmiStat: 857192Sgblack@eecs.umich.edu if (rxQueue.empty()) 867192Sgblack@eecs.umich.edu status.rxfull = 0; 877192Sgblack@eecs.umich.edu else 887192Sgblack@eecs.umich.edu status.rxfull = 1; 897192Sgblack@eecs.umich.edu 907192Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); 917192Sgblack@eecs.umich.edu data = status; 927192Sgblack@eecs.umich.edu break; 937192Sgblack@eecs.umich.edu case kmiData: 947192Sgblack@eecs.umich.edu if (rxQueue.empty()) { 957191Sgblack@eecs.umich.edu data = 0; 967191Sgblack@eecs.umich.edu } else { 977191Sgblack@eecs.umich.edu data = rxQueue.front(); 987191Sgblack@eecs.umich.edu rxQueue.pop_front(); 997191Sgblack@eecs.umich.edu } 1007191Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); 1017191Sgblack@eecs.umich.edu updateIntStatus(); 1027191Sgblack@eecs.umich.edu break; 1037191Sgblack@eecs.umich.edu case kmiClkDiv: 1047191Sgblack@eecs.umich.edu data = clkdiv; 1057191Sgblack@eecs.umich.edu break; 1067191Sgblack@eecs.umich.edu case kmiISR: 1077191Sgblack@eecs.umich.edu data = interrupts; 1087191Sgblack@eecs.umich.edu DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); 1097191Sgblack@eecs.umich.edu break; 1107191Sgblack@eecs.umich.edu default: 1117248Sgblack@eecs.umich.edu if (readId(pkt, ambaId, pioAddr)) { 1127191Sgblack@eecs.umich.edu // Hack for variable size accesses 1137192Sgblack@eecs.umich.edu data = pkt->get<uint32_t>(); 1147192Sgblack@eecs.umich.edu break; 1157192Sgblack@eecs.umich.edu } 1167192Sgblack@eecs.umich.edu 1177192Sgblack@eecs.umich.edu warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr); 1187192Sgblack@eecs.umich.edu break; 1197192Sgblack@eecs.umich.edu } 1207192Sgblack@eecs.umich.edu 1217192Sgblack@eecs.umich.edu switch(pkt->getSize()) { 1227192Sgblack@eecs.umich.edu case 1: 1237192Sgblack@eecs.umich.edu pkt->set<uint8_t>(data); 1247192Sgblack@eecs.umich.edu break; 1257192Sgblack@eecs.umich.edu case 2: 1267192Sgblack@eecs.umich.edu pkt->set<uint16_t>(data); 1277191Sgblack@eecs.umich.edu break; 1287192Sgblack@eecs.umich.edu case 4: 1297192Sgblack@eecs.umich.edu pkt->set<uint32_t>(data); 1307192Sgblack@eecs.umich.edu break; 1317192Sgblack@eecs.umich.edu default: 1327192Sgblack@eecs.umich.edu panic("KMI read size too big?\n"); 1337192Sgblack@eecs.umich.edu break; 1347192Sgblack@eecs.umich.edu } 1357192Sgblack@eecs.umich.edu 1367192Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 1377192Sgblack@eecs.umich.edu return pioDelay; 1387192Sgblack@eecs.umich.edu} 1397192Sgblack@eecs.umich.edu 1407192Sgblack@eecs.umich.eduTick 1417192Sgblack@eecs.umich.eduPl050::write(PacketPtr pkt) 1427192Sgblack@eecs.umich.edu{ 1437192Sgblack@eecs.umich.edu 1447192Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1457192Sgblack@eecs.umich.edu 1467192Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 1477192Sgblack@eecs.umich.edu 1487192Sgblack@eecs.umich.edu assert(pkt->getSize() == sizeof(uint8_t)); 1497192Sgblack@eecs.umich.edu 1507192Sgblack@eecs.umich.edu 1517192Sgblack@eecs.umich.edu switch (daddr) { 1527192Sgblack@eecs.umich.edu case kmiCr: 1537192Sgblack@eecs.umich.edu DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>()); 1547192Sgblack@eecs.umich.edu control = pkt->get<uint8_t>(); 1557192Sgblack@eecs.umich.edu updateIntStatus(); 1567192Sgblack@eecs.umich.edu break; 1577192Sgblack@eecs.umich.edu case kmiData: 1587191Sgblack@eecs.umich.edu DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>()); 1597191Sgblack@eecs.umich.edu processCommand(pkt->get<uint8_t>()); 1607191Sgblack@eecs.umich.edu updateIntStatus(); 1617191Sgblack@eecs.umich.edu break; 1627191Sgblack@eecs.umich.edu case kmiClkDiv: 1637191Sgblack@eecs.umich.edu clkdiv = pkt->get<uint8_t>(); 1647191Sgblack@eecs.umich.edu break; 1657191Sgblack@eecs.umich.edu default: 1667191Sgblack@eecs.umich.edu warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); 1677191Sgblack@eecs.umich.edu break; 1687293Sgblack@eecs.umich.edu } 1697293Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 1707293Sgblack@eecs.umich.edu return pioDelay; 1717293Sgblack@eecs.umich.edu} 1727293Sgblack@eecs.umich.edu 1737293Sgblack@eecs.umich.eduvoid 1747293Sgblack@eecs.umich.eduPl050::processCommand(uint8_t byte) 1757293Sgblack@eecs.umich.edu{ 1767293Sgblack@eecs.umich.edu using namespace Ps2; 1777293Sgblack@eecs.umich.edu 1787293Sgblack@eecs.umich.edu if (ackNext) { 1797293Sgblack@eecs.umich.edu ackNext--; 1807293Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 1817293Sgblack@eecs.umich.edu updateIntStatus(); 1827293Sgblack@eecs.umich.edu return; 1837293Sgblack@eecs.umich.edu } 1847293Sgblack@eecs.umich.edu 1857293Sgblack@eecs.umich.edu switch (byte) { 1867293Sgblack@eecs.umich.edu case Ps2Reset: 1877293Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 1887293Sgblack@eecs.umich.edu rxQueue.push_back(SelfTestPass); 1897293Sgblack@eecs.umich.edu break; 1907293Sgblack@eecs.umich.edu case SetResolution: 1917293Sgblack@eecs.umich.edu case SetRate: 1927293Sgblack@eecs.umich.edu case SetStatusLed: 1937293Sgblack@eecs.umich.edu case SetScaling1_1: 1947293Sgblack@eecs.umich.edu case SetScaling1_2: 1957191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 1967191Sgblack@eecs.umich.edu ackNext = 1; 1977191Sgblack@eecs.umich.edu break; 1987191Sgblack@eecs.umich.edu case ReadId: 1997191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 2007191Sgblack@eecs.umich.edu if (params()->is_mouse) 2017191Sgblack@eecs.umich.edu rxQueue.push_back(MouseId); 2027191Sgblack@eecs.umich.edu else 2037191Sgblack@eecs.umich.edu rxQueue.push_back(KeyboardId); 2047191Sgblack@eecs.umich.edu break; 2057191Sgblack@eecs.umich.edu case TpReadId: 2067191Sgblack@eecs.umich.edu if (!params()->is_mouse) 2077191Sgblack@eecs.umich.edu break; 2087191Sgblack@eecs.umich.edu // We're not a trackpoint device, this should make the probe go away 2097191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 2107191Sgblack@eecs.umich.edu rxQueue.push_back(0); 2117191Sgblack@eecs.umich.edu rxQueue.push_back(0); 2127191Sgblack@eecs.umich.edu // fall through 2137191Sgblack@eecs.umich.edu case Disable: 2147191Sgblack@eecs.umich.edu case Enable: 2157191Sgblack@eecs.umich.edu case SetDefaults: 2167191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 2177191Sgblack@eecs.umich.edu break; 2187191Sgblack@eecs.umich.edu case StatusRequest: 2197191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 2207191Sgblack@eecs.umich.edu rxQueue.push_back(0); 2217191Sgblack@eecs.umich.edu rxQueue.push_back(2); // default resolution 2227191Sgblack@eecs.umich.edu rxQueue.push_back(100); // default sample rate 2237191Sgblack@eecs.umich.edu break; 2247191Sgblack@eecs.umich.edu case TouchKitId: 2257191Sgblack@eecs.umich.edu ackNext = 2; 2267191Sgblack@eecs.umich.edu rxQueue.push_back(Ack); 2277191Sgblack@eecs.umich.edu rxQueue.push_back(TouchKitId); 2287191Sgblack@eecs.umich.edu rxQueue.push_back(1); 2297191Sgblack@eecs.umich.edu rxQueue.push_back('A'); 2307191Sgblack@eecs.umich.edu 2317191Sgblack@eecs.umich.edu driverInitialized = true; 2327191Sgblack@eecs.umich.edu break; 2337191Sgblack@eecs.umich.edu default: 2347191Sgblack@eecs.umich.edu panic("Unknown byte received: %d\n", byte); 2357191Sgblack@eecs.umich.edu } 2367191Sgblack@eecs.umich.edu 2377191Sgblack@eecs.umich.edu updateIntStatus(); 2387191Sgblack@eecs.umich.edu} 2397191Sgblack@eecs.umich.edu 2407191Sgblack@eecs.umich.edu 2417191Sgblack@eecs.umich.eduvoid 2427191Sgblack@eecs.umich.eduPl050::updateIntStatus() 2437191Sgblack@eecs.umich.edu{ 2447191Sgblack@eecs.umich.edu if (!rxQueue.empty()) 2457191Sgblack@eecs.umich.edu rawInterrupts.rx = 1; 2467191Sgblack@eecs.umich.edu else 2477191Sgblack@eecs.umich.edu rawInterrupts.rx = 0; 2487191Sgblack@eecs.umich.edu 2497192Sgblack@eecs.umich.edu interrupts.tx = rawInterrupts.tx & control.txint_enable; 2507192Sgblack@eecs.umich.edu interrupts.rx = rawInterrupts.rx & control.rxint_enable; 2517192Sgblack@eecs.umich.edu 2527192Sgblack@eecs.umich.edu DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n", 2537192Sgblack@eecs.umich.edu (uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts); 2547192Sgblack@eecs.umich.edu 2557192Sgblack@eecs.umich.edu if (interrupts && !intEvent.scheduled()) 2567192Sgblack@eecs.umich.edu schedule(intEvent, curTick() + intDelay); 2577192Sgblack@eecs.umich.edu} 2587192Sgblack@eecs.umich.edu 2597192Sgblack@eecs.umich.eduvoid 2607192Sgblack@eecs.umich.eduPl050::generateInterrupt() 2617293Sgblack@eecs.umich.edu{ 2627293Sgblack@eecs.umich.edu 2637293Sgblack@eecs.umich.edu if (interrupts) { 2647293Sgblack@eecs.umich.edu gic->sendInt(intNum); 2657293Sgblack@eecs.umich.edu DPRINTF(Pl050, "Generated interrupt\n"); 2667293Sgblack@eecs.umich.edu } 2677293Sgblack@eecs.umich.edu} 2687293Sgblack@eecs.umich.edu 2697293Sgblack@eecs.umich.eduvoid 2707192Sgblack@eecs.umich.eduPl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) 2717191Sgblack@eecs.umich.edu{ 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