virtio-input-hid.c (16860B)
1/* 2 * This work is licensed under the terms of the GNU GPL, version 2 or 3 * (at your option) any later version. See the COPYING file in the 4 * top-level directory. 5 */ 6 7#include "qemu/osdep.h" 8#include "qemu/iov.h" 9#include "qemu/module.h" 10 11#include "hw/virtio/virtio.h" 12#include "hw/qdev-properties.h" 13#include "hw/virtio/virtio-input.h" 14 15#include "ui/console.h" 16 17#include "standard-headers/linux/input.h" 18 19#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard" 20#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse" 21#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet" 22 23/* ----------------------------------------------------------------- */ 24 25static const unsigned short keymap_button[INPUT_BUTTON__MAX] = { 26 [INPUT_BUTTON_LEFT] = BTN_LEFT, 27 [INPUT_BUTTON_RIGHT] = BTN_RIGHT, 28 [INPUT_BUTTON_MIDDLE] = BTN_MIDDLE, 29 [INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP, 30 [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN, 31 [INPUT_BUTTON_SIDE] = BTN_SIDE, 32 [INPUT_BUTTON_EXTRA] = BTN_EXTRA, 33}; 34 35static const unsigned short axismap_rel[INPUT_AXIS__MAX] = { 36 [INPUT_AXIS_X] = REL_X, 37 [INPUT_AXIS_Y] = REL_Y, 38}; 39 40static const unsigned short axismap_abs[INPUT_AXIS__MAX] = { 41 [INPUT_AXIS_X] = ABS_X, 42 [INPUT_AXIS_Y] = ABS_Y, 43}; 44 45/* ----------------------------------------------------------------- */ 46 47static void virtio_input_key_config(VirtIOInput *vinput, 48 const unsigned short *keymap, 49 size_t mapsize) 50{ 51 virtio_input_config keys; 52 int i, bit, byte, bmax = 0; 53 54 memset(&keys, 0, sizeof(keys)); 55 for (i = 0; i < mapsize; i++) { 56 bit = keymap[i]; 57 if (!bit) { 58 continue; 59 } 60 byte = bit / 8; 61 bit = bit % 8; 62 keys.u.bitmap[byte] |= (1 << bit); 63 if (bmax < byte+1) { 64 bmax = byte+1; 65 } 66 } 67 keys.select = VIRTIO_INPUT_CFG_EV_BITS; 68 keys.subsel = EV_KEY; 69 keys.size = bmax; 70 virtio_input_add_config(vinput, &keys); 71} 72 73static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, 74 InputEvent *evt) 75{ 76 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); 77 VirtIOInput *vinput = VIRTIO_INPUT(dev); 78 virtio_input_event event; 79 int qcode; 80 InputKeyEvent *key; 81 InputMoveEvent *move; 82 InputBtnEvent *btn; 83 84 switch (evt->type) { 85 case INPUT_EVENT_KIND_KEY: 86 key = evt->u.key.data; 87 qcode = qemu_input_key_value_to_qcode(key->key); 88 if (qcode < qemu_input_map_qcode_to_linux_len && 89 qemu_input_map_qcode_to_linux[qcode]) { 90 event.type = cpu_to_le16(EV_KEY); 91 event.code = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]); 92 event.value = cpu_to_le32(key->down ? 1 : 0); 93 virtio_input_send(vinput, &event); 94 } else { 95 if (key->down) { 96 fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__, 97 qcode, QKeyCode_str(qcode)); 98 } 99 } 100 break; 101 case INPUT_EVENT_KIND_BTN: 102 btn = evt->u.btn.data; 103 if (vhid->wheel_axis && 104 (btn->button == INPUT_BUTTON_WHEEL_UP || 105 btn->button == INPUT_BUTTON_WHEEL_DOWN) && 106 btn->down) { 107 event.type = cpu_to_le16(EV_REL); 108 event.code = cpu_to_le16(REL_WHEEL); 109 event.value = cpu_to_le32(btn->button == INPUT_BUTTON_WHEEL_UP 110 ? 1 : -1); 111 virtio_input_send(vinput, &event); 112 } else if (keymap_button[btn->button]) { 113 event.type = cpu_to_le16(EV_KEY); 114 event.code = cpu_to_le16(keymap_button[btn->button]); 115 event.value = cpu_to_le32(btn->down ? 1 : 0); 116 virtio_input_send(vinput, &event); 117 } else { 118 if (btn->down) { 119 fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__, 120 btn->button, 121 InputButton_str(btn->button)); 122 } 123 } 124 break; 125 case INPUT_EVENT_KIND_REL: 126 move = evt->u.rel.data; 127 event.type = cpu_to_le16(EV_REL); 128 event.code = cpu_to_le16(axismap_rel[move->axis]); 129 event.value = cpu_to_le32(move->value); 130 virtio_input_send(vinput, &event); 131 break; 132 case INPUT_EVENT_KIND_ABS: 133 move = evt->u.abs.data; 134 event.type = cpu_to_le16(EV_ABS); 135 event.code = cpu_to_le16(axismap_abs[move->axis]); 136 event.value = cpu_to_le32(move->value); 137 virtio_input_send(vinput, &event); 138 break; 139 default: 140 /* keep gcc happy */ 141 break; 142 } 143} 144 145static void virtio_input_handle_sync(DeviceState *dev) 146{ 147 VirtIOInput *vinput = VIRTIO_INPUT(dev); 148 virtio_input_event event = { 149 .type = cpu_to_le16(EV_SYN), 150 .code = cpu_to_le16(SYN_REPORT), 151 .value = 0, 152 }; 153 154 virtio_input_send(vinput, &event); 155} 156 157static void virtio_input_hid_realize(DeviceState *dev, Error **errp) 158{ 159 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); 160 161 vhid->hs = qemu_input_handler_register(dev, vhid->handler); 162 if (vhid->display && vhid->hs) { 163 qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL); 164 } 165} 166 167static void virtio_input_hid_unrealize(DeviceState *dev) 168{ 169 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev); 170 qemu_input_handler_unregister(vhid->hs); 171} 172 173static void virtio_input_hid_change_active(VirtIOInput *vinput) 174{ 175 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput); 176 177 if (vinput->active) { 178 qemu_input_handler_activate(vhid->hs); 179 } else { 180 qemu_input_handler_deactivate(vhid->hs); 181 } 182} 183 184static void virtio_input_hid_handle_status(VirtIOInput *vinput, 185 virtio_input_event *event) 186{ 187 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput); 188 int ledbit = 0; 189 190 switch (le16_to_cpu(event->type)) { 191 case EV_LED: 192 if (event->code == LED_NUML) { 193 ledbit = QEMU_NUM_LOCK_LED; 194 } else if (event->code == LED_CAPSL) { 195 ledbit = QEMU_CAPS_LOCK_LED; 196 } else if (event->code == LED_SCROLLL) { 197 ledbit = QEMU_SCROLL_LOCK_LED; 198 } 199 if (event->value) { 200 vhid->ledstate |= ledbit; 201 } else { 202 vhid->ledstate &= ~ledbit; 203 } 204 kbd_put_ledstate(vhid->ledstate); 205 break; 206 default: 207 fprintf(stderr, "%s: unknown type %d\n", __func__, 208 le16_to_cpu(event->type)); 209 break; 210 } 211} 212 213static Property virtio_input_hid_properties[] = { 214 DEFINE_PROP_STRING("display", VirtIOInputHID, display), 215 DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0), 216 DEFINE_PROP_END_OF_LIST(), 217}; 218 219static void virtio_input_hid_class_init(ObjectClass *klass, void *data) 220{ 221 DeviceClass *dc = DEVICE_CLASS(klass); 222 VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); 223 224 device_class_set_props(dc, virtio_input_hid_properties); 225 vic->realize = virtio_input_hid_realize; 226 vic->unrealize = virtio_input_hid_unrealize; 227 vic->change_active = virtio_input_hid_change_active; 228 vic->handle_status = virtio_input_hid_handle_status; 229} 230 231static const TypeInfo virtio_input_hid_info = { 232 .name = TYPE_VIRTIO_INPUT_HID, 233 .parent = TYPE_VIRTIO_INPUT, 234 .instance_size = sizeof(VirtIOInputHID), 235 .class_init = virtio_input_hid_class_init, 236 .abstract = true, 237}; 238 239/* ----------------------------------------------------------------- */ 240 241static QemuInputHandler virtio_keyboard_handler = { 242 .name = VIRTIO_ID_NAME_KEYBOARD, 243 .mask = INPUT_EVENT_MASK_KEY, 244 .event = virtio_input_handle_event, 245 .sync = virtio_input_handle_sync, 246}; 247 248static struct virtio_input_config virtio_keyboard_config[] = { 249 { 250 .select = VIRTIO_INPUT_CFG_ID_NAME, 251 .size = sizeof(VIRTIO_ID_NAME_KEYBOARD), 252 .u.string = VIRTIO_ID_NAME_KEYBOARD, 253 },{ 254 .select = VIRTIO_INPUT_CFG_ID_DEVIDS, 255 .size = sizeof(struct virtio_input_devids), 256 .u.ids = { 257 .bustype = const_le16(BUS_VIRTUAL), 258 .vendor = const_le16(0x0627), /* same we use for usb hid devices */ 259 .product = const_le16(0x0001), 260 .version = const_le16(0x0001), 261 }, 262 },{ 263 .select = VIRTIO_INPUT_CFG_EV_BITS, 264 .subsel = EV_REP, 265 .size = 1, 266 },{ 267 .select = VIRTIO_INPUT_CFG_EV_BITS, 268 .subsel = EV_LED, 269 .size = 1, 270 .u.bitmap = { 271 (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL), 272 }, 273 }, 274 { /* end of list */ }, 275}; 276 277static void virtio_keyboard_init(Object *obj) 278{ 279 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); 280 VirtIOInput *vinput = VIRTIO_INPUT(obj); 281 282 vhid->handler = &virtio_keyboard_handler; 283 virtio_input_init_config(vinput, virtio_keyboard_config); 284 virtio_input_key_config(vinput, qemu_input_map_qcode_to_linux, 285 qemu_input_map_qcode_to_linux_len); 286} 287 288static const TypeInfo virtio_keyboard_info = { 289 .name = TYPE_VIRTIO_KEYBOARD, 290 .parent = TYPE_VIRTIO_INPUT_HID, 291 .instance_size = sizeof(VirtIOInputHID), 292 .instance_init = virtio_keyboard_init, 293}; 294 295/* ----------------------------------------------------------------- */ 296 297static QemuInputHandler virtio_mouse_handler = { 298 .name = VIRTIO_ID_NAME_MOUSE, 299 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 300 .event = virtio_input_handle_event, 301 .sync = virtio_input_handle_sync, 302}; 303 304static struct virtio_input_config virtio_mouse_config_v1[] = { 305 { 306 .select = VIRTIO_INPUT_CFG_ID_NAME, 307 .size = sizeof(VIRTIO_ID_NAME_MOUSE), 308 .u.string = VIRTIO_ID_NAME_MOUSE, 309 },{ 310 .select = VIRTIO_INPUT_CFG_ID_DEVIDS, 311 .size = sizeof(struct virtio_input_devids), 312 .u.ids = { 313 .bustype = const_le16(BUS_VIRTUAL), 314 .vendor = const_le16(0x0627), /* same we use for usb hid devices */ 315 .product = const_le16(0x0002), 316 .version = const_le16(0x0001), 317 }, 318 },{ 319 .select = VIRTIO_INPUT_CFG_EV_BITS, 320 .subsel = EV_REL, 321 .size = 1, 322 .u.bitmap = { 323 (1 << REL_X) | (1 << REL_Y), 324 }, 325 }, 326 { /* end of list */ }, 327}; 328 329static struct virtio_input_config virtio_mouse_config_v2[] = { 330 { 331 .select = VIRTIO_INPUT_CFG_ID_NAME, 332 .size = sizeof(VIRTIO_ID_NAME_MOUSE), 333 .u.string = VIRTIO_ID_NAME_MOUSE, 334 },{ 335 .select = VIRTIO_INPUT_CFG_ID_DEVIDS, 336 .size = sizeof(struct virtio_input_devids), 337 .u.ids = { 338 .bustype = const_le16(BUS_VIRTUAL), 339 .vendor = const_le16(0x0627), /* same we use for usb hid devices */ 340 .product = const_le16(0x0002), 341 .version = const_le16(0x0002), 342 }, 343 },{ 344 .select = VIRTIO_INPUT_CFG_EV_BITS, 345 .subsel = EV_REL, 346 .size = 2, 347 .u.bitmap = { 348 (1 << REL_X) | (1 << REL_Y), 349 (1 << (REL_WHEEL - 8)) 350 }, 351 }, 352 { /* end of list */ }, 353}; 354 355static Property virtio_mouse_properties[] = { 356 DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true), 357 DEFINE_PROP_END_OF_LIST(), 358}; 359 360static void virtio_mouse_class_init(ObjectClass *klass, void *data) 361{ 362 DeviceClass *dc = DEVICE_CLASS(klass); 363 364 device_class_set_props(dc, virtio_mouse_properties); 365} 366 367static void virtio_mouse_init(Object *obj) 368{ 369 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); 370 VirtIOInput *vinput = VIRTIO_INPUT(obj); 371 372 vhid->handler = &virtio_mouse_handler; 373 virtio_input_init_config(vinput, vhid->wheel_axis 374 ? virtio_mouse_config_v2 375 : virtio_mouse_config_v1); 376 virtio_input_key_config(vinput, keymap_button, 377 ARRAY_SIZE(keymap_button)); 378} 379 380static const TypeInfo virtio_mouse_info = { 381 .name = TYPE_VIRTIO_MOUSE, 382 .parent = TYPE_VIRTIO_INPUT_HID, 383 .instance_size = sizeof(VirtIOInputHID), 384 .instance_init = virtio_mouse_init, 385 .class_init = virtio_mouse_class_init, 386}; 387 388/* ----------------------------------------------------------------- */ 389 390static QemuInputHandler virtio_tablet_handler = { 391 .name = VIRTIO_ID_NAME_TABLET, 392 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, 393 .event = virtio_input_handle_event, 394 .sync = virtio_input_handle_sync, 395}; 396 397static struct virtio_input_config virtio_tablet_config_v1[] = { 398 { 399 .select = VIRTIO_INPUT_CFG_ID_NAME, 400 .size = sizeof(VIRTIO_ID_NAME_TABLET), 401 .u.string = VIRTIO_ID_NAME_TABLET, 402 },{ 403 .select = VIRTIO_INPUT_CFG_ID_DEVIDS, 404 .size = sizeof(struct virtio_input_devids), 405 .u.ids = { 406 .bustype = const_le16(BUS_VIRTUAL), 407 .vendor = const_le16(0x0627), /* same we use for usb hid devices */ 408 .product = const_le16(0x0003), 409 .version = const_le16(0x0001), 410 }, 411 },{ 412 .select = VIRTIO_INPUT_CFG_EV_BITS, 413 .subsel = EV_ABS, 414 .size = 1, 415 .u.bitmap = { 416 (1 << ABS_X) | (1 << ABS_Y), 417 }, 418 },{ 419 .select = VIRTIO_INPUT_CFG_ABS_INFO, 420 .subsel = ABS_X, 421 .size = sizeof(virtio_input_absinfo), 422 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), 423 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), 424 },{ 425 .select = VIRTIO_INPUT_CFG_ABS_INFO, 426 .subsel = ABS_Y, 427 .size = sizeof(virtio_input_absinfo), 428 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), 429 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), 430 }, 431 { /* end of list */ }, 432}; 433 434static struct virtio_input_config virtio_tablet_config_v2[] = { 435 { 436 .select = VIRTIO_INPUT_CFG_ID_NAME, 437 .size = sizeof(VIRTIO_ID_NAME_TABLET), 438 .u.string = VIRTIO_ID_NAME_TABLET, 439 },{ 440 .select = VIRTIO_INPUT_CFG_ID_DEVIDS, 441 .size = sizeof(struct virtio_input_devids), 442 .u.ids = { 443 .bustype = const_le16(BUS_VIRTUAL), 444 .vendor = const_le16(0x0627), /* same we use for usb hid devices */ 445 .product = const_le16(0x0003), 446 .version = const_le16(0x0002), 447 }, 448 },{ 449 .select = VIRTIO_INPUT_CFG_EV_BITS, 450 .subsel = EV_ABS, 451 .size = 1, 452 .u.bitmap = { 453 (1 << ABS_X) | (1 << ABS_Y), 454 }, 455 },{ 456 .select = VIRTIO_INPUT_CFG_EV_BITS, 457 .subsel = EV_REL, 458 .size = 2, 459 .u.bitmap = { 460 0, 461 (1 << (REL_WHEEL - 8)) 462 }, 463 },{ 464 .select = VIRTIO_INPUT_CFG_ABS_INFO, 465 .subsel = ABS_X, 466 .size = sizeof(virtio_input_absinfo), 467 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), 468 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), 469 },{ 470 .select = VIRTIO_INPUT_CFG_ABS_INFO, 471 .subsel = ABS_Y, 472 .size = sizeof(virtio_input_absinfo), 473 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), 474 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), 475 }, 476 { /* end of list */ }, 477}; 478 479static Property virtio_tablet_properties[] = { 480 DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true), 481 DEFINE_PROP_END_OF_LIST(), 482}; 483 484static void virtio_tablet_class_init(ObjectClass *klass, void *data) 485{ 486 DeviceClass *dc = DEVICE_CLASS(klass); 487 488 device_class_set_props(dc, virtio_tablet_properties); 489} 490 491static void virtio_tablet_init(Object *obj) 492{ 493 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); 494 VirtIOInput *vinput = VIRTIO_INPUT(obj); 495 496 vhid->handler = &virtio_tablet_handler; 497 virtio_input_init_config(vinput, vhid->wheel_axis 498 ? virtio_tablet_config_v2 499 : virtio_tablet_config_v1); 500 virtio_input_key_config(vinput, keymap_button, 501 ARRAY_SIZE(keymap_button)); 502} 503 504static const TypeInfo virtio_tablet_info = { 505 .name = TYPE_VIRTIO_TABLET, 506 .parent = TYPE_VIRTIO_INPUT_HID, 507 .instance_size = sizeof(VirtIOInputHID), 508 .instance_init = virtio_tablet_init, 509 .class_init = virtio_tablet_class_init, 510}; 511 512/* ----------------------------------------------------------------- */ 513 514static void virtio_register_types(void) 515{ 516 type_register_static(&virtio_input_hid_info); 517 type_register_static(&virtio_keyboard_info); 518 type_register_static(&virtio_mouse_info); 519 type_register_static(&virtio_tablet_info); 520} 521 522type_init(virtio_register_types)