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