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 "qemu/module.h" 29 #include "adb-internal.h" 30 #include "trace.h" 31 32 #define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) 33 34 typedef struct MouseState { 35 /*< public >*/ 36 ADBDevice parent_obj; 37 /*< private >*/ 38 39 int buttons_state, last_buttons_state; 40 int dx, dy, dz; 41 } MouseState; 42 43 #define ADB_MOUSE_CLASS(class) \ 44 OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) 45 #define ADB_MOUSE_GET_CLASS(obj) \ 46 OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) 47 48 typedef struct ADBMouseClass { 49 /*< public >*/ 50 ADBDeviceClass parent_class; 51 /*< private >*/ 52 53 DeviceRealize parent_realize; 54 } ADBMouseClass; 55 56 static void adb_mouse_event(void *opaque, 57 int dx1, int dy1, int dz1, int buttons_state) 58 { 59 MouseState *s = opaque; 60 61 s->dx += dx1; 62 s->dy += dy1; 63 s->dz += dz1; 64 s->buttons_state = buttons_state; 65 } 66 67 68 static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) 69 { 70 MouseState *s = ADB_MOUSE(d); 71 int dx, dy; 72 73 if (s->last_buttons_state == s->buttons_state && 74 s->dx == 0 && s->dy == 0) { 75 return 0; 76 } 77 78 dx = s->dx; 79 if (dx < -63) { 80 dx = -63; 81 } else if (dx > 63) { 82 dx = 63; 83 } 84 85 dy = s->dy; 86 if (dy < -63) { 87 dy = -63; 88 } else if (dy > 63) { 89 dy = 63; 90 } 91 92 s->dx -= dx; 93 s->dy -= dy; 94 s->last_buttons_state = s->buttons_state; 95 96 dx &= 0x7f; 97 dy &= 0x7f; 98 99 if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) { 100 dy |= 0x80; 101 } 102 if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) { 103 dx |= 0x80; 104 } 105 106 obuf[0] = dy; 107 obuf[1] = dx; 108 return 2; 109 } 110 111 static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, 112 const uint8_t *buf, int len) 113 { 114 MouseState *s = ADB_MOUSE(d); 115 int cmd, reg, olen; 116 117 if ((buf[0] & 0x0f) == ADB_FLUSH) { 118 /* flush mouse fifo */ 119 s->buttons_state = s->last_buttons_state; 120 s->dx = 0; 121 s->dy = 0; 122 s->dz = 0; 123 trace_adb_mouse_flush(); 124 return 0; 125 } 126 127 cmd = buf[0] & 0xc; 128 reg = buf[0] & 0x3; 129 olen = 0; 130 switch (cmd) { 131 case ADB_WRITEREG: 132 trace_adb_mouse_writereg(reg, buf[1]); 133 switch (reg) { 134 case 2: 135 break; 136 case 3: 137 switch (buf[2]) { 138 case ADB_CMD_SELF_TEST: 139 break; 140 case ADB_CMD_CHANGE_ID: 141 case ADB_CMD_CHANGE_ID_AND_ACT: 142 case ADB_CMD_CHANGE_ID_AND_ENABLE: 143 d->devaddr = buf[1] & 0xf; 144 trace_adb_mouse_request_change_addr(d->devaddr); 145 break; 146 default: 147 if (!d->disable_direct_reg3_writes) { 148 d->devaddr = buf[1] & 0xf; 149 150 /* we support handlers: 151 * 0x01: Classic Apple Mouse Protocol / 100 cpi operations 152 * 0x02: Classic Apple Mouse Protocol / 200 cpi operations 153 * we don't support handlers (at least): 154 * 0x03: Mouse systems A3 trackball 155 * 0x04: Extended Apple Mouse Protocol 156 * 0x2f: Microspeed mouse 157 * 0x42: Macally 158 * 0x5f: Microspeed mouse 159 * 0x66: Microspeed mouse 160 */ 161 if (buf[2] == 1 || buf[2] == 2) { 162 d->handler = buf[2]; 163 } 164 165 trace_adb_mouse_request_change_addr_and_handler( 166 d->devaddr, d->handler); 167 } 168 break; 169 } 170 } 171 break; 172 case ADB_READREG: 173 switch (reg) { 174 case 0: 175 olen = adb_mouse_poll(d, obuf); 176 break; 177 case 1: 178 break; 179 case 3: 180 obuf[0] = d->devaddr; 181 obuf[1] = d->handler; 182 olen = 2; 183 break; 184 } 185 trace_adb_mouse_readreg(reg, obuf[0], obuf[1]); 186 break; 187 } 188 return olen; 189 } 190 191 static void adb_mouse_reset(DeviceState *dev) 192 { 193 ADBDevice *d = ADB_DEVICE(dev); 194 MouseState *s = ADB_MOUSE(dev); 195 196 d->handler = 2; 197 d->devaddr = ADB_DEVID_MOUSE; 198 s->last_buttons_state = s->buttons_state = 0; 199 s->dx = s->dy = s->dz = 0; 200 } 201 202 static const VMStateDescription vmstate_adb_mouse = { 203 .name = "adb_mouse", 204 .version_id = 2, 205 .minimum_version_id = 2, 206 .fields = (VMStateField[]) { 207 VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device, 208 ADBDevice), 209 VMSTATE_INT32(buttons_state, MouseState), 210 VMSTATE_INT32(last_buttons_state, MouseState), 211 VMSTATE_INT32(dx, MouseState), 212 VMSTATE_INT32(dy, MouseState), 213 VMSTATE_INT32(dz, MouseState), 214 VMSTATE_END_OF_LIST() 215 } 216 }; 217 218 static void adb_mouse_realizefn(DeviceState *dev, Error **errp) 219 { 220 MouseState *s = ADB_MOUSE(dev); 221 ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); 222 223 amc->parent_realize(dev, errp); 224 225 qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); 226 } 227 228 static void adb_mouse_initfn(Object *obj) 229 { 230 ADBDevice *d = ADB_DEVICE(obj); 231 232 d->devaddr = ADB_DEVID_MOUSE; 233 } 234 235 static void adb_mouse_class_init(ObjectClass *oc, void *data) 236 { 237 DeviceClass *dc = DEVICE_CLASS(oc); 238 ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); 239 ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); 240 241 device_class_set_parent_realize(dc, adb_mouse_realizefn, 242 &amc->parent_realize); 243 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 244 245 adc->devreq = adb_mouse_request; 246 dc->reset = adb_mouse_reset; 247 dc->vmsd = &vmstate_adb_mouse; 248 } 249 250 static const TypeInfo adb_mouse_type_info = { 251 .name = TYPE_ADB_MOUSE, 252 .parent = TYPE_ADB_DEVICE, 253 .instance_size = sizeof(MouseState), 254 .instance_init = adb_mouse_initfn, 255 .class_init = adb_mouse_class_init, 256 .class_size = sizeof(ADBMouseClass), 257 }; 258 259 static void adb_mouse_register_types(void) 260 { 261 type_register_static(&adb_mouse_type_info); 262 } 263 264 type_init(adb_mouse_register_types) 265