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