qemu/contrib/vhost-user-input/main.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
   9#include <linux/input.h>
  10
  11#include "qemu/iov.h"
  12#include "qemu/bswap.h"
  13#include "qemu/sockets.h"
  14#include "libvhost-user-glib.h"
  15#include "standard-headers/linux/virtio_input.h"
  16#include "qapi/error.h"
  17
  18enum {
  19    VHOST_USER_INPUT_MAX_QUEUES = 2,
  20};
  21
  22typedef struct virtio_input_event virtio_input_event;
  23typedef struct virtio_input_config virtio_input_config;
  24
  25typedef struct VuInput {
  26    VugDev dev;
  27    GSource *evsrc;
  28    int evdevfd;
  29    GArray *config;
  30    virtio_input_config *sel_config;
  31    struct {
  32        virtio_input_event event;
  33        VuVirtqElement *elem;
  34    } *queue;
  35    uint32_t qindex, qsize;
  36} VuInput;
  37
  38static void vi_input_send(VuInput *vi, struct virtio_input_event *event)
  39{
  40    VuDev *dev = &vi->dev.parent;
  41    VuVirtq *vq = vu_get_queue(dev, 0);
  42    VuVirtqElement *elem;
  43    int i, len;
  44
  45    /* queue up events ... */
  46    if (vi->qindex == vi->qsize) {
  47        vi->qsize++;
  48        vi->queue = g_realloc_n(vi->queue, vi->qsize, sizeof(vi->queue[0]));
  49    }
  50    vi->queue[vi->qindex++].event = *event;
  51
  52    /* ... until we see a report sync ... */
  53    if (event->type != htole16(EV_SYN) ||
  54        event->code != htole16(SYN_REPORT)) {
  55        return;
  56    }
  57
  58    /* ... then check available space ... */
  59    for (i = 0; i < vi->qindex; i++) {
  60        elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
  61        if (!elem) {
  62            while (--i >= 0) {
  63                vu_queue_unpop(dev, vq, vi->queue[i].elem, 0);
  64            }
  65            vi->qindex = 0;
  66            g_warning("virtio-input queue full");
  67            return;
  68        }
  69        vi->queue[i].elem = elem;
  70    }
  71
  72    /* ... and finally pass them to the guest */
  73    for (i = 0; i < vi->qindex; i++) {
  74        elem = vi->queue[i].elem;
  75        len = iov_from_buf(elem->in_sg, elem->in_num,
  76                           0, &vi->queue[i].event, sizeof(virtio_input_event));
  77        vu_queue_push(dev, vq, elem, len);
  78        free(elem);
  79    }
  80
  81    vu_queue_notify(&vi->dev.parent, vq);
  82    vi->qindex = 0;
  83}
  84
  85static void
  86vi_evdev_watch(VuDev *dev, int condition, void *data)
  87{
  88    VuInput *vi = data;
  89    int fd = vi->evdevfd;
  90
  91    g_debug("Got evdev condition %x", condition);
  92
  93    struct virtio_input_event virtio;
  94    struct input_event evdev;
  95    int rc;
  96
  97    for (;;) {
  98        rc = read(fd, &evdev, sizeof(evdev));
  99        if (rc != sizeof(evdev)) {
 100            break;
 101        }
 102
 103        g_debug("input %d %d %d", evdev.type, evdev.code, evdev.value);
 104
 105        virtio.type  = htole16(evdev.type);
 106        virtio.code  = htole16(evdev.code);
 107        virtio.value = htole32(evdev.value);
 108        vi_input_send(vi, &virtio);
 109    }
 110}
 111
 112
 113static void vi_handle_status(VuInput *vi, virtio_input_event *event)
 114{
 115    struct input_event evdev;
 116    int rc;
 117
 118    if (gettimeofday(&evdev.time, NULL)) {
 119        perror("vi_handle_status: gettimeofday");
 120        return;
 121    }
 122
 123    evdev.type = le16toh(event->type);
 124    evdev.code = le16toh(event->code);
 125    evdev.value = le32toh(event->value);
 126
 127    rc = write(vi->evdevfd, &evdev, sizeof(evdev));
 128    if (rc == -1) {
 129        perror("vi_host_handle_status: write");
 130    }
 131}
 132
 133static void vi_handle_sts(VuDev *dev, int qidx)
 134{
 135    VuInput *vi = container_of(dev, VuInput, dev.parent);
 136    VuVirtq *vq = vu_get_queue(dev, qidx);
 137    virtio_input_event event;
 138    VuVirtqElement *elem;
 139    int len;
 140
 141    g_debug("%s", G_STRFUNC);
 142
 143    for (;;) {
 144        elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
 145        if (!elem) {
 146            break;
 147        }
 148
 149        memset(&event, 0, sizeof(event));
 150        len = iov_to_buf(elem->out_sg, elem->out_num,
 151                         0, &event, sizeof(event));
 152        vi_handle_status(vi, &event);
 153        vu_queue_push(dev, vq, elem, len);
 154        free(elem);
 155    }
 156
 157    vu_queue_notify(&vi->dev.parent, vq);
 158}
 159
 160static void
 161vi_panic(VuDev *dev, const char *msg)
 162{
 163    g_critical("%s\n", msg);
 164    exit(EXIT_FAILURE);
 165}
 166
 167static void
 168vi_queue_set_started(VuDev *dev, int qidx, bool started)
 169{
 170    VuInput *vi = container_of(dev, VuInput, dev.parent);
 171    VuVirtq *vq = vu_get_queue(dev, qidx);
 172
 173    g_debug("queue started %d:%d", qidx, started);
 174
 175    if (qidx == 1) {
 176        vu_set_queue_handler(dev, vq, started ? vi_handle_sts : NULL);
 177    }
 178
 179    started = vu_queue_started(dev, vu_get_queue(dev, 0)) &&
 180        vu_queue_started(dev, vu_get_queue(dev, 1));
 181
 182    if (started && !vi->evsrc) {
 183        vi->evsrc = vug_source_new(&vi->dev, vi->evdevfd,
 184                                   G_IO_IN, vi_evdev_watch, vi);
 185    }
 186
 187    if (!started && vi->evsrc) {
 188        vug_source_destroy(vi->evsrc);
 189        vi->evsrc = NULL;
 190    }
 191}
 192
 193static virtio_input_config *
 194vi_find_config(VuInput *vi, uint8_t select, uint8_t subsel)
 195{
 196    virtio_input_config *cfg;
 197    int i;
 198
 199    for (i = 0; i < vi->config->len; i++) {
 200        cfg = &g_array_index(vi->config, virtio_input_config, i);
 201        if (select == cfg->select && subsel == cfg->subsel) {
 202            return cfg;
 203        }
 204    }
 205
 206    return NULL;
 207}
 208
 209static int vi_get_config(VuDev *dev, uint8_t *config, uint32_t len)
 210{
 211    VuInput *vi = container_of(dev, VuInput, dev.parent);
 212
 213    if (len > sizeof(*vi->sel_config)) {
 214        return -1;
 215    }
 216
 217    if (vi->sel_config) {
 218        memcpy(config, vi->sel_config, len);
 219    } else {
 220        memset(config, 0, len);
 221    }
 222
 223    return 0;
 224}
 225
 226static int vi_set_config(VuDev *dev, const uint8_t *data,
 227                         uint32_t offset, uint32_t size,
 228                         uint32_t flags)
 229{
 230    VuInput *vi = container_of(dev, VuInput, dev.parent);
 231    virtio_input_config *config = (virtio_input_config *)data;
 232
 233    vi->sel_config = vi_find_config(vi, config->select, config->subsel);
 234
 235    return 0;
 236}
 237
 238static const VuDevIface vuiface = {
 239    .queue_set_started = vi_queue_set_started,
 240    .get_config = vi_get_config,
 241    .set_config = vi_set_config,
 242};
 243
 244static void
 245vi_bits_config(VuInput *vi, int type, int count)
 246{
 247    virtio_input_config bits;
 248    int rc, i, size = 0;
 249
 250    memset(&bits, 0, sizeof(bits));
 251    rc = ioctl(vi->evdevfd, EVIOCGBIT(type, count / 8), bits.u.bitmap);
 252    if (rc < 0) {
 253        return;
 254    }
 255
 256    for (i = 0; i < count / 8; i++) {
 257        if (bits.u.bitmap[i]) {
 258            size = i + 1;
 259        }
 260    }
 261    if (size == 0) {
 262        return;
 263    }
 264
 265    bits.select = VIRTIO_INPUT_CFG_EV_BITS;
 266    bits.subsel = type;
 267    bits.size   = size;
 268    g_array_append_val(vi->config, bits);
 269}
 270
 271static char *opt_evdev;
 272static int opt_fdnum = -1;
 273static char *opt_socket_path;
 274static gboolean opt_nograb;
 275static gboolean opt_print_caps;
 276
 277static GOptionEntry entries[] = {
 278    { "print-capabilities", 'c', 0, G_OPTION_ARG_NONE, &opt_print_caps,
 279      "Print capabilities", NULL },
 280    { "no-grab", 'n', 0, G_OPTION_ARG_NONE, &opt_nograb,
 281      "Don't grab device", NULL },
 282    { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum,
 283      "Use inherited fd socket", "FDNUM" },
 284    { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path,
 285      "Use UNIX socket path", "PATH" },
 286    { "evdev-path", 'p', 0, G_OPTION_ARG_FILENAME, &opt_evdev,
 287      "evdev input device path", "PATH" },
 288    { NULL, }
 289};
 290
 291int
 292main(int argc, char *argv[])
 293{
 294    GMainLoop *loop = NULL;
 295    VuInput vi = { 0, };
 296    int rc, ver, fd;
 297    virtio_input_config id;
 298    struct input_id ids;
 299    GError *error = NULL;
 300    GOptionContext *context;
 301
 302    context = g_option_context_new(NULL);
 303    g_option_context_add_main_entries(context, entries, NULL);
 304    if (!g_option_context_parse(context, &argc, &argv, &error)) {
 305        g_printerr("Option parsing failed: %s\n", error->message);
 306        exit(EXIT_FAILURE);
 307    }
 308    if (opt_print_caps) {
 309        g_print("{\n");
 310        g_print("  \"type\": \"input\",\n");
 311        g_print("  \"features\": [\n");
 312        g_print("    \"evdev-path\",\n");
 313        g_print("    \"no-grab\"\n");
 314        g_print("  ]\n");
 315        g_print("}\n");
 316        exit(EXIT_SUCCESS);
 317    }
 318    if (!opt_evdev) {
 319        g_printerr("Please specify an evdev path\n");
 320        exit(EXIT_FAILURE);
 321    }
 322    if ((!!opt_socket_path + (opt_fdnum != -1)) != 1) {
 323        g_printerr("Please specify either --fd or --socket-path\n");
 324        exit(EXIT_FAILURE);
 325    }
 326
 327    vi.evdevfd = open(opt_evdev, O_RDWR);
 328    if (vi.evdevfd < 0) {
 329        g_printerr("Failed to open evdev: %s\n", g_strerror(errno));
 330        exit(EXIT_FAILURE);
 331    }
 332
 333    rc = ioctl(vi.evdevfd, EVIOCGVERSION, &ver);
 334    if (rc < 0) {
 335        g_printerr("%s: is not an evdev device\n", argv[1]);
 336        exit(EXIT_FAILURE);
 337    }
 338
 339    if (!opt_nograb) {
 340        rc = ioctl(vi.evdevfd, EVIOCGRAB, 1);
 341        if (rc < 0) {
 342            g_printerr("Failed to grab device\n");
 343            exit(EXIT_FAILURE);
 344        }
 345    }
 346
 347    vi.config = g_array_new(false, false, sizeof(virtio_input_config));
 348    memset(&id, 0, sizeof(id));
 349    if (ioctl(vi.evdevfd, EVIOCGNAME(sizeof(id.u.string) - 1),
 350              id.u.string) < 0) {
 351        g_printerr("Failed to get evdev name: %s\n", g_strerror(errno));
 352        exit(EXIT_FAILURE);
 353    }
 354    id.select = VIRTIO_INPUT_CFG_ID_NAME;
 355    id.size = strlen(id.u.string);
 356    g_array_append_val(vi.config, id);
 357
 358    if (ioctl(vi.evdevfd, EVIOCGID, &ids) == 0) {
 359        memset(&id, 0, sizeof(id));
 360        id.select = VIRTIO_INPUT_CFG_ID_DEVIDS;
 361        id.size = sizeof(struct virtio_input_devids);
 362        id.u.ids.bustype = cpu_to_le16(ids.bustype);
 363        id.u.ids.vendor  = cpu_to_le16(ids.vendor);
 364        id.u.ids.product = cpu_to_le16(ids.product);
 365        id.u.ids.version = cpu_to_le16(ids.version);
 366        g_array_append_val(vi.config, id);
 367    }
 368
 369    vi_bits_config(&vi, EV_KEY, KEY_CNT);
 370    vi_bits_config(&vi, EV_REL, REL_CNT);
 371    vi_bits_config(&vi, EV_ABS, ABS_CNT);
 372    vi_bits_config(&vi, EV_MSC, MSC_CNT);
 373    vi_bits_config(&vi, EV_SW,  SW_CNT);
 374    g_debug("config length: %u", vi.config->len);
 375
 376    if (opt_socket_path) {
 377        int lsock = unix_listen(opt_socket_path, &error_fatal);
 378        if (lsock < 0) {
 379            g_printerr("Failed to listen on %s.\n", opt_socket_path);
 380            exit(EXIT_FAILURE);
 381        }
 382        fd = accept(lsock, NULL, NULL);
 383        close(lsock);
 384    } else {
 385        fd = opt_fdnum;
 386    }
 387    if (fd == -1) {
 388        g_printerr("Invalid vhost-user socket.\n");
 389        exit(EXIT_FAILURE);
 390    }
 391
 392    if (!vug_init(&vi.dev, VHOST_USER_INPUT_MAX_QUEUES, fd, vi_panic,
 393                  &vuiface)) {
 394        g_printerr("Failed to initialize libvhost-user-glib.\n");
 395        exit(EXIT_FAILURE);
 396    }
 397
 398    loop = g_main_loop_new(NULL, FALSE);
 399    g_main_loop_run(loop);
 400    g_main_loop_unref(loop);
 401
 402    vug_deinit(&vi.dev);
 403
 404    vug_source_destroy(vi.evsrc);
 405    g_array_free(vi.config, TRUE);
 406    g_free(vi.queue);
 407    return 0;
 408}
 409