1*6b10e573SMarc-André Lureau /* 2*6b10e573SMarc-André Lureau * QEMU Microsoft serial mouse emulation 3*6b10e573SMarc-André Lureau * 4*6b10e573SMarc-André Lureau * Copyright (c) 2008 Lubomir Rintel 5*6b10e573SMarc-André Lureau * 6*6b10e573SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 7*6b10e573SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 8*6b10e573SMarc-André Lureau * in the Software without restriction, including without limitation the rights 9*6b10e573SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*6b10e573SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 11*6b10e573SMarc-André Lureau * furnished to do so, subject to the following conditions: 12*6b10e573SMarc-André Lureau * 13*6b10e573SMarc-André Lureau * The above copyright notice and this permission notice shall be included in 14*6b10e573SMarc-André Lureau * all copies or substantial portions of the Software. 15*6b10e573SMarc-André Lureau * 16*6b10e573SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*6b10e573SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*6b10e573SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*6b10e573SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*6b10e573SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*6b10e573SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*6b10e573SMarc-André Lureau * THE SOFTWARE. 23*6b10e573SMarc-André Lureau */ 24*6b10e573SMarc-André Lureau #include "qemu/osdep.h" 25*6b10e573SMarc-André Lureau #include "qemu-common.h" 26*6b10e573SMarc-André Lureau #include "chardev/char.h" 27*6b10e573SMarc-André Lureau #include "ui/console.h" 28*6b10e573SMarc-André Lureau #include "ui/input.h" 29*6b10e573SMarc-André Lureau 30*6b10e573SMarc-André Lureau #define MSMOUSE_LO6(n) ((n) & 0x3f) 31*6b10e573SMarc-André Lureau #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) 32*6b10e573SMarc-André Lureau 33*6b10e573SMarc-André Lureau typedef struct { 34*6b10e573SMarc-André Lureau Chardev parent; 35*6b10e573SMarc-André Lureau 36*6b10e573SMarc-André Lureau QemuInputHandlerState *hs; 37*6b10e573SMarc-André Lureau int axis[INPUT_AXIS__MAX]; 38*6b10e573SMarc-André Lureau bool btns[INPUT_BUTTON__MAX]; 39*6b10e573SMarc-André Lureau bool btnc[INPUT_BUTTON__MAX]; 40*6b10e573SMarc-André Lureau uint8_t outbuf[32]; 41*6b10e573SMarc-André Lureau int outlen; 42*6b10e573SMarc-André Lureau } MouseChardev; 43*6b10e573SMarc-André Lureau 44*6b10e573SMarc-André Lureau #define TYPE_CHARDEV_MSMOUSE "chardev-msmouse" 45*6b10e573SMarc-André Lureau #define MOUSE_CHARDEV(obj) \ 46*6b10e573SMarc-André Lureau OBJECT_CHECK(MouseChardev, (obj), TYPE_CHARDEV_MSMOUSE) 47*6b10e573SMarc-André Lureau 48*6b10e573SMarc-André Lureau static void msmouse_chr_accept_input(Chardev *chr) 49*6b10e573SMarc-André Lureau { 50*6b10e573SMarc-André Lureau MouseChardev *mouse = MOUSE_CHARDEV(chr); 51*6b10e573SMarc-André Lureau int len; 52*6b10e573SMarc-André Lureau 53*6b10e573SMarc-André Lureau len = qemu_chr_be_can_write(chr); 54*6b10e573SMarc-André Lureau if (len > mouse->outlen) { 55*6b10e573SMarc-André Lureau len = mouse->outlen; 56*6b10e573SMarc-André Lureau } 57*6b10e573SMarc-André Lureau if (!len) { 58*6b10e573SMarc-André Lureau return; 59*6b10e573SMarc-André Lureau } 60*6b10e573SMarc-André Lureau 61*6b10e573SMarc-André Lureau qemu_chr_be_write(chr, mouse->outbuf, len); 62*6b10e573SMarc-André Lureau mouse->outlen -= len; 63*6b10e573SMarc-André Lureau if (mouse->outlen) { 64*6b10e573SMarc-André Lureau memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen); 65*6b10e573SMarc-André Lureau } 66*6b10e573SMarc-André Lureau } 67*6b10e573SMarc-André Lureau 68*6b10e573SMarc-André Lureau static void msmouse_queue_event(MouseChardev *mouse) 69*6b10e573SMarc-André Lureau { 70*6b10e573SMarc-André Lureau unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 }; 71*6b10e573SMarc-André Lureau int dx, dy, count = 3; 72*6b10e573SMarc-André Lureau 73*6b10e573SMarc-André Lureau dx = mouse->axis[INPUT_AXIS_X]; 74*6b10e573SMarc-André Lureau mouse->axis[INPUT_AXIS_X] = 0; 75*6b10e573SMarc-André Lureau 76*6b10e573SMarc-André Lureau dy = mouse->axis[INPUT_AXIS_Y]; 77*6b10e573SMarc-André Lureau mouse->axis[INPUT_AXIS_Y] = 0; 78*6b10e573SMarc-André Lureau 79*6b10e573SMarc-André Lureau /* Movement deltas */ 80*6b10e573SMarc-André Lureau bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx); 81*6b10e573SMarc-André Lureau bytes[1] |= MSMOUSE_LO6(dx); 82*6b10e573SMarc-André Lureau bytes[2] |= MSMOUSE_LO6(dy); 83*6b10e573SMarc-André Lureau 84*6b10e573SMarc-André Lureau /* Buttons */ 85*6b10e573SMarc-André Lureau bytes[0] |= (mouse->btns[INPUT_BUTTON_LEFT] ? 0x20 : 0x00); 86*6b10e573SMarc-André Lureau bytes[0] |= (mouse->btns[INPUT_BUTTON_RIGHT] ? 0x10 : 0x00); 87*6b10e573SMarc-André Lureau if (mouse->btns[INPUT_BUTTON_MIDDLE] || 88*6b10e573SMarc-André Lureau mouse->btnc[INPUT_BUTTON_MIDDLE]) { 89*6b10e573SMarc-André Lureau bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00); 90*6b10e573SMarc-André Lureau mouse->btnc[INPUT_BUTTON_MIDDLE] = false; 91*6b10e573SMarc-André Lureau count = 4; 92*6b10e573SMarc-André Lureau } 93*6b10e573SMarc-André Lureau 94*6b10e573SMarc-André Lureau if (mouse->outlen <= sizeof(mouse->outbuf) - count) { 95*6b10e573SMarc-André Lureau memcpy(mouse->outbuf + mouse->outlen, bytes, count); 96*6b10e573SMarc-André Lureau mouse->outlen += count; 97*6b10e573SMarc-André Lureau } else { 98*6b10e573SMarc-André Lureau /* queue full -> drop event */ 99*6b10e573SMarc-André Lureau } 100*6b10e573SMarc-André Lureau } 101*6b10e573SMarc-André Lureau 102*6b10e573SMarc-André Lureau static void msmouse_input_event(DeviceState *dev, QemuConsole *src, 103*6b10e573SMarc-André Lureau InputEvent *evt) 104*6b10e573SMarc-André Lureau { 105*6b10e573SMarc-André Lureau MouseChardev *mouse = MOUSE_CHARDEV(dev); 106*6b10e573SMarc-André Lureau InputMoveEvent *move; 107*6b10e573SMarc-André Lureau InputBtnEvent *btn; 108*6b10e573SMarc-André Lureau 109*6b10e573SMarc-André Lureau switch (evt->type) { 110*6b10e573SMarc-André Lureau case INPUT_EVENT_KIND_REL: 111*6b10e573SMarc-André Lureau move = evt->u.rel.data; 112*6b10e573SMarc-André Lureau mouse->axis[move->axis] += move->value; 113*6b10e573SMarc-André Lureau break; 114*6b10e573SMarc-André Lureau 115*6b10e573SMarc-André Lureau case INPUT_EVENT_KIND_BTN: 116*6b10e573SMarc-André Lureau btn = evt->u.btn.data; 117*6b10e573SMarc-André Lureau mouse->btns[btn->button] = btn->down; 118*6b10e573SMarc-André Lureau mouse->btnc[btn->button] = true; 119*6b10e573SMarc-André Lureau break; 120*6b10e573SMarc-André Lureau 121*6b10e573SMarc-André Lureau default: 122*6b10e573SMarc-André Lureau /* keep gcc happy */ 123*6b10e573SMarc-André Lureau break; 124*6b10e573SMarc-André Lureau } 125*6b10e573SMarc-André Lureau } 126*6b10e573SMarc-André Lureau 127*6b10e573SMarc-André Lureau static void msmouse_input_sync(DeviceState *dev) 128*6b10e573SMarc-André Lureau { 129*6b10e573SMarc-André Lureau MouseChardev *mouse = MOUSE_CHARDEV(dev); 130*6b10e573SMarc-André Lureau Chardev *chr = CHARDEV(dev); 131*6b10e573SMarc-André Lureau 132*6b10e573SMarc-André Lureau msmouse_queue_event(mouse); 133*6b10e573SMarc-André Lureau msmouse_chr_accept_input(chr); 134*6b10e573SMarc-André Lureau } 135*6b10e573SMarc-André Lureau 136*6b10e573SMarc-André Lureau static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) 137*6b10e573SMarc-André Lureau { 138*6b10e573SMarc-André Lureau /* Ignore writes to mouse port */ 139*6b10e573SMarc-André Lureau return len; 140*6b10e573SMarc-André Lureau } 141*6b10e573SMarc-André Lureau 142*6b10e573SMarc-André Lureau static void char_msmouse_finalize(Object *obj) 143*6b10e573SMarc-André Lureau { 144*6b10e573SMarc-André Lureau MouseChardev *mouse = MOUSE_CHARDEV(obj); 145*6b10e573SMarc-André Lureau 146*6b10e573SMarc-André Lureau qemu_input_handler_unregister(mouse->hs); 147*6b10e573SMarc-André Lureau } 148*6b10e573SMarc-André Lureau 149*6b10e573SMarc-André Lureau static QemuInputHandler msmouse_handler = { 150*6b10e573SMarc-André Lureau .name = "QEMU Microsoft Mouse", 151*6b10e573SMarc-André Lureau .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 152*6b10e573SMarc-André Lureau .event = msmouse_input_event, 153*6b10e573SMarc-André Lureau .sync = msmouse_input_sync, 154*6b10e573SMarc-André Lureau }; 155*6b10e573SMarc-André Lureau 156*6b10e573SMarc-André Lureau static void msmouse_chr_open(Chardev *chr, 157*6b10e573SMarc-André Lureau ChardevBackend *backend, 158*6b10e573SMarc-André Lureau bool *be_opened, 159*6b10e573SMarc-André Lureau Error **errp) 160*6b10e573SMarc-André Lureau { 161*6b10e573SMarc-André Lureau MouseChardev *mouse = MOUSE_CHARDEV(chr); 162*6b10e573SMarc-André Lureau 163*6b10e573SMarc-André Lureau *be_opened = false; 164*6b10e573SMarc-André Lureau mouse->hs = qemu_input_handler_register((DeviceState *)mouse, 165*6b10e573SMarc-André Lureau &msmouse_handler); 166*6b10e573SMarc-André Lureau } 167*6b10e573SMarc-André Lureau 168*6b10e573SMarc-André Lureau static void char_msmouse_class_init(ObjectClass *oc, void *data) 169*6b10e573SMarc-André Lureau { 170*6b10e573SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 171*6b10e573SMarc-André Lureau 172*6b10e573SMarc-André Lureau cc->open = msmouse_chr_open; 173*6b10e573SMarc-André Lureau cc->chr_write = msmouse_chr_write; 174*6b10e573SMarc-André Lureau cc->chr_accept_input = msmouse_chr_accept_input; 175*6b10e573SMarc-André Lureau } 176*6b10e573SMarc-André Lureau 177*6b10e573SMarc-André Lureau static const TypeInfo char_msmouse_type_info = { 178*6b10e573SMarc-André Lureau .name = TYPE_CHARDEV_MSMOUSE, 179*6b10e573SMarc-André Lureau .parent = TYPE_CHARDEV, 180*6b10e573SMarc-André Lureau .instance_size = sizeof(MouseChardev), 181*6b10e573SMarc-André Lureau .instance_finalize = char_msmouse_finalize, 182*6b10e573SMarc-André Lureau .class_init = char_msmouse_class_init, 183*6b10e573SMarc-André Lureau }; 184*6b10e573SMarc-André Lureau 185*6b10e573SMarc-André Lureau static void register_types(void) 186*6b10e573SMarc-André Lureau { 187*6b10e573SMarc-André Lureau type_register_static(&char_msmouse_type_info); 188*6b10e573SMarc-André Lureau } 189*6b10e573SMarc-André Lureau 190*6b10e573SMarc-André Lureau type_init(register_types); 191