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