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