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 int buttons_state, last_buttons_state;
42 int dx, dy, dz;
43 };
44
45
46 struct ADBMouseClass {
47 /*< public >*/
48 ADBDeviceClass parent_class;
49 /*< private >*/
50
51 DeviceRealize parent_realize;
52 };
53
adb_mouse_event(void * opaque,int dx1,int dy1,int dz1,int buttons_state)54 static 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
adb_mouse_poll(ADBDevice * d,uint8_t * obuf)66 static 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
adb_mouse_request(ADBDevice * d,uint8_t * obuf,const uint8_t * buf,int len)109 static 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
adb_mouse_has_data(ADBDevice * d)197 static 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
adb_mouse_reset(DeviceState * dev)205 static 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
216 static const VMStateDescription vmstate_adb_mouse = {
217 .name = "adb_mouse",
218 .version_id = 2,
219 .minimum_version_id = 2,
220 .fields = (const 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
adb_mouse_realizefn(DeviceState * dev,Error ** errp)232 static 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
adb_mouse_initfn(Object * obj)242 static void adb_mouse_initfn(Object *obj)
243 {
244 ADBDevice *d = ADB_DEVICE(obj);
245
246 d->devaddr = ADB_DEVID_MOUSE;
247 }
248
adb_mouse_class_init(ObjectClass * oc,void * data)249 static 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
265 static 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
adb_mouse_register_types(void)274 static void adb_mouse_register_types(void)
275 {
276 type_register_static(&adb_mouse_type_info);
277 }
278
279 type_init(adb_mouse_register_types)
280