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#include "qemu/osdep.h"
  25#include "ui/console.h"
  26#include "hw/input/adb.h"
  27#include "adb-internal.h"
  28#include "trace.h"
  29
  30#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
  31
  32typedef struct MouseState {
  33    /*< public >*/
  34    ADBDevice parent_obj;
  35    /*< private >*/
  36
  37    int buttons_state, last_buttons_state;
  38    int dx, dy, dz;
  39} MouseState;
  40
  41#define ADB_MOUSE_CLASS(class) \
  42    OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
  43#define ADB_MOUSE_GET_CLASS(obj) \
  44    OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
  45
  46typedef struct ADBMouseClass {
  47    /*< public >*/
  48    ADBDeviceClass parent_class;
  49    /*< private >*/
  50
  51    DeviceRealize parent_realize;
  52} ADBMouseClass;
  53
  54static void adb_mouse_event(void *opaque,
  55                            int dx1, int dy1, int dz1, int buttons_state)
  56{
  57    MouseState *s = opaque;
  58
  59    s->dx += dx1;
  60    s->dy += dy1;
  61    s->dz += dz1;
  62    s->buttons_state = buttons_state;
  63}
  64
  65
  66static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
  67{
  68    MouseState *s = ADB_MOUSE(d);
  69    int dx, dy;
  70
  71    if (s->last_buttons_state == s->buttons_state &&
  72        s->dx == 0 && s->dy == 0) {
  73        return 0;
  74    }
  75
  76    dx = s->dx;
  77    if (dx < -63) {
  78        dx = -63;
  79    } else if (dx > 63) {
  80        dx = 63;
  81    }
  82
  83    dy = s->dy;
  84    if (dy < -63) {
  85        dy = -63;
  86    } else if (dy > 63) {
  87        dy = 63;
  88    }
  89
  90    s->dx -= dx;
  91    s->dy -= dy;
  92    s->last_buttons_state = s->buttons_state;
  93
  94    dx &= 0x7f;
  95    dy &= 0x7f;
  96
  97    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) {
  98        dy |= 0x80;
  99    }
 100    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) {
 101        dx |= 0x80;
 102    }
 103
 104    obuf[0] = dy;
 105    obuf[1] = dx;
 106    return 2;
 107}
 108
 109static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
 110                             const uint8_t *buf, int len)
 111{
 112    MouseState *s = ADB_MOUSE(d);
 113    int cmd, reg, olen;
 114
 115    if ((buf[0] & 0x0f) == ADB_FLUSH) {
 116        /* flush mouse fifo */
 117        s->buttons_state = s->last_buttons_state;
 118        s->dx = 0;
 119        s->dy = 0;
 120        s->dz = 0;
 121        trace_adb_mouse_flush();
 122        return 0;
 123    }
 124
 125    cmd = buf[0] & 0xc;
 126    reg = buf[0] & 0x3;
 127    olen = 0;
 128    switch (cmd) {
 129    case ADB_WRITEREG:
 130        trace_adb_mouse_writereg(reg, buf[1]);
 131        switch (reg) {
 132        case 2:
 133            break;
 134        case 3:
 135            switch (buf[2]) {
 136            case ADB_CMD_SELF_TEST:
 137                break;
 138            case ADB_CMD_CHANGE_ID:
 139            case ADB_CMD_CHANGE_ID_AND_ACT:
 140            case ADB_CMD_CHANGE_ID_AND_ENABLE:
 141                d->devaddr = buf[1] & 0xf;
 142                trace_adb_mouse_request_change_addr(d->devaddr);
 143                break;
 144            default:
 145                if (!d->disable_direct_reg3_writes) {
 146                    d->devaddr = buf[1] & 0xf;
 147
 148                    /* we support handlers:
 149                     * 0x01: Classic Apple Mouse Protocol / 100 cpi operations
 150                     * 0x02: Classic Apple Mouse Protocol / 200 cpi operations
 151                     * we don't support handlers (at least):
 152                     * 0x03: Mouse systems A3 trackball
 153                     * 0x04: Extended Apple Mouse Protocol
 154                     * 0x2f: Microspeed mouse
 155                     * 0x42: Macally
 156                     * 0x5f: Microspeed mouse
 157                     * 0x66: Microspeed mouse
 158                     */
 159                    if (buf[2] == 1 || buf[2] == 2) {
 160                        d->handler = buf[2];
 161                    }
 162
 163                    trace_adb_mouse_request_change_addr_and_handler(
 164                        d->devaddr, d->handler);
 165                }
 166                break;
 167            }
 168        }
 169        break;
 170    case ADB_READREG:
 171        switch (reg) {
 172        case 0:
 173            olen = adb_mouse_poll(d, obuf);
 174            break;
 175        case 1:
 176            break;
 177        case 3:
 178            obuf[0] = d->devaddr;
 179            obuf[1] = d->handler;
 180            olen = 2;
 181            break;
 182        }
 183        trace_adb_mouse_readreg(reg, obuf[0], obuf[1]);
 184        break;
 185    }
 186    return olen;
 187}
 188
 189static void adb_mouse_reset(DeviceState *dev)
 190{
 191    ADBDevice *d = ADB_DEVICE(dev);
 192    MouseState *s = ADB_MOUSE(dev);
 193
 194    d->handler = 2;
 195    d->devaddr = ADB_DEVID_MOUSE;
 196    s->last_buttons_state = s->buttons_state = 0;
 197    s->dx = s->dy = s->dz = 0;
 198}
 199
 200static const VMStateDescription vmstate_adb_mouse = {
 201    .name = "adb_mouse",
 202    .version_id = 2,
 203    .minimum_version_id = 2,
 204    .fields = (VMStateField[]) {
 205        VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
 206                       ADBDevice),
 207        VMSTATE_INT32(buttons_state, MouseState),
 208        VMSTATE_INT32(last_buttons_state, MouseState),
 209        VMSTATE_INT32(dx, MouseState),
 210        VMSTATE_INT32(dy, MouseState),
 211        VMSTATE_INT32(dz, MouseState),
 212        VMSTATE_END_OF_LIST()
 213    }
 214};
 215
 216static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
 217{
 218    MouseState *s = ADB_MOUSE(dev);
 219    ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
 220
 221    amc->parent_realize(dev, errp);
 222
 223    qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
 224}
 225
 226static void adb_mouse_initfn(Object *obj)
 227{
 228    ADBDevice *d = ADB_DEVICE(obj);
 229
 230    d->devaddr = ADB_DEVID_MOUSE;
 231}
 232
 233static void adb_mouse_class_init(ObjectClass *oc, void *data)
 234{
 235    DeviceClass *dc = DEVICE_CLASS(oc);
 236    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
 237    ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
 238
 239    device_class_set_parent_realize(dc, adb_mouse_realizefn,
 240                                    &amc->parent_realize);
 241    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 242
 243    adc->devreq = adb_mouse_request;
 244    dc->reset = adb_mouse_reset;
 245    dc->vmsd = &vmstate_adb_mouse;
 246}
 247
 248static const TypeInfo adb_mouse_type_info = {
 249    .name = TYPE_ADB_MOUSE,
 250    .parent = TYPE_ADB_DEVICE,
 251    .instance_size = sizeof(MouseState),
 252    .instance_init = adb_mouse_initfn,
 253    .class_init = adb_mouse_class_init,
 254    .class_size = sizeof(ADBMouseClass),
 255};
 256
 257static void adb_mouse_register_types(void)
 258{
 259    type_register_static(&adb_mouse_type_info);
 260}
 261
 262type_init(adb_mouse_register_types)
 263