Statistics
| Branch: | Revision:

root / hw / hid.c @ 21635e12

History | View | Annotate | Download (11.6 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 dcfda673 Gerd Hoffmann
#include "hw.h"
26 dcfda673 Gerd Hoffmann
#include "console.h"
27 b069d348 Gerd Hoffmann
#include "qemu-timer.h"
28 dcfda673 Gerd Hoffmann
#include "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 dcfda673 Gerd Hoffmann
    return hs->n > 0;
75 dcfda673 Gerd Hoffmann
}
76 dcfda673 Gerd Hoffmann
77 b069d348 Gerd Hoffmann
void hid_set_next_idle(HIDState *hs, int64_t curtime)
78 b069d348 Gerd Hoffmann
{
79 b069d348 Gerd Hoffmann
    hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
80 b069d348 Gerd Hoffmann
}
81 b069d348 Gerd Hoffmann
82 dcfda673 Gerd Hoffmann
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
83 dcfda673 Gerd Hoffmann
{
84 dcfda673 Gerd Hoffmann
    e->xdx = e->ydy = e->dz = 0;
85 dcfda673 Gerd Hoffmann
    e->buttons_state = buttons;
86 dcfda673 Gerd Hoffmann
}
87 dcfda673 Gerd Hoffmann
88 dcfda673 Gerd Hoffmann
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
89 dcfda673 Gerd Hoffmann
                                      int x1, int y1, int z1) {
90 dcfda673 Gerd Hoffmann
    if (xyrel) {
91 dcfda673 Gerd Hoffmann
        e->xdx += x1;
92 dcfda673 Gerd Hoffmann
        e->ydy += y1;
93 dcfda673 Gerd Hoffmann
    } else {
94 dcfda673 Gerd Hoffmann
        e->xdx = x1;
95 dcfda673 Gerd Hoffmann
        e->ydy = y1;
96 dcfda673 Gerd Hoffmann
        /* Windows drivers do not like the 0/0 position and ignore such
97 dcfda673 Gerd Hoffmann
         * events. */
98 dcfda673 Gerd Hoffmann
        if (!(x1 | y1)) {
99 dcfda673 Gerd Hoffmann
            x1 = 1;
100 dcfda673 Gerd Hoffmann
        }
101 dcfda673 Gerd Hoffmann
    }
102 dcfda673 Gerd Hoffmann
    e->dz += z1;
103 dcfda673 Gerd Hoffmann
}
104 dcfda673 Gerd Hoffmann
105 dcfda673 Gerd Hoffmann
static void hid_pointer_event(void *opaque,
106 dcfda673 Gerd Hoffmann
                              int x1, int y1, int z1, int buttons_state)
107 dcfda673 Gerd Hoffmann
{
108 dcfda673 Gerd Hoffmann
    HIDState *hs = opaque;
109 dcfda673 Gerd Hoffmann
    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
110 dcfda673 Gerd Hoffmann
    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
111 dcfda673 Gerd Hoffmann
112 dcfda673 Gerd Hoffmann
    /* We combine events where feasible to keep the queue small.  We shouldn't
113 dcfda673 Gerd Hoffmann
     * combine anything with the first event of a particular button state, as
114 dcfda673 Gerd Hoffmann
     * that would change the location of the button state change.  When the
115 dcfda673 Gerd Hoffmann
     * queue is empty, a second event is needed because we don't know if
116 dcfda673 Gerd Hoffmann
     * the first event changed the button state.  */
117 dcfda673 Gerd Hoffmann
    if (hs->n == QUEUE_LENGTH) {
118 dcfda673 Gerd Hoffmann
        /* Queue full.  Discard old button state, combine motion normally.  */
119 dcfda673 Gerd Hoffmann
        hs->ptr.queue[use_slot].buttons_state = buttons_state;
120 dcfda673 Gerd Hoffmann
    } else if (hs->n < 2 ||
121 dcfda673 Gerd Hoffmann
               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
122 dcfda673 Gerd Hoffmann
               hs->ptr.queue[previous_slot].buttons_state !=
123 dcfda673 Gerd Hoffmann
               hs->ptr.queue[use_slot].buttons_state) {
124 dcfda673 Gerd Hoffmann
        /* Cannot or should not combine, so add an empty item to the queue.  */
125 dcfda673 Gerd Hoffmann
        QUEUE_INCR(use_slot);
126 dcfda673 Gerd Hoffmann
        hs->n++;
127 dcfda673 Gerd Hoffmann
        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
128 dcfda673 Gerd Hoffmann
    }
129 dcfda673 Gerd Hoffmann
    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
130 dcfda673 Gerd Hoffmann
                              hs->kind == HID_MOUSE,
131 dcfda673 Gerd Hoffmann
                              x1, y1, z1);
132 dcfda673 Gerd Hoffmann
    hs->event(hs);
133 dcfda673 Gerd Hoffmann
}
134 dcfda673 Gerd Hoffmann
135 dcfda673 Gerd Hoffmann
static void hid_keyboard_event(void *opaque, int keycode)
136 dcfda673 Gerd Hoffmann
{
137 dcfda673 Gerd Hoffmann
    HIDState *hs = opaque;
138 dcfda673 Gerd Hoffmann
    int slot;
139 dcfda673 Gerd Hoffmann
140 dcfda673 Gerd Hoffmann
    if (hs->n == QUEUE_LENGTH) {
141 dcfda673 Gerd Hoffmann
        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
142 dcfda673 Gerd Hoffmann
        return;
143 dcfda673 Gerd Hoffmann
    }
144 dcfda673 Gerd Hoffmann
    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
145 dcfda673 Gerd Hoffmann
    hs->kbd.keycodes[slot] = keycode;
146 dcfda673 Gerd Hoffmann
    hs->event(hs);
147 dcfda673 Gerd Hoffmann
}
148 dcfda673 Gerd Hoffmann
149 dcfda673 Gerd Hoffmann
static void hid_keyboard_process_keycode(HIDState *hs)
150 dcfda673 Gerd Hoffmann
{
151 dcfda673 Gerd Hoffmann
    uint8_t hid_code, key;
152 dcfda673 Gerd Hoffmann
    int i, keycode, slot;
153 dcfda673 Gerd Hoffmann
154 dcfda673 Gerd Hoffmann
    if (hs->n == 0) {
155 dcfda673 Gerd Hoffmann
        return;
156 dcfda673 Gerd Hoffmann
    }
157 dcfda673 Gerd Hoffmann
    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
158 dcfda673 Gerd Hoffmann
    keycode = hs->kbd.keycodes[slot];
159 dcfda673 Gerd Hoffmann
160 dcfda673 Gerd Hoffmann
    key = keycode & 0x7f;
161 dcfda673 Gerd Hoffmann
    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
162 dcfda673 Gerd Hoffmann
    hs->kbd.modifiers &= ~(1 << 8);
163 dcfda673 Gerd Hoffmann
164 dcfda673 Gerd Hoffmann
    switch (hid_code) {
165 dcfda673 Gerd Hoffmann
    case 0x00:
166 dcfda673 Gerd Hoffmann
        return;
167 dcfda673 Gerd Hoffmann
168 dcfda673 Gerd Hoffmann
    case 0xe0:
169 dcfda673 Gerd Hoffmann
        if (hs->kbd.modifiers & (1 << 9)) {
170 dcfda673 Gerd Hoffmann
            hs->kbd.modifiers ^= 3 << 8;
171 dcfda673 Gerd Hoffmann
            return;
172 dcfda673 Gerd Hoffmann
        }
173 dcfda673 Gerd Hoffmann
    case 0xe1 ... 0xe7:
174 dcfda673 Gerd Hoffmann
        if (keycode & (1 << 7)) {
175 dcfda673 Gerd Hoffmann
            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
176 dcfda673 Gerd Hoffmann
            return;
177 dcfda673 Gerd Hoffmann
        }
178 dcfda673 Gerd Hoffmann
    case 0xe8 ... 0xef:
179 dcfda673 Gerd Hoffmann
        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
180 dcfda673 Gerd Hoffmann
        return;
181 dcfda673 Gerd Hoffmann
    }
182 dcfda673 Gerd Hoffmann
183 dcfda673 Gerd Hoffmann
    if (keycode & (1 << 7)) {
184 dcfda673 Gerd Hoffmann
        for (i = hs->kbd.keys - 1; i >= 0; i--) {
185 dcfda673 Gerd Hoffmann
            if (hs->kbd.key[i] == hid_code) {
186 dcfda673 Gerd Hoffmann
                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
187 dcfda673 Gerd Hoffmann
                hs->kbd.key[hs->kbd.keys] = 0x00;
188 dcfda673 Gerd Hoffmann
                break;
189 dcfda673 Gerd Hoffmann
            }
190 dcfda673 Gerd Hoffmann
        }
191 dcfda673 Gerd Hoffmann
        if (i < 0) {
192 dcfda673 Gerd Hoffmann
            return;
193 dcfda673 Gerd Hoffmann
        }
194 dcfda673 Gerd Hoffmann
    } else {
195 dcfda673 Gerd Hoffmann
        for (i = hs->kbd.keys - 1; i >= 0; i--) {
196 dcfda673 Gerd Hoffmann
            if (hs->kbd.key[i] == hid_code) {
197 dcfda673 Gerd Hoffmann
                break;
198 dcfda673 Gerd Hoffmann
            }
199 dcfda673 Gerd Hoffmann
        }
200 dcfda673 Gerd Hoffmann
        if (i < 0) {
201 dcfda673 Gerd Hoffmann
            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
202 dcfda673 Gerd Hoffmann
                hs->kbd.key[hs->kbd.keys++] = hid_code;
203 dcfda673 Gerd Hoffmann
            }
204 dcfda673 Gerd Hoffmann
        } else {
205 dcfda673 Gerd Hoffmann
            return;
206 dcfda673 Gerd Hoffmann
        }
207 dcfda673 Gerd Hoffmann
    }
208 dcfda673 Gerd Hoffmann
}
209 dcfda673 Gerd Hoffmann
210 dcfda673 Gerd Hoffmann
static inline int int_clamp(int val, int vmin, int vmax)
211 dcfda673 Gerd Hoffmann
{
212 dcfda673 Gerd Hoffmann
    if (val < vmin) {
213 dcfda673 Gerd Hoffmann
        return vmin;
214 dcfda673 Gerd Hoffmann
    } else if (val > vmax) {
215 dcfda673 Gerd Hoffmann
        return vmax;
216 dcfda673 Gerd Hoffmann
    } else {
217 dcfda673 Gerd Hoffmann
        return val;
218 dcfda673 Gerd Hoffmann
    }
219 dcfda673 Gerd Hoffmann
}
220 dcfda673 Gerd Hoffmann
221 21635e12 Gerd Hoffmann
void hid_pointer_activate(HIDState *hs)
222 21635e12 Gerd Hoffmann
{
223 21635e12 Gerd Hoffmann
    if (!hs->ptr.mouse_grabbed) {
224 21635e12 Gerd Hoffmann
        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
225 21635e12 Gerd Hoffmann
        hs->ptr.mouse_grabbed = 1;
226 21635e12 Gerd Hoffmann
    }
227 21635e12 Gerd Hoffmann
}
228 21635e12 Gerd Hoffmann
229 dcfda673 Gerd Hoffmann
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
230 dcfda673 Gerd Hoffmann
{
231 dcfda673 Gerd Hoffmann
    int dx, dy, dz, b, l;
232 dcfda673 Gerd Hoffmann
    int index;
233 dcfda673 Gerd Hoffmann
    HIDPointerEvent *e;
234 dcfda673 Gerd Hoffmann
235 21635e12 Gerd Hoffmann
    hid_pointer_activate(hs);
236 dcfda673 Gerd Hoffmann
237 dcfda673 Gerd Hoffmann
    /* When the buffer is empty, return the last event.  Relative
238 dcfda673 Gerd Hoffmann
       movements will all be zero.  */
239 dcfda673 Gerd Hoffmann
    index = (hs->n ? hs->head : hs->head - 1);
240 dcfda673 Gerd Hoffmann
    e = &hs->ptr.queue[index & QUEUE_MASK];
241 dcfda673 Gerd Hoffmann
242 dcfda673 Gerd Hoffmann
    if (hs->kind == HID_MOUSE) {
243 dcfda673 Gerd Hoffmann
        dx = int_clamp(e->xdx, -127, 127);
244 dcfda673 Gerd Hoffmann
        dy = int_clamp(e->ydy, -127, 127);
245 dcfda673 Gerd Hoffmann
        e->xdx -= dx;
246 dcfda673 Gerd Hoffmann
        e->ydy -= dy;
247 dcfda673 Gerd Hoffmann
    } else {
248 dcfda673 Gerd Hoffmann
        dx = e->xdx;
249 dcfda673 Gerd Hoffmann
        dy = e->ydy;
250 dcfda673 Gerd Hoffmann
    }
251 dcfda673 Gerd Hoffmann
    dz = int_clamp(e->dz, -127, 127);
252 dcfda673 Gerd Hoffmann
    e->dz -= dz;
253 dcfda673 Gerd Hoffmann
254 dcfda673 Gerd Hoffmann
    b = 0;
255 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
256 dcfda673 Gerd Hoffmann
        b |= 0x01;
257 dcfda673 Gerd Hoffmann
    }
258 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
259 dcfda673 Gerd Hoffmann
        b |= 0x02;
260 dcfda673 Gerd Hoffmann
    }
261 dcfda673 Gerd Hoffmann
    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
262 dcfda673 Gerd Hoffmann
        b |= 0x04;
263 dcfda673 Gerd Hoffmann
    }
264 dcfda673 Gerd Hoffmann
265 dcfda673 Gerd Hoffmann
    if (hs->n &&
266 dcfda673 Gerd Hoffmann
        !e->dz &&
267 dcfda673 Gerd Hoffmann
        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
268 dcfda673 Gerd Hoffmann
        /* that deals with this event */
269 dcfda673 Gerd Hoffmann
        QUEUE_INCR(hs->head);
270 dcfda673 Gerd Hoffmann
        hs->n--;
271 dcfda673 Gerd Hoffmann
    }
272 dcfda673 Gerd Hoffmann
273 dcfda673 Gerd Hoffmann
    /* Appears we have to invert the wheel direction */
274 dcfda673 Gerd Hoffmann
    dz = 0 - dz;
275 dcfda673 Gerd Hoffmann
    l = 0;
276 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
277 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
278 dcfda673 Gerd Hoffmann
        if (len > l) {
279 dcfda673 Gerd Hoffmann
            buf[l++] = b;
280 dcfda673 Gerd Hoffmann
        }
281 dcfda673 Gerd Hoffmann
        if (len > l) {
282 dcfda673 Gerd Hoffmann
            buf[l++] = dx;
283 dcfda673 Gerd Hoffmann
        }
284 dcfda673 Gerd Hoffmann
        if (len > l) {
285 dcfda673 Gerd Hoffmann
            buf[l++] = dy;
286 dcfda673 Gerd Hoffmann
        }
287 dcfda673 Gerd Hoffmann
        if (len > l) {
288 dcfda673 Gerd Hoffmann
            buf[l++] = dz;
289 dcfda673 Gerd Hoffmann
        }
290 dcfda673 Gerd Hoffmann
        break;
291 dcfda673 Gerd Hoffmann
292 dcfda673 Gerd Hoffmann
    case HID_TABLET:
293 dcfda673 Gerd Hoffmann
        if (len > l) {
294 dcfda673 Gerd Hoffmann
            buf[l++] = b;
295 dcfda673 Gerd Hoffmann
        }
296 dcfda673 Gerd Hoffmann
        if (len > l) {
297 dcfda673 Gerd Hoffmann
            buf[l++] = dx & 0xff;
298 dcfda673 Gerd Hoffmann
        }
299 dcfda673 Gerd Hoffmann
        if (len > l) {
300 dcfda673 Gerd Hoffmann
            buf[l++] = dx >> 8;
301 dcfda673 Gerd Hoffmann
        }
302 dcfda673 Gerd Hoffmann
        if (len > l) {
303 dcfda673 Gerd Hoffmann
            buf[l++] = dy & 0xff;
304 dcfda673 Gerd Hoffmann
        }
305 dcfda673 Gerd Hoffmann
        if (len > l) {
306 dcfda673 Gerd Hoffmann
            buf[l++] = dy >> 8;
307 dcfda673 Gerd Hoffmann
        }
308 dcfda673 Gerd Hoffmann
        if (len > l) {
309 dcfda673 Gerd Hoffmann
            buf[l++] = dz;
310 dcfda673 Gerd Hoffmann
        }
311 dcfda673 Gerd Hoffmann
        break;
312 dcfda673 Gerd Hoffmann
313 dcfda673 Gerd Hoffmann
    default:
314 dcfda673 Gerd Hoffmann
        abort();
315 dcfda673 Gerd Hoffmann
    }
316 dcfda673 Gerd Hoffmann
317 dcfda673 Gerd Hoffmann
    return l;
318 dcfda673 Gerd Hoffmann
}
319 dcfda673 Gerd Hoffmann
320 dcfda673 Gerd Hoffmann
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
321 dcfda673 Gerd Hoffmann
{
322 dcfda673 Gerd Hoffmann
    if (len < 2) {
323 dcfda673 Gerd Hoffmann
        return 0;
324 dcfda673 Gerd Hoffmann
    }
325 dcfda673 Gerd Hoffmann
326 dcfda673 Gerd Hoffmann
    hid_keyboard_process_keycode(hs);
327 dcfda673 Gerd Hoffmann
328 dcfda673 Gerd Hoffmann
    buf[0] = hs->kbd.modifiers & 0xff;
329 dcfda673 Gerd Hoffmann
    buf[1] = 0;
330 dcfda673 Gerd Hoffmann
    if (hs->kbd.keys > 6) {
331 dcfda673 Gerd Hoffmann
        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
332 dcfda673 Gerd Hoffmann
    } else {
333 dcfda673 Gerd Hoffmann
        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
334 dcfda673 Gerd Hoffmann
    }
335 dcfda673 Gerd Hoffmann
336 dcfda673 Gerd Hoffmann
    return MIN(8, len);
337 dcfda673 Gerd Hoffmann
}
338 dcfda673 Gerd Hoffmann
339 dcfda673 Gerd Hoffmann
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
340 dcfda673 Gerd Hoffmann
{
341 dcfda673 Gerd Hoffmann
    if (len > 0) {
342 dcfda673 Gerd Hoffmann
        int ledstate = 0;
343 dcfda673 Gerd Hoffmann
        /* 0x01: Num Lock LED
344 dcfda673 Gerd Hoffmann
         * 0x02: Caps Lock LED
345 dcfda673 Gerd Hoffmann
         * 0x04: Scroll Lock LED
346 dcfda673 Gerd Hoffmann
         * 0x08: Compose LED
347 dcfda673 Gerd Hoffmann
         * 0x10: Kana LED */
348 dcfda673 Gerd Hoffmann
        hs->kbd.leds = buf[0];
349 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x04) {
350 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_SCROLL_LOCK_LED;
351 dcfda673 Gerd Hoffmann
        }
352 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x01) {
353 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_NUM_LOCK_LED;
354 dcfda673 Gerd Hoffmann
        }
355 dcfda673 Gerd Hoffmann
        if (hs->kbd.leds & 0x02) {
356 dcfda673 Gerd Hoffmann
            ledstate |= QEMU_CAPS_LOCK_LED;
357 dcfda673 Gerd Hoffmann
        }
358 dcfda673 Gerd Hoffmann
        kbd_put_ledstate(ledstate);
359 dcfda673 Gerd Hoffmann
    }
360 dcfda673 Gerd Hoffmann
    return 0;
361 dcfda673 Gerd Hoffmann
}
362 dcfda673 Gerd Hoffmann
363 dcfda673 Gerd Hoffmann
void hid_reset(HIDState *hs)
364 dcfda673 Gerd Hoffmann
{
365 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
366 dcfda673 Gerd Hoffmann
    case HID_KEYBOARD:
367 dcfda673 Gerd Hoffmann
        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
368 dcfda673 Gerd Hoffmann
        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
369 dcfda673 Gerd Hoffmann
        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
370 dcfda673 Gerd Hoffmann
        hs->kbd.keys = 0;
371 dcfda673 Gerd Hoffmann
        break;
372 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
373 dcfda673 Gerd Hoffmann
    case HID_TABLET:
374 dcfda673 Gerd Hoffmann
        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
375 dcfda673 Gerd Hoffmann
        break;
376 dcfda673 Gerd Hoffmann
    }
377 dcfda673 Gerd Hoffmann
    hs->head = 0;
378 dcfda673 Gerd Hoffmann
    hs->n = 0;
379 b069d348 Gerd Hoffmann
    hs->protocol = 1;
380 b069d348 Gerd Hoffmann
    hs->idle = 0;
381 dcfda673 Gerd Hoffmann
}
382 dcfda673 Gerd Hoffmann
383 dcfda673 Gerd Hoffmann
void hid_free(HIDState *hs)
384 dcfda673 Gerd Hoffmann
{
385 dcfda673 Gerd Hoffmann
    switch (hs->kind) {
386 dcfda673 Gerd Hoffmann
    case HID_KEYBOARD:
387 dcfda673 Gerd Hoffmann
        qemu_remove_kbd_event_handler();
388 dcfda673 Gerd Hoffmann
        break;
389 dcfda673 Gerd Hoffmann
    case HID_MOUSE:
390 dcfda673 Gerd Hoffmann
    case HID_TABLET:
391 dcfda673 Gerd Hoffmann
        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
392 dcfda673 Gerd Hoffmann
        break;
393 dcfda673 Gerd Hoffmann
    }
394 dcfda673 Gerd Hoffmann
}
395 dcfda673 Gerd Hoffmann
396 dcfda673 Gerd Hoffmann
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
397 dcfda673 Gerd Hoffmann
{
398 dcfda673 Gerd Hoffmann
    hs->kind = kind;
399 dcfda673 Gerd Hoffmann
    hs->event = event;
400 dcfda673 Gerd Hoffmann
401 dcfda673 Gerd Hoffmann
    if (hs->kind == HID_MOUSE) {
402 dcfda673 Gerd Hoffmann
        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
403 dcfda673 Gerd Hoffmann
                                                        0, "QEMU HID Mouse");
404 dcfda673 Gerd Hoffmann
    } else if (hs->kind == HID_TABLET) {
405 dcfda673 Gerd Hoffmann
        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
406 dcfda673 Gerd Hoffmann
                                                        1, "QEMU HID Tablet");
407 dcfda673 Gerd Hoffmann
    }
408 dcfda673 Gerd Hoffmann
}