106914c97SMarc-André Lureau /* 206914c97SMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or 306914c97SMarc-André Lureau * (at your option) any later version. See the COPYING file in the 406914c97SMarc-André Lureau * top-level directory. 506914c97SMarc-André Lureau */ 606914c97SMarc-André Lureau 706914c97SMarc-André Lureau #include "qemu/osdep.h" 806914c97SMarc-André Lureau 906914c97SMarc-André Lureau #include <glib.h> 1006914c97SMarc-André Lureau #include <linux/input.h> 1106914c97SMarc-André Lureau 1206914c97SMarc-André Lureau #include "qemu/iov.h" 1306914c97SMarc-André Lureau #include "qemu/bswap.h" 1406914c97SMarc-André Lureau #include "qemu/sockets.h" 1506914c97SMarc-André Lureau #include "contrib/libvhost-user/libvhost-user.h" 1606914c97SMarc-André Lureau #include "contrib/libvhost-user/libvhost-user-glib.h" 1706914c97SMarc-André Lureau #include "standard-headers/linux/virtio_input.h" 1806914c97SMarc-André Lureau #include "qapi/error.h" 1906914c97SMarc-André Lureau 2006914c97SMarc-André Lureau typedef struct virtio_input_event virtio_input_event; 2106914c97SMarc-André Lureau typedef struct virtio_input_config virtio_input_config; 2206914c97SMarc-André Lureau 2306914c97SMarc-André Lureau typedef struct VuInput { 2406914c97SMarc-André Lureau VugDev dev; 2506914c97SMarc-André Lureau GSource *evsrc; 2606914c97SMarc-André Lureau int evdevfd; 2706914c97SMarc-André Lureau GArray *config; 2806914c97SMarc-André Lureau virtio_input_config *sel_config; 2906914c97SMarc-André Lureau struct { 3006914c97SMarc-André Lureau virtio_input_event event; 3106914c97SMarc-André Lureau VuVirtqElement *elem; 3206914c97SMarc-André Lureau } *queue; 3306914c97SMarc-André Lureau uint32_t qindex, qsize; 3406914c97SMarc-André Lureau } VuInput; 3506914c97SMarc-André Lureau 3606914c97SMarc-André Lureau static void vi_input_send(VuInput *vi, struct virtio_input_event *event) 3706914c97SMarc-André Lureau { 3806914c97SMarc-André Lureau VuDev *dev = &vi->dev.parent; 3906914c97SMarc-André Lureau VuVirtq *vq = vu_get_queue(dev, 0); 4006914c97SMarc-André Lureau VuVirtqElement *elem; 4106914c97SMarc-André Lureau int i, len; 4206914c97SMarc-André Lureau 4306914c97SMarc-André Lureau /* queue up events ... */ 4406914c97SMarc-André Lureau if (vi->qindex == vi->qsize) { 4506914c97SMarc-André Lureau vi->qsize++; 4606914c97SMarc-André Lureau vi->queue = g_realloc_n(vi->queue, vi->qsize, sizeof(vi->queue[0])); 4706914c97SMarc-André Lureau } 4806914c97SMarc-André Lureau vi->queue[vi->qindex++].event = *event; 4906914c97SMarc-André Lureau 5006914c97SMarc-André Lureau /* ... until we see a report sync ... */ 5106914c97SMarc-André Lureau if (event->type != htole16(EV_SYN) || 5206914c97SMarc-André Lureau event->code != htole16(SYN_REPORT)) { 5306914c97SMarc-André Lureau return; 5406914c97SMarc-André Lureau } 5506914c97SMarc-André Lureau 5606914c97SMarc-André Lureau /* ... then check available space ... */ 5706914c97SMarc-André Lureau for (i = 0; i < vi->qindex; i++) { 5806914c97SMarc-André Lureau elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); 5906914c97SMarc-André Lureau if (!elem) { 6006914c97SMarc-André Lureau while (--i >= 0) { 6106914c97SMarc-André Lureau vu_queue_unpop(dev, vq, vi->queue[i].elem, 0); 6206914c97SMarc-André Lureau } 6306914c97SMarc-André Lureau vi->qindex = 0; 6406914c97SMarc-André Lureau g_warning("virtio-input queue full"); 6506914c97SMarc-André Lureau return; 6606914c97SMarc-André Lureau } 6706914c97SMarc-André Lureau vi->queue[i].elem = elem; 6806914c97SMarc-André Lureau } 6906914c97SMarc-André Lureau 7006914c97SMarc-André Lureau /* ... and finally pass them to the guest */ 7106914c97SMarc-André Lureau for (i = 0; i < vi->qindex; i++) { 7206914c97SMarc-André Lureau elem = vi->queue[i].elem; 7306914c97SMarc-André Lureau len = iov_from_buf(elem->in_sg, elem->in_num, 7406914c97SMarc-André Lureau 0, &vi->queue[i].event, sizeof(virtio_input_event)); 7506914c97SMarc-André Lureau vu_queue_push(dev, vq, elem, len); 7606914c97SMarc-André Lureau g_free(elem); 7706914c97SMarc-André Lureau } 7806914c97SMarc-André Lureau 7906914c97SMarc-André Lureau vu_queue_notify(&vi->dev.parent, vq); 8006914c97SMarc-André Lureau vi->qindex = 0; 8106914c97SMarc-André Lureau } 8206914c97SMarc-André Lureau 8306914c97SMarc-André Lureau static void 8406914c97SMarc-André Lureau vi_evdev_watch(VuDev *dev, int condition, void *data) 8506914c97SMarc-André Lureau { 8606914c97SMarc-André Lureau VuInput *vi = data; 8706914c97SMarc-André Lureau int fd = vi->evdevfd; 8806914c97SMarc-André Lureau 8906914c97SMarc-André Lureau g_debug("Got evdev condition %x", condition); 9006914c97SMarc-André Lureau 9106914c97SMarc-André Lureau struct virtio_input_event virtio; 9206914c97SMarc-André Lureau struct input_event evdev; 9306914c97SMarc-André Lureau int rc; 9406914c97SMarc-André Lureau 9506914c97SMarc-André Lureau for (;;) { 9606914c97SMarc-André Lureau rc = read(fd, &evdev, sizeof(evdev)); 9706914c97SMarc-André Lureau if (rc != sizeof(evdev)) { 9806914c97SMarc-André Lureau break; 9906914c97SMarc-André Lureau } 10006914c97SMarc-André Lureau 10106914c97SMarc-André Lureau g_debug("input %d %d %d", evdev.type, evdev.code, evdev.value); 10206914c97SMarc-André Lureau 10306914c97SMarc-André Lureau virtio.type = htole16(evdev.type); 10406914c97SMarc-André Lureau virtio.code = htole16(evdev.code); 10506914c97SMarc-André Lureau virtio.value = htole32(evdev.value); 10606914c97SMarc-André Lureau vi_input_send(vi, &virtio); 10706914c97SMarc-André Lureau } 10806914c97SMarc-André Lureau } 10906914c97SMarc-André Lureau 11006914c97SMarc-André Lureau 11106914c97SMarc-André Lureau static void vi_handle_status(VuInput *vi, virtio_input_event *event) 11206914c97SMarc-André Lureau { 11306914c97SMarc-André Lureau struct input_event evdev; 11406914c97SMarc-André Lureau int rc; 11506914c97SMarc-André Lureau 11606914c97SMarc-André Lureau if (gettimeofday(&evdev.time, NULL)) { 11706914c97SMarc-André Lureau perror("vi_handle_status: gettimeofday"); 11806914c97SMarc-André Lureau return; 11906914c97SMarc-André Lureau } 12006914c97SMarc-André Lureau 12106914c97SMarc-André Lureau evdev.type = le16toh(event->type); 12206914c97SMarc-André Lureau evdev.code = le16toh(event->code); 12306914c97SMarc-André Lureau evdev.value = le32toh(event->value); 12406914c97SMarc-André Lureau 12506914c97SMarc-André Lureau rc = write(vi->evdevfd, &evdev, sizeof(evdev)); 12606914c97SMarc-André Lureau if (rc == -1) { 12706914c97SMarc-André Lureau perror("vi_host_handle_status: write"); 12806914c97SMarc-André Lureau } 12906914c97SMarc-André Lureau } 13006914c97SMarc-André Lureau 13106914c97SMarc-André Lureau static void vi_handle_sts(VuDev *dev, int qidx) 13206914c97SMarc-André Lureau { 13306914c97SMarc-André Lureau VuInput *vi = container_of(dev, VuInput, dev.parent); 13406914c97SMarc-André Lureau VuVirtq *vq = vu_get_queue(dev, qidx); 13506914c97SMarc-André Lureau virtio_input_event event; 13606914c97SMarc-André Lureau VuVirtqElement *elem; 13706914c97SMarc-André Lureau int len; 13806914c97SMarc-André Lureau 13906914c97SMarc-André Lureau g_debug("%s", G_STRFUNC); 14006914c97SMarc-André Lureau 14106914c97SMarc-André Lureau for (;;) { 14206914c97SMarc-André Lureau elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); 14306914c97SMarc-André Lureau if (!elem) { 14406914c97SMarc-André Lureau break; 14506914c97SMarc-André Lureau } 14606914c97SMarc-André Lureau 14706914c97SMarc-André Lureau memset(&event, 0, sizeof(event)); 14806914c97SMarc-André Lureau len = iov_to_buf(elem->out_sg, elem->out_num, 14906914c97SMarc-André Lureau 0, &event, sizeof(event)); 15006914c97SMarc-André Lureau vi_handle_status(vi, &event); 15106914c97SMarc-André Lureau vu_queue_push(dev, vq, elem, len); 15206914c97SMarc-André Lureau g_free(elem); 15306914c97SMarc-André Lureau } 15406914c97SMarc-André Lureau 15506914c97SMarc-André Lureau vu_queue_notify(&vi->dev.parent, vq); 15606914c97SMarc-André Lureau } 15706914c97SMarc-André Lureau 15806914c97SMarc-André Lureau static void 15906914c97SMarc-André Lureau vi_panic(VuDev *dev, const char *msg) 16006914c97SMarc-André Lureau { 16106914c97SMarc-André Lureau g_critical("%s\n", msg); 16206914c97SMarc-André Lureau exit(EXIT_FAILURE); 16306914c97SMarc-André Lureau } 16406914c97SMarc-André Lureau 16506914c97SMarc-André Lureau static void 16606914c97SMarc-André Lureau vi_queue_set_started(VuDev *dev, int qidx, bool started) 16706914c97SMarc-André Lureau { 16806914c97SMarc-André Lureau VuInput *vi = container_of(dev, VuInput, dev.parent); 16906914c97SMarc-André Lureau VuVirtq *vq = vu_get_queue(dev, qidx); 17006914c97SMarc-André Lureau 17106914c97SMarc-André Lureau g_debug("queue started %d:%d", qidx, started); 17206914c97SMarc-André Lureau 17306914c97SMarc-André Lureau if (qidx == 1) { 17406914c97SMarc-André Lureau vu_set_queue_handler(dev, vq, started ? vi_handle_sts : NULL); 17506914c97SMarc-André Lureau } 17606914c97SMarc-André Lureau 17706914c97SMarc-André Lureau started = vu_queue_started(dev, vu_get_queue(dev, 0)) && 17806914c97SMarc-André Lureau vu_queue_started(dev, vu_get_queue(dev, 1)); 17906914c97SMarc-André Lureau 18006914c97SMarc-André Lureau if (started && !vi->evsrc) { 18106914c97SMarc-André Lureau vi->evsrc = vug_source_new(&vi->dev, vi->evdevfd, 18206914c97SMarc-André Lureau G_IO_IN, vi_evdev_watch, vi); 18306914c97SMarc-André Lureau } 18406914c97SMarc-André Lureau 18506914c97SMarc-André Lureau if (!started && vi->evsrc) { 18606914c97SMarc-André Lureau g_source_destroy(vi->evsrc); 18706914c97SMarc-André Lureau vi->evsrc = NULL; 18806914c97SMarc-André Lureau } 18906914c97SMarc-André Lureau } 19006914c97SMarc-André Lureau 19106914c97SMarc-André Lureau static virtio_input_config * 19206914c97SMarc-André Lureau vi_find_config(VuInput *vi, uint8_t select, uint8_t subsel) 19306914c97SMarc-André Lureau { 19406914c97SMarc-André Lureau virtio_input_config *cfg; 19506914c97SMarc-André Lureau int i; 19606914c97SMarc-André Lureau 19706914c97SMarc-André Lureau for (i = 0; i < vi->config->len; i++) { 19806914c97SMarc-André Lureau cfg = &g_array_index(vi->config, virtio_input_config, i); 19906914c97SMarc-André Lureau if (select == cfg->select && subsel == cfg->subsel) { 20006914c97SMarc-André Lureau return cfg; 20106914c97SMarc-André Lureau } 20206914c97SMarc-André Lureau } 20306914c97SMarc-André Lureau 20406914c97SMarc-André Lureau return NULL; 20506914c97SMarc-André Lureau } 20606914c97SMarc-André Lureau 20706914c97SMarc-André Lureau static int vi_get_config(VuDev *dev, uint8_t *config, uint32_t len) 20806914c97SMarc-André Lureau { 20906914c97SMarc-André Lureau VuInput *vi = container_of(dev, VuInput, dev.parent); 21006914c97SMarc-André Lureau 21106914c97SMarc-André Lureau g_return_val_if_fail(len <= sizeof(*vi->sel_config), -1); 21206914c97SMarc-André Lureau 21306914c97SMarc-André Lureau if (vi->sel_config) { 21406914c97SMarc-André Lureau memcpy(config, vi->sel_config, len); 21506914c97SMarc-André Lureau } else { 21606914c97SMarc-André Lureau memset(config, 0, len); 21706914c97SMarc-André Lureau } 21806914c97SMarc-André Lureau 21906914c97SMarc-André Lureau return 0; 22006914c97SMarc-André Lureau } 22106914c97SMarc-André Lureau 22206914c97SMarc-André Lureau static int vi_set_config(VuDev *dev, const uint8_t *data, 22306914c97SMarc-André Lureau uint32_t offset, uint32_t size, 22406914c97SMarc-André Lureau uint32_t flags) 22506914c97SMarc-André Lureau { 22606914c97SMarc-André Lureau VuInput *vi = container_of(dev, VuInput, dev.parent); 22706914c97SMarc-André Lureau virtio_input_config *config = (virtio_input_config *)data; 22806914c97SMarc-André Lureau 22906914c97SMarc-André Lureau vi->sel_config = vi_find_config(vi, config->select, config->subsel); 23006914c97SMarc-André Lureau 23106914c97SMarc-André Lureau return 0; 23206914c97SMarc-André Lureau } 23306914c97SMarc-André Lureau 23406914c97SMarc-André Lureau static const VuDevIface vuiface = { 23506914c97SMarc-André Lureau .queue_set_started = vi_queue_set_started, 23606914c97SMarc-André Lureau .get_config = vi_get_config, 23706914c97SMarc-André Lureau .set_config = vi_set_config, 23806914c97SMarc-André Lureau }; 23906914c97SMarc-André Lureau 24006914c97SMarc-André Lureau static void 24106914c97SMarc-André Lureau vi_bits_config(VuInput *vi, int type, int count) 24206914c97SMarc-André Lureau { 24306914c97SMarc-André Lureau virtio_input_config bits; 24406914c97SMarc-André Lureau int rc, i, size = 0; 24506914c97SMarc-André Lureau 24606914c97SMarc-André Lureau memset(&bits, 0, sizeof(bits)); 24706914c97SMarc-André Lureau rc = ioctl(vi->evdevfd, EVIOCGBIT(type, count / 8), bits.u.bitmap); 24806914c97SMarc-André Lureau if (rc < 0) { 24906914c97SMarc-André Lureau return; 25006914c97SMarc-André Lureau } 25106914c97SMarc-André Lureau 25206914c97SMarc-André Lureau for (i = 0; i < count / 8; i++) { 25306914c97SMarc-André Lureau if (bits.u.bitmap[i]) { 25406914c97SMarc-André Lureau size = i + 1; 25506914c97SMarc-André Lureau } 25606914c97SMarc-André Lureau } 25706914c97SMarc-André Lureau if (size == 0) { 25806914c97SMarc-André Lureau return; 25906914c97SMarc-André Lureau } 26006914c97SMarc-André Lureau 26106914c97SMarc-André Lureau bits.select = VIRTIO_INPUT_CFG_EV_BITS; 26206914c97SMarc-André Lureau bits.subsel = type; 26306914c97SMarc-André Lureau bits.size = size; 26406914c97SMarc-André Lureau g_array_append_val(vi->config, bits); 26506914c97SMarc-André Lureau } 26606914c97SMarc-André Lureau 26706914c97SMarc-André Lureau static char *opt_evdev; 26806914c97SMarc-André Lureau static int opt_fdnum = -1; 26906914c97SMarc-André Lureau static char *opt_socket_path; 27006914c97SMarc-André Lureau static gboolean opt_nograb; 27106914c97SMarc-André Lureau static gboolean opt_print_caps; 27206914c97SMarc-André Lureau 27306914c97SMarc-André Lureau static GOptionEntry entries[] = { 27406914c97SMarc-André Lureau { "print-capabilities", 'c', 0, G_OPTION_ARG_NONE, &opt_print_caps, 27506914c97SMarc-André Lureau "Print capabilities", NULL }, 27606914c97SMarc-André Lureau { "no-grab", 'n', 0, G_OPTION_ARG_NONE, &opt_nograb, 27706914c97SMarc-André Lureau "Don't grab device", NULL }, 27806914c97SMarc-André Lureau { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum, 27906914c97SMarc-André Lureau "Use inherited fd socket", "FDNUM" }, 28006914c97SMarc-André Lureau { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path, 28106914c97SMarc-André Lureau "Use UNIX socket path", "PATH" }, 28206914c97SMarc-André Lureau { "evdev-path", 'p', 0, G_OPTION_ARG_FILENAME, &opt_evdev, 28306914c97SMarc-André Lureau "evdev input device path", "PATH" }, 28406914c97SMarc-André Lureau { NULL, } 28506914c97SMarc-André Lureau }; 28606914c97SMarc-André Lureau 28706914c97SMarc-André Lureau int 28806914c97SMarc-André Lureau main(int argc, char *argv[]) 28906914c97SMarc-André Lureau { 29006914c97SMarc-André Lureau GMainLoop *loop = NULL; 29106914c97SMarc-André Lureau VuInput vi = { 0, }; 29206914c97SMarc-André Lureau int rc, ver, fd; 29306914c97SMarc-André Lureau virtio_input_config id; 29406914c97SMarc-André Lureau struct input_id ids; 29506914c97SMarc-André Lureau GError *error = NULL; 29606914c97SMarc-André Lureau GOptionContext *context; 29706914c97SMarc-André Lureau 29806914c97SMarc-André Lureau context = g_option_context_new(NULL); 29906914c97SMarc-André Lureau g_option_context_add_main_entries(context, entries, NULL); 30006914c97SMarc-André Lureau if (!g_option_context_parse(context, &argc, &argv, &error)) { 30106914c97SMarc-André Lureau g_printerr("Option parsing failed: %s\n", error->message); 30206914c97SMarc-André Lureau exit(EXIT_FAILURE); 30306914c97SMarc-André Lureau } 30406914c97SMarc-André Lureau if (opt_print_caps) { 30506914c97SMarc-André Lureau g_print("{\n"); 30606914c97SMarc-André Lureau g_print(" \"type\": \"input\",\n"); 30706914c97SMarc-André Lureau g_print(" \"features\": [\n"); 30806914c97SMarc-André Lureau g_print(" \"evdev-path\",\n"); 30906914c97SMarc-André Lureau g_print(" \"no-grab\"\n"); 31006914c97SMarc-André Lureau g_print(" ]\n"); 31106914c97SMarc-André Lureau g_print("}\n"); 31206914c97SMarc-André Lureau exit(EXIT_SUCCESS); 31306914c97SMarc-André Lureau } 31406914c97SMarc-André Lureau if (!opt_evdev) { 31506914c97SMarc-André Lureau g_printerr("Please specify an evdev path\n"); 31606914c97SMarc-André Lureau exit(EXIT_FAILURE); 31706914c97SMarc-André Lureau } 31806914c97SMarc-André Lureau if ((!!opt_socket_path + (opt_fdnum != -1)) != 1) { 31906914c97SMarc-André Lureau g_printerr("Please specify either --fd or --socket-path\n"); 32006914c97SMarc-André Lureau exit(EXIT_FAILURE); 32106914c97SMarc-André Lureau } 32206914c97SMarc-André Lureau 32306914c97SMarc-André Lureau vi.evdevfd = open(opt_evdev, O_RDWR); 32406914c97SMarc-André Lureau if (vi.evdevfd < 0) { 32506914c97SMarc-André Lureau g_printerr("Failed to open evdev: %s\n", g_strerror(errno)); 32606914c97SMarc-André Lureau exit(EXIT_FAILURE); 32706914c97SMarc-André Lureau } 32806914c97SMarc-André Lureau 32906914c97SMarc-André Lureau rc = ioctl(vi.evdevfd, EVIOCGVERSION, &ver); 33006914c97SMarc-André Lureau if (rc < 0) { 33106914c97SMarc-André Lureau g_printerr("%s: is not an evdev device\n", argv[1]); 33206914c97SMarc-André Lureau exit(EXIT_FAILURE); 33306914c97SMarc-André Lureau } 33406914c97SMarc-André Lureau 33506914c97SMarc-André Lureau if (!opt_nograb) { 33606914c97SMarc-André Lureau rc = ioctl(vi.evdevfd, EVIOCGRAB, 1); 33706914c97SMarc-André Lureau if (rc < 0) { 33806914c97SMarc-André Lureau g_printerr("Failed to grab device\n"); 33906914c97SMarc-André Lureau exit(EXIT_FAILURE); 34006914c97SMarc-André Lureau } 34106914c97SMarc-André Lureau } 34206914c97SMarc-André Lureau 34306914c97SMarc-André Lureau vi.config = g_array_new(false, false, sizeof(virtio_input_config)); 34406914c97SMarc-André Lureau memset(&id, 0, sizeof(id)); 34506914c97SMarc-André Lureau ioctl(vi.evdevfd, EVIOCGNAME(sizeof(id.u.string) - 1), id.u.string); 34606914c97SMarc-André Lureau id.select = VIRTIO_INPUT_CFG_ID_NAME; 34706914c97SMarc-André Lureau id.size = strlen(id.u.string); 34806914c97SMarc-André Lureau g_array_append_val(vi.config, id); 34906914c97SMarc-André Lureau 35006914c97SMarc-André Lureau if (ioctl(vi.evdevfd, EVIOCGID, &ids) == 0) { 35106914c97SMarc-André Lureau memset(&id, 0, sizeof(id)); 35206914c97SMarc-André Lureau id.select = VIRTIO_INPUT_CFG_ID_DEVIDS; 35306914c97SMarc-André Lureau id.size = sizeof(struct virtio_input_devids); 35406914c97SMarc-André Lureau id.u.ids.bustype = cpu_to_le16(ids.bustype); 35506914c97SMarc-André Lureau id.u.ids.vendor = cpu_to_le16(ids.vendor); 35606914c97SMarc-André Lureau id.u.ids.product = cpu_to_le16(ids.product); 35706914c97SMarc-André Lureau id.u.ids.version = cpu_to_le16(ids.version); 35806914c97SMarc-André Lureau g_array_append_val(vi.config, id); 35906914c97SMarc-André Lureau } 36006914c97SMarc-André Lureau 36106914c97SMarc-André Lureau vi_bits_config(&vi, EV_KEY, KEY_CNT); 36206914c97SMarc-André Lureau vi_bits_config(&vi, EV_REL, REL_CNT); 36306914c97SMarc-André Lureau vi_bits_config(&vi, EV_ABS, ABS_CNT); 36406914c97SMarc-André Lureau vi_bits_config(&vi, EV_MSC, MSC_CNT); 36506914c97SMarc-André Lureau vi_bits_config(&vi, EV_SW, SW_CNT); 36606914c97SMarc-André Lureau g_debug("config length: %u", vi.config->len); 36706914c97SMarc-André Lureau 36806914c97SMarc-André Lureau if (opt_socket_path) { 36906914c97SMarc-André Lureau int lsock = unix_listen(opt_socket_path, &error_fatal); 370*24af03b9SMarc-André Lureau if (lsock < 0) { 371*24af03b9SMarc-André Lureau g_printerr("Failed to listen on %s.\n", opt_socket_path); 372*24af03b9SMarc-André Lureau exit(EXIT_FAILURE); 373*24af03b9SMarc-André Lureau } 37406914c97SMarc-André Lureau fd = accept(lsock, NULL, NULL); 37506914c97SMarc-André Lureau close(lsock); 37606914c97SMarc-André Lureau } else { 37706914c97SMarc-André Lureau fd = opt_fdnum; 37806914c97SMarc-André Lureau } 37906914c97SMarc-André Lureau if (fd == -1) { 38006914c97SMarc-André Lureau g_printerr("Invalid socket"); 38106914c97SMarc-André Lureau exit(EXIT_FAILURE); 38206914c97SMarc-André Lureau } 38306914c97SMarc-André Lureau vug_init(&vi.dev, fd, vi_panic, &vuiface); 38406914c97SMarc-André Lureau 38506914c97SMarc-André Lureau loop = g_main_loop_new(NULL, FALSE); 38606914c97SMarc-André Lureau g_main_loop_run(loop); 38706914c97SMarc-André Lureau g_main_loop_unref(loop); 38806914c97SMarc-André Lureau 38906914c97SMarc-André Lureau vug_deinit(&vi.dev); 39006914c97SMarc-André Lureau 39106914c97SMarc-André Lureau if (vi.evsrc) { 39206914c97SMarc-André Lureau g_source_unref(vi.evsrc); 39306914c97SMarc-André Lureau } 39406914c97SMarc-André Lureau g_array_free(vi.config, TRUE); 39506914c97SMarc-André Lureau g_free(vi.queue); 39606914c97SMarc-André Lureau return 0; 39706914c97SMarc-André Lureau } 398