1
2
3
4
5
6
7#include "qemu/osdep.h"
8#include "qemu/iov.h"
9#include "qemu/module.h"
10
11#include "hw/virtio/virtio.h"
12#include "hw/qdev-properties.h"
13#include "hw/virtio/virtio-input.h"
14
15#include "ui/console.h"
16
17#include "standard-headers/linux/input.h"
18
19#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard"
20#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse"
21#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet"
22
23
24
25static const unsigned short keymap_button[INPUT_BUTTON__MAX] = {
26 [INPUT_BUTTON_LEFT] = BTN_LEFT,
27 [INPUT_BUTTON_RIGHT] = BTN_RIGHT,
28 [INPUT_BUTTON_MIDDLE] = BTN_MIDDLE,
29 [INPUT_BUTTON_WHEEL_UP] = BTN_GEAR_UP,
30 [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN,
31 [INPUT_BUTTON_SIDE] = BTN_SIDE,
32 [INPUT_BUTTON_EXTRA] = BTN_EXTRA,
33};
34
35static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
36 [INPUT_AXIS_X] = REL_X,
37 [INPUT_AXIS_Y] = REL_Y,
38};
39
40static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
41 [INPUT_AXIS_X] = ABS_X,
42 [INPUT_AXIS_Y] = ABS_Y,
43};
44
45
46
47static void virtio_input_key_config(VirtIOInput *vinput,
48 const unsigned short *keymap,
49 size_t mapsize)
50{
51 virtio_input_config keys;
52 int i, bit, byte, bmax = 0;
53
54 memset(&keys, 0, sizeof(keys));
55 for (i = 0; i < mapsize; i++) {
56 bit = keymap[i];
57 if (!bit) {
58 continue;
59 }
60 byte = bit / 8;
61 bit = bit % 8;
62 keys.u.bitmap[byte] |= (1 << bit);
63 if (bmax < byte+1) {
64 bmax = byte+1;
65 }
66 }
67 keys.select = VIRTIO_INPUT_CFG_EV_BITS;
68 keys.subsel = EV_KEY;
69 keys.size = bmax;
70 virtio_input_add_config(vinput, &keys);
71}
72
73static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
74 InputEvent *evt)
75{
76 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
77 VirtIOInput *vinput = VIRTIO_INPUT(dev);
78 virtio_input_event event;
79 int qcode;
80 InputKeyEvent *key;
81 InputMoveEvent *move;
82 InputBtnEvent *btn;
83
84 switch (evt->type) {
85 case INPUT_EVENT_KIND_KEY:
86 key = evt->u.key.data;
87 qcode = qemu_input_key_value_to_qcode(key->key);
88 if (qcode < qemu_input_map_qcode_to_linux_len &&
89 qemu_input_map_qcode_to_linux[qcode]) {
90 event.type = cpu_to_le16(EV_KEY);
91 event.code = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]);
92 event.value = cpu_to_le32(key->down ? 1 : 0);
93 virtio_input_send(vinput, &event);
94 } else {
95 if (key->down) {
96 fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
97 qcode, QKeyCode_str(qcode));
98 }
99 }
100 break;
101 case INPUT_EVENT_KIND_BTN:
102 btn = evt->u.btn.data;
103 if (vhid->wheel_axis &&
104 (btn->button == INPUT_BUTTON_WHEEL_UP ||
105 btn->button == INPUT_BUTTON_WHEEL_DOWN) &&
106 btn->down) {
107 event.type = cpu_to_le16(EV_REL);
108 event.code = cpu_to_le16(REL_WHEEL);
109 event.value = cpu_to_le32(btn->button == INPUT_BUTTON_WHEEL_UP
110 ? 1 : -1);
111 virtio_input_send(vinput, &event);
112 } else if (keymap_button[btn->button]) {
113 event.type = cpu_to_le16(EV_KEY);
114 event.code = cpu_to_le16(keymap_button[btn->button]);
115 event.value = cpu_to_le32(btn->down ? 1 : 0);
116 virtio_input_send(vinput, &event);
117 } else {
118 if (btn->down) {
119 fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
120 btn->button,
121 InputButton_str(btn->button));
122 }
123 }
124 break;
125 case INPUT_EVENT_KIND_REL:
126 move = evt->u.rel.data;
127 event.type = cpu_to_le16(EV_REL);
128 event.code = cpu_to_le16(axismap_rel[move->axis]);
129 event.value = cpu_to_le32(move->value);
130 virtio_input_send(vinput, &event);
131 break;
132 case INPUT_EVENT_KIND_ABS:
133 move = evt->u.abs.data;
134 event.type = cpu_to_le16(EV_ABS);
135 event.code = cpu_to_le16(axismap_abs[move->axis]);
136 event.value = cpu_to_le32(move->value);
137 virtio_input_send(vinput, &event);
138 break;
139 default:
140
141 break;
142 }
143}
144
145static void virtio_input_handle_sync(DeviceState *dev)
146{
147 VirtIOInput *vinput = VIRTIO_INPUT(dev);
148 virtio_input_event event = {
149 .type = cpu_to_le16(EV_SYN),
150 .code = cpu_to_le16(SYN_REPORT),
151 .value = 0,
152 };
153
154 virtio_input_send(vinput, &event);
155}
156
157static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
158{
159 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
160
161 vhid->hs = qemu_input_handler_register(dev, vhid->handler);
162 if (vhid->display && vhid->hs) {
163 qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL);
164 }
165}
166
167static void virtio_input_hid_unrealize(DeviceState *dev)
168{
169 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
170 qemu_input_handler_unregister(vhid->hs);
171}
172
173static void virtio_input_hid_change_active(VirtIOInput *vinput)
174{
175 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
176
177 if (vinput->active) {
178 qemu_input_handler_activate(vhid->hs);
179 } else {
180 qemu_input_handler_deactivate(vhid->hs);
181 }
182}
183
184static void virtio_input_hid_handle_status(VirtIOInput *vinput,
185 virtio_input_event *event)
186{
187 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
188 int ledbit = 0;
189
190 switch (le16_to_cpu(event->type)) {
191 case EV_LED:
192 if (event->code == LED_NUML) {
193 ledbit = QEMU_NUM_LOCK_LED;
194 } else if (event->code == LED_CAPSL) {
195 ledbit = QEMU_CAPS_LOCK_LED;
196 } else if (event->code == LED_SCROLLL) {
197 ledbit = QEMU_SCROLL_LOCK_LED;
198 }
199 if (event->value) {
200 vhid->ledstate |= ledbit;
201 } else {
202 vhid->ledstate &= ~ledbit;
203 }
204 kbd_put_ledstate(vhid->ledstate);
205 break;
206 default:
207 fprintf(stderr, "%s: unknown type %d\n", __func__,
208 le16_to_cpu(event->type));
209 break;
210 }
211}
212
213static Property virtio_input_hid_properties[] = {
214 DEFINE_PROP_STRING("display", VirtIOInputHID, display),
215 DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
216 DEFINE_PROP_END_OF_LIST(),
217};
218
219static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
220{
221 DeviceClass *dc = DEVICE_CLASS(klass);
222 VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
223
224 device_class_set_props(dc, virtio_input_hid_properties);
225 vic->realize = virtio_input_hid_realize;
226 vic->unrealize = virtio_input_hid_unrealize;
227 vic->change_active = virtio_input_hid_change_active;
228 vic->handle_status = virtio_input_hid_handle_status;
229}
230
231static const TypeInfo virtio_input_hid_info = {
232 .name = TYPE_VIRTIO_INPUT_HID,
233 .parent = TYPE_VIRTIO_INPUT,
234 .instance_size = sizeof(VirtIOInputHID),
235 .class_init = virtio_input_hid_class_init,
236 .abstract = true,
237};
238
239
240
241static QemuInputHandler virtio_keyboard_handler = {
242 .name = VIRTIO_ID_NAME_KEYBOARD,
243 .mask = INPUT_EVENT_MASK_KEY,
244 .event = virtio_input_handle_event,
245 .sync = virtio_input_handle_sync,
246};
247
248static struct virtio_input_config virtio_keyboard_config[] = {
249 {
250 .select = VIRTIO_INPUT_CFG_ID_NAME,
251 .size = sizeof(VIRTIO_ID_NAME_KEYBOARD),
252 .u.string = VIRTIO_ID_NAME_KEYBOARD,
253 },{
254 .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
255 .size = sizeof(struct virtio_input_devids),
256 .u.ids = {
257 .bustype = const_le16(BUS_VIRTUAL),
258 .vendor = const_le16(0x0627),
259 .product = const_le16(0x0001),
260 .version = const_le16(0x0001),
261 },
262 },{
263 .select = VIRTIO_INPUT_CFG_EV_BITS,
264 .subsel = EV_REP,
265 .size = 1,
266 },{
267 .select = VIRTIO_INPUT_CFG_EV_BITS,
268 .subsel = EV_LED,
269 .size = 1,
270 .u.bitmap = {
271 (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
272 },
273 },
274 { },
275};
276
277static void virtio_keyboard_init(Object *obj)
278{
279 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
280 VirtIOInput *vinput = VIRTIO_INPUT(obj);
281
282 vhid->handler = &virtio_keyboard_handler;
283 virtio_input_init_config(vinput, virtio_keyboard_config);
284 virtio_input_key_config(vinput, qemu_input_map_qcode_to_linux,
285 qemu_input_map_qcode_to_linux_len);
286}
287
288static const TypeInfo virtio_keyboard_info = {
289 .name = TYPE_VIRTIO_KEYBOARD,
290 .parent = TYPE_VIRTIO_INPUT_HID,
291 .instance_size = sizeof(VirtIOInputHID),
292 .instance_init = virtio_keyboard_init,
293};
294
295
296
297static QemuInputHandler virtio_mouse_handler = {
298 .name = VIRTIO_ID_NAME_MOUSE,
299 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
300 .event = virtio_input_handle_event,
301 .sync = virtio_input_handle_sync,
302};
303
304static struct virtio_input_config virtio_mouse_config_v1[] = {
305 {
306 .select = VIRTIO_INPUT_CFG_ID_NAME,
307 .size = sizeof(VIRTIO_ID_NAME_MOUSE),
308 .u.string = VIRTIO_ID_NAME_MOUSE,
309 },{
310 .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
311 .size = sizeof(struct virtio_input_devids),
312 .u.ids = {
313 .bustype = const_le16(BUS_VIRTUAL),
314 .vendor = const_le16(0x0627),
315 .product = const_le16(0x0002),
316 .version = const_le16(0x0001),
317 },
318 },{
319 .select = VIRTIO_INPUT_CFG_EV_BITS,
320 .subsel = EV_REL,
321 .size = 1,
322 .u.bitmap = {
323 (1 << REL_X) | (1 << REL_Y),
324 },
325 },
326 { },
327};
328
329static struct virtio_input_config virtio_mouse_config_v2[] = {
330 {
331 .select = VIRTIO_INPUT_CFG_ID_NAME,
332 .size = sizeof(VIRTIO_ID_NAME_MOUSE),
333 .u.string = VIRTIO_ID_NAME_MOUSE,
334 },{
335 .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
336 .size = sizeof(struct virtio_input_devids),
337 .u.ids = {
338 .bustype = const_le16(BUS_VIRTUAL),
339 .vendor = const_le16(0x0627),
340 .product = const_le16(0x0002),
341 .version = const_le16(0x0002),
342 },
343 },{
344 .select = VIRTIO_INPUT_CFG_EV_BITS,
345 .subsel = EV_REL,
346 .size = 2,
347 .u.bitmap = {
348 (1 << REL_X) | (1 << REL_Y),
349 (1 << (REL_WHEEL - 8))
350 },
351 },
352 { },
353};
354
355static Property virtio_mouse_properties[] = {
356 DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
357 DEFINE_PROP_END_OF_LIST(),
358};
359
360static void virtio_mouse_class_init(ObjectClass *klass, void *data)
361{
362 DeviceClass *dc = DEVICE_CLASS(klass);
363
364 device_class_set_props(dc, virtio_mouse_properties);
365}
366
367static void virtio_mouse_init(Object *obj)
368{
369 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
370 VirtIOInput *vinput = VIRTIO_INPUT(obj);
371
372 vhid->handler = &virtio_mouse_handler;
373 virtio_input_init_config(vinput, vhid->wheel_axis
374 ? virtio_mouse_config_v2
375 : virtio_mouse_config_v1);
376 virtio_input_key_config(vinput, keymap_button,
377 ARRAY_SIZE(keymap_button));
378}
379
380static const TypeInfo virtio_mouse_info = {
381 .name = TYPE_VIRTIO_MOUSE,
382 .parent = TYPE_VIRTIO_INPUT_HID,
383 .instance_size = sizeof(VirtIOInputHID),
384 .instance_init = virtio_mouse_init,
385 .class_init = virtio_mouse_class_init,
386};
387
388
389
390static QemuInputHandler virtio_tablet_handler = {
391 .name = VIRTIO_ID_NAME_TABLET,
392 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
393 .event = virtio_input_handle_event,
394 .sync = virtio_input_handle_sync,
395};
396
397static struct virtio_input_config virtio_tablet_config_v1[] = {
398 {
399 .select = VIRTIO_INPUT_CFG_ID_NAME,
400 .size = sizeof(VIRTIO_ID_NAME_TABLET),
401 .u.string = VIRTIO_ID_NAME_TABLET,
402 },{
403 .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
404 .size = sizeof(struct virtio_input_devids),
405 .u.ids = {
406 .bustype = const_le16(BUS_VIRTUAL),
407 .vendor = const_le16(0x0627),
408 .product = const_le16(0x0003),
409 .version = const_le16(0x0001),
410 },
411 },{
412 .select = VIRTIO_INPUT_CFG_EV_BITS,
413 .subsel = EV_ABS,
414 .size = 1,
415 .u.bitmap = {
416 (1 << ABS_X) | (1 << ABS_Y),
417 },
418 },{
419 .select = VIRTIO_INPUT_CFG_ABS_INFO,
420 .subsel = ABS_X,
421 .size = sizeof(virtio_input_absinfo),
422 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
423 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
424 },{
425 .select = VIRTIO_INPUT_CFG_ABS_INFO,
426 .subsel = ABS_Y,
427 .size = sizeof(virtio_input_absinfo),
428 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
429 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
430 },
431 { },
432};
433
434static struct virtio_input_config virtio_tablet_config_v2[] = {
435 {
436 .select = VIRTIO_INPUT_CFG_ID_NAME,
437 .size = sizeof(VIRTIO_ID_NAME_TABLET),
438 .u.string = VIRTIO_ID_NAME_TABLET,
439 },{
440 .select = VIRTIO_INPUT_CFG_ID_DEVIDS,
441 .size = sizeof(struct virtio_input_devids),
442 .u.ids = {
443 .bustype = const_le16(BUS_VIRTUAL),
444 .vendor = const_le16(0x0627),
445 .product = const_le16(0x0003),
446 .version = const_le16(0x0002),
447 },
448 },{
449 .select = VIRTIO_INPUT_CFG_EV_BITS,
450 .subsel = EV_ABS,
451 .size = 1,
452 .u.bitmap = {
453 (1 << ABS_X) | (1 << ABS_Y),
454 },
455 },{
456 .select = VIRTIO_INPUT_CFG_EV_BITS,
457 .subsel = EV_REL,
458 .size = 2,
459 .u.bitmap = {
460 0,
461 (1 << (REL_WHEEL - 8))
462 },
463 },{
464 .select = VIRTIO_INPUT_CFG_ABS_INFO,
465 .subsel = ABS_X,
466 .size = sizeof(virtio_input_absinfo),
467 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
468 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
469 },{
470 .select = VIRTIO_INPUT_CFG_ABS_INFO,
471 .subsel = ABS_Y,
472 .size = sizeof(virtio_input_absinfo),
473 .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
474 .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
475 },
476 { },
477};
478
479static Property virtio_tablet_properties[] = {
480 DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
481 DEFINE_PROP_END_OF_LIST(),
482};
483
484static void virtio_tablet_class_init(ObjectClass *klass, void *data)
485{
486 DeviceClass *dc = DEVICE_CLASS(klass);
487
488 device_class_set_props(dc, virtio_tablet_properties);
489}
490
491static void virtio_tablet_init(Object *obj)
492{
493 VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
494 VirtIOInput *vinput = VIRTIO_INPUT(obj);
495
496 vhid->handler = &virtio_tablet_handler;
497 virtio_input_init_config(vinput, vhid->wheel_axis
498 ? virtio_tablet_config_v2
499 : virtio_tablet_config_v1);
500 virtio_input_key_config(vinput, keymap_button,
501 ARRAY_SIZE(keymap_button));
502}
503
504static const TypeInfo virtio_tablet_info = {
505 .name = TYPE_VIRTIO_TABLET,
506 .parent = TYPE_VIRTIO_INPUT_HID,
507 .instance_size = sizeof(VirtIOInputHID),
508 .instance_init = virtio_tablet_init,
509 .class_init = virtio_tablet_class_init,
510};
511
512
513
514static void virtio_register_types(void)
515{
516 type_register_static(&virtio_input_hid_info);
517 type_register_static(&virtio_keyboard_info);
518 type_register_static(&virtio_mouse_info);
519 type_register_static(&virtio_tablet_info);
520}
521
522type_init(virtio_register_types)
523