Revision dcfda673
b/Makefile.objs | ||
---|---|---|
89 | 89 |
common-obj-y += eeprom93xx.o |
90 | 90 |
common-obj-y += scsi-disk.o cdrom.o |
91 | 91 |
common-obj-y += scsi-generic.o scsi-bus.o |
92 |
common-obj-y += hid.o |
|
92 | 93 |
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o |
93 | 94 |
common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o |
94 | 95 |
common-obj-$(CONFIG_SSI) += ssi.o |
b/hw/hid.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU HID devices |
|
3 |
* |
|
4 |
* Copyright (c) 2005 Fabrice Bellard |
|
5 |
* Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) |
|
6 |
* |
|
7 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8 |
* of this software and associated documentation files (the "Software"), to deal |
|
9 |
* in the Software without restriction, including without limitation the rights |
|
10 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11 |
* copies of the Software, and to permit persons to whom the Software is |
|
12 |
* furnished to do so, subject to the following conditions: |
|
13 |
* |
|
14 |
* The above copyright notice and this permission notice shall be included in |
|
15 |
* all copies or substantial portions of the Software. |
|
16 |
* |
|
17 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
20 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23 |
* THE SOFTWARE. |
|
24 |
*/ |
|
25 |
#include "hw.h" |
|
26 |
#include "console.h" |
|
27 |
#include "hid.h" |
|
28 |
|
|
29 |
#define HID_USAGE_ERROR_ROLLOVER 0x01 |
|
30 |
#define HID_USAGE_POSTFAIL 0x02 |
|
31 |
#define HID_USAGE_ERROR_UNDEFINED 0x03 |
|
32 |
|
|
33 |
/* Indices are QEMU keycodes, values are from HID Usage Table. Indices |
|
34 |
* above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ |
|
35 |
static const uint8_t hid_usage_keys[0x100] = { |
|
36 |
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
|
37 |
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, |
|
38 |
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, |
|
39 |
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, |
|
40 |
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, |
|
41 |
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, |
|
42 |
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, |
|
43 |
0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, |
|
44 |
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, |
|
45 |
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, |
|
46 |
0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, |
|
47 |
0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, |
|
48 |
0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, |
|
49 |
0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, |
|
50 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
51 |
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, |
|
52 |
|
|
53 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
54 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
55 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
56 |
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, |
|
57 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
58 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
59 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, |
|
60 |
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
61 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, |
|
62 |
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, |
|
63 |
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, |
|
64 |
0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, |
|
65 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
66 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
67 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
68 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
69 |
}; |
|
70 |
|
|
71 |
bool hid_has_events(HIDState *hs) |
|
72 |
{ |
|
73 |
return hs->n > 0; |
|
74 |
} |
|
75 |
|
|
76 |
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) |
|
77 |
{ |
|
78 |
e->xdx = e->ydy = e->dz = 0; |
|
79 |
e->buttons_state = buttons; |
|
80 |
} |
|
81 |
|
|
82 |
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, |
|
83 |
int x1, int y1, int z1) { |
|
84 |
if (xyrel) { |
|
85 |
e->xdx += x1; |
|
86 |
e->ydy += y1; |
|
87 |
} else { |
|
88 |
e->xdx = x1; |
|
89 |
e->ydy = y1; |
|
90 |
/* Windows drivers do not like the 0/0 position and ignore such |
|
91 |
* events. */ |
|
92 |
if (!(x1 | y1)) { |
|
93 |
x1 = 1; |
|
94 |
} |
|
95 |
} |
|
96 |
e->dz += z1; |
|
97 |
} |
|
98 |
|
|
99 |
static void hid_pointer_event(void *opaque, |
|
100 |
int x1, int y1, int z1, int buttons_state) |
|
101 |
{ |
|
102 |
HIDState *hs = opaque; |
|
103 |
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; |
|
104 |
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; |
|
105 |
|
|
106 |
/* We combine events where feasible to keep the queue small. We shouldn't |
|
107 |
* combine anything with the first event of a particular button state, as |
|
108 |
* that would change the location of the button state change. When the |
|
109 |
* queue is empty, a second event is needed because we don't know if |
|
110 |
* the first event changed the button state. */ |
|
111 |
if (hs->n == QUEUE_LENGTH) { |
|
112 |
/* Queue full. Discard old button state, combine motion normally. */ |
|
113 |
hs->ptr.queue[use_slot].buttons_state = buttons_state; |
|
114 |
} else if (hs->n < 2 || |
|
115 |
hs->ptr.queue[use_slot].buttons_state != buttons_state || |
|
116 |
hs->ptr.queue[previous_slot].buttons_state != |
|
117 |
hs->ptr.queue[use_slot].buttons_state) { |
|
118 |
/* Cannot or should not combine, so add an empty item to the queue. */ |
|
119 |
QUEUE_INCR(use_slot); |
|
120 |
hs->n++; |
|
121 |
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); |
|
122 |
} |
|
123 |
hid_pointer_event_combine(&hs->ptr.queue[use_slot], |
|
124 |
hs->kind == HID_MOUSE, |
|
125 |
x1, y1, z1); |
|
126 |
hs->event(hs); |
|
127 |
} |
|
128 |
|
|
129 |
static void hid_keyboard_event(void *opaque, int keycode) |
|
130 |
{ |
|
131 |
HIDState *hs = opaque; |
|
132 |
int slot; |
|
133 |
|
|
134 |
if (hs->n == QUEUE_LENGTH) { |
|
135 |
fprintf(stderr, "usb-kbd: warning: key event queue full\n"); |
|
136 |
return; |
|
137 |
} |
|
138 |
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; |
|
139 |
hs->kbd.keycodes[slot] = keycode; |
|
140 |
hs->event(hs); |
|
141 |
} |
|
142 |
|
|
143 |
static void hid_keyboard_process_keycode(HIDState *hs) |
|
144 |
{ |
|
145 |
uint8_t hid_code, key; |
|
146 |
int i, keycode, slot; |
|
147 |
|
|
148 |
if (hs->n == 0) { |
|
149 |
return; |
|
150 |
} |
|
151 |
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; |
|
152 |
keycode = hs->kbd.keycodes[slot]; |
|
153 |
|
|
154 |
key = keycode & 0x7f; |
|
155 |
hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))]; |
|
156 |
hs->kbd.modifiers &= ~(1 << 8); |
|
157 |
|
|
158 |
switch (hid_code) { |
|
159 |
case 0x00: |
|
160 |
return; |
|
161 |
|
|
162 |
case 0xe0: |
|
163 |
if (hs->kbd.modifiers & (1 << 9)) { |
|
164 |
hs->kbd.modifiers ^= 3 << 8; |
|
165 |
return; |
|
166 |
} |
|
167 |
case 0xe1 ... 0xe7: |
|
168 |
if (keycode & (1 << 7)) { |
|
169 |
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); |
|
170 |
return; |
|
171 |
} |
|
172 |
case 0xe8 ... 0xef: |
|
173 |
hs->kbd.modifiers |= 1 << (hid_code & 0x0f); |
|
174 |
return; |
|
175 |
} |
|
176 |
|
|
177 |
if (keycode & (1 << 7)) { |
|
178 |
for (i = hs->kbd.keys - 1; i >= 0; i--) { |
|
179 |
if (hs->kbd.key[i] == hid_code) { |
|
180 |
hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; |
|
181 |
hs->kbd.key[hs->kbd.keys] = 0x00; |
|
182 |
break; |
|
183 |
} |
|
184 |
} |
|
185 |
if (i < 0) { |
|
186 |
return; |
|
187 |
} |
|
188 |
} else { |
|
189 |
for (i = hs->kbd.keys - 1; i >= 0; i--) { |
|
190 |
if (hs->kbd.key[i] == hid_code) { |
|
191 |
break; |
|
192 |
} |
|
193 |
} |
|
194 |
if (i < 0) { |
|
195 |
if (hs->kbd.keys < sizeof(hs->kbd.key)) { |
|
196 |
hs->kbd.key[hs->kbd.keys++] = hid_code; |
|
197 |
} |
|
198 |
} else { |
|
199 |
return; |
|
200 |
} |
|
201 |
} |
|
202 |
} |
|
203 |
|
|
204 |
static inline int int_clamp(int val, int vmin, int vmax) |
|
205 |
{ |
|
206 |
if (val < vmin) { |
|
207 |
return vmin; |
|
208 |
} else if (val > vmax) { |
|
209 |
return vmax; |
|
210 |
} else { |
|
211 |
return val; |
|
212 |
} |
|
213 |
} |
|
214 |
|
|
215 |
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) |
|
216 |
{ |
|
217 |
int dx, dy, dz, b, l; |
|
218 |
int index; |
|
219 |
HIDPointerEvent *e; |
|
220 |
|
|
221 |
if (!hs->ptr.mouse_grabbed) { |
|
222 |
qemu_activate_mouse_event_handler(hs->ptr.eh_entry); |
|
223 |
hs->ptr.mouse_grabbed = 1; |
|
224 |
} |
|
225 |
|
|
226 |
/* When the buffer is empty, return the last event. Relative |
|
227 |
movements will all be zero. */ |
|
228 |
index = (hs->n ? hs->head : hs->head - 1); |
|
229 |
e = &hs->ptr.queue[index & QUEUE_MASK]; |
|
230 |
|
|
231 |
if (hs->kind == HID_MOUSE) { |
|
232 |
dx = int_clamp(e->xdx, -127, 127); |
|
233 |
dy = int_clamp(e->ydy, -127, 127); |
|
234 |
e->xdx -= dx; |
|
235 |
e->ydy -= dy; |
|
236 |
} else { |
|
237 |
dx = e->xdx; |
|
238 |
dy = e->ydy; |
|
239 |
} |
|
240 |
dz = int_clamp(e->dz, -127, 127); |
|
241 |
e->dz -= dz; |
|
242 |
|
|
243 |
b = 0; |
|
244 |
if (e->buttons_state & MOUSE_EVENT_LBUTTON) { |
|
245 |
b |= 0x01; |
|
246 |
} |
|
247 |
if (e->buttons_state & MOUSE_EVENT_RBUTTON) { |
|
248 |
b |= 0x02; |
|
249 |
} |
|
250 |
if (e->buttons_state & MOUSE_EVENT_MBUTTON) { |
|
251 |
b |= 0x04; |
|
252 |
} |
|
253 |
|
|
254 |
if (hs->n && |
|
255 |
!e->dz && |
|
256 |
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { |
|
257 |
/* that deals with this event */ |
|
258 |
QUEUE_INCR(hs->head); |
|
259 |
hs->n--; |
|
260 |
} |
|
261 |
|
|
262 |
/* Appears we have to invert the wheel direction */ |
|
263 |
dz = 0 - dz; |
|
264 |
l = 0; |
|
265 |
switch (hs->kind) { |
|
266 |
case HID_MOUSE: |
|
267 |
if (len > l) { |
|
268 |
buf[l++] = b; |
|
269 |
} |
|
270 |
if (len > l) { |
|
271 |
buf[l++] = dx; |
|
272 |
} |
|
273 |
if (len > l) { |
|
274 |
buf[l++] = dy; |
|
275 |
} |
|
276 |
if (len > l) { |
|
277 |
buf[l++] = dz; |
|
278 |
} |
|
279 |
break; |
|
280 |
|
|
281 |
case HID_TABLET: |
|
282 |
if (len > l) { |
|
283 |
buf[l++] = b; |
|
284 |
} |
|
285 |
if (len > l) { |
|
286 |
buf[l++] = dx & 0xff; |
|
287 |
} |
|
288 |
if (len > l) { |
|
289 |
buf[l++] = dx >> 8; |
|
290 |
} |
|
291 |
if (len > l) { |
|
292 |
buf[l++] = dy & 0xff; |
|
293 |
} |
|
294 |
if (len > l) { |
|
295 |
buf[l++] = dy >> 8; |
|
296 |
} |
|
297 |
if (len > l) { |
|
298 |
buf[l++] = dz; |
|
299 |
} |
|
300 |
break; |
|
301 |
|
|
302 |
default: |
|
303 |
abort(); |
|
304 |
} |
|
305 |
|
|
306 |
return l; |
|
307 |
} |
|
308 |
|
|
309 |
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) |
|
310 |
{ |
|
311 |
if (len < 2) { |
|
312 |
return 0; |
|
313 |
} |
|
314 |
|
|
315 |
hid_keyboard_process_keycode(hs); |
|
316 |
|
|
317 |
buf[0] = hs->kbd.modifiers & 0xff; |
|
318 |
buf[1] = 0; |
|
319 |
if (hs->kbd.keys > 6) { |
|
320 |
memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); |
|
321 |
} else { |
|
322 |
memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); |
|
323 |
} |
|
324 |
|
|
325 |
return MIN(8, len); |
|
326 |
} |
|
327 |
|
|
328 |
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) |
|
329 |
{ |
|
330 |
if (len > 0) { |
|
331 |
int ledstate = 0; |
|
332 |
/* 0x01: Num Lock LED |
|
333 |
* 0x02: Caps Lock LED |
|
334 |
* 0x04: Scroll Lock LED |
|
335 |
* 0x08: Compose LED |
|
336 |
* 0x10: Kana LED */ |
|
337 |
hs->kbd.leds = buf[0]; |
|
338 |
if (hs->kbd.leds & 0x04) { |
|
339 |
ledstate |= QEMU_SCROLL_LOCK_LED; |
|
340 |
} |
|
341 |
if (hs->kbd.leds & 0x01) { |
|
342 |
ledstate |= QEMU_NUM_LOCK_LED; |
|
343 |
} |
|
344 |
if (hs->kbd.leds & 0x02) { |
|
345 |
ledstate |= QEMU_CAPS_LOCK_LED; |
|
346 |
} |
|
347 |
kbd_put_ledstate(ledstate); |
|
348 |
} |
|
349 |
return 0; |
|
350 |
} |
|
351 |
|
|
352 |
void hid_reset(HIDState *hs) |
|
353 |
{ |
|
354 |
switch (hs->kind) { |
|
355 |
case HID_KEYBOARD: |
|
356 |
qemu_add_kbd_event_handler(hid_keyboard_event, hs); |
|
357 |
memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); |
|
358 |
memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); |
|
359 |
hs->kbd.keys = 0; |
|
360 |
break; |
|
361 |
case HID_MOUSE: |
|
362 |
case HID_TABLET: |
|
363 |
memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); |
|
364 |
break; |
|
365 |
} |
|
366 |
hs->head = 0; |
|
367 |
hs->n = 0; |
|
368 |
} |
|
369 |
|
|
370 |
void hid_free(HIDState *hs) |
|
371 |
{ |
|
372 |
switch (hs->kind) { |
|
373 |
case HID_KEYBOARD: |
|
374 |
qemu_remove_kbd_event_handler(); |
|
375 |
break; |
|
376 |
case HID_MOUSE: |
|
377 |
case HID_TABLET: |
|
378 |
qemu_remove_mouse_event_handler(hs->ptr.eh_entry); |
|
379 |
break; |
|
380 |
} |
|
381 |
} |
|
382 |
|
|
383 |
void hid_init(HIDState *hs, int kind, HIDEventFunc event) |
|
384 |
{ |
|
385 |
hs->kind = kind; |
|
386 |
hs->event = event; |
|
387 |
|
|
388 |
if (hs->kind == HID_MOUSE) { |
|
389 |
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, |
|
390 |
0, "QEMU HID Mouse"); |
|
391 |
} else if (hs->kind == HID_TABLET) { |
|
392 |
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, |
|
393 |
1, "QEMU HID Tablet"); |
|
394 |
} |
|
395 |
} |
b/hw/hid.h | ||
---|---|---|
1 |
#ifndef QEMU_HID_H |
|
2 |
#define QEMU_HID_H |
|
3 |
|
|
4 |
#define HID_MOUSE 1 |
|
5 |
#define HID_TABLET 2 |
|
6 |
#define HID_KEYBOARD 3 |
|
7 |
|
|
8 |
typedef struct HIDPointerEvent { |
|
9 |
int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */ |
|
10 |
int32_t dz, buttons_state; |
|
11 |
} HIDPointerEvent; |
|
12 |
|
|
13 |
#define QUEUE_LENGTH 16 /* should be enough for a triple-click */ |
|
14 |
#define QUEUE_MASK (QUEUE_LENGTH-1u) |
|
15 |
#define QUEUE_INCR(v) ((v)++, (v) &= QUEUE_MASK) |
|
16 |
|
|
17 |
typedef struct HIDState HIDState; |
|
18 |
typedef void (*HIDEventFunc)(HIDState *s); |
|
19 |
|
|
20 |
typedef struct HIDMouseState { |
|
21 |
HIDPointerEvent queue[QUEUE_LENGTH]; |
|
22 |
int mouse_grabbed; |
|
23 |
QEMUPutMouseEntry *eh_entry; |
|
24 |
} HIDMouseState; |
|
25 |
|
|
26 |
typedef struct HIDKeyboardState { |
|
27 |
uint32_t keycodes[QUEUE_LENGTH]; |
|
28 |
uint16_t modifiers; |
|
29 |
uint8_t leds; |
|
30 |
uint8_t key[16]; |
|
31 |
int32_t keys; |
|
32 |
} HIDKeyboardState; |
|
33 |
|
|
34 |
struct HIDState { |
|
35 |
union { |
|
36 |
HIDMouseState ptr; |
|
37 |
HIDKeyboardState kbd; |
|
38 |
}; |
|
39 |
uint32_t head; /* index into circular queue */ |
|
40 |
uint32_t n; |
|
41 |
int kind; |
|
42 |
HIDEventFunc event; |
|
43 |
}; |
|
44 |
|
|
45 |
void hid_init(HIDState *hs, int kind, HIDEventFunc event); |
|
46 |
void hid_reset(HIDState *hs); |
|
47 |
void hid_free(HIDState *hs); |
|
48 |
|
|
49 |
bool hid_has_events(HIDState *hs); |
|
50 |
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len); |
|
51 |
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len); |
|
52 |
int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len); |
|
53 |
|
|
54 |
#endif /* QEMU_HID_H */ |
b/hw/usb-hid.c | ||
---|---|---|
27 | 27 |
#include "usb.h" |
28 | 28 |
#include "usb-desc.h" |
29 | 29 |
#include "qemu-timer.h" |
30 |
#include "hid.h" |
|
30 | 31 |
|
31 | 32 |
/* HID interface requests */ |
32 | 33 |
#define GET_REPORT 0xa101 |
... | ... | |
41 | 42 |
#define USB_DT_REPORT 0x22 |
42 | 43 |
#define USB_DT_PHY 0x23 |
43 | 44 |
|
44 |
#define HID_MOUSE 1 |
|
45 |
#define HID_TABLET 2 |
|
46 |
#define HID_KEYBOARD 3 |
|
47 |
|
|
48 |
typedef struct HIDPointerEvent { |
|
49 |
int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */ |
|
50 |
int32_t dz, buttons_state; |
|
51 |
} HIDPointerEvent; |
|
52 |
|
|
53 |
#define QUEUE_LENGTH 16 /* should be enough for a triple-click */ |
|
54 |
#define QUEUE_MASK (QUEUE_LENGTH-1u) |
|
55 |
#define QUEUE_INCR(v) ((v)++, (v) &= QUEUE_MASK) |
|
56 |
|
|
57 |
typedef struct HIDState HIDState; |
|
58 |
typedef void (*HIDEventFunc)(HIDState *s); |
|
59 |
|
|
60 |
typedef struct HIDMouseState { |
|
61 |
HIDPointerEvent queue[QUEUE_LENGTH]; |
|
62 |
int mouse_grabbed; |
|
63 |
QEMUPutMouseEntry *eh_entry; |
|
64 |
} HIDMouseState; |
|
65 |
|
|
66 |
typedef struct HIDKeyboardState { |
|
67 |
uint32_t keycodes[QUEUE_LENGTH]; |
|
68 |
uint16_t modifiers; |
|
69 |
uint8_t leds; |
|
70 |
uint8_t key[16]; |
|
71 |
int32_t keys; |
|
72 |
} HIDKeyboardState; |
|
73 |
|
|
74 |
struct HIDState { |
|
75 |
union { |
|
76 |
HIDMouseState ptr; |
|
77 |
HIDKeyboardState kbd; |
|
78 |
}; |
|
79 |
uint32_t head; /* index into circular queue */ |
|
80 |
uint32_t n; |
|
81 |
int kind; |
|
82 |
HIDEventFunc event; |
|
83 |
}; |
|
84 |
|
|
85 | 45 |
typedef struct USBHIDState { |
86 | 46 |
USBDevice dev; |
87 | 47 |
HIDState hid; |
... | ... | |
401 | 361 |
0xc0, /* End Collection */ |
402 | 362 |
}; |
403 | 363 |
|
404 |
#define USB_HID_USAGE_ERROR_ROLLOVER 0x01 |
|
405 |
#define USB_HID_USAGE_POSTFAIL 0x02 |
|
406 |
#define USB_HID_USAGE_ERROR_UNDEFINED 0x03 |
|
407 |
|
|
408 |
/* Indices are QEMU keycodes, values are from HID Usage Table. Indices |
|
409 |
* above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ |
|
410 |
static const uint8_t usb_hid_usage_keys[0x100] = { |
|
411 |
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
|
412 |
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, |
|
413 |
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, |
|
414 |
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, |
|
415 |
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, |
|
416 |
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, |
|
417 |
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, |
|
418 |
0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, |
|
419 |
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, |
|
420 |
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, |
|
421 |
0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, |
|
422 |
0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, |
|
423 |
0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, |
|
424 |
0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, |
|
425 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
426 |
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, |
|
427 |
|
|
428 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
429 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
430 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
431 |
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, |
|
432 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
433 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
434 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, |
|
435 |
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
436 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, |
|
437 |
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, |
|
438 |
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, |
|
439 |
0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, |
|
440 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
441 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
442 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
443 |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
444 |
}; |
|
445 |
|
|
446 |
static bool hid_has_events(HIDState *hs) |
|
447 |
{ |
|
448 |
return hs->n > 0; |
|
449 |
} |
|
450 |
|
|
451 | 364 |
static void usb_hid_changed(HIDState *hs) |
452 | 365 |
{ |
453 | 366 |
USBHIDState *us = container_of(hs, USBHIDState, hid); |
... | ... | |
459 | 372 |
usb_wakeup(&us->dev); |
460 | 373 |
} |
461 | 374 |
|
462 |
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) |
|
463 |
{ |
|
464 |
e->xdx = e->ydy = e->dz = 0; |
|
465 |
e->buttons_state = buttons; |
|
466 |
} |
|
467 |
|
|
468 |
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, |
|
469 |
int x1, int y1, int z1) { |
|
470 |
if (xyrel) { |
|
471 |
e->xdx += x1; |
|
472 |
e->ydy += y1; |
|
473 |
} else { |
|
474 |
e->xdx = x1; |
|
475 |
e->ydy = y1; |
|
476 |
/* Windows drivers do not like the 0/0 position and ignore such |
|
477 |
* events. */ |
|
478 |
if (!(x1 | y1)) { |
|
479 |
x1 = 1; |
|
480 |
} |
|
481 |
} |
|
482 |
e->dz += z1; |
|
483 |
} |
|
484 |
|
|
485 |
static void hid_pointer_event(void *opaque, |
|
486 |
int x1, int y1, int z1, int buttons_state) |
|
487 |
{ |
|
488 |
HIDState *hs = opaque; |
|
489 |
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; |
|
490 |
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; |
|
491 |
|
|
492 |
/* We combine events where feasible to keep the queue small. We shouldn't |
|
493 |
* combine anything with the first event of a particular button state, as |
|
494 |
* that would change the location of the button state change. When the |
|
495 |
* queue is empty, a second event is needed because we don't know if |
|
496 |
* the first event changed the button state. */ |
|
497 |
if (hs->n == QUEUE_LENGTH) { |
|
498 |
/* Queue full. Discard old button state, combine motion normally. */ |
|
499 |
hs->ptr.queue[use_slot].buttons_state = buttons_state; |
|
500 |
} else if (hs->n < 2 || |
|
501 |
hs->ptr.queue[use_slot].buttons_state != buttons_state || |
|
502 |
hs->ptr.queue[previous_slot].buttons_state != |
|
503 |
hs->ptr.queue[use_slot].buttons_state) { |
|
504 |
/* Cannot or should not combine, so add an empty item to the queue. */ |
|
505 |
QUEUE_INCR(use_slot); |
|
506 |
hs->n++; |
|
507 |
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); |
|
508 |
} |
|
509 |
hid_pointer_event_combine(&hs->ptr.queue[use_slot], |
|
510 |
hs->kind == HID_MOUSE, |
|
511 |
x1, y1, z1); |
|
512 |
hs->event(hs); |
|
513 |
} |
|
514 |
|
|
515 |
static void hid_keyboard_event(void *opaque, int keycode) |
|
516 |
{ |
|
517 |
HIDState *hs = opaque; |
|
518 |
int slot; |
|
519 |
|
|
520 |
if (hs->n == QUEUE_LENGTH) { |
|
521 |
fprintf(stderr, "usb-kbd: warning: key event queue full\n"); |
|
522 |
return; |
|
523 |
} |
|
524 |
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; |
|
525 |
hs->kbd.keycodes[slot] = keycode; |
|
526 |
hs->event(hs); |
|
527 |
} |
|
528 |
|
|
529 |
static void hid_keyboard_process_keycode(HIDState *hs) |
|
530 |
{ |
|
531 |
uint8_t hid_code, key; |
|
532 |
int i, keycode, slot; |
|
533 |
|
|
534 |
if (hs->n == 0) { |
|
535 |
return; |
|
536 |
} |
|
537 |
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; |
|
538 |
keycode = hs->kbd.keycodes[slot]; |
|
539 |
|
|
540 |
key = keycode & 0x7f; |
|
541 |
hid_code = usb_hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))]; |
|
542 |
hs->kbd.modifiers &= ~(1 << 8); |
|
543 |
|
|
544 |
switch (hid_code) { |
|
545 |
case 0x00: |
|
546 |
return; |
|
547 |
|
|
548 |
case 0xe0: |
|
549 |
if (hs->kbd.modifiers & (1 << 9)) { |
|
550 |
hs->kbd.modifiers ^= 3 << 8; |
|
551 |
return; |
|
552 |
} |
|
553 |
case 0xe1 ... 0xe7: |
|
554 |
if (keycode & (1 << 7)) { |
|
555 |
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); |
|
556 |
return; |
|
557 |
} |
|
558 |
case 0xe8 ... 0xef: |
|
559 |
hs->kbd.modifiers |= 1 << (hid_code & 0x0f); |
|
560 |
return; |
|
561 |
} |
|
562 |
|
|
563 |
if (keycode & (1 << 7)) { |
|
564 |
for (i = hs->kbd.keys - 1; i >= 0; i--) { |
|
565 |
if (hs->kbd.key[i] == hid_code) { |
|
566 |
hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; |
|
567 |
hs->kbd.key[hs->kbd.keys] = 0x00; |
|
568 |
break; |
|
569 |
} |
|
570 |
} |
|
571 |
if (i < 0) { |
|
572 |
return; |
|
573 |
} |
|
574 |
} else { |
|
575 |
for (i = hs->kbd.keys - 1; i >= 0; i--) { |
|
576 |
if (hs->kbd.key[i] == hid_code) { |
|
577 |
break; |
|
578 |
} |
|
579 |
} |
|
580 |
if (i < 0) { |
|
581 |
if (hs->kbd.keys < sizeof(hs->kbd.key)) { |
|
582 |
hs->kbd.key[hs->kbd.keys++] = hid_code; |
|
583 |
} |
|
584 |
} else { |
|
585 |
return; |
|
586 |
} |
|
587 |
} |
|
588 |
} |
|
589 |
|
|
590 |
static inline int int_clamp(int val, int vmin, int vmax) |
|
591 |
{ |
|
592 |
if (val < vmin) |
|
593 |
return vmin; |
|
594 |
else if (val > vmax) |
|
595 |
return vmax; |
|
596 |
else |
|
597 |
return val; |
|
598 |
} |
|
599 |
|
|
600 |
static int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) |
|
601 |
{ |
|
602 |
int dx, dy, dz, b, l; |
|
603 |
int index; |
|
604 |
HIDPointerEvent *e; |
|
605 |
|
|
606 |
if (!hs->ptr.mouse_grabbed) { |
|
607 |
qemu_activate_mouse_event_handler(hs->ptr.eh_entry); |
|
608 |
hs->ptr.mouse_grabbed = 1; |
|
609 |
} |
|
610 |
|
|
611 |
/* When the buffer is empty, return the last event. Relative |
|
612 |
movements will all be zero. */ |
|
613 |
index = (hs->n ? hs->head : hs->head - 1); |
|
614 |
e = &hs->ptr.queue[index & QUEUE_MASK]; |
|
615 |
|
|
616 |
if (hs->kind == HID_MOUSE) { |
|
617 |
dx = int_clamp(e->xdx, -127, 127); |
|
618 |
dy = int_clamp(e->ydy, -127, 127); |
|
619 |
e->xdx -= dx; |
|
620 |
e->ydy -= dy; |
|
621 |
} else { |
|
622 |
dx = e->xdx; |
|
623 |
dy = e->ydy; |
|
624 |
} |
|
625 |
dz = int_clamp(e->dz, -127, 127); |
|
626 |
e->dz -= dz; |
|
627 |
|
|
628 |
b = 0; |
|
629 |
if (e->buttons_state & MOUSE_EVENT_LBUTTON) |
|
630 |
b |= 0x01; |
|
631 |
if (e->buttons_state & MOUSE_EVENT_RBUTTON) |
|
632 |
b |= 0x02; |
|
633 |
if (e->buttons_state & MOUSE_EVENT_MBUTTON) |
|
634 |
b |= 0x04; |
|
635 |
|
|
636 |
if (hs->n && |
|
637 |
!e->dz && |
|
638 |
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { |
|
639 |
/* that deals with this event */ |
|
640 |
QUEUE_INCR(hs->head); |
|
641 |
hs->n--; |
|
642 |
} |
|
643 |
|
|
644 |
/* Appears we have to invert the wheel direction */ |
|
645 |
dz = 0 - dz; |
|
646 |
l = 0; |
|
647 |
switch (hs->kind) { |
|
648 |
case HID_MOUSE: |
|
649 |
if (len > l) |
|
650 |
buf[l++] = b; |
|
651 |
if (len > l) |
|
652 |
buf[l++] = dx; |
|
653 |
if (len > l) |
|
654 |
buf[l++] = dy; |
|
655 |
if (len > l) |
|
656 |
buf[l++] = dz; |
|
657 |
break; |
|
658 |
|
|
659 |
case HID_TABLET: |
|
660 |
if (len > l) |
|
661 |
buf[l++] = b; |
|
662 |
if (len > l) |
|
663 |
buf[l++] = dx & 0xff; |
|
664 |
if (len > l) |
|
665 |
buf[l++] = dx >> 8; |
|
666 |
if (len > l) |
|
667 |
buf[l++] = dy & 0xff; |
|
668 |
if (len > l) |
|
669 |
buf[l++] = dy >> 8; |
|
670 |
if (len > l) |
|
671 |
buf[l++] = dz; |
|
672 |
break; |
|
673 |
|
|
674 |
default: |
|
675 |
abort(); |
|
676 |
} |
|
677 |
|
|
678 |
return l; |
|
679 |
} |
|
680 |
|
|
681 |
static int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) |
|
682 |
{ |
|
683 |
if (len < 2) |
|
684 |
return 0; |
|
685 |
|
|
686 |
hid_keyboard_process_keycode(hs); |
|
687 |
|
|
688 |
buf[0] = hs->kbd.modifiers & 0xff; |
|
689 |
buf[1] = 0; |
|
690 |
if (hs->kbd.keys > 6) { |
|
691 |
memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); |
|
692 |
} else { |
|
693 |
memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); |
|
694 |
} |
|
695 |
|
|
696 |
return MIN(8, len); |
|
697 |
} |
|
698 |
|
|
699 |
static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) |
|
700 |
{ |
|
701 |
if (len > 0) { |
|
702 |
int ledstate = 0; |
|
703 |
/* 0x01: Num Lock LED |
|
704 |
* 0x02: Caps Lock LED |
|
705 |
* 0x04: Scroll Lock LED |
|
706 |
* 0x08: Compose LED |
|
707 |
* 0x10: Kana LED */ |
|
708 |
hs->kbd.leds = buf[0]; |
|
709 |
if (hs->kbd.leds & 0x04) { |
|
710 |
ledstate |= QEMU_SCROLL_LOCK_LED; |
|
711 |
} |
|
712 |
if (hs->kbd.leds & 0x01) { |
|
713 |
ledstate |= QEMU_NUM_LOCK_LED; |
|
714 |
} |
|
715 |
if (hs->kbd.leds & 0x02) { |
|
716 |
ledstate |= QEMU_CAPS_LOCK_LED; |
|
717 |
} |
|
718 |
kbd_put_ledstate(ledstate); |
|
719 |
} |
|
720 |
return 0; |
|
721 |
} |
|
722 |
|
|
723 |
static void hid_handle_reset(HIDState *hs) |
|
724 |
{ |
|
725 |
switch (hs->kind) { |
|
726 |
case HID_KEYBOARD: |
|
727 |
qemu_add_kbd_event_handler(hid_keyboard_event, hs); |
|
728 |
memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); |
|
729 |
memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); |
|
730 |
hs->kbd.keys = 0; |
|
731 |
break; |
|
732 |
case HID_MOUSE: |
|
733 |
case HID_TABLET: |
|
734 |
memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); |
|
735 |
break; |
|
736 |
} |
|
737 |
hs->head = 0; |
|
738 |
hs->n = 0; |
|
739 |
} |
|
740 |
|
|
741 | 375 |
static void usb_hid_handle_reset(USBDevice *dev) |
742 | 376 |
{ |
743 | 377 |
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); |
744 | 378 |
|
745 |
hid_handle_reset(&us->hid);
|
|
379 |
hid_reset(&us->hid); |
|
746 | 380 |
us->protocol = 1; |
747 | 381 |
us->idle = 0; |
748 | 382 |
} |
... | ... | |
875 | 509 |
return ret; |
876 | 510 |
} |
877 | 511 |
|
878 |
static void hid_free(HIDState *hs) |
|
879 |
{ |
|
880 |
switch (hs->kind) { |
|
881 |
case HID_KEYBOARD: |
|
882 |
qemu_remove_kbd_event_handler(); |
|
883 |
break; |
|
884 |
case HID_MOUSE: |
|
885 |
case HID_TABLET: |
|
886 |
qemu_remove_mouse_event_handler(hs->ptr.eh_entry); |
|
887 |
break; |
|
888 |
} |
|
889 |
} |
|
890 |
|
|
891 | 512 |
static void usb_hid_handle_destroy(USBDevice *dev) |
892 | 513 |
{ |
893 | 514 |
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); |
... | ... | |
895 | 516 |
hid_free(&us->hid); |
896 | 517 |
} |
897 | 518 |
|
898 |
static void hid_init(HIDState *hs, int kind, HIDEventFunc event) |
|
899 |
{ |
|
900 |
hs->kind = kind; |
|
901 |
hs->event = event; |
|
902 |
|
|
903 |
if (hs->kind == HID_MOUSE) { |
|
904 |
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, |
|
905 |
0, "QEMU HID Mouse"); |
|
906 |
} else if (hs->kind == HID_TABLET) { |
|
907 |
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, |
|
908 |
1, "QEMU HID Tablet"); |
|
909 |
} |
|
910 |
} |
|
911 |
|
|
912 | 519 |
static int usb_hid_initfn(USBDevice *dev, int kind) |
913 | 520 |
{ |
914 | 521 |
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); |
Also available in: Unified diff