qemu/chardev/msmouse.c
<<
>>
Prefs
   1/*
   2 * QEMU Microsoft serial mouse emulation
   3 *
   4 * Copyright (c) 2008 Lubomir Rintel
   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 "qemu/module.h"
  27#include "chardev/char.h"
  28#include "ui/console.h"
  29#include "ui/input.h"
  30#include "qom/object.h"
  31
  32#define MSMOUSE_LO6(n) ((n) & 0x3f)
  33#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
  34
  35struct MouseChardev {
  36    Chardev parent;
  37
  38    QemuInputHandlerState *hs;
  39    int axis[INPUT_AXIS__MAX];
  40    bool btns[INPUT_BUTTON__MAX];
  41    bool btnc[INPUT_BUTTON__MAX];
  42    uint8_t outbuf[32];
  43    int outlen;
  44};
  45typedef struct MouseChardev MouseChardev;
  46
  47#define TYPE_CHARDEV_MSMOUSE "chardev-msmouse"
  48DECLARE_INSTANCE_CHECKER(MouseChardev, MOUSE_CHARDEV,
  49                         TYPE_CHARDEV_MSMOUSE)
  50
  51static void msmouse_chr_accept_input(Chardev *chr)
  52{
  53    MouseChardev *mouse = MOUSE_CHARDEV(chr);
  54    int len;
  55
  56    len = qemu_chr_be_can_write(chr);
  57    if (len > mouse->outlen) {
  58        len = mouse->outlen;
  59    }
  60    if (!len) {
  61        return;
  62    }
  63
  64    qemu_chr_be_write(chr, mouse->outbuf, len);
  65    mouse->outlen -= len;
  66    if (mouse->outlen) {
  67        memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen);
  68    }
  69}
  70
  71static void msmouse_queue_event(MouseChardev *mouse)
  72{
  73    unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
  74    int dx, dy, count = 3;
  75
  76    dx = mouse->axis[INPUT_AXIS_X];
  77    mouse->axis[INPUT_AXIS_X] = 0;
  78
  79    dy = mouse->axis[INPUT_AXIS_Y];
  80    mouse->axis[INPUT_AXIS_Y] = 0;
  81
  82    /* Movement deltas */
  83    bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
  84    bytes[1] |= MSMOUSE_LO6(dx);
  85    bytes[2] |= MSMOUSE_LO6(dy);
  86
  87    /* Buttons */
  88    bytes[0] |= (mouse->btns[INPUT_BUTTON_LEFT]   ? 0x20 : 0x00);
  89    bytes[0] |= (mouse->btns[INPUT_BUTTON_RIGHT]  ? 0x10 : 0x00);
  90    if (mouse->btns[INPUT_BUTTON_MIDDLE] ||
  91        mouse->btnc[INPUT_BUTTON_MIDDLE]) {
  92        bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00);
  93        mouse->btnc[INPUT_BUTTON_MIDDLE] = false;
  94        count = 4;
  95    }
  96
  97    if (mouse->outlen <= sizeof(mouse->outbuf) - count) {
  98        memcpy(mouse->outbuf + mouse->outlen, bytes, count);
  99        mouse->outlen += count;
 100    } else {
 101        /* queue full -> drop event */
 102    }
 103}
 104
 105static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
 106                                InputEvent *evt)
 107{
 108    MouseChardev *mouse = MOUSE_CHARDEV(dev);
 109    InputMoveEvent *move;
 110    InputBtnEvent *btn;
 111
 112    switch (evt->type) {
 113    case INPUT_EVENT_KIND_REL:
 114        move = evt->u.rel.data;
 115        mouse->axis[move->axis] += move->value;
 116        break;
 117
 118    case INPUT_EVENT_KIND_BTN:
 119        btn = evt->u.btn.data;
 120        mouse->btns[btn->button] = btn->down;
 121        mouse->btnc[btn->button] = true;
 122        break;
 123
 124    default:
 125        /* keep gcc happy */
 126        break;
 127    }
 128}
 129
 130static void msmouse_input_sync(DeviceState *dev)
 131{
 132    MouseChardev *mouse = MOUSE_CHARDEV(dev);
 133    Chardev *chr = CHARDEV(dev);
 134
 135    msmouse_queue_event(mouse);
 136    msmouse_chr_accept_input(chr);
 137}
 138
 139static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
 140{
 141    /* Ignore writes to mouse port */
 142    return len;
 143}
 144
 145static void char_msmouse_finalize(Object *obj)
 146{
 147    MouseChardev *mouse = MOUSE_CHARDEV(obj);
 148
 149    qemu_input_handler_unregister(mouse->hs);
 150}
 151
 152static QemuInputHandler msmouse_handler = {
 153    .name  = "QEMU Microsoft Mouse",
 154    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
 155    .event = msmouse_input_event,
 156    .sync  = msmouse_input_sync,
 157};
 158
 159static void msmouse_chr_open(Chardev *chr,
 160                             ChardevBackend *backend,
 161                             bool *be_opened,
 162                             Error **errp)
 163{
 164    MouseChardev *mouse = MOUSE_CHARDEV(chr);
 165
 166    *be_opened = false;
 167    mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
 168                                            &msmouse_handler);
 169}
 170
 171static void char_msmouse_class_init(ObjectClass *oc, void *data)
 172{
 173    ChardevClass *cc = CHARDEV_CLASS(oc);
 174
 175    cc->open = msmouse_chr_open;
 176    cc->chr_write = msmouse_chr_write;
 177    cc->chr_accept_input = msmouse_chr_accept_input;
 178}
 179
 180static const TypeInfo char_msmouse_type_info = {
 181    .name = TYPE_CHARDEV_MSMOUSE,
 182    .parent = TYPE_CHARDEV,
 183    .instance_size = sizeof(MouseChardev),
 184    .instance_finalize = char_msmouse_finalize,
 185    .class_init = char_msmouse_class_init,
 186};
 187
 188static void register_types(void)
 189{
 190    type_register_static(&char_msmouse_type_info);
 191}
 192
 193type_init(register_types);
 194