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