Statistics
| Branch: | Revision:

root / hw / input / hid.c @ a8aec295

History | View | Annotate | Download (14.1 kB)

1 dcfda673 Gerd Hoffmann
/*
2 dcfda673 Gerd Hoffmann
 * QEMU HID devices
3 dcfda673 Gerd Hoffmann
 *
4 dcfda673 Gerd Hoffmann
 * Copyright (c) 2005 Fabrice Bellard
5 dcfda673 Gerd Hoffmann
 * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
6 dcfda673 Gerd Hoffmann
 *
7 dcfda673 Gerd Hoffmann
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 dcfda673 Gerd Hoffmann
 * of this software and associated documentation files (the "Software"), to deal
9 dcfda673 Gerd Hoffmann
 * in the Software without restriction, including without limitation the rights
10 dcfda673 Gerd Hoffmann
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 dcfda673 Gerd Hoffmann
 * copies of the Software, and to permit persons to whom the Software is
12 dcfda673 Gerd Hoffmann
 * furnished to do so, subject to the following conditions:
13 dcfda673 Gerd Hoffmann
 *
14 dcfda673 Gerd Hoffmann
 * The above copyright notice and this permission notice shall be included in
15 dcfda673 Gerd Hoffmann
 * all copies or substantial portions of the Software.
16 dcfda673 Gerd Hoffmann
 *
17 dcfda673 Gerd Hoffmann
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 dcfda673 Gerd Hoffmann
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 dcfda673 Gerd Hoffmann
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 dcfda673 Gerd Hoffmann
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 dcfda673 Gerd Hoffmann
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 dcfda673 Gerd Hoffmann
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 dcfda673 Gerd Hoffmann
 * THE SOFTWARE.
24 dcfda673 Gerd Hoffmann
 */
25 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
26 28ecbaee Paolo Bonzini
#include "ui/console.h"
27 1de7afc9 Paolo Bonzini
#include "qemu/timer.h"
28 0d09e41a Paolo Bonzini
#include "hw/input/hid.h"
29 dcfda673 Gerd Hoffmann
30 dcfda673 Gerd Hoffmann
#define HID_USAGE_ERROR_ROLLOVER        0x01
31 dcfda673 Gerd Hoffmann
#define HID_USAGE_POSTFAIL              0x02
32 dcfda673 Gerd Hoffmann
#define HID_USAGE_ERROR_UNDEFINED       0x03
33 dcfda673 Gerd Hoffmann
34 dcfda673 Gerd Hoffmann
/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
35 dcfda673 Gerd Hoffmann
 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
36 dcfda673 Gerd Hoffmann
static const uint8_t hid_usage_keys[0x100] = {
37 dcfda673 Gerd Hoffmann
    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
38 dcfda673 Gerd Hoffmann
    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
39 dcfda673 Gerd Hoffmann
    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
40 dcfda673 Gerd Hoffmann
    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
41 dcfda673 Gerd Hoffmann
    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
42 dcfda673 Gerd Hoffmann
    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
43 dcfda673 Gerd Hoffmann
    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
44 dcfda673 Gerd Hoffmann
    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
45 dcfda673 Gerd Hoffmann
    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
46 dcfda673 Gerd Hoffmann
    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
47 dcfda673 Gerd Hoffmann
    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
48 dcfda673 Gerd Hoffmann
    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
49 dcfda673 Gerd Hoffmann
    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
50 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
51 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
53 dcfda673 Gerd Hoffmann
54 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
58 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
61 dcfda673 Gerd Hoffmann
    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
63 dcfda673 Gerd Hoffmann
    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
64 dcfda673 Gerd Hoffmann
    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
65 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
66 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 dcfda673 Gerd Hoffmann
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 dcfda673 Gerd Hoffmann
};
71 dcfda673 Gerd Hoffmann
72 dcfda673 Gerd Hoffmann
bool hid_has_events(HIDState *hs)
73 dcfda673 Gerd Hoffmann
{
74 027c03f7 Hans de Goede
    return hs->n > 0 || hs->idle_pending;
75 dcfda673 Gerd Hoffmann
}
76 dcfda673 Gerd Hoffmann
77 027c03f7 Hans de Goede
static void hid_idle_timer(void *opaque)
78 b069d348 Gerd Hoffmann
{
79 027c03f7 Hans de Goede
    HIDState *hs = opaque;
80 027c03f7 Hans de Goede
81 027c03f7 Hans de Goede
    hs->idle_pending = true;
82 027c03f7 Hans de Goede
    hs->event(hs);
83 027c03f7 Hans de Goede
}
84 027c03f7 Hans de Goede
85 027c03f7 Hans de Goede
static void hid_del_idle_timer(HIDState *hs)
86 027c03f7 Hans de Goede
{
87 027c03f7 Hans de Goede
    if (hs->idle_timer) {
88 027c03f7 Hans de Goede
        qemu_del_timer(hs->idle_timer);
89 027c03f7 Hans de Goede
        qemu_free_timer(hs->idle_timer);
90 027c03f7 Hans de Goede
        hs->idle_timer = NULL;
91 027c03f7 Hans de Goede
    }
92 027c03f7 Hans de Goede
}
93 027c03f7 Hans de Goede
94 027c03f7 Hans de Goede
void hid_set_next_idle(HIDState *hs)
95 027c03f7 Hans de Goede
{
96 027c03f7 Hans de Goede
    if (hs->idle) {
97 027c03f7 Hans de Goede
        uint64_t expire_time = qemu_get_clock_ns(vm_clock) +
98 027c03f7 Hans de Goede
                               get_ticks_per_sec() * hs->idle * 4 / 1000;
99 027c03f7 Hans de Goede
        if (!hs->idle_timer) {
100 027c03f7 Hans de Goede
            hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs);
101 027c03f7 Hans de Goede
        }
102 027c03f7 Hans de Goede
        qemu_mod_timer_ns(hs->idle_timer, expire_time);
103 027c03f7 Hans de Goede
    } else {
104 027c03f7 Hans de Goede
        hid_del_idle_timer(hs);
105 027c03f7 Hans de Goede
    }
106 b069d348 Gerd Hoffmann
}
107 b069d348 Gerd Hoffmann
108 dcfda673 Gerd Hoffmann
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
109 dcfda673 Gerd Hoffmann
{
110 dcfda673 Gerd Hoffmann
    e->xdx = e->ydy = e->dz = 0;
111 dcfda673 Gerd Hoffmann
    e->buttons_state = buttons;
112 dcfda673 Gerd Hoffmann
}
113 dcfda673 Gerd Hoffmann
114 dcfda673 Gerd Hoffmann
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
115 dcfda673 Gerd Hoffmann
                                      int x1, int y1, int z1) {
116 dcfda673 Gerd Hoffmann
    if (xyrel) {
117 dcfda673 Gerd Hoffmann
        e->xdx += x1;
118 dcfda673 Gerd Hoffmann
        e->ydy += y1;
119 dcfda673 Gerd Hoffmann
    } else {
120 dcfda673 Gerd Hoffmann
        e->xdx = x1;
121 dcfda673 Gerd Hoffmann
        e->ydy = y1;
122 dcfda673 Gerd Hoffmann
        /* Windows drivers do not like the 0/0 position and ignore such
123 dcfda673 Gerd Hoffmann
         * events. */
124 dcfda673 Gerd Hoffmann
        if (!(x1 | y1)) {
125 18f88f11 Blue Swirl
            e->xdx = 1;
126 dcfda673 Gerd Hoffmann
        }
127 dcfda673 Gerd Hoffmann
    }
128 dcfda673 Gerd Hoffmann
    e->dz += z1;
129 dcfda673 Gerd Hoffmann
}
130 dcfda673 Gerd Hoffmann
131 dcfda673 Gerd Hoffmann
static void hid_pointer_event(void *opaque,
132 dcfda673 Gerd Hoffmann
                              int x1, int y1, int z1, int buttons_state)
133 dcfda673 Gerd Hoffmann
{
134 dcfda673 Gerd Hoffmann
    HIDState *hs = opaque;
135 dcfda673 Gerd Hoffmann
    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
136 dcfda673 Gerd Hoffmann
    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
137 dcfda673 Gerd Hoffmann
138 dcfda673 Gerd Hoffmann
    /* We combine events where feasible to keep the queue small.  We shouldn't
139 dcfda673 Gerd Hoffmann
     * combine anything with the first event of a particular button state, as
140 dcfda673 Gerd Hoffmann
     * that would change the location of the button state change.  When the
141 dcfda673 Gerd Hoffmann
     * queue is empty, a second event is needed because we don't know if
142 dcfda673 Gerd Hoffmann
     * the first event changed the button state.  */
143 dcfda673 Gerd Hoffmann
    if (hs->n == QUEUE_LENGTH) {
144 dcfda673 Gerd Hoffmann
        /* Queue full.  Discard old button state, combine motion normally.  */
145 dcfda673 Gerd Hoffmann
        hs->ptr.queue[use_slot].buttons_state = buttons_state;
146 dcfda673 Gerd Hoffmann
    } else if (hs->n < 2 ||
147 dcfda673 Gerd Hoffmann
               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
148 dcfda673 Gerd Hoffmann
               hs->ptr.queue[previous_slot].buttons_state !=
149 dcfda673 Gerd Hoffmann
               hs->ptr.queue[use_slot].buttons_state) {
150 dcfda673 Gerd Hoffmann
        /* Cannot or should not combine, so add an empty item to the queue.  */
151 dcfda673 Gerd Hoffmann
        QUEUE_INCR(use_slot);
152 dcfda673 Gerd Hoffmann
        hs->n++;
153 dcfda673 Gerd Hoffmann
        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
154 dcfda673 Gerd Hoffmann
    }
155 dcfda673 Gerd Hoffmann
    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
156 dcfda673 Gerd Hoffmann
                              hs->kind == HID_MOUSE,
157 dcfda673 Gerd Hoffmann
                              x1, y1, z1);
158 dcfda673 Gerd Hoffmann
    hs->event(hs);
159 dcfda673 Gerd Hoffmann
}
160 dcfda673 Gerd Hoffmann
161 dcfda673 Gerd Hoffmann
static void hid_keyboard_event(void *opaque, int keycode)
162 dcfda673 Gerd Hoffmann
{
163 dcfda673 Gerd Hoffmann
    HIDState *hs = opaque;
164 dcfda673 Gerd Hoffmann
    int slot;
165 dcfda673 Gerd Hoffmann
166 dcfda673 Gerd Hoffmann
    if (hs->n == QUEUE_LENGTH) {
167 dcfda673 Gerd Hoffmann
        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
168 dcfda673 Gerd Hoffmann
        return;
169 dcfda673 Gerd Hoffmann
    }
170 dcfda673 Gerd Hoffmann
    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
171 dcfda673 Gerd Hoffmann
    hs->kbd.keycodes[slot] = keycode;
172 dcfda673 Gerd Hoffmann
    hs->event(hs);
173 dcfda673 Gerd Hoffmann
}
174 dcfda673 Gerd Hoffmann
175 dcfda673 Gerd Hoffmann
static void hid_keyboard_process_keycode(HIDState *hs)
176 dcfda673 Gerd Hoffmann
{
177 dcfda673 Gerd Hoffmann
    uint8_t hid_code, key;
178 dcfda673 Gerd Hoffmann
    int i, keycode, slot;
179 dcfda673 Gerd Hoffmann
180 dcfda673 Gerd Hoffmann
    if (hs->n == 0) {
181 dcfda673 Gerd Hoffmann
        return;
182 dcfda673 Gerd Hoffmann
    }
183 dcfda673 Gerd Hoffmann
    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
184 dcfda673 Gerd Hoffmann
    keycode = hs->kbd.keycodes[slot];
185 dcfda673 Gerd Hoffmann
186 dcfda673 Gerd Hoffmann
    key = keycode & 0x7f;
187 dcfda673 Gerd Hoffmann
    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
188 dcfda673 Gerd Hoffmann
    hs->kbd.modifiers &= ~(1 << 8);
189 dcfda673 Gerd Hoffmann
190 dcfda673 Gerd Hoffmann
    switch (hid_code) {
191 dcfda673 Gerd Hoffmann
    case 0x00:
192 dcfda673 Gerd Hoffmann
        return;
193 dcfda673 Gerd Hoffmann
194 dcfda673 Gerd Hoffmann
    case 0xe0:
195 dcfda673 Gerd Hoffmann
        if (hs->kbd.modifiers & (1 << 9)) {
196 dcfda673 Gerd Hoffmann
            hs->kbd.modifiers ^= 3 << 8;
197 dcfda673 Gerd Hoffmann
            return;
198 dcfda673 Gerd Hoffmann
        }
199 dcfda673 Gerd Hoffmann
    case 0xe1 ... 0xe7:
200 dcfda673 Gerd Hoffmann
        if (keycode & (1 << 7)) {
201 dcfda673 Gerd Hoffmann
            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
202 dcfda673 Gerd Hoffmann
            return;
203 dcfda673 Gerd Hoffmann
        }
204 dcfda673 Gerd Hoffmann
    case 0xe8 ... 0xef:
205 dcfda673 Gerd Hoffmann
        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
206 dcfda673 Gerd Hoffmann
        return;
207 dcfda673 Gerd Hoffmann
    }
208 dcfda673 Gerd Hoffmann
209 dcfda673 Gerd Hoffmann
    if (keycode & (1 << 7)) {
210 dcfda673 Gerd Hoffmann
        for (i = hs->kbd.keys - 1; i >= 0; i--) {
211 dcfda673 Gerd Hoffmann
            if (hs->kbd.key[i] == hid_code) {
212 dcfda673 Gerd Hoffmann
                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
213 dcfda673 Gerd Hoffmann
                hs->kbd.key[hs->kbd.keys] = 0x00;
214 dcfda673 Gerd Hoffmann
                break;
215 dcfda673 Gerd Hoffmann
            }
216 dcfda673 Gerd Hoffmann
        }
217 dcfda673 Gerd Hoffmann
        if (i < 0) {
218 dcfda673 Gerd Hoffmann
            return;
219 dcfda673 Gerd Hoffmann
        }
220 dcfda673 Gerd Hoffmann
    } else {
221 dcfda673 Gerd Hoffmann
        for (i = hs->kbd.keys - 1; i >= 0; i--) {
222 dcfda673 Gerd Hoffmann
            if (hs->kbd.key[i] == hid_code) {
223 dcfda673 Gerd Hoffmann
                break;
224 dcfda673 Gerd Hoffmann
            }
225 dcfda673 Gerd Hoffmann
        }
226 dcfda673 Gerd Hoffmann
        if (i < 0) {
227 dcfda673 Gerd Hoffmann
            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
228 dcfda673 Gerd Hoffmann
                hs->kbd.key[hs->kbd.keys++] = hid_code;
229 dcfda673 Gerd Hoffmann
            }
230 dcfda673 Gerd Hoffmann
        } else {
231 dcfda673 Gerd Hoffmann
            return;
232 dcfda673 Gerd Hoffmann
        }
233 dcfda673 Gerd Hoffmann
    }
234 dcfda673 Gerd Hoffmann
}
235 dcfda673 Gerd Hoffmann
236 dcfda673 Gerd Hoffmann
static inline int int_clamp(int val, int vmin, int vmax)
237 dcfda673 Gerd Hoffmann
{
238 dcfda673 Gerd Hoffmann
    if (val < vmin) {
239 dcfda673 Gerd Hoffmann
        return vmin;
240 dcfda673 Gerd Hoffmann
    } else if (val > vmax) {
241 dcfda673 Gerd Hoffmann
        return vmax;
242 dcfda673 Gerd Hoffmann
    } else {
243 dcfda673 Gerd Hoffmann
        return val;
244 dcfda673 Gerd Hoffmann
    }
245 dcfda673 Gerd Hoffmann
}
246 dcfda673 Gerd Hoffmann
247 21635e12 Gerd Hoffmann
void hid_pointer_activate(HIDState *hs)
248 21635e12 Gerd Hoffmann
{
249 21635e12 Gerd Hoffmann
    if (!hs->ptr.mouse_grabbed) {
250 21635e12 Gerd Hoffmann
        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
251 21635e12 Gerd Hoffmann
        hs->ptr.mouse_grabbed = 1;
252 21635e12 Gerd Hoffmann
    }
253 21635e12 Gerd Hoffmann
}
254 21635e12 Gerd Hoffmann
255 dcfda673 Gerd Hoffmann
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
256 dcfda673 Gerd Hoffmann
{
257 dcfda673 Gerd Hoffmann
    int dx, dy, dz, b, l;
258 dcfda673 Gerd Hoffmann
    int index;
259 dcfda673 Gerd Hoffmann
    HIDPointerEvent *e;
260 dcfda673 Gerd Hoffmann
261 027c03f7 Hans de Goede
    hs->idle_pending = false;
262 027c03f7 Hans de Goede
263 21635e12 Gerd Hoffmann
    hid_pointer_activate(hs);
264 dcfda673 Gerd Hoffmann
265 dcfda673 Gerd Hoffmann
    /* When the buffer is empty, return the last event.  Relative
266 dcfda673 Gerd Hoffmann
       movements will all be zero.  */
267 dcfda673 Gerd Hoffmann
    index = (hs->n ? hs->head : hs->head - 1);
268 dcfda673 Gerd Hoffmann
    e = &hs->ptr.queue[index & QUEUE_MASK];
269 dcfda673 Gerd Hoffmann
270 dcfda673 Gerd Hoffmann
    if (hs->kind == HID_MOUSE) {
271 dcfda673 Gerd Hoffmann
        dx = int_clamp(e->xdx, -127, 127);
272 dcfda673 Gerd Hoffmann
        dy = int_clamp(e->ydy, -127, 127);
273 dcfda673 Gerd Hoffmann
        e->xdx -= dx;
274 dcfda673 Gerd Hoffmann
        e->ydy -= dy;
275 dcfda673 Gerd Hoffmann
    } else {
276 dcfda673 Gerd Hoffmann
        dx = e->xdx;
277 dcfda673 Gerd Hoffmann
        dy = e->ydy;
278 dcfda673 Gerd Hoffmann
    }
279 dcfda673 Gerd Hoffmann
    dz = int_clamp(e->dz, -127, 127);
280 dcfda673 Gerd Hoffmann
    e->dz -= dz;
281 dcfda673 Gerd Hoffmann
282 dcfda673 Gerd Hoffmann
    b = 0;
283 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
284 dcfda673 Gerd Hoffmann
        b |= 0x01;
285 dcfda673 Gerd Hoffmann
    }
286 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
287 dcfda673 Gerd Hoffmann
        b |= 0x02;
288 dcfda673 Gerd Hoffmann
    }
289 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
290 dcfda673 Gerd Hoffmann
        b |= 0x04;
291 dcfda673 Gerd Hoffmann
    }
292 dcfda673 Gerd Hoffmann
293 dcfda673 Gerd Hoffmann
    if (hs->n &&
294 dcfda673 Gerd Hoffmann
        !e->dz &&
295 dcfda673 Gerd Hoffmann
        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
296 dcfda673 Gerd Hoffmann
        /* that deals with this event */
297 dcfda673 Gerd Hoffmann
        QUEUE_INCR(hs->head);
298 dcfda673 Gerd Hoffmann
        hs->n--;
299 dcfda673 Gerd Hoffmann
    }
300 dcfda673 Gerd Hoffmann
301 dcfda673 Gerd Hoffmann
    /* Appears we have to invert the wheel direction */
302 dcfda673 Gerd Hoffmann
    dz = 0 - dz;
303 dcfda673 Gerd Hoffmann
    l = 0;
304 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
305 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
306 dcfda673 Gerd Hoffmann
        if (len > l) {
307 dcfda673 Gerd Hoffmann
            buf[l++] = b;
308 dcfda673 Gerd Hoffmann
        }
309 dcfda673 Gerd Hoffmann
        if (len > l) {
310 dcfda673 Gerd Hoffmann
            buf[l++] = dx;
311 dcfda673 Gerd Hoffmann
        }
312 dcfda673 Gerd Hoffmann
        if (len > l) {
313 dcfda673 Gerd Hoffmann
            buf[l++] = dy;
314 dcfda673 Gerd Hoffmann
        }
315 dcfda673 Gerd Hoffmann
        if (len > l) {
316 dcfda673 Gerd Hoffmann
            buf[l++] = dz;
317 dcfda673 Gerd Hoffmann
        }
318 dcfda673 Gerd Hoffmann
        break;
319 dcfda673 Gerd Hoffmann
320 dcfda673 Gerd Hoffmann
    case HID_TABLET:
321 dcfda673 Gerd Hoffmann
        if (len > l) {
322 dcfda673 Gerd Hoffmann
            buf[l++] = b;
323 dcfda673 Gerd Hoffmann
        }
324 dcfda673 Gerd Hoffmann
        if (len > l) {
325 dcfda673 Gerd Hoffmann
            buf[l++] = dx & 0xff;
326 dcfda673 Gerd Hoffmann
        }
327 dcfda673 Gerd Hoffmann
        if (len > l) {
328 dcfda673 Gerd Hoffmann
            buf[l++] = dx >> 8;
329 dcfda673 Gerd Hoffmann
        }
330 dcfda673 Gerd Hoffmann
        if (len > l) {
331 dcfda673 Gerd Hoffmann
            buf[l++] = dy & 0xff;
332 dcfda673 Gerd Hoffmann
        }
333 dcfda673 Gerd Hoffmann
        if (len > l) {
334 dcfda673 Gerd Hoffmann
            buf[l++] = dy >> 8;
335 dcfda673 Gerd Hoffmann
        }
336 dcfda673 Gerd Hoffmann
        if (len > l) {
337 dcfda673 Gerd Hoffmann
            buf[l++] = dz;
338 dcfda673 Gerd Hoffmann
        }
339 dcfda673 Gerd Hoffmann
        break;
340 dcfda673 Gerd Hoffmann
341 dcfda673 Gerd Hoffmann
    default:
342 dcfda673 Gerd Hoffmann
        abort();
343 dcfda673 Gerd Hoffmann
    }
344 dcfda673 Gerd Hoffmann
345 dcfda673 Gerd Hoffmann
    return l;
346 dcfda673 Gerd Hoffmann
}
347 dcfda673 Gerd Hoffmann
348 dcfda673 Gerd Hoffmann
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
349 dcfda673 Gerd Hoffmann
{
350 027c03f7 Hans de Goede
    hs->idle_pending = false;
351 027c03f7 Hans de Goede
352 dcfda673 Gerd Hoffmann
    if (len < 2) {
353 dcfda673 Gerd Hoffmann
        return 0;
354 dcfda673 Gerd Hoffmann
    }
355 dcfda673 Gerd Hoffmann
356 dcfda673 Gerd Hoffmann
    hid_keyboard_process_keycode(hs);
357 dcfda673 Gerd Hoffmann
358 dcfda673 Gerd Hoffmann
    buf[0] = hs->kbd.modifiers & 0xff;
359 dcfda673 Gerd Hoffmann
    buf[1] = 0;
360 dcfda673 Gerd Hoffmann
    if (hs->kbd.keys > 6) {
361 dcfda673 Gerd Hoffmann
        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
362 dcfda673 Gerd Hoffmann
    } else {
363 dcfda673 Gerd Hoffmann
        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
364 dcfda673 Gerd Hoffmann
    }
365 dcfda673 Gerd Hoffmann
366 dcfda673 Gerd Hoffmann
    return MIN(8, len);
367 dcfda673 Gerd Hoffmann
}
368 dcfda673 Gerd Hoffmann
369 dcfda673 Gerd Hoffmann
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
370 dcfda673 Gerd Hoffmann
{
371 dcfda673 Gerd Hoffmann
    if (len > 0) {
372 dcfda673 Gerd Hoffmann
        int ledstate = 0;
373 dcfda673 Gerd Hoffmann
        /* 0x01: Num Lock LED
374 dcfda673 Gerd Hoffmann
         * 0x02: Caps Lock LED
375 dcfda673 Gerd Hoffmann
         * 0x04: Scroll Lock LED
376 dcfda673 Gerd Hoffmann
         * 0x08: Compose LED
377 dcfda673 Gerd Hoffmann
         * 0x10: Kana LED */
378 dcfda673 Gerd Hoffmann
        hs->kbd.leds = buf[0];
379 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x04) {
380 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_SCROLL_LOCK_LED;
381 dcfda673 Gerd Hoffmann
        }
382 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x01) {
383 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_NUM_LOCK_LED;
384 dcfda673 Gerd Hoffmann
        }
385 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x02) {
386 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_CAPS_LOCK_LED;
387 dcfda673 Gerd Hoffmann
        }
388 dcfda673 Gerd Hoffmann
        kbd_put_ledstate(ledstate);
389 dcfda673 Gerd Hoffmann
    }
390 dcfda673 Gerd Hoffmann
    return 0;
391 dcfda673 Gerd Hoffmann
}
392 dcfda673 Gerd Hoffmann
393 dcfda673 Gerd Hoffmann
void hid_reset(HIDState *hs)
394 dcfda673 Gerd Hoffmann
{
395 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
396 dcfda673 Gerd Hoffmann
    case HID_KEYBOARD:
397 dcfda673 Gerd Hoffmann
        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
398 dcfda673 Gerd Hoffmann
        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
399 dcfda673 Gerd Hoffmann
        hs->kbd.keys = 0;
400 dcfda673 Gerd Hoffmann
        break;
401 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
402 dcfda673 Gerd Hoffmann
    case HID_TABLET:
403 dcfda673 Gerd Hoffmann
        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
404 dcfda673 Gerd Hoffmann
        break;
405 dcfda673 Gerd Hoffmann
    }
406 dcfda673 Gerd Hoffmann
    hs->head = 0;
407 dcfda673 Gerd Hoffmann
    hs->n = 0;
408 b069d348 Gerd Hoffmann
    hs->protocol = 1;
409 b069d348 Gerd Hoffmann
    hs->idle = 0;
410 027c03f7 Hans de Goede
    hs->idle_pending = false;
411 027c03f7 Hans de Goede
    hid_del_idle_timer(hs);
412 dcfda673 Gerd Hoffmann
}
413 dcfda673 Gerd Hoffmann
414 dcfda673 Gerd Hoffmann
void hid_free(HIDState *hs)
415 dcfda673 Gerd Hoffmann
{
416 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
417 dcfda673 Gerd Hoffmann
    case HID_KEYBOARD:
418 5a37532d Gerd Hoffmann
        qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
419 dcfda673 Gerd Hoffmann
        break;
420 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
421 dcfda673 Gerd Hoffmann
    case HID_TABLET:
422 dcfda673 Gerd Hoffmann
        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
423 dcfda673 Gerd Hoffmann
        break;
424 dcfda673 Gerd Hoffmann
    }
425 027c03f7 Hans de Goede
    hid_del_idle_timer(hs);
426 dcfda673 Gerd Hoffmann
}
427 dcfda673 Gerd Hoffmann
428 dcfda673 Gerd Hoffmann
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
429 dcfda673 Gerd Hoffmann
{
430 dcfda673 Gerd Hoffmann
    hs->kind = kind;
431 dcfda673 Gerd Hoffmann
    hs->event = event;
432 dcfda673 Gerd Hoffmann
433 bb0db527 Michael Walle
    if (hs->kind == HID_KEYBOARD) {
434 5a37532d Gerd Hoffmann
        hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs);
435 bb0db527 Michael Walle
    } else if (hs->kind == HID_MOUSE) {
436 dcfda673 Gerd Hoffmann
        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
437 dcfda673 Gerd Hoffmann
                                                        0, "QEMU HID Mouse");
438 dcfda673 Gerd Hoffmann
    } else if (hs->kind == HID_TABLET) {
439 dcfda673 Gerd Hoffmann
        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
440 dcfda673 Gerd Hoffmann
                                                        1, "QEMU HID Tablet");
441 dcfda673 Gerd Hoffmann
    }
442 dcfda673 Gerd Hoffmann
}
443 ccd4ed06 Michael Walle
444 ccd4ed06 Michael Walle
static int hid_post_load(void *opaque, int version_id)
445 ccd4ed06 Michael Walle
{
446 ccd4ed06 Michael Walle
    HIDState *s = opaque;
447 ccd4ed06 Michael Walle
448 027c03f7 Hans de Goede
    hid_set_next_idle(s);
449 ccd4ed06 Michael Walle
    return 0;
450 ccd4ed06 Michael Walle
}
451 ccd4ed06 Michael Walle
452 ccd4ed06 Michael Walle
static const VMStateDescription vmstate_hid_ptr_queue = {
453 ccd4ed06 Michael Walle
    .name = "HIDPointerEventQueue",
454 ccd4ed06 Michael Walle
    .version_id = 1,
455 ccd4ed06 Michael Walle
    .minimum_version_id = 1,
456 ccd4ed06 Michael Walle
    .fields = (VMStateField[]) {
457 ccd4ed06 Michael Walle
        VMSTATE_INT32(xdx, HIDPointerEvent),
458 ccd4ed06 Michael Walle
        VMSTATE_INT32(ydy, HIDPointerEvent),
459 ccd4ed06 Michael Walle
        VMSTATE_INT32(dz, HIDPointerEvent),
460 ccd4ed06 Michael Walle
        VMSTATE_INT32(buttons_state, HIDPointerEvent),
461 ccd4ed06 Michael Walle
        VMSTATE_END_OF_LIST()
462 ccd4ed06 Michael Walle
    }
463 ccd4ed06 Michael Walle
};
464 ccd4ed06 Michael Walle
465 ccd4ed06 Michael Walle
const VMStateDescription vmstate_hid_ptr_device = {
466 ccd4ed06 Michael Walle
    .name = "HIDPointerDevice",
467 ccd4ed06 Michael Walle
    .version_id = 1,
468 ccd4ed06 Michael Walle
    .minimum_version_id = 1,
469 ccd4ed06 Michael Walle
    .post_load = hid_post_load,
470 ccd4ed06 Michael Walle
    .fields = (VMStateField[]) {
471 ccd4ed06 Michael Walle
        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
472 ccd4ed06 Michael Walle
                             vmstate_hid_ptr_queue, HIDPointerEvent),
473 ccd4ed06 Michael Walle
        VMSTATE_UINT32(head, HIDState),
474 ccd4ed06 Michael Walle
        VMSTATE_UINT32(n, HIDState),
475 ccd4ed06 Michael Walle
        VMSTATE_INT32(protocol, HIDState),
476 ccd4ed06 Michael Walle
        VMSTATE_UINT8(idle, HIDState),
477 ccd4ed06 Michael Walle
        VMSTATE_END_OF_LIST(),
478 ccd4ed06 Michael Walle
    }
479 ccd4ed06 Michael Walle
};
480 ccd4ed06 Michael Walle
481 ccd4ed06 Michael Walle
const VMStateDescription vmstate_hid_keyboard_device = {
482 ccd4ed06 Michael Walle
    .name = "HIDKeyboardDevice",
483 ccd4ed06 Michael Walle
    .version_id = 1,
484 ccd4ed06 Michael Walle
    .minimum_version_id = 1,
485 ccd4ed06 Michael Walle
    .post_load = hid_post_load,
486 ccd4ed06 Michael Walle
    .fields = (VMStateField[]) {
487 ccd4ed06 Michael Walle
        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
488 ccd4ed06 Michael Walle
        VMSTATE_UINT32(head, HIDState),
489 ccd4ed06 Michael Walle
        VMSTATE_UINT32(n, HIDState),
490 ccd4ed06 Michael Walle
        VMSTATE_UINT16(kbd.modifiers, HIDState),
491 ccd4ed06 Michael Walle
        VMSTATE_UINT8(kbd.leds, HIDState),
492 ccd4ed06 Michael Walle
        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
493 ccd4ed06 Michael Walle
        VMSTATE_INT32(kbd.keys, HIDState),
494 ccd4ed06 Michael Walle
        VMSTATE_INT32(protocol, HIDState),
495 ccd4ed06 Michael Walle
        VMSTATE_UINT8(idle, HIDState),
496 ccd4ed06 Michael Walle
        VMSTATE_END_OF_LIST(),
497 ccd4ed06 Michael Walle
    }
498 ccd4ed06 Michael Walle
};