kmi.cc revision 10905:a6ca6831e775
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, 0xfff), control(0), status(0x43), clkdiv(0), 55 interrupts(0), rawInterrupts(0), ackNext(false), shiftDown(false), 56 vnc(p->vnc), driverInitialized(false), intEvent(this) 57{ 58 if (vnc) { 59 if (!p->is_mouse) 60 vnc->setKeyboard(this); 61 else 62 vnc->setMouse(this); 63 } 64} 65 66Tick 67Pl050::read(PacketPtr pkt) 68{ 69 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 70 71 Addr daddr = pkt->getAddr() - pioAddr; 72 73 uint32_t data = 0; 74 75 switch (daddr) { 76 case kmiCr: 77 DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); 78 data = control; 79 break; 80 case kmiStat: 81 if (rxQueue.empty()) 82 status.rxfull = 0; 83 else 84 status.rxfull = 1; 85 86 DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); 87 data = status; 88 break; 89 case kmiData: 90 if (rxQueue.empty()) { 91 data = 0; 92 } else { 93 data = rxQueue.front(); 94 rxQueue.pop_front(); 95 } 96 DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); 97 updateIntStatus(); 98 break; 99 case kmiClkDiv: 100 data = clkdiv; 101 break; 102 case kmiISR: 103 data = interrupts; 104 DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); 105 break; 106 default: 107 if (readId(pkt, ambaId, pioAddr)) { 108 // Hack for variable size accesses 109 data = pkt->get<uint32_t>(); 110 break; 111 } 112 113 warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr); 114 break; 115 } 116 117 switch(pkt->getSize()) { 118 case 1: 119 pkt->set<uint8_t>(data); 120 break; 121 case 2: 122 pkt->set<uint16_t>(data); 123 break; 124 case 4: 125 pkt->set<uint32_t>(data); 126 break; 127 default: 128 panic("KMI read size too big?\n"); 129 break; 130 } 131 132 pkt->makeAtomicResponse(); 133 return pioDelay; 134} 135 136Tick 137Pl050::write(PacketPtr pkt) 138{ 139 140 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 141 142 Addr daddr = pkt->getAddr() - pioAddr; 143 144 assert(pkt->getSize() == sizeof(uint8_t)); 145 146 147 switch (daddr) { 148 case kmiCr: 149 DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>()); 150 control = pkt->get<uint8_t>(); 151 updateIntStatus(); 152 break; 153 case kmiData: 154 DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>()); 155 processCommand(pkt->get<uint8_t>()); 156 updateIntStatus(); 157 break; 158 case kmiClkDiv: 159 clkdiv = pkt->get<uint8_t>(); 160 break; 161 default: 162 warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); 163 break; 164 } 165 pkt->makeAtomicResponse(); 166 return pioDelay; 167} 168 169void 170Pl050::processCommand(uint8_t byte) 171{ 172 using namespace Ps2; 173 174 if (ackNext) { 175 ackNext--; 176 rxQueue.push_back(Ack); 177 updateIntStatus(); 178 return; 179 } 180 181 switch (byte) { 182 case Ps2Reset: 183 rxQueue.push_back(Ack); 184 rxQueue.push_back(SelfTestPass); 185 break; 186 case SetResolution: 187 case SetRate: 188 case SetStatusLed: 189 case SetScaling1_1: 190 case SetScaling1_2: 191 rxQueue.push_back(Ack); 192 ackNext = 1; 193 break; 194 case ReadId: 195 rxQueue.push_back(Ack); 196 if (params()->is_mouse) 197 rxQueue.push_back(MouseId); 198 else 199 rxQueue.push_back(KeyboardId); 200 break; 201 case TpReadId: 202 if (!params()->is_mouse) 203 break; 204 // We're not a trackpoint device, this should make the probe go away 205 rxQueue.push_back(Ack); 206 rxQueue.push_back(0); 207 rxQueue.push_back(0); 208 // fall through 209 case Disable: 210 case Enable: 211 case SetDefaults: 212 rxQueue.push_back(Ack); 213 break; 214 case StatusRequest: 215 rxQueue.push_back(Ack); 216 rxQueue.push_back(0); 217 rxQueue.push_back(2); // default resolution 218 rxQueue.push_back(100); // default sample rate 219 break; 220 case TouchKitId: 221 ackNext = 2; 222 rxQueue.push_back(Ack); 223 rxQueue.push_back(TouchKitId); 224 rxQueue.push_back(1); 225 rxQueue.push_back('A'); 226 227 driverInitialized = true; 228 break; 229 default: 230 panic("Unknown byte received: %d\n", byte); 231 } 232 233 updateIntStatus(); 234} 235 236 237void 238Pl050::updateIntStatus() 239{ 240 if (!rxQueue.empty()) 241 rawInterrupts.rx = 1; 242 else 243 rawInterrupts.rx = 0; 244 245 interrupts.tx = rawInterrupts.tx & control.txint_enable; 246 interrupts.rx = rawInterrupts.rx & control.rxint_enable; 247 248 DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n", 249 (uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts); 250 251 if (interrupts && !intEvent.scheduled()) 252 schedule(intEvent, curTick() + intDelay); 253} 254 255void 256Pl050::generateInterrupt() 257{ 258 259 if (interrupts) { 260 gic->sendInt(intNum); 261 DPRINTF(Pl050, "Generated interrupt\n"); 262 } 263} 264 265void 266Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) 267{ 268 using namespace Ps2; 269 270 // If the driver hasn't initialized the device yet, no need to try and send 271 // it anything. Similarly we can get vnc mouse events orders of maginture 272 // faster than m5 can process them. Only queue up two sets mouse movements 273 // and don't add more until those are processed. 274 if (!driverInitialized || rxQueue.size() > 10) 275 return; 276 277 // We shouldn't be here unless a vnc server called us in which case 278 // we should have a pointer to it 279 assert(vnc); 280 281 // Convert screen coordinates to touchpad coordinates 282 uint16_t _x = (2047.0/vnc->videoWidth()) * x; 283 uint16_t _y = (2047.0/vnc->videoHeight()) * y; 284 285 rxQueue.push_back(buttons); 286 rxQueue.push_back(_x >> 7); 287 rxQueue.push_back(_x & 0x7f); 288 rxQueue.push_back(_y >> 7); 289 rxQueue.push_back(_y & 0x7f); 290 291 updateIntStatus(); 292} 293 294 295void 296Pl050::keyPress(uint32_t key, bool down) 297{ 298 using namespace Ps2; 299 300 std::list<uint8_t> keys; 301 302 // convert the X11 keysym into ps2 codes 303 keySymToPs2(key, down, shiftDown, keys); 304 305 // Insert into our queue of charecters 306 rxQueue.splice(rxQueue.end(), keys); 307 updateIntStatus(); 308} 309 310void 311Pl050::serialize(CheckpointOut &cp) const 312{ 313 uint8_t ctrlreg = control; 314 SERIALIZE_SCALAR(ctrlreg); 315 316 uint8_t stsreg = status; 317 SERIALIZE_SCALAR(stsreg); 318 SERIALIZE_SCALAR(clkdiv); 319 320 uint8_t ints = interrupts; 321 SERIALIZE_SCALAR(ints); 322 323 uint8_t raw_ints = rawInterrupts; 324 SERIALIZE_SCALAR(raw_ints); 325 326 SERIALIZE_SCALAR(ackNext); 327 SERIALIZE_SCALAR(shiftDown); 328 SERIALIZE_SCALAR(driverInitialized); 329 330 SERIALIZE_CONTAINER(rxQueue); 331} 332 333void 334Pl050::unserialize(CheckpointIn &cp) 335{ 336 uint8_t ctrlreg; 337 UNSERIALIZE_SCALAR(ctrlreg); 338 control = ctrlreg; 339 340 uint8_t stsreg; 341 UNSERIALIZE_SCALAR(stsreg); 342 status = stsreg; 343 344 UNSERIALIZE_SCALAR(clkdiv); 345 346 uint8_t ints; 347 UNSERIALIZE_SCALAR(ints); 348 interrupts = ints; 349 350 uint8_t raw_ints; 351 UNSERIALIZE_SCALAR(raw_ints); 352 rawInterrupts = raw_ints; 353 354 UNSERIALIZE_SCALAR(ackNext); 355 UNSERIALIZE_SCALAR(shiftDown); 356 UNSERIALIZE_SCALAR(driverInitialized); 357 358 UNSERIALIZE_CONTAINER(rxQueue); 359} 360 361 362 363Pl050 * 364Pl050Params::create() 365{ 366 return new Pl050(this); 367} 368