/*
 * Copyright (c) 2010, 2017-2018 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          William Wang
 *          Andreas Sandberg
 */

#include "dev/ps2/touchkit.hh"

#include "base/logging.hh"
#include "debug/PS2.hh"
#include "dev/ps2/types.hh"
#include "params/PS2TouchKit.hh"

PS2TouchKit::PS2TouchKit(const PS2TouchKitParams *p)
    : PS2Device(p),
      vnc(p->vnc),
      enabled(false), touchKitEnabled(false)
{
    if (vnc)
        vnc->setMouse(this);
}

void
PS2TouchKit::serialize(CheckpointOut &cp) const
{
    PS2Device::serialize(cp);

    SERIALIZE_SCALAR(enabled);
    SERIALIZE_SCALAR(touchKitEnabled);
}

void
PS2TouchKit::unserialize(CheckpointIn &cp)
{
    PS2Device::unserialize(cp);

    UNSERIALIZE_SCALAR(enabled);
    UNSERIALIZE_SCALAR(touchKitEnabled);
}

bool
PS2TouchKit::recv(const std::vector<uint8_t> &data)
{
    switch (data[0]) {
      case Ps2::Reset:
        DPRINTF(PS2, "Resetting device.\n");
        enabled = false;
        touchKitEnabled = false;
        sendAck();
        send(Ps2::SelfTestPass);
        return true;

      case Ps2::ReadID:
        sendAck();
        send(Ps2::Mouse::ID);
        return true;

      case Ps2::Disable:
        DPRINTF(PS2, "Disabling device.\n");
        enabled = false;
        sendAck();
        return true;

      case Ps2::Enable:
        DPRINTF(PS2, "Enabling device.\n");
        enabled = true;
        sendAck();
        return true;

      case Ps2::DefaultsAndDisable:
        DPRINTF(PS2, "Setting defaults and disabling device.\n");
        enabled = false;
        sendAck();
        return true;

      case Ps2::Mouse::Scale1to1:
      case Ps2::Mouse::Scale2to1:
        sendAck();
        return true;

      case Ps2::Mouse::SetResolution:
      case Ps2::Mouse::SampleRate:
        sendAck();
        return data.size() == 2;

      case Ps2::Mouse::GetStatus:
        sendAck();
        send(0);
        send(2); // default resolution
        send(100); // default sample rate
        return true;

      case TpReadId:
        // We're not a trackpoint device, this should make the probe
        // go away
        sendAck();
        send(0);
        send(0);
        sendAck();
        return true;

      case TouchKitDiag:
        return recvTouchKit(data);

      default:
        panic("Unknown byte received: %#x\n", data[0]);
    }
}

bool
PS2TouchKit::recvTouchKit(const std::vector<uint8_t> &data)
{
    // Ack all incoming bytes
    sendAck();

    // Packet format is: 0x0A SIZE CMD DATA
    assert(data[0] == TouchKitDiag);
    if (data.size() < 3 || data.size() - 2 < data[1])
        return false;

    const uint8_t len = data[1];
    const uint8_t cmd = data[2];

    // We have received at least one TouchKit diagnostic
    // command. Enabled TouchKit reports.
    touchKitEnabled = true;


    switch (cmd) {
      case TouchKitActive:
        warn_if(len != 1, "Unexpected activate packet length: %u\n", len);
        sendTouchKit('A');
        return true;

      default:
        panic("Unimplemented touchscreen command: %#x\n", cmd);
    }
}

void
PS2TouchKit::sendTouchKit(const uint8_t *data, size_t size)
{
    send(TouchKitDiag);
    send(size);
    for (int i = 0; i < size; ++i)
        send(data[i]);
}


void
PS2TouchKit::mouseAt(uint16_t x, uint16_t y, uint8_t buttons)
{
    // If the driver hasn't initialized the device yet, no need to try and send
    // it anything. Similarly we can get vnc mouse events orders of magnitude
    // faster than m5 can process them. Only queue up two sets mouse movements
    // and don't add more until those are processed.
    if (!enabled || !touchKitEnabled || sendPending() > 10)
        return;

    // Convert screen coordinates to touchpad coordinates
    const uint16_t _x = (2047.0 / vnc->videoWidth()) * x;
    const uint16_t _y = (2047.0 / vnc->videoHeight()) * y;

    const uint8_t resp[] = {
        buttons,
        (uint8_t)(_x >> 7), (uint8_t)(_x & 0x7f),
        (uint8_t)(_y >> 7), (uint8_t)(_y & 0x7f),
    };

    send(resp, sizeof(resp));
}

PS2TouchKit *
PS2TouchKitParams::create()
{
    return new PS2TouchKit(this);
}
