xref: /openbmc/qemu/contrib/vhost-user-input/main.c (revision d2623129a7dec1d3041ad1221dda1ca49c667532)
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 <glib.h>
10  #include <linux/input.h>
11  
12  #include "qemu/iov.h"
13  #include "qemu/bswap.h"
14  #include "qemu/sockets.h"
15  #include "contrib/libvhost-user/libvhost-user.h"
16  #include "contrib/libvhost-user/libvhost-user-glib.h"
17  #include "standard-headers/linux/virtio_input.h"
18  #include "qapi/error.h"
19  
20  enum {
21      VHOST_USER_INPUT_MAX_QUEUES = 2,
22  };
23  
24  typedef struct virtio_input_event virtio_input_event;
25  typedef struct virtio_input_config virtio_input_config;
26  
27  typedef struct VuInput {
28      VugDev dev;
29      GSource *evsrc;
30      int evdevfd;
31      GArray *config;
32      virtio_input_config *sel_config;
33      struct {
34          virtio_input_event event;
35          VuVirtqElement *elem;
36      } *queue;
37      uint32_t qindex, qsize;
38  } VuInput;
39  
40  static void vi_input_send(VuInput *vi, struct virtio_input_event *event)
41  {
42      VuDev *dev = &vi->dev.parent;
43      VuVirtq *vq = vu_get_queue(dev, 0);
44      VuVirtqElement *elem;
45      int i, len;
46  
47      /* queue up events ... */
48      if (vi->qindex == vi->qsize) {
49          vi->qsize++;
50          vi->queue = g_realloc_n(vi->queue, vi->qsize, sizeof(vi->queue[0]));
51      }
52      vi->queue[vi->qindex++].event = *event;
53  
54      /* ... until we see a report sync ... */
55      if (event->type != htole16(EV_SYN) ||
56          event->code != htole16(SYN_REPORT)) {
57          return;
58      }
59  
60      /* ... then check available space ... */
61      for (i = 0; i < vi->qindex; i++) {
62          elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
63          if (!elem) {
64              while (--i >= 0) {
65                  vu_queue_unpop(dev, vq, vi->queue[i].elem, 0);
66              }
67              vi->qindex = 0;
68              g_warning("virtio-input queue full");
69              return;
70          }
71          vi->queue[i].elem = elem;
72      }
73  
74      /* ... and finally pass them to the guest */
75      for (i = 0; i < vi->qindex; i++) {
76          elem = vi->queue[i].elem;
77          len = iov_from_buf(elem->in_sg, elem->in_num,
78                             0, &vi->queue[i].event, sizeof(virtio_input_event));
79          vu_queue_push(dev, vq, elem, len);
80          free(elem);
81      }
82  
83      vu_queue_notify(&vi->dev.parent, vq);
84      vi->qindex = 0;
85  }
86  
87  static void
88  vi_evdev_watch(VuDev *dev, int condition, void *data)
89  {
90      VuInput *vi = data;
91      int fd = vi->evdevfd;
92  
93      g_debug("Got evdev condition %x", condition);
94  
95      struct virtio_input_event virtio;
96      struct input_event evdev;
97      int rc;
98  
99      for (;;) {
100          rc = read(fd, &evdev, sizeof(evdev));
101          if (rc != sizeof(evdev)) {
102              break;
103          }
104  
105          g_debug("input %d %d %d", evdev.type, evdev.code, evdev.value);
106  
107          virtio.type  = htole16(evdev.type);
108          virtio.code  = htole16(evdev.code);
109          virtio.value = htole32(evdev.value);
110          vi_input_send(vi, &virtio);
111      }
112  }
113  
114  
115  static void vi_handle_status(VuInput *vi, virtio_input_event *event)
116  {
117      struct input_event evdev;
118      int rc;
119  
120      if (gettimeofday(&evdev.time, NULL)) {
121          perror("vi_handle_status: gettimeofday");
122          return;
123      }
124  
125      evdev.type = le16toh(event->type);
126      evdev.code = le16toh(event->code);
127      evdev.value = le32toh(event->value);
128  
129      rc = write(vi->evdevfd, &evdev, sizeof(evdev));
130      if (rc == -1) {
131          perror("vi_host_handle_status: write");
132      }
133  }
134  
135  static void vi_handle_sts(VuDev *dev, int qidx)
136  {
137      VuInput *vi = container_of(dev, VuInput, dev.parent);
138      VuVirtq *vq = vu_get_queue(dev, qidx);
139      virtio_input_event event;
140      VuVirtqElement *elem;
141      int len;
142  
143      g_debug("%s", G_STRFUNC);
144  
145      for (;;) {
146          elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
147          if (!elem) {
148              break;
149          }
150  
151          memset(&event, 0, sizeof(event));
152          len = iov_to_buf(elem->out_sg, elem->out_num,
153                           0, &event, sizeof(event));
154          vi_handle_status(vi, &event);
155          vu_queue_push(dev, vq, elem, len);
156          free(elem);
157      }
158  
159      vu_queue_notify(&vi->dev.parent, vq);
160  }
161  
162  static void
163  vi_panic(VuDev *dev, const char *msg)
164  {
165      g_critical("%s\n", msg);
166      exit(EXIT_FAILURE);
167  }
168  
169  static void
170  vi_queue_set_started(VuDev *dev, int qidx, bool started)
171  {
172      VuInput *vi = container_of(dev, VuInput, dev.parent);
173      VuVirtq *vq = vu_get_queue(dev, qidx);
174  
175      g_debug("queue started %d:%d", qidx, started);
176  
177      if (qidx == 1) {
178          vu_set_queue_handler(dev, vq, started ? vi_handle_sts : NULL);
179      }
180  
181      started = vu_queue_started(dev, vu_get_queue(dev, 0)) &&
182          vu_queue_started(dev, vu_get_queue(dev, 1));
183  
184      if (started && !vi->evsrc) {
185          vi->evsrc = vug_source_new(&vi->dev, vi->evdevfd,
186                                     G_IO_IN, vi_evdev_watch, vi);
187      }
188  
189      if (!started && vi->evsrc) {
190          vug_source_destroy(vi->evsrc);
191          vi->evsrc = NULL;
192      }
193  }
194  
195  static virtio_input_config *
196  vi_find_config(VuInput *vi, uint8_t select, uint8_t subsel)
197  {
198      virtio_input_config *cfg;
199      int i;
200  
201      for (i = 0; i < vi->config->len; i++) {
202          cfg = &g_array_index(vi->config, virtio_input_config, i);
203          if (select == cfg->select && subsel == cfg->subsel) {
204              return cfg;
205          }
206      }
207  
208      return NULL;
209  }
210  
211  static int vi_get_config(VuDev *dev, uint8_t *config, uint32_t len)
212  {
213      VuInput *vi = container_of(dev, VuInput, dev.parent);
214  
215      g_return_val_if_fail(len <= sizeof(*vi->sel_config), -1);
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  
226  static 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  
238  static 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  
244  static void
245  vi_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  
271  static char *opt_evdev;
272  static int opt_fdnum = -1;
273  static char *opt_socket_path;
274  static gboolean opt_nograb;
275  static gboolean opt_print_caps;
276  
277  static 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  
291  int
292  main(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