]> Git Repo - qemu.git/blob - hw/vmmouse.c
Merge remote-tracking branch 'kraxel/build.1' into staging
[qemu.git] / hw / vmmouse.c
1 /*
2  * QEMU VMMouse emulation
3  *
4  * Copyright (C) 2007 Anthony Liguori <[email protected]>
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 #include "hw.h"
25 #include "ui/console.h"
26 #include "ps2.h"
27 #include "pc.h"
28 #include "qdev.h"
29
30 /* debug only vmmouse */
31 //#define DEBUG_VMMOUSE
32
33 /* VMMouse Commands */
34 #define VMMOUSE_GETVERSION      10
35 #define VMMOUSE_DATA            39
36 #define VMMOUSE_STATUS          40
37 #define VMMOUSE_COMMAND         41
38
39 #define VMMOUSE_READ_ID                 0x45414552
40 #define VMMOUSE_DISABLE                 0x000000f5
41 #define VMMOUSE_REQUEST_RELATIVE        0x4c455252
42 #define VMMOUSE_REQUEST_ABSOLUTE        0x53424152
43
44 #define VMMOUSE_QUEUE_SIZE      1024
45
46 #define VMMOUSE_VERSION         0x3442554a
47
48 #ifdef DEBUG_VMMOUSE
49 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
50 #else
51 #define DPRINTF(fmt, ...) do { } while (0)
52 #endif
53
54 typedef struct _VMMouseState
55 {
56     ISADevice dev;
57     uint32_t queue[VMMOUSE_QUEUE_SIZE];
58     int32_t queue_size;
59     uint16_t nb_queue;
60     uint16_t status;
61     uint8_t absolute;
62     QEMUPutMouseEntry *entry;
63     void *ps2_mouse;
64 } VMMouseState;
65
66 static uint32_t vmmouse_get_status(VMMouseState *s)
67 {
68     DPRINTF("vmmouse_get_status()\n");
69     return (s->status << 16) | s->nb_queue;
70 }
71
72 static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
73 {
74     VMMouseState *s = opaque;
75     int buttons = 0;
76
77     if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
78         return;
79
80     DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
81             x, y, dz, buttons_state);
82
83     if ((buttons_state & MOUSE_EVENT_LBUTTON))
84         buttons |= 0x20;
85     if ((buttons_state & MOUSE_EVENT_RBUTTON))
86         buttons |= 0x10;
87     if ((buttons_state & MOUSE_EVENT_MBUTTON))
88         buttons |= 0x08;
89
90     if (s->absolute) {
91         x <<= 1;
92         y <<= 1;
93     }
94
95     s->queue[s->nb_queue++] = buttons;
96     s->queue[s->nb_queue++] = x;
97     s->queue[s->nb_queue++] = y;
98     s->queue[s->nb_queue++] = dz;
99
100     /* need to still generate PS2 events to notify driver to
101        read from queue */
102     i8042_isa_mouse_fake_event(s->ps2_mouse);
103 }
104
105 static void vmmouse_remove_handler(VMMouseState *s)
106 {
107     if (s->entry) {
108         qemu_remove_mouse_event_handler(s->entry);
109         s->entry = NULL;
110     }
111 }
112
113 static void vmmouse_update_handler(VMMouseState *s, int absolute)
114 {
115     if (s->status != 0) {
116         return;
117     }
118     if (s->absolute != absolute) {
119         s->absolute = absolute;
120         vmmouse_remove_handler(s);
121     }
122     if (s->entry == NULL) {
123         s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
124                                                 s, s->absolute,
125                                                 "vmmouse");
126         qemu_activate_mouse_event_handler(s->entry);
127     }
128 }
129
130 static void vmmouse_read_id(VMMouseState *s)
131 {
132     DPRINTF("vmmouse_read_id()\n");
133
134     if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
135         return;
136
137     s->queue[s->nb_queue++] = VMMOUSE_VERSION;
138     s->status = 0;
139 }
140
141 static void vmmouse_request_relative(VMMouseState *s)
142 {
143     DPRINTF("vmmouse_request_relative()\n");
144     vmmouse_update_handler(s, 0);
145 }
146
147 static void vmmouse_request_absolute(VMMouseState *s)
148 {
149     DPRINTF("vmmouse_request_absolute()\n");
150     vmmouse_update_handler(s, 1);
151 }
152
153 static void vmmouse_disable(VMMouseState *s)
154 {
155     DPRINTF("vmmouse_disable()\n");
156     s->status = 0xffff;
157     vmmouse_remove_handler(s);
158 }
159
160 static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
161 {
162     int i;
163
164     DPRINTF("vmmouse_data(%d)\n", size);
165
166     if (size == 0 || size > 6 || size > s->nb_queue) {
167         printf("vmmouse: driver requested too much data %d\n", size);
168         s->status = 0xffff;
169         vmmouse_remove_handler(s);
170         return;
171     }
172
173     for (i = 0; i < size; i++)
174         data[i] = s->queue[i];
175
176     s->nb_queue -= size;
177     if (s->nb_queue)
178         memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
179 }
180
181 static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
182 {
183     VMMouseState *s = opaque;
184     uint32_t data[6];
185     uint16_t command;
186
187     vmmouse_get_data(data);
188
189     command = data[2] & 0xFFFF;
190
191     switch (command) {
192     case VMMOUSE_STATUS:
193         data[0] = vmmouse_get_status(s);
194         break;
195     case VMMOUSE_COMMAND:
196         switch (data[1]) {
197         case VMMOUSE_DISABLE:
198             vmmouse_disable(s);
199             break;
200         case VMMOUSE_READ_ID:
201             vmmouse_read_id(s);
202             break;
203         case VMMOUSE_REQUEST_RELATIVE:
204             vmmouse_request_relative(s);
205             break;
206         case VMMOUSE_REQUEST_ABSOLUTE:
207             vmmouse_request_absolute(s);
208             break;
209         default:
210             printf("vmmouse: unknown command %x\n", data[1]);
211             break;
212         }
213         break;
214     case VMMOUSE_DATA:
215         vmmouse_data(s, data, data[1]);
216         break;
217     default:
218         printf("vmmouse: unknown command %x\n", command);
219         break;
220     }
221
222     vmmouse_set_data(data);
223     return data[0];
224 }
225
226 static int vmmouse_post_load(void *opaque, int version_id)
227 {
228     VMMouseState *s = opaque;
229
230     vmmouse_remove_handler(s);
231     vmmouse_update_handler(s, s->absolute);
232     return 0;
233 }
234
235 static const VMStateDescription vmstate_vmmouse = {
236     .name = "vmmouse",
237     .version_id = 0,
238     .minimum_version_id = 0,
239     .minimum_version_id_old = 0,
240     .post_load = vmmouse_post_load,
241     .fields      = (VMStateField []) {
242         VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
243         VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
244         VMSTATE_UINT16(nb_queue, VMMouseState),
245         VMSTATE_UINT16(status, VMMouseState),
246         VMSTATE_UINT8(absolute, VMMouseState),
247         VMSTATE_END_OF_LIST()
248     }
249 };
250
251 static void vmmouse_reset(DeviceState *d)
252 {
253     VMMouseState *s = container_of(d, VMMouseState, dev.qdev);
254
255     s->queue_size = VMMOUSE_QUEUE_SIZE;
256
257     vmmouse_disable(s);
258 }
259
260 static int vmmouse_initfn(ISADevice *dev)
261 {
262     VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev);
263
264     DPRINTF("vmmouse_init\n");
265
266     vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
267     vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
268     vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
269
270     return 0;
271 }
272
273 static Property vmmouse_properties[] = {
274     DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
275     DEFINE_PROP_END_OF_LIST(),
276 };
277
278 static void vmmouse_class_initfn(ObjectClass *klass, void *data)
279 {
280     DeviceClass *dc = DEVICE_CLASS(klass);
281     ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
282     ic->init = vmmouse_initfn;
283     dc->no_user = 1;
284     dc->reset = vmmouse_reset;
285     dc->vmsd = &vmstate_vmmouse;
286     dc->props = vmmouse_properties;
287 }
288
289 static TypeInfo vmmouse_info = {
290     .name          = "vmmouse",
291     .parent        = TYPE_ISA_DEVICE,
292     .instance_size = sizeof(VMMouseState),
293     .class_init    = vmmouse_class_initfn,
294 };
295
296 static void vmmouse_register_types(void)
297 {
298     type_register_static(&vmmouse_info);
299 }
300
301 type_init(vmmouse_register_types)
This page took 0.040514 seconds and 4 git commands to generate.