diff options
Diffstat (limited to 'chardev/msmouse.c')
-rw-r--r-- | chardev/msmouse.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/chardev/msmouse.c b/chardev/msmouse.c new file mode 100644 index 0000000000..0ffd137ce8 --- /dev/null +++ b/chardev/msmouse.c @@ -0,0 +1,190 @@ +/* + * QEMU Microsoft serial mouse emulation + * + * Copyright (c) 2008 Lubomir Rintel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "chardev/char.h" +#include "ui/console.h" +#include "ui/input.h" + +#define MSMOUSE_LO6(n) ((n) & 0x3f) +#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) + +typedef struct { + Chardev parent; + + QemuInputHandlerState *hs; + int axis[INPUT_AXIS__MAX]; + bool btns[INPUT_BUTTON__MAX]; + bool btnc[INPUT_BUTTON__MAX]; + uint8_t outbuf[32]; + int outlen; +} MouseChardev; + +#define TYPE_CHARDEV_MSMOUSE "chardev-msmouse" +#define MOUSE_CHARDEV(obj) \ + OBJECT_CHECK(MouseChardev, (obj), TYPE_CHARDEV_MSMOUSE) + +static void msmouse_chr_accept_input(Chardev *chr) +{ + MouseChardev *mouse = MOUSE_CHARDEV(chr); + int len; + + len = qemu_chr_be_can_write(chr); + if (len > mouse->outlen) { + len = mouse->outlen; + } + if (!len) { + return; + } + + qemu_chr_be_write(chr, mouse->outbuf, len); + mouse->outlen -= len; + if (mouse->outlen) { + memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen); + } +} + +static void msmouse_queue_event(MouseChardev *mouse) +{ + unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 }; + int dx, dy, count = 3; + + dx = mouse->axis[INPUT_AXIS_X]; + mouse->axis[INPUT_AXIS_X] = 0; + + dy = mouse->axis[INPUT_AXIS_Y]; + mouse->axis[INPUT_AXIS_Y] = 0; + + /* Movement deltas */ + bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx); + bytes[1] |= MSMOUSE_LO6(dx); + bytes[2] |= MSMOUSE_LO6(dy); + + /* Buttons */ + bytes[0] |= (mouse->btns[INPUT_BUTTON_LEFT] ? 0x20 : 0x00); + bytes[0] |= (mouse->btns[INPUT_BUTTON_RIGHT] ? 0x10 : 0x00); + if (mouse->btns[INPUT_BUTTON_MIDDLE] || + mouse->btnc[INPUT_BUTTON_MIDDLE]) { + bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00); + mouse->btnc[INPUT_BUTTON_MIDDLE] = false; + count = 4; + } + + if (mouse->outlen <= sizeof(mouse->outbuf) - count) { + memcpy(mouse->outbuf + mouse->outlen, bytes, count); + mouse->outlen += count; + } else { + /* queue full -> drop event */ + } +} + +static void msmouse_input_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + MouseChardev *mouse = MOUSE_CHARDEV(dev); + InputMoveEvent *move; + InputBtnEvent *btn; + + switch (evt->type) { + case INPUT_EVENT_KIND_REL: + move = evt->u.rel.data; + mouse->axis[move->axis] += move->value; + break; + + case INPUT_EVENT_KIND_BTN: + btn = evt->u.btn.data; + mouse->btns[btn->button] = btn->down; + mouse->btnc[btn->button] = true; + break; + + default: + /* keep gcc happy */ + break; + } +} + +static void msmouse_input_sync(DeviceState *dev) +{ + MouseChardev *mouse = MOUSE_CHARDEV(dev); + Chardev *chr = CHARDEV(dev); + + msmouse_queue_event(mouse); + msmouse_chr_accept_input(chr); +} + +static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) +{ + /* Ignore writes to mouse port */ + return len; +} + +static void char_msmouse_finalize(Object *obj) +{ + MouseChardev *mouse = MOUSE_CHARDEV(obj); + + qemu_input_handler_unregister(mouse->hs); +} + +static QemuInputHandler msmouse_handler = { + .name = "QEMU Microsoft Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = msmouse_input_event, + .sync = msmouse_input_sync, +}; + +static void msmouse_chr_open(Chardev *chr, + ChardevBackend *backend, + bool *be_opened, + Error **errp) +{ + MouseChardev *mouse = MOUSE_CHARDEV(chr); + + *be_opened = false; + mouse->hs = qemu_input_handler_register((DeviceState *)mouse, + &msmouse_handler); +} + +static void char_msmouse_class_init(ObjectClass *oc, void *data) +{ + ChardevClass *cc = CHARDEV_CLASS(oc); + + cc->open = msmouse_chr_open; + cc->chr_write = msmouse_chr_write; + cc->chr_accept_input = msmouse_chr_accept_input; +} + +static const TypeInfo char_msmouse_type_info = { + .name = TYPE_CHARDEV_MSMOUSE, + .parent = TYPE_CHARDEV, + .instance_size = sizeof(MouseChardev), + .instance_finalize = char_msmouse_finalize, + .class_init = char_msmouse_class_init, +}; + +static void register_types(void) +{ + type_register_static(&char_msmouse_type_info); +} + +type_init(register_types); |