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/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)
 523