kmi.cc revision 9330
1/* 2 * Copyright (c) 2010 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ali Saidi 41 * William Wang 42 */ 43 44#include "base/vnc/vncinput.hh" 45#include "base/trace.hh" 46#include "debug/Pl050.hh" 47#include "dev/arm/amba_device.hh" 48#include "dev/arm/kmi.hh" 49#include "dev/ps2.hh" 50#include "mem/packet.hh" 51#include "mem/packet_access.hh" 52 53Pl050::Pl050(const Params *p) 54 : AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0), 55 rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc), 56 driverInitialized(false), intEvent(this) 57{ 58 pioSize = 0xfff; 59 60 if (vnc) { 61 if (!p->is_mouse) 62 vnc->setKeyboard(this); 63 else 64 vnc->setMouse(this); 65 } 66} 67 68Tick 69Pl050::read(PacketPtr pkt) 70{ 71 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 72 73 Addr daddr = pkt->getAddr() - pioAddr; 74 pkt->allocate(); 75 76 77 uint32_t data = 0; 78 79 switch (daddr) { 80 case kmiCr: 81 DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); 82 data = control; 83 break; 84 case kmiStat: 85 if (rxQueue.empty()) 86 status.rxfull = 0; 87 else 88 status.rxfull = 1; 89 90 DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); 91 data = status; 92 break; 93 case kmiData: 94 if (rxQueue.empty()) { 95 data = 0; 96 } else { 97 data = rxQueue.front(); 98 rxQueue.pop_front(); 99 } 100 DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); 101 updateIntStatus(); 102 break; 103 case kmiClkDiv: 104 data = clkdiv; 105 break; 106 case kmiISR: 107 data = interrupts; 108 DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); 109 break; 110 default: 111 if (AmbaDev::readId(pkt, ambaId, pioAddr)) { 112 // Hack for variable size accesses 113 data = pkt->get<uint32_t>(); 114 break; 115 } 116 117 warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr); 118 break; 119 } 120 121 switch(pkt->getSize()) { 122 case 1: 123 pkt->set<uint8_t>(data); 124 break; 125 case 2: 126 pkt->set<uint16_t>(data); 127 break; 128 case 4: 129 pkt->set<uint32_t>(data); 130 break; 131 default: 132 panic("KMI read size too big?\n"); 133 break; 134 } 135 136 pkt->makeAtomicResponse(); 137 return pioDelay; 138} 139 140Tick 141Pl050::write(PacketPtr pkt) 142{ 143 144 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 145 146 Addr daddr = pkt->getAddr() - pioAddr; 147 148 assert(pkt->getSize() == sizeof(uint8_t)); 149 150 151 switch (daddr) { 152 case kmiCr: 153 DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>()); 154 control = pkt->get<uint8_t>(); 155 updateIntStatus(); 156 break; 157 case kmiData: 158 DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>()); 159 processCommand(pkt->get<uint8_t>()); 160 updateIntStatus(); 161 break; 162 case kmiClkDiv: 163 clkdiv = pkt->get<uint8_t>(); 164 break; 165 default: 166 warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); 167 break; 168 } 169 pkt->makeAtomicResponse(); 170 return pioDelay; 171} 172 173void 174Pl050::processCommand(uint8_t byte) 175{ 176 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