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 35 struct 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 }; 45 typedef struct MouseChardev MouseChardev; 46 47 #define TYPE_CHARDEV_MSMOUSE "chardev-msmouse" 48 DECLARE_INSTANCE_CHECKER(MouseChardev, MOUSE_CHARDEV, 49 TYPE_CHARDEV_MSMOUSE) 50 51 static 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 71 static 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 105 static 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 130 static 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 139 static 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 145 static void char_msmouse_finalize(Object *obj) 146 { 147 MouseChardev *mouse = MOUSE_CHARDEV(obj); 148 149 qemu_input_handler_unregister(mouse->hs); 150 } 151 152 static 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 159 static 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 171 static 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 180 static 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 188 static void register_types(void) 189 { 190 type_register_static(&char_msmouse_type_info); 191 } 192 193 type_init(register_types); 194