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
7 #include "qemu/osdep.h"
8 #include "qapi/error.h"
9 #include "qemu/module.h"
10 #include "qemu/sockets.h"
12 #include "hw/virtio/virtio.h"
13 #include "hw/qdev-properties.h"
14 #include "hw/virtio/virtio-input.h"
16 #include <sys/ioctl.h>
17 #include "standard-headers/linux/input.h"
19 /* ----------------------------------------------------------------- */
21 static struct virtio_input_config virtio_input_host_config
[] = {
25 static void virtio_input_host_event(void *opaque
)
27 VirtIOInputHost
*vih
= opaque
;
28 VirtIOInput
*vinput
= VIRTIO_INPUT(vih
);
29 struct virtio_input_event virtio
;
30 struct input_event evdev
;
34 rc
= read(vih
->fd
, &evdev
, sizeof(evdev
));
35 if (rc
!= sizeof(evdev
)) {
39 virtio
.type
= cpu_to_le16(evdev
.type
);
40 virtio
.code
= cpu_to_le16(evdev
.code
);
41 virtio
.value
= cpu_to_le32(evdev
.value
);
42 virtio_input_send(vinput
, &virtio
);
46 static void virtio_input_bits_config(VirtIOInputHost
*vih
,
49 virtio_input_config bits
;
52 memset(&bits
, 0, sizeof(bits
));
53 rc
= ioctl(vih
->fd
, EVIOCGBIT(type
, count
/8), bits
.u
.bitmap
);
58 for (i
= 0; i
< count
/8; i
++) {
59 if (bits
.u
.bitmap
[i
]) {
67 bits
.select
= VIRTIO_INPUT_CFG_EV_BITS
;
70 virtio_input_add_config(VIRTIO_INPUT(vih
), &bits
);
73 static void virtio_input_abs_config(VirtIOInputHost
*vih
, int axis
)
75 virtio_input_config config
;
76 struct input_absinfo absinfo
;
79 rc
= ioctl(vih
->fd
, EVIOCGABS(axis
), &absinfo
);
84 memset(&config
, 0, sizeof(config
));
85 config
.select
= VIRTIO_INPUT_CFG_ABS_INFO
;
87 config
.size
= sizeof(virtio_input_absinfo
);
89 config
.u
.abs
.min
= cpu_to_le32(absinfo
.minimum
);
90 config
.u
.abs
.max
= cpu_to_le32(absinfo
.maximum
);
91 config
.u
.abs
.fuzz
= cpu_to_le32(absinfo
.fuzz
);
92 config
.u
.abs
.flat
= cpu_to_le32(absinfo
.flat
);
93 config
.u
.abs
.res
= cpu_to_le32(absinfo
.resolution
);
95 virtio_input_add_config(VIRTIO_INPUT(vih
), &config
);
98 static void virtio_input_host_realize(DeviceState
*dev
, Error
**errp
)
100 VirtIOInputHost
*vih
= VIRTIO_INPUT_HOST(dev
);
101 VirtIOInput
*vinput
= VIRTIO_INPUT(dev
);
102 virtio_input_config id
, *abs
;
104 int rc
, ver
, i
, axis
;
108 error_setg(errp
, "evdev property is required");
112 vih
->fd
= open(vih
->evdev
, O_RDWR
);
114 error_setg_file_open(errp
, errno
, vih
->evdev
);
117 qemu_set_nonblock(vih
->fd
);
119 rc
= ioctl(vih
->fd
, EVIOCGVERSION
, &ver
);
121 error_setg(errp
, "%s: is not an evdev device", vih
->evdev
);
125 rc
= ioctl(vih
->fd
, EVIOCGRAB
, 1);
127 error_setg_errno(errp
, errno
, "%s: failed to get exclusive access",
132 memset(&id
, 0, sizeof(id
));
133 ioctl(vih
->fd
, EVIOCGNAME(sizeof(id
.u
.string
)-1), id
.u
.string
);
134 id
.select
= VIRTIO_INPUT_CFG_ID_NAME
;
135 id
.size
= strlen(id
.u
.string
);
136 virtio_input_add_config(vinput
, &id
);
138 if (ioctl(vih
->fd
, EVIOCGID
, &ids
) == 0) {
139 memset(&id
, 0, sizeof(id
));
140 id
.select
= VIRTIO_INPUT_CFG_ID_DEVIDS
;
141 id
.size
= sizeof(struct virtio_input_devids
);
142 id
.u
.ids
.bustype
= cpu_to_le16(ids
.bustype
);
143 id
.u
.ids
.vendor
= cpu_to_le16(ids
.vendor
);
144 id
.u
.ids
.product
= cpu_to_le16(ids
.product
);
145 id
.u
.ids
.version
= cpu_to_le16(ids
.version
);
146 virtio_input_add_config(vinput
, &id
);
149 virtio_input_bits_config(vih
, EV_KEY
, KEY_CNT
);
150 virtio_input_bits_config(vih
, EV_REL
, REL_CNT
);
151 virtio_input_bits_config(vih
, EV_ABS
, ABS_CNT
);
152 virtio_input_bits_config(vih
, EV_MSC
, MSC_CNT
);
153 virtio_input_bits_config(vih
, EV_SW
, SW_CNT
);
154 virtio_input_bits_config(vih
, EV_LED
, LED_CNT
);
156 abs
= virtio_input_find_config(VIRTIO_INPUT(vih
),
157 VIRTIO_INPUT_CFG_EV_BITS
, EV_ABS
);
159 for (i
= 0; i
< abs
->size
; i
++) {
160 byte
= abs
->u
.bitmap
[i
];
164 virtio_input_abs_config(vih
, axis
);
172 qemu_set_fd_handler(vih
->fd
, virtio_input_host_event
, NULL
, vih
);
181 static void virtio_input_host_unrealize(DeviceState
*dev
)
183 VirtIOInputHost
*vih
= VIRTIO_INPUT_HOST(dev
);
186 qemu_set_fd_handler(vih
->fd
, NULL
, NULL
, NULL
);
191 static void virtio_input_host_handle_status(VirtIOInput
*vinput
,
192 virtio_input_event
*event
)
194 VirtIOInputHost
*vih
= VIRTIO_INPUT_HOST(vinput
);
195 struct input_event evdev
;
199 if (gettimeofday(&tval
, NULL
)) {
200 perror("virtio_input_host_handle_status: gettimeofday");
204 evdev
.input_event_sec
= tval
.tv_sec
;
205 evdev
.input_event_usec
= tval
.tv_usec
;
206 evdev
.type
= le16_to_cpu(event
->type
);
207 evdev
.code
= le16_to_cpu(event
->code
);
208 evdev
.value
= le32_to_cpu(event
->value
);
210 rc
= write(vih
->fd
, &evdev
, sizeof(evdev
));
212 perror("virtio_input_host_handle_status: write");
216 static const VMStateDescription vmstate_virtio_input_host
= {
217 .name
= "virtio-input-host",
221 static Property virtio_input_host_properties
[] = {
222 DEFINE_PROP_STRING("evdev", VirtIOInputHost
, evdev
),
223 DEFINE_PROP_END_OF_LIST(),
226 static void virtio_input_host_class_init(ObjectClass
*klass
, void *data
)
228 VirtIOInputClass
*vic
= VIRTIO_INPUT_CLASS(klass
);
229 DeviceClass
*dc
= DEVICE_CLASS(klass
);
231 dc
->vmsd
= &vmstate_virtio_input_host
;
232 device_class_set_props(dc
, virtio_input_host_properties
);
233 vic
->realize
= virtio_input_host_realize
;
234 vic
->unrealize
= virtio_input_host_unrealize
;
235 vic
->handle_status
= virtio_input_host_handle_status
;
238 static void virtio_input_host_init(Object
*obj
)
240 VirtIOInput
*vinput
= VIRTIO_INPUT(obj
);
242 virtio_input_init_config(vinput
, virtio_input_host_config
);
245 static const TypeInfo virtio_input_host_info
= {
246 .name
= TYPE_VIRTIO_INPUT_HOST
,
247 .parent
= TYPE_VIRTIO_INPUT
,
248 .instance_size
= sizeof(VirtIOInputHost
),
249 .instance_init
= virtio_input_host_init
,
250 .class_init
= virtio_input_host_class_init
,
253 /* ----------------------------------------------------------------- */
255 static void virtio_register_types(void)
257 type_register_static(&virtio_input_host_info
);
260 type_init(virtio_register_types
)