qemu/hw/input/adb-mouse.c
<<
>>
Prefs
   1/*
   2 * QEMU ADB mouse support
   3 *
   4 * Copyright (c) 2004 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "ui/console.h"
  27#include "hw/input/adb.h"
  28#include "qemu/module.h"
  29#include "adb-internal.h"
  30#include "trace.h"
  31
  32#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
  33
  34typedef struct MouseState {
  35    /*< public >*/
  36    ADBDevice parent_obj;
  37    /*< private >*/
  38
  39    int buttons_state, last_buttons_state;
  40    int dx, dy, dz;
  41} MouseState;
  42
  43#define ADB_MOUSE_CLASS(class) \
  44    OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
  45#define ADB_MOUSE_GET_CLASS(obj) \
  46    OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
  47
  48typedef struct ADBMouseClass {
  49    /*< public >*/
  50    ADBDeviceClass parent_class;
  51    /*< private >*/
  52
  53    DeviceRealize parent_realize;
  54} ADBMouseClass;
  55
  56static void adb_mouse_event(void *opaque,
  57                            int dx1, int dy1, int dz1, int buttons_state)
  58{
  59    MouseState *s = opaque;
  60
  61    s->dx += dx1;
  62    s->dy += dy1;
  63    s->dz += dz1;
  64    s->buttons_state = buttons_state;
  65}
  66
  67
  68static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
  69{
  70    MouseState *s = ADB_MOUSE(d);
  71    int dx, dy;
  72
  73    if (s->last_buttons_state == s->buttons_state &&
  74        s->dx == 0 && s->dy == 0) {
  75        return 0;
  76    }
  77
  78    dx = s->dx;
  79    if (dx < -63) {
  80        dx = -63;
  81    } else if (dx > 63) {
  82        dx = 63;
  83    }
  84
  85    dy = s->dy;
  86    if (dy < -63) {
  87        dy = -63;
  88    } else if (dy > 63) {
  89        dy = 63;
  90    }
  91
  92    s->dx -= dx;
  93    s->dy -= dy;
  94    s->last_buttons_state = s->buttons_state;
  95
  96    dx &= 0x7f;
  97    dy &= 0x7f;
  98
  99    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) {
 100        dy |= 0x80;
 101    }
 102    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) {
 103        dx |= 0x80;
 104    }
 105
 106    obuf[0] = dy;
 107    obuf[1] = dx;
 108    return 2;
 109}
 110
 111static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
 112                             const uint8_t *buf, int len)
 113{
 114    MouseState *s = ADB_MOUSE(d);
 115    int cmd, reg, olen;
 116
 117    if ((buf[0] & 0x0f) == ADB_FLUSH) {
 118        /* flush mouse fifo */
 119        s->buttons_state = s->last_buttons_state;
 120        s->dx = 0;
 121        s->dy = 0;
 122        s->dz = 0;
 123        trace_adb_mouse_flush();
 124        return 0;
 125    }
 126
 127    cmd = buf[0] & 0xc;
 128    reg = buf[0] & 0x3;
 129    olen = 0;
 130    switch (cmd) {
 131    case ADB_WRITEREG:
 132        trace_adb_mouse_writereg(reg, buf[1]);
 133        switch (reg) {
 134        case 2:
 135            break;
 136        case 3:
 137            switch (buf[2]) {
 138            case ADB_CMD_SELF_TEST:
 139                break;
 140            case ADB_CMD_CHANGE_ID:
 141            case ADB_CMD_CHANGE_ID_AND_ACT:
 142            case ADB_CMD_CHANGE_ID_AND_ENABLE:
 143                d->devaddr = buf[1] & 0xf;
 144                trace_adb_mouse_request_change_addr(d->devaddr);
 145                break;
 146            default:
 147                if (!d->disable_direct_reg3_writes) {
 148                    d->devaddr = buf[1] & 0xf;
 149
 150                    /* we support handlers:
 151                     * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
 152                     * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
 153                     * we don't support handlers (at least):
 154                     * 0x03: Mouse systems A3 trackball
 155                     * 0x04: Extended Apple Mouse Protocol
 156                     * 0x2f: Microspeed mouse
 157                     * 0x42: Macally
 158                     * 0x5f: Microspeed mouse
 159                     * 0x66: Microspeed mouse
 160                     */
 161                    if (buf[2] == 1 || buf[2] == 2) {
 162                        d->handler = buf[2];
 163                    }
 164
 165                    trace_adb_mouse_request_change_addr_and_handler(
 166                        d->devaddr, d->handler);
 167                }
 168                break;
 169            }
 170        }
 171        break;
 172    case ADB_READREG:
 173        switch (reg) {
 174        case 0:
 175            olen = adb_mouse_poll(d, obuf);
 176            break;
 177        case 1:
 178            break;
 179        case 3:
 180            obuf[0] = d->devaddr;
 181            obuf[1] = d->handler;
 182            olen = 2;
 183            break;
 184        }
 185        trace_adb_mouse_readreg(reg, obuf[0], obuf[1]);
 186        break;
 187    }
 188    return olen;
 189}
 190
 191static void adb_mouse_reset(DeviceState *dev)
 192{
 193    ADBDevice *d = ADB_DEVICE(dev);
 194    MouseState *s = ADB_MOUSE(dev);
 195
 196    d->handler = 2;
 197    d->devaddr = ADB_DEVID_MOUSE;
 198    s->last_buttons_state = s->buttons_state = 0;
 199    s->dx = s->dy = s->dz = 0;
 200}
 201
 202static const VMStateDescription vmstate_adb_mouse = {
 203    .name = "adb_mouse",
 204    .version_id = 2,
 205    .minimum_version_id = 2,
 206    .fields = (VMStateField[]) {
 207        VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
 208                       ADBDevice),
 209        VMSTATE_INT32(buttons_state, MouseState),
 210        VMSTATE_INT32(last_buttons_state, MouseState),
 211        VMSTATE_INT32(dx, MouseState),
 212        VMSTATE_INT32(dy, MouseState),
 213        VMSTATE_INT32(dz, MouseState),
 214        VMSTATE_END_OF_LIST()
 215    }
 216};
 217
 218static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
 219{
 220    MouseState *s = ADB_MOUSE(dev);
 221    ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
 222
 223    amc->parent_realize(dev, errp);
 224
 225    qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
 226}
 227
 228static void adb_mouse_initfn(Object *obj)
 229{
 230    ADBDevice *d = ADB_DEVICE(obj);
 231
 232    d->devaddr = ADB_DEVID_MOUSE;
 233}
 234
 235static void adb_mouse_class_init(ObjectClass *oc, void *data)
 236{
 237    DeviceClass *dc = DEVICE_CLASS(oc);
 238    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
 239    ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
 240
 241    device_class_set_parent_realize(dc, adb_mouse_realizefn,
 242                                    &amc->parent_realize);
 243    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 244
 245    adc->devreq = adb_mouse_request;
 246    dc->reset = adb_mouse_reset;
 247    dc->vmsd = &vmstate_adb_mouse;
 248}
 249
 250static const TypeInfo adb_mouse_type_info = {
 251    .name = TYPE_ADB_MOUSE,
 252    .parent = TYPE_ADB_DEVICE,
 253    .instance_size = sizeof(MouseState),
 254    .instance_init = adb_mouse_initfn,
 255    .class_init = adb_mouse_class_init,
 256    .class_size = sizeof(ADBMouseClass),
 257};
 258
 259static void adb_mouse_register_types(void)
 260{
 261    type_register_static(&adb_mouse_type_info);
 262}
 263
 264type_init(adb_mouse_register_types)
 265