Statistics
| Branch: | Revision:

root / hw / vmmouse.c @ 0d913fdb

History | View | Annotate | Download (7.5 kB)

1
/*
2
 * QEMU VMMouse emulation
3
 *
4
 * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
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 "vl.h"
25

    
26
/* debug only vmmouse */
27
//#define DEBUG_VMMOUSE
28

    
29
/* VMMouse Commands */
30
#define VMMOUSE_GETVERSION        10
31
#define VMMOUSE_DATA                39
32
#define VMMOUSE_STATUS                40
33
#define VMMOUSE_COMMAND                41
34

    
35
#define VMMOUSE_READ_ID                        0x45414552
36
#define VMMOUSE_DISABLE                        0x000000f5
37
#define VMMOUSE_REQUEST_RELATIVE        0x4c455252
38
#define VMMOUSE_REQUEST_ABSOLUTE        0x53424152
39

    
40
#define VMMOUSE_QUEUE_SIZE        1024
41

    
42
#define VMMOUSE_VERSION                0x3442554a
43

    
44
#ifdef DEBUG_VMMOUSE
45
#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
46
#else
47
#define DPRINTF(fmt, ...) do { } while (0)
48
#endif
49

    
50
typedef struct _VMMouseState
51
{
52
    uint32_t queue[VMMOUSE_QUEUE_SIZE];
53
    uint16_t nb_queue;
54
    uint16_t status;
55
    uint8_t absolute;
56
    QEMUPutMouseEntry *entry;
57
    void *ps2_mouse;
58
} VMMouseState;
59

    
60
static uint32_t vmmouse_get_status(VMMouseState *s)
61
{
62
    DPRINTF("vmmouse_get_status()\n");
63
    return (s->status << 16) | s->nb_queue;
64
}
65

    
66
static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
67
{
68
    VMMouseState *s = opaque;
69
    int buttons = 0;
70

    
71
    if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
72
        return;
73

    
74
    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
75
            x, y, dz, buttons_state);
76

    
77
    if ((buttons_state & MOUSE_EVENT_LBUTTON))
78
        buttons |= 0x20;
79
    if ((buttons_state & MOUSE_EVENT_RBUTTON))
80
        buttons |= 0x10;
81
    if ((buttons_state & MOUSE_EVENT_MBUTTON))
82
        buttons |= 0x08;
83

    
84
    if (s->absolute) {
85
        x <<= 1;
86
        y <<= 1;
87
    }
88

    
89
    s->queue[s->nb_queue++] = buttons;
90
    s->queue[s->nb_queue++] = x;
91
    s->queue[s->nb_queue++] = y;
92
    s->queue[s->nb_queue++] = dz;
93

    
94
    /* need to still generate PS2 events to notify driver to
95
       read from queue */
96
    ps2_mouse_fake_event(s->ps2_mouse);
97
}
98

    
99
static void vmmouse_update_handler(VMMouseState *s)
100
{
101
    if (s->entry) {
102
        qemu_remove_mouse_event_handler(s->entry);
103
        s->entry = NULL;
104
    }
105
    if (s->status == 0)
106
        s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
107
                                                s, s->absolute,
108
                                                "vmmouse");
109
}
110

    
111
static void vmmouse_read_id(VMMouseState *s)
112
{
113
    DPRINTF("vmmouse_read_id()\n");
114

    
115
    if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
116
        return;
117

    
118
    s->queue[s->nb_queue++] = VMMOUSE_VERSION;
119
    s->status = 0;
120
    vmmouse_update_handler(s);
121
}
122

    
123
static void vmmouse_request_relative(VMMouseState *s)
124
{
125
    DPRINTF("vmmouse_request_relative()\n");
126
    s->absolute = 0;
127
    vmmouse_update_handler(s);
128
}
129

    
130
static void vmmouse_request_absolute(VMMouseState *s)
131
{
132
    DPRINTF("vmmouse_request_absolute()\n");
133
    s->absolute = 1;
134
    vmmouse_update_handler(s);
135
}
136

    
137
static void vmmouse_disable(VMMouseState *s)
138
{
139
    DPRINTF("vmmouse_disable()\n");
140
    s->status = 0xffff;
141
    vmmouse_update_handler(s);
142
}
143

    
144
static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
145
{
146
    int i;
147

    
148
    DPRINTF("vmmouse_data(%d)\n", size);
149

    
150
    if (size == 0 || size > 6 || size > s->nb_queue) {
151
        printf("vmmouse: driver requested too much data %d\n", size);
152
        s->status = 0xffff;
153
        vmmouse_update_handler(s);
154
        return;
155
    }
156

    
157
    for (i = 0; i < size; i++)
158
        data[i] = s->queue[i];
159

    
160
    s->nb_queue -= size;
161
    if (s->nb_queue)
162
        memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
163
}
164

    
165
static void vmmouse_get_data(uint32_t *data)
166
{
167
    CPUState *env = cpu_single_env;
168

    
169
    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
170
    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
171
    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
172

    
173
    DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n",
174
            data[0], data[1], data[2], data[3], data[4], data[5]);
175
}
176

    
177
static void vmmouse_set_data(const uint32_t *data)
178
{
179
    CPUState *env = cpu_single_env;
180

    
181
    DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n",
182
            data[0], data[1], data[2], data[3], data[4], data[5]);
183

    
184
    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
185
    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
186
    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
187
}
188

    
189
static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
190
{
191
    VMMouseState *s = opaque;
192
    uint32_t data[6];
193
    uint16_t command;
194

    
195
    vmmouse_get_data(data);
196

    
197
    command = data[2] & 0xFFFF;
198

    
199
    switch (command) {
200
    case VMMOUSE_STATUS:
201
        data[0] = vmmouse_get_status(s);
202
        break;
203
    case VMMOUSE_COMMAND:
204
        switch (data[1]) {
205
        case VMMOUSE_DISABLE:
206
            vmmouse_disable(s);
207
            break;
208
        case VMMOUSE_READ_ID:
209
            vmmouse_read_id(s);
210
            break;
211
        case VMMOUSE_REQUEST_RELATIVE:
212
            vmmouse_request_relative(s);
213
            break;
214
        case VMMOUSE_REQUEST_ABSOLUTE:
215
            vmmouse_request_absolute(s);
216
            break;
217
        default:
218
            printf("vmmouse: unknown command %x\n", data[1]);
219
            break;
220
        }
221
        break;
222
    case VMMOUSE_DATA:
223
        vmmouse_data(s, data, data[1]);
224
        break;
225
    default:
226
        printf("vmmouse: unknown command %x\n", command);
227
        break;
228
    }
229

    
230
    vmmouse_set_data(data);
231
    return data[0];
232
}
233

    
234
static void vmmouse_save(QEMUFile *f, void *opaque)
235
{
236
    VMMouseState *s = opaque;
237
    int i;
238

    
239
    qemu_put_be32(f, VMMOUSE_QUEUE_SIZE);
240
    for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
241
        qemu_put_be32s(f, &s->queue[i]);
242
    qemu_put_be16s(f, &s->nb_queue);
243
    qemu_put_be16s(f, &s->status);
244
    qemu_put_8s(f, &s->absolute);
245
}
246

    
247
static int vmmouse_load(QEMUFile *f, void *opaque, int version_id)
248
{
249
    VMMouseState *s = opaque;
250
    int i;
251

    
252
    if (version_id != 0)
253
        return -EINVAL;
254

    
255
    if (qemu_get_be32(f) != VMMOUSE_QUEUE_SIZE)
256
        return -EINVAL;
257
    for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
258
        qemu_get_be32s(f, &s->queue[i]);
259
    qemu_get_be16s(f, &s->nb_queue);
260
    qemu_get_be16s(f, &s->status);
261
    qemu_get_8s(f, &s->absolute);
262

    
263
    vmmouse_update_handler(s);
264

    
265
    return 0;
266
}
267

    
268
void *vmmouse_init(void *m)
269
{
270
    VMMouseState *s = NULL;
271

    
272
    DPRINTF("vmmouse_init\n");
273

    
274
    s = qemu_mallocz(sizeof(VMMouseState));
275
    if (!s)
276
        return NULL;
277

    
278
    s->status = 0xffff;
279
    s->ps2_mouse = m;
280

    
281
    vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
282
    vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
283
    vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
284
    register_savevm("vmmouse", 0, 0, vmmouse_save, vmmouse_load, s);
285

    
286
    return s;
287
}
288