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