xref: /openbmc/qemu/hw/input/adb-mouse.c (revision 9601076b)
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