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 } 396