xref: /freebsd/usr.sbin/bhyve/pci_virtio_input.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
1054accacSCorvin Köhne /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3054accacSCorvin Köhne  *
4054accacSCorvin Köhne  * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5054accacSCorvin Köhne  * All rights reserved.
6054accacSCorvin Köhne  *
7054accacSCorvin Köhne  * Redistribution and use in source and binary forms, with or without
8054accacSCorvin Köhne  * modification, are permitted provided that the following conditions
9054accacSCorvin Köhne  * are met:
10054accacSCorvin Köhne  * 1. Redistributions of source code must retain the above copyright
11054accacSCorvin Köhne  *    notice, this list of conditions and the following disclaimer
12054accacSCorvin Köhne  *    in this position and unchanged.
13054accacSCorvin Köhne  * 2. Redistributions in binary form must reproduce the above copyright
14054accacSCorvin Köhne  *    notice, this list of conditions and the following disclaimer in the
15054accacSCorvin Köhne  *    documentation and/or other materials provided with the distribution.
16054accacSCorvin Köhne  *
17054accacSCorvin Köhne  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18054accacSCorvin Köhne  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19054accacSCorvin Köhne  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20054accacSCorvin Köhne  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21054accacSCorvin Köhne  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22054accacSCorvin Köhne  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23054accacSCorvin Köhne  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24054accacSCorvin Köhne  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25054accacSCorvin Köhne  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26054accacSCorvin Köhne  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27054accacSCorvin Köhne  * SUCH DAMAGE.
28054accacSCorvin Köhne  */
29054accacSCorvin Köhne 
30054accacSCorvin Köhne /*
31054accacSCorvin Köhne  * virtio input device emulation.
32054accacSCorvin Köhne  */
33054accacSCorvin Köhne 
34054accacSCorvin Köhne #include <sys/param.h>
35054accacSCorvin Köhne #ifndef WITHOUT_CAPSICUM
36054accacSCorvin Köhne #include <sys/capsicum.h>
37054accacSCorvin Köhne 
38054accacSCorvin Köhne #include <capsicum_helpers.h>
39054accacSCorvin Köhne #endif
40054accacSCorvin Köhne #include <sys/ioctl.h>
41054accacSCorvin Köhne #include <sys/linker_set.h>
42054accacSCorvin Köhne #include <sys/uio.h>
43054accacSCorvin Köhne 
44054accacSCorvin Köhne #include <dev/evdev/input.h>
45054accacSCorvin Köhne 
46054accacSCorvin Köhne #include <assert.h>
47054accacSCorvin Köhne #include <err.h>
48054accacSCorvin Köhne #include <errno.h>
49054accacSCorvin Köhne #include <fcntl.h>
50054accacSCorvin Köhne #include <pthread.h>
51054accacSCorvin Köhne #include <stddef.h>
52054accacSCorvin Köhne #include <stdio.h>
53054accacSCorvin Köhne #include <stdlib.h>
54054accacSCorvin Köhne #include <string.h>
55054accacSCorvin Köhne #include <sysexits.h>
56054accacSCorvin Köhne #include <unistd.h>
57054accacSCorvin Köhne 
58054accacSCorvin Köhne #include "bhyverun.h"
59054accacSCorvin Köhne #include "config.h"
60054accacSCorvin Köhne #include "debug.h"
61054accacSCorvin Köhne #include "mevent.h"
62054accacSCorvin Köhne #include "pci_emul.h"
63054accacSCorvin Köhne #include "virtio.h"
64054accacSCorvin Köhne 
65054accacSCorvin Köhne #define VTINPUT_RINGSZ 64
66054accacSCorvin Köhne 
67054accacSCorvin Köhne #define VTINPUT_MAX_PKT_LEN 10
68054accacSCorvin Köhne 
69054accacSCorvin Köhne /*
70054accacSCorvin Köhne  * Queue definitions.
71054accacSCorvin Köhne  */
72054accacSCorvin Köhne #define VTINPUT_EVENTQ 0
73054accacSCorvin Köhne #define VTINPUT_STATUSQ 1
74054accacSCorvin Köhne 
75054accacSCorvin Köhne #define VTINPUT_MAXQ 2
76054accacSCorvin Köhne 
77054accacSCorvin Köhne static int pci_vtinput_debug;
78054accacSCorvin Köhne #define DPRINTF(params)        \
79054accacSCorvin Köhne 	if (pci_vtinput_debug) \
80054accacSCorvin Köhne 	PRINTLN params
81054accacSCorvin Köhne #define WPRINTF(params) PRINTLN params
82054accacSCorvin Köhne 
83054accacSCorvin Köhne enum vtinput_config_select {
84054accacSCorvin Köhne 	VTINPUT_CFG_UNSET = 0x00,
85054accacSCorvin Köhne 	VTINPUT_CFG_ID_NAME = 0x01,
86054accacSCorvin Köhne 	VTINPUT_CFG_ID_SERIAL = 0x02,
87054accacSCorvin Köhne 	VTINPUT_CFG_ID_DEVIDS = 0x03,
88054accacSCorvin Köhne 	VTINPUT_CFG_PROP_BITS = 0x10,
89054accacSCorvin Köhne 	VTINPUT_CFG_EV_BITS = 0x11,
90054accacSCorvin Köhne 	VTINPUT_CFG_ABS_INFO = 0x12
91054accacSCorvin Köhne };
92054accacSCorvin Köhne 
93054accacSCorvin Köhne struct vtinput_absinfo {
94054accacSCorvin Köhne 	uint32_t min;
95054accacSCorvin Köhne 	uint32_t max;
96054accacSCorvin Köhne 	uint32_t fuzz;
97054accacSCorvin Köhne 	uint32_t flat;
98054accacSCorvin Köhne 	uint32_t res;
99054accacSCorvin Köhne } __packed;
100054accacSCorvin Köhne 
101054accacSCorvin Köhne struct vtinput_devids {
102054accacSCorvin Köhne 	uint16_t bustype;
103054accacSCorvin Köhne 	uint16_t vendor;
104054accacSCorvin Köhne 	uint16_t product;
105054accacSCorvin Köhne 	uint16_t version;
106054accacSCorvin Köhne } __packed;
107054accacSCorvin Köhne 
108054accacSCorvin Köhne struct vtinput_config {
109054accacSCorvin Köhne 	uint8_t select;
110054accacSCorvin Köhne 	uint8_t subsel;
111054accacSCorvin Köhne 	uint8_t size;
112054accacSCorvin Köhne 	uint8_t reserved[5];
113054accacSCorvin Köhne 	union {
114054accacSCorvin Köhne 		char string[128];
115054accacSCorvin Köhne 		uint8_t bitmap[128];
116054accacSCorvin Köhne 		struct vtinput_absinfo abs;
117054accacSCorvin Köhne 		struct vtinput_devids ids;
118054accacSCorvin Köhne 	} u;
119054accacSCorvin Köhne } __packed;
120054accacSCorvin Köhne 
121054accacSCorvin Köhne struct vtinput_event {
122054accacSCorvin Köhne 	uint16_t type;
123054accacSCorvin Köhne 	uint16_t code;
124054accacSCorvin Köhne 	uint32_t value;
125054accacSCorvin Köhne } __packed;
126054accacSCorvin Köhne 
127054accacSCorvin Köhne struct vtinput_event_elem {
128054accacSCorvin Köhne 	struct vtinput_event event;
129054accacSCorvin Köhne 	struct iovec iov;
130054accacSCorvin Köhne 	uint16_t idx;
131054accacSCorvin Köhne };
132054accacSCorvin Köhne 
133054accacSCorvin Köhne struct vtinput_eventqueue {
134054accacSCorvin Köhne 	struct vtinput_event_elem *events;
135054accacSCorvin Köhne 	uint32_t size;
136054accacSCorvin Köhne 	uint32_t idx;
137054accacSCorvin Köhne };
138054accacSCorvin Köhne 
139054accacSCorvin Köhne /*
140054accacSCorvin Köhne  * Per-device softc
141054accacSCorvin Köhne  */
142054accacSCorvin Köhne struct pci_vtinput_softc {
143054accacSCorvin Köhne 	struct virtio_softc vsc_vs;
144054accacSCorvin Köhne 	struct vqueue_info vsc_queues[VTINPUT_MAXQ];
145054accacSCorvin Köhne 	pthread_mutex_t vsc_mtx;
146054accacSCorvin Köhne 	const char *vsc_evdev;
147054accacSCorvin Köhne 	int vsc_fd;
148054accacSCorvin Köhne 	struct vtinput_config vsc_config;
149054accacSCorvin Köhne 	int vsc_config_valid;
150054accacSCorvin Köhne 	struct mevent *vsc_evp;
151054accacSCorvin Köhne 	struct vtinput_eventqueue vsc_eventqueue;
152054accacSCorvin Köhne };
153054accacSCorvin Köhne 
154054accacSCorvin Köhne static void pci_vtinput_reset(void *);
155054accacSCorvin Köhne static int pci_vtinput_cfgread(void *, int, int, uint32_t *);
156054accacSCorvin Köhne static int pci_vtinput_cfgwrite(void *, int, int, uint32_t);
157054accacSCorvin Köhne 
158054accacSCorvin Köhne static struct virtio_consts vtinput_vi_consts = {
1596cb26162SMark Johnston 	.vc_name =	"vtinput",
1606cb26162SMark Johnston 	.vc_nvq =	VTINPUT_MAXQ,
1616cb26162SMark Johnston 	.vc_cfgsize =	sizeof(struct vtinput_config),
1626cb26162SMark Johnston 	.vc_reset =	pci_vtinput_reset,
1636cb26162SMark Johnston 	.vc_cfgread =	pci_vtinput_cfgread,
1646cb26162SMark Johnston 	.vc_cfgwrite =	pci_vtinput_cfgwrite,
1656cb26162SMark Johnston 	.vc_hv_caps =	0,
166054accacSCorvin Köhne };
167054accacSCorvin Köhne 
168054accacSCorvin Köhne static void
pci_vtinput_reset(void * vsc)169054accacSCorvin Köhne pci_vtinput_reset(void *vsc)
170054accacSCorvin Köhne {
171054accacSCorvin Köhne 	struct pci_vtinput_softc *sc = vsc;
172054accacSCorvin Köhne 
173054accacSCorvin Köhne 	DPRINTF(("%s: device reset requested", __func__));
174054accacSCorvin Köhne 	vi_reset_dev(&sc->vsc_vs);
175054accacSCorvin Köhne }
176054accacSCorvin Köhne 
177054accacSCorvin Köhne static void
pci_vtinput_notify_eventq(void * vsc __unused,struct vqueue_info * vq __unused)17898d920d9SMark Johnston pci_vtinput_notify_eventq(void *vsc __unused, struct vqueue_info *vq __unused)
179054accacSCorvin Köhne {
180054accacSCorvin Köhne 	DPRINTF(("%s", __func__));
181054accacSCorvin Köhne }
182054accacSCorvin Köhne 
183054accacSCorvin Köhne static void
pci_vtinput_notify_statusq(void * vsc,struct vqueue_info * vq)184054accacSCorvin Köhne pci_vtinput_notify_statusq(void *vsc, struct vqueue_info *vq)
185054accacSCorvin Köhne {
186054accacSCorvin Köhne 	struct pci_vtinput_softc *sc = vsc;
187054accacSCorvin Köhne 
188054accacSCorvin Köhne 	while (vq_has_descs(vq)) {
189054accacSCorvin Köhne 		/* get descriptor chain */
190054accacSCorvin Köhne 		struct iovec iov;
191054accacSCorvin Köhne 		struct vi_req req;
192054accacSCorvin Köhne 		const int n = vq_getchain(vq, &iov, 1, &req);
193054accacSCorvin Köhne 		if (n <= 0) {
194054accacSCorvin Köhne 			WPRINTF(("%s: invalid descriptor: %d", __func__, n));
195054accacSCorvin Köhne 			return;
196054accacSCorvin Köhne 		}
197054accacSCorvin Köhne 
198054accacSCorvin Köhne 		/* get event */
199054accacSCorvin Köhne 		struct vtinput_event event;
200054accacSCorvin Köhne 		memcpy(&event, iov.iov_base, sizeof(event));
201054accacSCorvin Köhne 
202054accacSCorvin Köhne 		/*
203054accacSCorvin Köhne 		 * on multi touch devices:
204054accacSCorvin Köhne 		 * - host send EV_MSC to guest
205054accacSCorvin Köhne 		 * - guest sends EV_MSC back to host
206054accacSCorvin Köhne 		 * - host writes EV_MSC to evdev
207054accacSCorvin Köhne 		 * - evdev saves EV_MSC in it's event buffer
208054accacSCorvin Köhne 		 * - host receives an extra EV_MSC by reading the evdev event
209054accacSCorvin Köhne 		 *   buffer
210054accacSCorvin Köhne 		 * - frames become larger and larger
211054accacSCorvin Köhne 		 * avoid endless loops by ignoring EV_MSC
212054accacSCorvin Köhne 		 */
213054accacSCorvin Köhne 		if (event.type == EV_MSC) {
214054accacSCorvin Köhne 			vq_relchain(vq, req.idx, sizeof(event));
215054accacSCorvin Köhne 			continue;
216054accacSCorvin Köhne 		}
217054accacSCorvin Köhne 
218054accacSCorvin Köhne 		/* send event to evdev */
219054accacSCorvin Köhne 		struct input_event host_event;
220054accacSCorvin Köhne 		host_event.type = event.type;
221054accacSCorvin Köhne 		host_event.code = event.code;
222054accacSCorvin Köhne 		host_event.value = event.value;
223054accacSCorvin Köhne 		if (gettimeofday(&host_event.time, NULL) != 0) {
224054accacSCorvin Köhne 			WPRINTF(("%s: failed gettimeofday", __func__));
225054accacSCorvin Köhne 		}
226054accacSCorvin Köhne 		if (write(sc->vsc_fd, &host_event, sizeof(host_event)) == -1) {
227054accacSCorvin Köhne 			WPRINTF(("%s: failed to write host_event", __func__));
228054accacSCorvin Köhne 		}
229054accacSCorvin Köhne 
230054accacSCorvin Köhne 		vq_relchain(vq, req.idx, sizeof(event));
231054accacSCorvin Köhne 	}
232054accacSCorvin Köhne 	vq_endchains(vq, 1);
233054accacSCorvin Köhne }
234054accacSCorvin Köhne 
235054accacSCorvin Köhne static int
pci_vtinput_get_bitmap(struct pci_vtinput_softc * sc,int cmd,int count)236054accacSCorvin Köhne pci_vtinput_get_bitmap(struct pci_vtinput_softc *sc, int cmd, int count)
237054accacSCorvin Köhne {
238054accacSCorvin Köhne 	if (count <= 0 || !sc) {
239054accacSCorvin Köhne 		return (-1);
240054accacSCorvin Köhne 	}
241054accacSCorvin Köhne 
242054accacSCorvin Köhne 	/* query bitmap */
243054accacSCorvin Köhne 	memset(sc->vsc_config.u.bitmap, 0, sizeof(sc->vsc_config.u.bitmap));
244054accacSCorvin Köhne 	if (ioctl(sc->vsc_fd, cmd, sc->vsc_config.u.bitmap) < 0) {
245054accacSCorvin Köhne 		return (-1);
246054accacSCorvin Köhne 	}
247054accacSCorvin Köhne 
248054accacSCorvin Köhne 	/* get number of set bytes in bitmap */
249054accacSCorvin Köhne 	for (int i = count - 1; i >= 0; i--) {
250054accacSCorvin Köhne 		if (sc->vsc_config.u.bitmap[i]) {
251054accacSCorvin Köhne 			return i + 1;
252054accacSCorvin Köhne 		}
253054accacSCorvin Köhne 	}
254054accacSCorvin Köhne 
255054accacSCorvin Köhne 	return (-1);
256054accacSCorvin Köhne }
257054accacSCorvin Köhne 
258054accacSCorvin Köhne static int
pci_vtinput_read_config_id_name(struct pci_vtinput_softc * sc)259054accacSCorvin Köhne pci_vtinput_read_config_id_name(struct pci_vtinput_softc *sc)
260054accacSCorvin Köhne {
261054accacSCorvin Köhne 	char name[128];
262054accacSCorvin Köhne 	if (ioctl(sc->vsc_fd, EVIOCGNAME(sizeof(name) - 1), name) < 0) {
263054accacSCorvin Köhne 		return (1);
264054accacSCorvin Köhne 	}
265054accacSCorvin Köhne 
266054accacSCorvin Köhne 	memcpy(sc->vsc_config.u.string, name, sizeof(name));
267054accacSCorvin Köhne 	sc->vsc_config.size = strnlen(name, sizeof(name));
268054accacSCorvin Köhne 
269054accacSCorvin Köhne 	return (0);
270054accacSCorvin Köhne }
271054accacSCorvin Köhne 
272054accacSCorvin Köhne static int
pci_vtinput_read_config_id_serial(struct pci_vtinput_softc * sc)273054accacSCorvin Köhne pci_vtinput_read_config_id_serial(struct pci_vtinput_softc *sc)
274054accacSCorvin Köhne {
275054accacSCorvin Köhne 	/* serial isn't supported */
276054accacSCorvin Köhne 	sc->vsc_config.size = 0;
277054accacSCorvin Köhne 
278054accacSCorvin Köhne 	return (0);
279054accacSCorvin Köhne }
280054accacSCorvin Köhne 
281054accacSCorvin Köhne static int
pci_vtinput_read_config_id_devids(struct pci_vtinput_softc * sc)282054accacSCorvin Köhne pci_vtinput_read_config_id_devids(struct pci_vtinput_softc *sc)
283054accacSCorvin Köhne {
284054accacSCorvin Köhne 	struct input_id devids;
285054accacSCorvin Köhne 	if (ioctl(sc->vsc_fd, EVIOCGID, &devids)) {
286054accacSCorvin Köhne 		return (1);
287054accacSCorvin Köhne 	}
288054accacSCorvin Köhne 
289054accacSCorvin Köhne 	sc->vsc_config.u.ids.bustype = devids.bustype;
290054accacSCorvin Köhne 	sc->vsc_config.u.ids.vendor = devids.vendor;
291054accacSCorvin Köhne 	sc->vsc_config.u.ids.product = devids.product;
292054accacSCorvin Köhne 	sc->vsc_config.u.ids.version = devids.version;
293054accacSCorvin Köhne 	sc->vsc_config.size = sizeof(struct vtinput_devids);
294054accacSCorvin Köhne 
295054accacSCorvin Köhne 	return (0);
296054accacSCorvin Köhne }
297054accacSCorvin Köhne 
298054accacSCorvin Köhne static int
pci_vtinput_read_config_prop_bits(struct pci_vtinput_softc * sc)299054accacSCorvin Köhne pci_vtinput_read_config_prop_bits(struct pci_vtinput_softc *sc)
300054accacSCorvin Köhne {
301054accacSCorvin Köhne 	/*
302054accacSCorvin Köhne 	 * Evdev bitmap countains 1 bit per count. Additionally evdev bitmaps
303054accacSCorvin Köhne 	 * are arrays of longs instead of chars. Calculate how many longs are
304054accacSCorvin Köhne 	 * required for evdev bitmap. Multiply that with sizeof(long) to get the
305054accacSCorvin Köhne 	 * number of elements.
306054accacSCorvin Köhne 	 */
307054accacSCorvin Köhne 	const int count = howmany(INPUT_PROP_CNT, sizeof(long) * 8) *
308054accacSCorvin Köhne 	    sizeof(long);
309054accacSCorvin Köhne 	const unsigned int cmd = EVIOCGPROP(count);
310054accacSCorvin Köhne 	const int size = pci_vtinput_get_bitmap(sc, cmd, count);
311054accacSCorvin Köhne 	if (size <= 0) {
312054accacSCorvin Köhne 		return (1);
313054accacSCorvin Köhne 	}
314054accacSCorvin Köhne 
315054accacSCorvin Köhne 	sc->vsc_config.size = size;
316054accacSCorvin Köhne 
317054accacSCorvin Köhne 	return (0);
318054accacSCorvin Köhne }
319054accacSCorvin Köhne 
320054accacSCorvin Köhne static int
pci_vtinput_read_config_ev_bits(struct pci_vtinput_softc * sc,uint8_t type)321054accacSCorvin Köhne pci_vtinput_read_config_ev_bits(struct pci_vtinput_softc *sc, uint8_t type)
322054accacSCorvin Köhne {
323054accacSCorvin Köhne 	int count;
324054accacSCorvin Köhne 
325054accacSCorvin Köhne 	switch (type) {
326054accacSCorvin Köhne 	case EV_KEY:
327054accacSCorvin Köhne 		count = KEY_CNT;
328054accacSCorvin Köhne 		break;
329054accacSCorvin Köhne 	case EV_REL:
330054accacSCorvin Köhne 		count = REL_CNT;
331054accacSCorvin Köhne 		break;
332054accacSCorvin Köhne 	case EV_ABS:
333054accacSCorvin Köhne 		count = ABS_CNT;
334054accacSCorvin Köhne 		break;
335054accacSCorvin Köhne 	case EV_MSC:
336054accacSCorvin Köhne 		count = MSC_CNT;
337054accacSCorvin Köhne 		break;
338054accacSCorvin Köhne 	case EV_SW:
339054accacSCorvin Köhne 		count = SW_CNT;
340054accacSCorvin Köhne 		break;
341054accacSCorvin Köhne 	case EV_LED:
342054accacSCorvin Köhne 		count = LED_CNT;
343054accacSCorvin Köhne 		break;
344054accacSCorvin Köhne 	default:
345054accacSCorvin Köhne 		return (1);
346054accacSCorvin Köhne 	}
347054accacSCorvin Köhne 
348054accacSCorvin Köhne 	/*
349054accacSCorvin Köhne 	 * Evdev bitmap countains 1 bit per count. Additionally evdev bitmaps
350054accacSCorvin Köhne 	 * are arrays of longs instead of chars. Calculate how many longs are
351054accacSCorvin Köhne 	 * required for evdev bitmap. Multiply that with sizeof(long) to get the
352054accacSCorvin Köhne 	 * number of elements.
353054accacSCorvin Köhne 	 */
354054accacSCorvin Köhne 	count = howmany(count, sizeof(long) * 8) * sizeof(long);
355054accacSCorvin Köhne 	const unsigned int cmd = EVIOCGBIT(sc->vsc_config.subsel, count);
356054accacSCorvin Köhne 	const int size = pci_vtinput_get_bitmap(sc, cmd, count);
357054accacSCorvin Köhne 	if (size <= 0) {
358054accacSCorvin Köhne 		return (1);
359054accacSCorvin Köhne 	}
360054accacSCorvin Köhne 
361054accacSCorvin Köhne 	sc->vsc_config.size = size;
362054accacSCorvin Köhne 
363054accacSCorvin Köhne 	return (0);
364054accacSCorvin Köhne }
365054accacSCorvin Köhne 
366054accacSCorvin Köhne static int
pci_vtinput_read_config_abs_info(struct pci_vtinput_softc * sc)367054accacSCorvin Köhne pci_vtinput_read_config_abs_info(struct pci_vtinput_softc *sc)
368054accacSCorvin Köhne {
369054accacSCorvin Köhne 	/* check if evdev has EV_ABS */
370054accacSCorvin Köhne 	if (!pci_vtinput_read_config_ev_bits(sc, EV_ABS)) {
371054accacSCorvin Köhne 		return (1);
372054accacSCorvin Köhne 	}
373054accacSCorvin Köhne 
374054accacSCorvin Köhne 	/* get abs information */
375054accacSCorvin Köhne 	struct input_absinfo abs;
376054accacSCorvin Köhne 	if (ioctl(sc->vsc_fd, EVIOCGABS(sc->vsc_config.subsel), &abs) < 0) {
377054accacSCorvin Köhne 		return (1);
378054accacSCorvin Köhne 	}
379054accacSCorvin Köhne 
380054accacSCorvin Köhne 	/* save abs information */
381054accacSCorvin Köhne 	sc->vsc_config.u.abs.min = abs.minimum;
382054accacSCorvin Köhne 	sc->vsc_config.u.abs.max = abs.maximum;
383054accacSCorvin Köhne 	sc->vsc_config.u.abs.fuzz = abs.fuzz;
384054accacSCorvin Köhne 	sc->vsc_config.u.abs.flat = abs.flat;
385054accacSCorvin Köhne 	sc->vsc_config.u.abs.res = abs.resolution;
386054accacSCorvin Köhne 	sc->vsc_config.size = sizeof(struct vtinput_absinfo);
387054accacSCorvin Köhne 
388054accacSCorvin Köhne 	return (0);
389054accacSCorvin Köhne }
390054accacSCorvin Köhne 
391054accacSCorvin Köhne static int
pci_vtinput_read_config(struct pci_vtinput_softc * sc)392054accacSCorvin Köhne pci_vtinput_read_config(struct pci_vtinput_softc *sc)
393054accacSCorvin Köhne {
394054accacSCorvin Köhne 	switch (sc->vsc_config.select) {
395054accacSCorvin Köhne 	case VTINPUT_CFG_UNSET:
396054accacSCorvin Köhne 		return (0);
397054accacSCorvin Köhne 	case VTINPUT_CFG_ID_NAME:
398054accacSCorvin Köhne 		return pci_vtinput_read_config_id_name(sc);
399054accacSCorvin Köhne 	case VTINPUT_CFG_ID_SERIAL:
400054accacSCorvin Köhne 		return pci_vtinput_read_config_id_serial(sc);
401054accacSCorvin Köhne 	case VTINPUT_CFG_ID_DEVIDS:
402054accacSCorvin Köhne 		return pci_vtinput_read_config_id_devids(sc);
403054accacSCorvin Köhne 	case VTINPUT_CFG_PROP_BITS:
404054accacSCorvin Köhne 		return pci_vtinput_read_config_prop_bits(sc);
405054accacSCorvin Köhne 	case VTINPUT_CFG_EV_BITS:
406054accacSCorvin Köhne 		return pci_vtinput_read_config_ev_bits(
407054accacSCorvin Köhne 		    sc, sc->vsc_config.subsel);
408054accacSCorvin Köhne 	case VTINPUT_CFG_ABS_INFO:
409054accacSCorvin Köhne 		return pci_vtinput_read_config_abs_info(sc);
410054accacSCorvin Köhne 	default:
411054accacSCorvin Köhne 		return (1);
412054accacSCorvin Köhne 	}
413054accacSCorvin Köhne }
414054accacSCorvin Köhne 
415054accacSCorvin Köhne static int
pci_vtinput_cfgread(void * vsc,int offset,int size,uint32_t * retval)416054accacSCorvin Köhne pci_vtinput_cfgread(void *vsc, int offset, int size, uint32_t *retval)
417054accacSCorvin Köhne {
418054accacSCorvin Köhne 	struct pci_vtinput_softc *sc = vsc;
419054accacSCorvin Köhne 
420054accacSCorvin Köhne 	/* check for valid offset and size */
421ed721684SMark Johnston 	if (offset + size > (int)sizeof(struct vtinput_config)) {
422054accacSCorvin Köhne 		WPRINTF(("%s: read to invalid offset/size %d/%d", __func__,
423054accacSCorvin Köhne 		    offset, size));
424054accacSCorvin Köhne 		memset(retval, 0, size);
425054accacSCorvin Köhne 		return (0);
426054accacSCorvin Köhne 	}
427054accacSCorvin Köhne 
428054accacSCorvin Köhne 	/* read new config values, if select and subsel changed. */
429054accacSCorvin Köhne 	if (!sc->vsc_config_valid) {
430054accacSCorvin Köhne 		if (pci_vtinput_read_config(sc) != 0) {
431054accacSCorvin Köhne 			DPRINTF(("%s: could not read config %d/%d", __func__,
432054accacSCorvin Köhne 			    sc->vsc_config.select, sc->vsc_config.subsel));
433054accacSCorvin Köhne 			memset(retval, 0, size);
434054accacSCorvin Köhne 			return (0);
435054accacSCorvin Köhne 		}
436054accacSCorvin Köhne 		sc->vsc_config_valid = 1;
437054accacSCorvin Köhne 	}
438054accacSCorvin Köhne 
439054accacSCorvin Köhne 	uint8_t *ptr = (uint8_t *)&sc->vsc_config;
440054accacSCorvin Köhne 	memcpy(retval, ptr + offset, size);
441054accacSCorvin Köhne 
442054accacSCorvin Köhne 	return (0);
443054accacSCorvin Köhne }
444054accacSCorvin Köhne 
445054accacSCorvin Köhne static int
pci_vtinput_cfgwrite(void * vsc,int offset,int size,uint32_t value)446054accacSCorvin Köhne pci_vtinput_cfgwrite(void *vsc, int offset, int size, uint32_t value)
447054accacSCorvin Köhne {
448054accacSCorvin Köhne 	struct pci_vtinput_softc *sc = vsc;
449054accacSCorvin Köhne 
450054accacSCorvin Köhne 	/* guest can only write to select and subsel fields */
451054accacSCorvin Köhne 	if (offset + size > 2) {
452054accacSCorvin Köhne 		WPRINTF(("%s: write to readonly reg %d", __func__, offset));
453054accacSCorvin Köhne 		return (1);
454054accacSCorvin Köhne 	}
455054accacSCorvin Köhne 
456054accacSCorvin Köhne 	/* copy value into config */
457054accacSCorvin Köhne 	uint8_t *ptr = (uint8_t *)&sc->vsc_config;
458054accacSCorvin Köhne 	memcpy(ptr + offset, &value, size);
459054accacSCorvin Köhne 
460054accacSCorvin Köhne 	/* select/subsel changed, query new config on next cfgread */
461054accacSCorvin Köhne 	sc->vsc_config_valid = 0;
462054accacSCorvin Köhne 
463054accacSCorvin Köhne 	return (0);
464054accacSCorvin Köhne }
465054accacSCorvin Köhne 
466054accacSCorvin Köhne static int
vtinput_eventqueue_add_event(struct vtinput_eventqueue * queue,struct input_event * e)467054accacSCorvin Köhne vtinput_eventqueue_add_event(
468054accacSCorvin Köhne     struct vtinput_eventqueue *queue, struct input_event *e)
469054accacSCorvin Köhne {
470054accacSCorvin Köhne 	/* check if queue is full */
471054accacSCorvin Köhne 	if (queue->idx >= queue->size) {
472054accacSCorvin Köhne 		/* alloc new elements for queue */
473054accacSCorvin Köhne 		const uint32_t newSize = queue->idx;
474eefd863cSMark Johnston 		void *newPtr = realloc(queue->events,
475054accacSCorvin Köhne 		    queue->size * sizeof(struct vtinput_event_elem));
476054accacSCorvin Köhne 		if (newPtr == NULL) {
477054accacSCorvin Köhne 			WPRINTF(("%s: realloc memory for eventqueue failed!",
478054accacSCorvin Köhne 			    __func__));
479054accacSCorvin Köhne 			return (1);
480054accacSCorvin Köhne 		}
481eefd863cSMark Johnston 		queue->events = newPtr;
482054accacSCorvin Köhne 		queue->size = newSize;
483054accacSCorvin Köhne 	}
484054accacSCorvin Köhne 
485054accacSCorvin Köhne 	/* save event */
486054accacSCorvin Köhne 	struct vtinput_event *event = &queue->events[queue->idx].event;
487054accacSCorvin Köhne 	event->type = e->type;
488054accacSCorvin Köhne 	event->code = e->code;
489054accacSCorvin Köhne 	event->value = e->value;
490054accacSCorvin Köhne 	queue->idx++;
491054accacSCorvin Köhne 
492054accacSCorvin Köhne 	return (0);
493054accacSCorvin Köhne }
494054accacSCorvin Köhne 
495054accacSCorvin Köhne static void
vtinput_eventqueue_clear(struct vtinput_eventqueue * queue)496054accacSCorvin Köhne vtinput_eventqueue_clear(struct vtinput_eventqueue *queue)
497054accacSCorvin Köhne {
498054accacSCorvin Köhne 	/* just reset index to clear queue */
499054accacSCorvin Köhne 	queue->idx = 0;
500054accacSCorvin Köhne }
501054accacSCorvin Köhne 
502054accacSCorvin Köhne static void
vtinput_eventqueue_send_events(struct vtinput_eventqueue * queue,struct vqueue_info * vq)503054accacSCorvin Köhne vtinput_eventqueue_send_events(
504054accacSCorvin Köhne     struct vtinput_eventqueue *queue, struct vqueue_info *vq)
505054accacSCorvin Köhne {
506054accacSCorvin Köhne 	/*
507054accacSCorvin Köhne 	 * First iteration through eventqueue:
508054accacSCorvin Köhne 	 *   Get descriptor chains.
509054accacSCorvin Köhne 	 */
510054accacSCorvin Köhne 	for (uint32_t i = 0; i < queue->idx; ++i) {
511054accacSCorvin Köhne 		/* get descriptor */
512054accacSCorvin Köhne 		if (!vq_has_descs(vq)) {
513054accacSCorvin Köhne 			/*
514054accacSCorvin Köhne 			 * We don't have enough descriptors for all events.
515054accacSCorvin Köhne 			 * Return chains back to guest.
516054accacSCorvin Köhne 			 */
517054accacSCorvin Köhne 			vq_retchains(vq, i);
518054accacSCorvin Köhne 			WPRINTF((
519054accacSCorvin Köhne 			    "%s: not enough available descriptors, dropping %d events",
520054accacSCorvin Köhne 			    __func__, queue->idx));
521054accacSCorvin Köhne 			goto done;
522054accacSCorvin Köhne 		}
523054accacSCorvin Köhne 
524054accacSCorvin Köhne 		/* get descriptor chain */
525054accacSCorvin Köhne 		struct iovec iov;
526054accacSCorvin Köhne 		struct vi_req req;
527054accacSCorvin Köhne 		const int n = vq_getchain(vq, &iov, 1, &req);
528054accacSCorvin Köhne 		if (n <= 0) {
529054accacSCorvin Köhne 			WPRINTF(("%s: invalid descriptor: %d", __func__, n));
530054accacSCorvin Köhne 			return;
531054accacSCorvin Köhne 		}
532054accacSCorvin Köhne 		if (n != 1) {
533054accacSCorvin Köhne 			WPRINTF(
534054accacSCorvin Köhne 			    ("%s: invalid number of descriptors in chain: %d",
535054accacSCorvin Köhne 				__func__, n));
536054accacSCorvin Köhne 			/* release invalid chain */
537054accacSCorvin Köhne 			vq_relchain(vq, req.idx, 0);
538054accacSCorvin Köhne 			return;
539054accacSCorvin Köhne 		}
540054accacSCorvin Köhne 		if (iov.iov_len < sizeof(struct vtinput_event)) {
541054accacSCorvin Köhne 			WPRINTF(("%s: invalid descriptor length: %lu", __func__,
542054accacSCorvin Köhne 			    iov.iov_len));
543054accacSCorvin Köhne 			/* release invalid chain */
544054accacSCorvin Köhne 			vq_relchain(vq, req.idx, 0);
545054accacSCorvin Köhne 			return;
546054accacSCorvin Köhne 		}
547054accacSCorvin Köhne 
548054accacSCorvin Köhne 		/* save descriptor */
549054accacSCorvin Köhne 		queue->events[i].iov = iov;
550054accacSCorvin Köhne 		queue->events[i].idx = req.idx;
551054accacSCorvin Köhne 	}
552054accacSCorvin Köhne 
553054accacSCorvin Köhne 	/*
554054accacSCorvin Köhne 	 * Second iteration through eventqueue:
555054accacSCorvin Köhne 	 *   Send events to guest by releasing chains
556054accacSCorvin Köhne 	 */
557054accacSCorvin Köhne 	for (uint32_t i = 0; i < queue->idx; ++i) {
558054accacSCorvin Köhne 		struct vtinput_event_elem event = queue->events[i];
559054accacSCorvin Köhne 		memcpy(event.iov.iov_base, &event.event,
560054accacSCorvin Köhne 		    sizeof(struct vtinput_event));
561054accacSCorvin Köhne 		vq_relchain(vq, event.idx, sizeof(struct vtinput_event));
562054accacSCorvin Köhne 	}
563054accacSCorvin Köhne done:
564054accacSCorvin Köhne 	/* clear queue and send interrupt to guest */
565054accacSCorvin Köhne 	vtinput_eventqueue_clear(queue);
566054accacSCorvin Köhne 	vq_endchains(vq, 1);
567054accacSCorvin Köhne }
568054accacSCorvin Köhne 
569054accacSCorvin Köhne static int
vtinput_read_event_from_host(int fd,struct input_event * event)570054accacSCorvin Köhne vtinput_read_event_from_host(int fd, struct input_event *event)
571054accacSCorvin Köhne {
572054accacSCorvin Köhne 	const int len = read(fd, event, sizeof(struct input_event));
573054accacSCorvin Köhne 	if (len != sizeof(struct input_event)) {
574054accacSCorvin Köhne 		if (len == -1 && errno != EAGAIN) {
575054accacSCorvin Köhne 			WPRINTF(("%s: event read failed! len = %d, errno = %d",
576054accacSCorvin Köhne 			    __func__, len, errno));
577054accacSCorvin Köhne 		}
578054accacSCorvin Köhne 
579054accacSCorvin Köhne 		/* host doesn't have more events for us */
580054accacSCorvin Köhne 		return (1);
581054accacSCorvin Köhne 	}
582054accacSCorvin Köhne 
583054accacSCorvin Köhne 	return (0);
584054accacSCorvin Köhne }
585054accacSCorvin Köhne 
586054accacSCorvin Köhne static void
vtinput_read_event(int fd __attribute ((unused)),enum ev_type t,void * arg)587054accacSCorvin Köhne vtinput_read_event(int fd __attribute((unused)),
588054accacSCorvin Köhne     enum ev_type t __attribute__((unused)), void *arg __attribute__((unused)))
589054accacSCorvin Köhne {
590054accacSCorvin Köhne 	struct pci_vtinput_softc *sc = arg;
591054accacSCorvin Köhne 
592054accacSCorvin Köhne 	/* skip if driver isn't ready */
593054accacSCorvin Köhne 	if (!(sc->vsc_vs.vs_status & VIRTIO_CONFIG_STATUS_DRIVER_OK))
594054accacSCorvin Köhne 		return;
595054accacSCorvin Köhne 
596054accacSCorvin Köhne 	/* read all events from host */
597054accacSCorvin Köhne 	struct input_event event;
598054accacSCorvin Köhne 	while (vtinput_read_event_from_host(sc->vsc_fd, &event) == 0) {
599054accacSCorvin Köhne 		/* add events to our queue */
600054accacSCorvin Köhne 		vtinput_eventqueue_add_event(&sc->vsc_eventqueue, &event);
601054accacSCorvin Köhne 
602054accacSCorvin Köhne 		/* only send events to guest on EV_SYN or SYN_REPORT */
603054accacSCorvin Köhne 		if (event.type != EV_SYN || event.type != SYN_REPORT) {
604054accacSCorvin Köhne 			continue;
605054accacSCorvin Köhne 		}
606054accacSCorvin Köhne 
607054accacSCorvin Köhne 		/* send host events to guest */
608054accacSCorvin Köhne 		vtinput_eventqueue_send_events(
609054accacSCorvin Köhne 		    &sc->vsc_eventqueue, &sc->vsc_queues[VTINPUT_EVENTQ]);
610054accacSCorvin Köhne 	}
611054accacSCorvin Köhne }
612054accacSCorvin Köhne 
613054accacSCorvin Köhne static int
pci_vtinput_legacy_config(nvlist_t * nvl,const char * opts)614054accacSCorvin Köhne pci_vtinput_legacy_config(nvlist_t *nvl, const char *opts)
615054accacSCorvin Köhne {
616054accacSCorvin Köhne 	if (opts == NULL)
617054accacSCorvin Köhne 		return (-1);
618054accacSCorvin Köhne 
619054accacSCorvin Köhne 	/*
620054accacSCorvin Köhne 	 * parse opts:
621054accacSCorvin Köhne 	 *   virtio-input,/dev/input/eventX
622054accacSCorvin Köhne 	 */
623054accacSCorvin Köhne 	char *cp = strchr(opts, ',');
624054accacSCorvin Köhne 	if (cp == NULL) {
625054accacSCorvin Köhne 		set_config_value_node(nvl, "path", opts);
626054accacSCorvin Köhne 		return (0);
627054accacSCorvin Köhne 	}
628054accacSCorvin Köhne 	char *path = strndup(opts, cp - opts);
629054accacSCorvin Köhne 	set_config_value_node(nvl, "path", path);
630054accacSCorvin Köhne 	free(path);
631054accacSCorvin Köhne 
632054accacSCorvin Köhne 	return (pci_parse_legacy_config(nvl, cp + 1));
633054accacSCorvin Köhne }
634054accacSCorvin Köhne 
635054accacSCorvin Köhne static int
pci_vtinput_init(struct pci_devinst * pi,nvlist_t * nvl)6366a284cacSJohn Baldwin pci_vtinput_init(struct pci_devinst *pi, nvlist_t *nvl)
637054accacSCorvin Köhne {
638054accacSCorvin Köhne 	struct pci_vtinput_softc *sc;
639054accacSCorvin Köhne 
640054accacSCorvin Köhne 	/*
641054accacSCorvin Köhne 	 * Keep it here.
642054accacSCorvin Köhne 	 * Else it's possible to access it uninitialized by jumping to failed.
643054accacSCorvin Köhne 	 */
644054accacSCorvin Köhne 	pthread_mutexattr_t mtx_attr = NULL;
645054accacSCorvin Köhne 
646054accacSCorvin Köhne 	sc = calloc(1, sizeof(struct pci_vtinput_softc));
647054accacSCorvin Köhne 
648054accacSCorvin Köhne 	sc->vsc_evdev = get_config_value_node(nvl, "path");
649054accacSCorvin Köhne 	if (sc->vsc_evdev == NULL) {
650054accacSCorvin Köhne 		WPRINTF(("%s: missing required path config value", __func__));
651054accacSCorvin Köhne 		goto failed;
652054accacSCorvin Köhne 	}
653054accacSCorvin Köhne 
654054accacSCorvin Köhne 	/*
655054accacSCorvin Köhne 	 * open evdev by using non blocking I/O:
656054accacSCorvin Köhne 	 *   read from /dev/input/eventX would block our thread otherwise
657054accacSCorvin Köhne 	 */
658054accacSCorvin Köhne 	sc->vsc_fd = open(sc->vsc_evdev, O_RDWR | O_NONBLOCK);
659054accacSCorvin Köhne 	if (sc->vsc_fd < 0) {
660054accacSCorvin Köhne 		WPRINTF(("%s: failed to open %s", __func__, sc->vsc_evdev));
661054accacSCorvin Köhne 		goto failed;
662054accacSCorvin Köhne 	}
663054accacSCorvin Köhne 
664054accacSCorvin Köhne 	/* check if evdev is really a evdev */
665054accacSCorvin Köhne 	int evversion;
666054accacSCorvin Köhne 	int error = ioctl(sc->vsc_fd, EVIOCGVERSION, &evversion);
667054accacSCorvin Köhne 	if (error < 0) {
668054accacSCorvin Köhne 		WPRINTF(("%s: %s is no evdev", __func__, sc->vsc_evdev));
669054accacSCorvin Köhne 		goto failed;
670054accacSCorvin Köhne 	}
671054accacSCorvin Köhne 
672054accacSCorvin Köhne 	/* gain exclusive access to evdev */
673054accacSCorvin Köhne 	error = ioctl(sc->vsc_fd, EVIOCGRAB, 1);
674054accacSCorvin Köhne 	if (error < 0) {
675054accacSCorvin Köhne 		WPRINTF(("%s: failed to grab %s", __func__, sc->vsc_evdev));
676054accacSCorvin Köhne 		goto failed;
677054accacSCorvin Köhne 	}
678054accacSCorvin Köhne 
679054accacSCorvin Köhne 	if (pthread_mutexattr_init(&mtx_attr)) {
680054accacSCorvin Köhne 		WPRINTF(("%s: init mutexattr failed", __func__));
681054accacSCorvin Köhne 		goto failed;
682054accacSCorvin Köhne 	}
683054accacSCorvin Köhne 	if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_RECURSIVE)) {
684054accacSCorvin Köhne 		WPRINTF(("%s: settype mutexattr failed", __func__));
685054accacSCorvin Köhne 		goto failed;
686054accacSCorvin Köhne 	}
687054accacSCorvin Köhne 	if (pthread_mutex_init(&sc->vsc_mtx, &mtx_attr)) {
688054accacSCorvin Köhne 		WPRINTF(("%s: init mutex failed", __func__));
689054accacSCorvin Köhne 		goto failed;
690054accacSCorvin Köhne 	}
691054accacSCorvin Köhne 
692054accacSCorvin Köhne 	/* init softc */
693054accacSCorvin Köhne 	sc->vsc_eventqueue.idx = 0;
694054accacSCorvin Köhne 	sc->vsc_eventqueue.size = VTINPUT_MAX_PKT_LEN;
695054accacSCorvin Köhne 	sc->vsc_eventqueue.events = calloc(
696054accacSCorvin Köhne 	    sc->vsc_eventqueue.size, sizeof(struct vtinput_event_elem));
697054accacSCorvin Köhne 	sc->vsc_config_valid = 0;
698054accacSCorvin Köhne 	if (sc->vsc_eventqueue.events == NULL) {
699054accacSCorvin Köhne 		WPRINTF(("%s: failed to alloc eventqueue", __func__));
700054accacSCorvin Köhne 		goto failed;
701054accacSCorvin Köhne 	}
702054accacSCorvin Köhne 
703054accacSCorvin Köhne 	/* register event handler */
704054accacSCorvin Köhne 	sc->vsc_evp = mevent_add(sc->vsc_fd, EVF_READ, vtinput_read_event, sc);
705054accacSCorvin Köhne 	if (sc->vsc_evp == NULL) {
706054accacSCorvin Köhne 		WPRINTF(("%s: could not register mevent", __func__));
707054accacSCorvin Köhne 		goto failed;
708054accacSCorvin Köhne 	}
709054accacSCorvin Köhne 
710054accacSCorvin Köhne #ifndef WITHOUT_CAPSICUM
711054accacSCorvin Köhne 	cap_rights_t rights;
712054accacSCorvin Köhne 	cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE);
713054accacSCorvin Köhne 	if (caph_rights_limit(sc->vsc_fd, &rights) == -1) {
714054accacSCorvin Köhne 		errx(EX_OSERR, "Unable to apply rights for sandbox");
715054accacSCorvin Köhne 	}
716054accacSCorvin Köhne #endif
717054accacSCorvin Köhne 
718054accacSCorvin Köhne 	/* link virtio to softc */
719054accacSCorvin Köhne 	vi_softc_linkup(
720054accacSCorvin Köhne 	    &sc->vsc_vs, &vtinput_vi_consts, sc, pi, sc->vsc_queues);
721054accacSCorvin Köhne 	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
722054accacSCorvin Köhne 
723054accacSCorvin Köhne 	/* init virtio queues */
724054accacSCorvin Köhne 	sc->vsc_queues[VTINPUT_EVENTQ].vq_qsize = VTINPUT_RINGSZ;
725054accacSCorvin Köhne 	sc->vsc_queues[VTINPUT_EVENTQ].vq_notify = pci_vtinput_notify_eventq;
726054accacSCorvin Köhne 	sc->vsc_queues[VTINPUT_STATUSQ].vq_qsize = VTINPUT_RINGSZ;
727054accacSCorvin Köhne 	sc->vsc_queues[VTINPUT_STATUSQ].vq_notify = pci_vtinput_notify_statusq;
728054accacSCorvin Köhne 
729054accacSCorvin Köhne 	/* initialize config space */
730054accacSCorvin Köhne 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_INPUT);
731054accacSCorvin Köhne 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
732054accacSCorvin Köhne 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_INPUTDEV);
733054accacSCorvin Köhne 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_INPUTDEV_OTHER);
734054accacSCorvin Köhne 	pci_set_cfgdata8(pi, PCIR_REVID, VIRTIO_REV_INPUT);
735054accacSCorvin Köhne 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_SUBDEV_INPUT);
736054accacSCorvin Köhne 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_SUBVEN_INPUT);
737054accacSCorvin Köhne 
738054accacSCorvin Köhne 	/* add MSI-X table BAR */
739054accacSCorvin Köhne 	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
740054accacSCorvin Köhne 		goto failed;
741054accacSCorvin Köhne 	/* add virtio register */
742054accacSCorvin Köhne 	vi_set_io_bar(&sc->vsc_vs, 0);
743054accacSCorvin Köhne 
744054accacSCorvin Köhne 	return (0);
745054accacSCorvin Köhne 
746054accacSCorvin Köhne failed:
747054accacSCorvin Köhne 	if (sc == NULL) {
748054accacSCorvin Köhne 		return (-1);
749054accacSCorvin Köhne 	}
750054accacSCorvin Köhne 
751054accacSCorvin Köhne 	if (sc->vsc_evp)
752054accacSCorvin Köhne 		mevent_delete(sc->vsc_evp);
753054accacSCorvin Köhne 	if (sc->vsc_eventqueue.events)
754054accacSCorvin Köhne 		free(sc->vsc_eventqueue.events);
755054accacSCorvin Köhne 	if (sc->vsc_mtx)
756054accacSCorvin Köhne 		pthread_mutex_destroy(&sc->vsc_mtx);
757054accacSCorvin Köhne 	if (mtx_attr)
758054accacSCorvin Köhne 		pthread_mutexattr_destroy(&mtx_attr);
759054accacSCorvin Köhne 	if (sc->vsc_fd)
760054accacSCorvin Köhne 		close(sc->vsc_fd);
761054accacSCorvin Köhne 
762054accacSCorvin Köhne 	free(sc);
763054accacSCorvin Köhne 
764054accacSCorvin Köhne 	return (-1);
765054accacSCorvin Köhne }
766054accacSCorvin Köhne 
76737045dfaSMark Johnston static const struct pci_devemu pci_de_vinput = {
768054accacSCorvin Köhne 	.pe_emu = "virtio-input",
769054accacSCorvin Köhne 	.pe_init = pci_vtinput_init,
770054accacSCorvin Köhne 	.pe_legacy_config = pci_vtinput_legacy_config,
771054accacSCorvin Köhne 	.pe_barwrite = vi_pci_write,
772054accacSCorvin Köhne 	.pe_barread = vi_pci_read,
773054accacSCorvin Köhne };
774054accacSCorvin Köhne PCI_EMUL_SET(pci_de_vinput);
775