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