1 /* 2 * QEMU ADB mouse support 3 * 4 * Copyright (c) 2004 Fabrice Bellard 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 "ui/console.h" 27 #include "hw/input/adb.h" 28 #include "migration/vmstate.h" 29 #include "qemu/module.h" 30 #include "adb-internal.h" 31 #include "trace.h" 32 #include "qom/object.h" 33 34 OBJECT_DECLARE_TYPE(MouseState, ADBMouseClass, ADB_MOUSE) 35 36 struct MouseState { 37 /*< public >*/ 38 ADBDevice parent_obj; 39 /*< private >*/ 40 41 QemuInputHandlerState *hs; 42 int buttons_state, last_buttons_state; 43 int dx, dy, dz; 44 }; 45 46 47 struct ADBMouseClass { 48 /*< public >*/ 49 ADBDeviceClass parent_class; 50 /*< private >*/ 51 52 DeviceRealize parent_realize; 53 }; 54 55 #define ADB_MOUSE_BUTTON_LEFT 0x01 56 #define ADB_MOUSE_BUTTON_RIGHT 0x02 57 58 static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src, 59 InputEvent *evt) 60 { 61 MouseState *s = (MouseState *)dev; 62 InputMoveEvent *move; 63 InputBtnEvent *btn; 64 static const int bmap[INPUT_BUTTON__MAX] = { 65 [INPUT_BUTTON_LEFT] = ADB_MOUSE_BUTTON_LEFT, 66 [INPUT_BUTTON_RIGHT] = ADB_MOUSE_BUTTON_RIGHT, 67 }; 68 69 switch (evt->type) { 70 case INPUT_EVENT_KIND_REL: 71 move = evt->u.rel.data; 72 if (move->axis == INPUT_AXIS_X) { 73 s->dx += move->value; 74 } else if (move->axis == INPUT_AXIS_Y) { 75 s->dy += move->value; 76 } 77 break; 78 79 case INPUT_EVENT_KIND_BTN: 80 btn = evt->u.btn.data; 81 if (bmap[btn->button]) { 82 if (btn->down) { 83 s->buttons_state |= bmap[btn->button]; 84 } else { 85 s->buttons_state &= ~bmap[btn->button]; 86 } 87 } 88 break; 89 90 default: 91 /* keep gcc happy */ 92 break; 93 } 94 } 95 96 static const QemuInputHandler adb_mouse_handler = { 97 .name = "QEMU ADB Mouse", 98 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 99 .event = adb_mouse_handle_event, 100 /* 101 * We do not need the .sync handler because unlike e.g. PS/2 where async 102 * mouse events are sent over the serial port, an ADB mouse is constantly 103 * polled by the host via the adb_mouse_poll() callback. 104 */ 105 }; 106 107 static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) 108 { 109 MouseState *s = ADB_MOUSE(d); 110 int dx, dy; 111 112 if (s->last_buttons_state == s->buttons_state && 113 s->dx == 0 && s->dy == 0) { 114 return 0; 115 } 116 117 dx = s->dx; 118 if (dx < -63) { 119 dx = -63; 120 } else if (dx > 63) { 121 dx = 63; 122 } 123 124 dy = s->dy; 125 if (dy < -63) { 126 dy = -63; 127 } else if (dy > 63) { 128 dy = 63; 129 } 130 131 s->dx -= dx; 132 s->dy -= dy; 133 s->last_buttons_state = s->buttons_state; 134 135 dx &= 0x7f; 136 dy &= 0x7f; 137 138 if (!(s->buttons_state & ADB_MOUSE_BUTTON_LEFT)) { 139 dy |= 0x80; 140 } 141 if (!(s->buttons_state & ADB_MOUSE_BUTTON_RIGHT)) { 142 dx |= 0x80; 143 } 144 145 obuf[0] = dy; 146 obuf[1] = dx; 147 return 2; 148 } 149 150 static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, 151 const uint8_t *buf, int len) 152 { 153 MouseState *s = ADB_MOUSE(d); 154 int cmd, reg, olen; 155 156 if ((buf[0] & 0x0f) == ADB_FLUSH) { 157 /* flush mouse fifo */ 158 s->buttons_state = s->last_buttons_state; 159 s->dx = 0; 160 s->dy = 0; 161 s->dz = 0; 162 trace_adb_device_mouse_flush(); 163 return 0; 164 } 165 166 cmd = buf[0] & 0xc; 167 reg = buf[0] & 0x3; 168 olen = 0; 169 switch (cmd) { 170 case ADB_WRITEREG: 171 trace_adb_device_mouse_writereg(reg, buf[1]); 172 switch (reg) { 173 case 2: 174 break; 175 case 3: 176 /* 177 * MacOS 9 has a bug in its ADB driver whereby after configuring 178 * the ADB bus devices it sends another write of invalid length 179 * to reg 3. Make sure we ignore it to prevent an address clash 180 * with the previous device. 181 */ 182 if (len != 3) { 183 return 0; 184 } 185 186 switch (buf[2]) { 187 case ADB_CMD_SELF_TEST: 188 break; 189 case ADB_CMD_CHANGE_ID: 190 case ADB_CMD_CHANGE_ID_AND_ACT: 191 case ADB_CMD_CHANGE_ID_AND_ENABLE: 192 d->devaddr = buf[1] & 0xf; 193 trace_adb_device_mouse_request_change_addr(d->devaddr); 194 break; 195 default: 196 d->devaddr = buf[1] & 0xf; 197 /* 198 * we support handlers: 199 * 0x01: Classic Apple Mouse Protocol / 100 cpi operations 200 * 0x02: Classic Apple Mouse Protocol / 200 cpi operations 201 * we don't support handlers (at least): 202 * 0x03: Mouse systems A3 trackball 203 * 0x04: Extended Apple Mouse Protocol 204 * 0x2f: Microspeed mouse 205 * 0x42: Macally 206 * 0x5f: Microspeed mouse 207 * 0x66: Microspeed mouse 208 */ 209 if (buf[2] == 1 || buf[2] == 2) { 210 d->handler = buf[2]; 211 } 212 213 trace_adb_device_mouse_request_change_addr_and_handler( 214 d->devaddr, d->handler); 215 break; 216 } 217 } 218 break; 219 case ADB_READREG: 220 switch (reg) { 221 case 0: 222 olen = adb_mouse_poll(d, obuf); 223 break; 224 case 1: 225 break; 226 case 3: 227 obuf[0] = d->devaddr; 228 obuf[1] = d->handler; 229 olen = 2; 230 break; 231 } 232 trace_adb_device_mouse_readreg(reg, obuf[0], obuf[1]); 233 break; 234 } 235 return olen; 236 } 237 238 static bool adb_mouse_has_data(ADBDevice *d) 239 { 240 MouseState *s = ADB_MOUSE(d); 241 242 return !(s->last_buttons_state == s->buttons_state && 243 s->dx == 0 && s->dy == 0); 244 } 245 246 static void adb_mouse_reset(DeviceState *dev) 247 { 248 ADBDevice *d = ADB_DEVICE(dev); 249 MouseState *s = ADB_MOUSE(dev); 250 251 d->handler = 2; 252 d->devaddr = ADB_DEVID_MOUSE; 253 s->last_buttons_state = s->buttons_state = 0; 254 s->dx = s->dy = s->dz = 0; 255 } 256 257 static const VMStateDescription vmstate_adb_mouse = { 258 .name = "adb_mouse", 259 .version_id = 2, 260 .minimum_version_id = 2, 261 .fields = (const VMStateField[]) { 262 VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device, 263 ADBDevice), 264 VMSTATE_INT32(buttons_state, MouseState), 265 VMSTATE_INT32(last_buttons_state, MouseState), 266 VMSTATE_INT32(dx, MouseState), 267 VMSTATE_INT32(dy, MouseState), 268 VMSTATE_INT32(dz, MouseState), 269 VMSTATE_END_OF_LIST() 270 } 271 }; 272 273 static void adb_mouse_realizefn(DeviceState *dev, Error **errp) 274 { 275 MouseState *s = ADB_MOUSE(dev); 276 ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); 277 278 amc->parent_realize(dev, errp); 279 280 s->hs = qemu_input_handler_register(dev, &adb_mouse_handler); 281 } 282 283 static void adb_mouse_initfn(Object *obj) 284 { 285 ADBDevice *d = ADB_DEVICE(obj); 286 287 d->devaddr = ADB_DEVID_MOUSE; 288 } 289 290 static void adb_mouse_class_init(ObjectClass *oc, void *data) 291 { 292 DeviceClass *dc = DEVICE_CLASS(oc); 293 ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); 294 ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); 295 296 device_class_set_parent_realize(dc, adb_mouse_realizefn, 297 &amc->parent_realize); 298 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 299 300 adc->devreq = adb_mouse_request; 301 adc->devhasdata = adb_mouse_has_data; 302 device_class_set_legacy_reset(dc, adb_mouse_reset); 303 dc->vmsd = &vmstate_adb_mouse; 304 } 305 306 static const TypeInfo adb_mouse_type_info = { 307 .name = TYPE_ADB_MOUSE, 308 .parent = TYPE_ADB_DEVICE, 309 .instance_size = sizeof(MouseState), 310 .instance_init = adb_mouse_initfn, 311 .class_init = adb_mouse_class_init, 312 .class_size = sizeof(ADBMouseClass), 313 }; 314 315 static void adb_mouse_register_types(void) 316 { 317 type_register_static(&adb_mouse_type_info); 318 } 319 320 type_init(adb_mouse_register_types) 321