qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     25 static 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 
     35 static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
     36     [INPUT_AXIS_X]                   = REL_X,
     37     [INPUT_AXIS_Y]                   = REL_Y,
     38 };
     39 
     40 static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
     41     [INPUT_AXIS_X]                   = ABS_X,
     42     [INPUT_AXIS_Y]                   = ABS_Y,
     43 };
     44 
     45 /* ----------------------------------------------------------------- */
     46 
     47 static 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 
     73 static 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 
    145 static 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 
    157 static 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 
    167 static void virtio_input_hid_unrealize(DeviceState *dev)
    168 {
    169     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
    170     qemu_input_handler_unregister(vhid->hs);
    171 }
    172 
    173 static 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 
    184 static 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 
    213 static 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 
    219 static 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 
    231 static 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 
    241 static 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 
    248 static 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 
    277 static 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 
    288 static 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 
    297 static 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 
    304 static 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 
    329 static 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 
    355 static Property virtio_mouse_properties[] = {
    356     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
    357     DEFINE_PROP_END_OF_LIST(),
    358 };
    359 
    360 static 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 
    367 static 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 
    380 static 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 
    390 static 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 
    397 static 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 
    434 static 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 
    479 static Property virtio_tablet_properties[] = {
    480     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
    481     DEFINE_PROP_END_OF_LIST(),
    482 };
    483 
    484 static 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 
    491 static 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 
    504 static 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 
    514 static 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 
    522 type_init(virtio_register_types)