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