xref: /qemu/hw/input/virtio-input-hid.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
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 #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 #define VIRTIO_ID_NAME_MULTITOUCH   "QEMU Virtio MultiTouch"
23 
24 /* ----------------------------------------------------------------- */
25 
26 static const unsigned short keymap_button[INPUT_BUTTON__MAX] = {
27     [INPUT_BUTTON_LEFT]              = BTN_LEFT,
28     [INPUT_BUTTON_RIGHT]             = BTN_RIGHT,
29     [INPUT_BUTTON_MIDDLE]            = BTN_MIDDLE,
30     [INPUT_BUTTON_WHEEL_UP]          = BTN_GEAR_UP,
31     [INPUT_BUTTON_WHEEL_DOWN]        = BTN_GEAR_DOWN,
32     [INPUT_BUTTON_SIDE]              = BTN_SIDE,
33     [INPUT_BUTTON_EXTRA]             = BTN_EXTRA,
34     [INPUT_BUTTON_TOUCH]             = BTN_TOUCH,
35 };
36 
37 static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
38     [INPUT_AXIS_X]                   = REL_X,
39     [INPUT_AXIS_Y]                   = REL_Y,
40 };
41 
42 static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
43     [INPUT_AXIS_X]                   = ABS_X,
44     [INPUT_AXIS_Y]                   = ABS_Y,
45 };
46 
47 static const unsigned short axismap_tch[INPUT_AXIS__MAX] = {
48     [INPUT_AXIS_X]                   = ABS_MT_POSITION_X,
49     [INPUT_AXIS_Y]                   = ABS_MT_POSITION_Y,
50 };
51 
52 /* ----------------------------------------------------------------- */
53 
54 static void virtio_input_extend_config(VirtIOInput *vinput,
55                                        const unsigned short *map,
56                                        size_t mapsize,
57                                        uint8_t select, uint8_t subsel)
58 {
59     virtio_input_config ext;
60     int i, bit, byte, bmax = 0;
61 
62     memset(&ext, 0, sizeof(ext));
63     for (i = 0; i < mapsize; i++) {
64         bit = map[i];
65         if (!bit) {
66             continue;
67         }
68         byte = bit / 8;
69         bit  = bit % 8;
70         ext.u.bitmap[byte] |= (1 << bit);
71         if (bmax < byte+1) {
72             bmax = byte+1;
73         }
74     }
75     ext.select = select;
76     ext.subsel = subsel;
77     ext.size   = bmax;
78     virtio_input_add_config(vinput, &ext);
79 }
80 
81 static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
82                                       InputEvent *evt)
83 {
84     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
85     VirtIOInput *vinput = VIRTIO_INPUT(dev);
86     virtio_input_event event;
87     int qcode;
88     InputKeyEvent *key;
89     InputMoveEvent *move;
90     InputBtnEvent *btn;
91     InputMultiTouchEvent *mtt;
92 
93     switch (evt->type) {
94     case INPUT_EVENT_KIND_KEY:
95         key = evt->u.key.data;
96         qcode = qemu_input_key_value_to_qcode(key->key);
97         if (qcode < qemu_input_map_qcode_to_linux_len &&
98             qemu_input_map_qcode_to_linux[qcode]) {
99             event.type  = cpu_to_le16(EV_KEY);
100             event.code  = cpu_to_le16(qemu_input_map_qcode_to_linux[qcode]);
101             event.value = cpu_to_le32(key->down ? 1 : 0);
102             virtio_input_send(vinput, &event);
103         } else {
104             if (key->down) {
105                 fprintf(stderr, "%s: unmapped key: %d [%s]\n", __func__,
106                         qcode, QKeyCode_str(qcode));
107             }
108         }
109         break;
110     case INPUT_EVENT_KIND_BTN:
111         btn = evt->u.btn.data;
112         if (vhid->wheel_axis &&
113             (btn->button == INPUT_BUTTON_WHEEL_UP ||
114              btn->button == INPUT_BUTTON_WHEEL_DOWN) &&
115             btn->down) {
116             event.type  = cpu_to_le16(EV_REL);
117             event.code  = cpu_to_le16(REL_WHEEL);
118             event.value = cpu_to_le32(btn->button == INPUT_BUTTON_WHEEL_UP
119                                       ? 1 : -1);
120             virtio_input_send(vinput, &event);
121         } else if (keymap_button[btn->button]) {
122             event.type  = cpu_to_le16(EV_KEY);
123             event.code  = cpu_to_le16(keymap_button[btn->button]);
124             event.value = cpu_to_le32(btn->down ? 1 : 0);
125             virtio_input_send(vinput, &event);
126         } else {
127             if (btn->down) {
128                 fprintf(stderr, "%s: unmapped button: %d [%s]\n", __func__,
129                         btn->button,
130                         InputButton_str(btn->button));
131             }
132         }
133         break;
134     case INPUT_EVENT_KIND_REL:
135         move = evt->u.rel.data;
136         event.type  = cpu_to_le16(EV_REL);
137         event.code  = cpu_to_le16(axismap_rel[move->axis]);
138         event.value = cpu_to_le32(move->value);
139         virtio_input_send(vinput, &event);
140         break;
141     case INPUT_EVENT_KIND_ABS:
142         move = evt->u.abs.data;
143         event.type  = cpu_to_le16(EV_ABS);
144         event.code  = cpu_to_le16(axismap_abs[move->axis]);
145         event.value = cpu_to_le32(move->value);
146         virtio_input_send(vinput, &event);
147         break;
148     case INPUT_EVENT_KIND_MTT:
149         mtt = evt->u.mtt.data;
150         if (mtt->type == INPUT_MULTI_TOUCH_TYPE_DATA) {
151             event.type  = cpu_to_le16(EV_ABS);
152             event.code  = cpu_to_le16(axismap_tch[mtt->axis]);
153             event.value = cpu_to_le32(mtt->value);
154             virtio_input_send(vinput, &event);
155         } else {
156             event.type  = cpu_to_le16(EV_ABS);
157             event.code  = cpu_to_le16(ABS_MT_SLOT);
158             event.value = cpu_to_le32(mtt->slot);
159             virtio_input_send(vinput, &event);
160             event.type  = cpu_to_le16(EV_ABS);
161             event.code  = cpu_to_le16(ABS_MT_TRACKING_ID);
162             event.value = cpu_to_le32(mtt->tracking_id);
163             virtio_input_send(vinput, &event);
164         }
165         break;
166     default:
167         /* keep gcc happy */
168         break;
169     }
170 }
171 
172 static void virtio_input_handle_sync(DeviceState *dev)
173 {
174     VirtIOInput *vinput = VIRTIO_INPUT(dev);
175     virtio_input_event event = {
176         .type  = cpu_to_le16(EV_SYN),
177         .code  = cpu_to_le16(SYN_REPORT),
178         .value = 0,
179     };
180 
181     virtio_input_send(vinput, &event);
182 }
183 
184 static void virtio_input_hid_realize(DeviceState *dev, Error **errp)
185 {
186     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
187 
188     vhid->hs = qemu_input_handler_register(dev, vhid->handler);
189     if (vhid->display && vhid->hs) {
190         qemu_input_handler_bind(vhid->hs, vhid->display, vhid->head, NULL);
191     }
192 }
193 
194 static void virtio_input_hid_unrealize(DeviceState *dev)
195 {
196     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
197     qemu_input_handler_unregister(vhid->hs);
198 }
199 
200 static void virtio_input_hid_change_active(VirtIOInput *vinput)
201 {
202     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
203 
204     if (vinput->active) {
205         qemu_input_handler_activate(vhid->hs);
206     } else {
207         qemu_input_handler_deactivate(vhid->hs);
208     }
209 }
210 
211 static void virtio_input_hid_handle_status(VirtIOInput *vinput,
212                                            virtio_input_event *event)
213 {
214     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(vinput);
215     int ledbit = 0;
216 
217     switch (le16_to_cpu(event->type)) {
218     case EV_LED:
219         if (event->code == LED_NUML) {
220             ledbit = QEMU_NUM_LOCK_LED;
221         } else if (event->code == LED_CAPSL) {
222             ledbit = QEMU_CAPS_LOCK_LED;
223         } else if (event->code == LED_SCROLLL) {
224             ledbit = QEMU_SCROLL_LOCK_LED;
225         }
226         if (event->value) {
227             vhid->ledstate |= ledbit;
228         } else {
229             vhid->ledstate &= ~ledbit;
230         }
231         kbd_put_ledstate(vhid->ledstate);
232         break;
233     default:
234         fprintf(stderr, "%s: unknown type %d\n", __func__,
235                 le16_to_cpu(event->type));
236         break;
237     }
238 }
239 
240 static const Property virtio_input_hid_properties[] = {
241     DEFINE_PROP_STRING("display", VirtIOInputHID, display),
242     DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0),
243 };
244 
245 static void virtio_input_hid_class_init(ObjectClass *klass, void *data)
246 {
247     DeviceClass *dc = DEVICE_CLASS(klass);
248     VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
249 
250     device_class_set_props(dc, virtio_input_hid_properties);
251     vic->realize       = virtio_input_hid_realize;
252     vic->unrealize     = virtio_input_hid_unrealize;
253     vic->change_active = virtio_input_hid_change_active;
254     vic->handle_status = virtio_input_hid_handle_status;
255 }
256 
257 static const TypeInfo virtio_input_hid_info = {
258     .name          = TYPE_VIRTIO_INPUT_HID,
259     .parent        = TYPE_VIRTIO_INPUT,
260     .instance_size = sizeof(VirtIOInputHID),
261     .class_init    = virtio_input_hid_class_init,
262     .abstract      = true,
263 };
264 
265 /* ----------------------------------------------------------------- */
266 
267 static const QemuInputHandler virtio_keyboard_handler = {
268     .name  = VIRTIO_ID_NAME_KEYBOARD,
269     .mask  = INPUT_EVENT_MASK_KEY,
270     .event = virtio_input_handle_event,
271     .sync  = virtio_input_handle_sync,
272 };
273 
274 static struct virtio_input_config virtio_keyboard_config[] = {
275     {
276         .select    = VIRTIO_INPUT_CFG_ID_NAME,
277         .size      = sizeof(VIRTIO_ID_NAME_KEYBOARD),
278         .u.string  = VIRTIO_ID_NAME_KEYBOARD,
279     },{
280         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
281         .size      = sizeof(struct virtio_input_devids),
282         .u.ids     = {
283             .bustype = const_le16(BUS_VIRTUAL),
284             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
285             .product = const_le16(0x0001),
286             .version = const_le16(0x0001),
287         },
288     },{
289         .select    = VIRTIO_INPUT_CFG_EV_BITS,
290         .subsel    = EV_REP,
291         .size      = 1,
292     },{
293         .select    = VIRTIO_INPUT_CFG_EV_BITS,
294         .subsel    = EV_LED,
295         .size      = 1,
296         .u.bitmap  = {
297             (1 << LED_NUML) | (1 << LED_CAPSL) | (1 << LED_SCROLLL),
298         },
299     },
300     { /* end of list */ },
301 };
302 
303 static void virtio_keyboard_init(Object *obj)
304 {
305     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
306     VirtIOInput *vinput = VIRTIO_INPUT(obj);
307 
308     vhid->handler = &virtio_keyboard_handler;
309     virtio_input_init_config(vinput, virtio_keyboard_config);
310     virtio_input_extend_config(vinput, qemu_input_map_qcode_to_linux,
311                                qemu_input_map_qcode_to_linux_len,
312                                VIRTIO_INPUT_CFG_EV_BITS, EV_KEY);
313 }
314 
315 static const TypeInfo virtio_keyboard_info = {
316     .name          = TYPE_VIRTIO_KEYBOARD,
317     .parent        = TYPE_VIRTIO_INPUT_HID,
318     .instance_size = sizeof(VirtIOInputHID),
319     .instance_init = virtio_keyboard_init,
320 };
321 
322 /* ----------------------------------------------------------------- */
323 
324 static const QemuInputHandler virtio_mouse_handler = {
325     .name  = VIRTIO_ID_NAME_MOUSE,
326     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
327     .event = virtio_input_handle_event,
328     .sync  = virtio_input_handle_sync,
329 };
330 
331 static struct virtio_input_config virtio_mouse_config_v1[] = {
332     {
333         .select    = VIRTIO_INPUT_CFG_ID_NAME,
334         .size      = sizeof(VIRTIO_ID_NAME_MOUSE),
335         .u.string  = VIRTIO_ID_NAME_MOUSE,
336     },{
337         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
338         .size      = sizeof(struct virtio_input_devids),
339         .u.ids     = {
340             .bustype = const_le16(BUS_VIRTUAL),
341             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
342             .product = const_le16(0x0002),
343             .version = const_le16(0x0001),
344         },
345     },{
346         .select    = VIRTIO_INPUT_CFG_EV_BITS,
347         .subsel    = EV_REL,
348         .size      = 1,
349         .u.bitmap  = {
350             (1 << REL_X) | (1 << REL_Y),
351         },
352     },
353     { /* end of list */ },
354 };
355 
356 static struct virtio_input_config virtio_mouse_config_v2[] = {
357     {
358         .select    = VIRTIO_INPUT_CFG_ID_NAME,
359         .size      = sizeof(VIRTIO_ID_NAME_MOUSE),
360         .u.string  = VIRTIO_ID_NAME_MOUSE,
361     },{
362         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
363         .size      = sizeof(struct virtio_input_devids),
364         .u.ids     = {
365             .bustype = const_le16(BUS_VIRTUAL),
366             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
367             .product = const_le16(0x0002),
368             .version = const_le16(0x0002),
369         },
370     },{
371         .select    = VIRTIO_INPUT_CFG_EV_BITS,
372         .subsel    = EV_REL,
373         .size      = 2,
374         .u.bitmap  = {
375             (1 << REL_X) | (1 << REL_Y),
376             (1 << (REL_WHEEL - 8))
377         },
378     },
379     { /* end of list */ },
380 };
381 
382 static const Property virtio_mouse_properties[] = {
383     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
384 };
385 
386 static void virtio_mouse_class_init(ObjectClass *klass, void *data)
387 {
388     DeviceClass *dc = DEVICE_CLASS(klass);
389 
390     device_class_set_props(dc, virtio_mouse_properties);
391 }
392 
393 static void virtio_mouse_init(Object *obj)
394 {
395     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
396     VirtIOInput *vinput = VIRTIO_INPUT(obj);
397 
398     vhid->handler = &virtio_mouse_handler;
399     virtio_input_init_config(vinput, vhid->wheel_axis
400                              ? virtio_mouse_config_v2
401                              : virtio_mouse_config_v1);
402     virtio_input_extend_config(vinput, keymap_button,
403                                ARRAY_SIZE(keymap_button),
404                                VIRTIO_INPUT_CFG_EV_BITS, EV_KEY);
405 }
406 
407 static const TypeInfo virtio_mouse_info = {
408     .name          = TYPE_VIRTIO_MOUSE,
409     .parent        = TYPE_VIRTIO_INPUT_HID,
410     .instance_size = sizeof(VirtIOInputHID),
411     .instance_init = virtio_mouse_init,
412     .class_init    = virtio_mouse_class_init,
413 };
414 
415 /* ----------------------------------------------------------------- */
416 
417 static const QemuInputHandler virtio_tablet_handler = {
418     .name  = VIRTIO_ID_NAME_TABLET,
419     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
420     .event = virtio_input_handle_event,
421     .sync  = virtio_input_handle_sync,
422 };
423 
424 static struct virtio_input_config virtio_tablet_config_v1[] = {
425     {
426         .select    = VIRTIO_INPUT_CFG_ID_NAME,
427         .size      = sizeof(VIRTIO_ID_NAME_TABLET),
428         .u.string  = VIRTIO_ID_NAME_TABLET,
429     },{
430         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
431         .size      = sizeof(struct virtio_input_devids),
432         .u.ids     = {
433             .bustype = const_le16(BUS_VIRTUAL),
434             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
435             .product = const_le16(0x0003),
436             .version = const_le16(0x0001),
437         },
438     },{
439         .select    = VIRTIO_INPUT_CFG_EV_BITS,
440         .subsel    = EV_ABS,
441         .size      = 1,
442         .u.bitmap  = {
443             (1 << ABS_X) | (1 << ABS_Y),
444         },
445     },{
446         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
447         .subsel    = ABS_X,
448         .size      = sizeof(virtio_input_absinfo),
449         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
450         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
451     },{
452         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
453         .subsel    = ABS_Y,
454         .size      = sizeof(virtio_input_absinfo),
455         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
456         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
457     },
458     { /* end of list */ },
459 };
460 
461 static struct virtio_input_config virtio_tablet_config_v2[] = {
462     {
463         .select    = VIRTIO_INPUT_CFG_ID_NAME,
464         .size      = sizeof(VIRTIO_ID_NAME_TABLET),
465         .u.string  = VIRTIO_ID_NAME_TABLET,
466     },{
467         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
468         .size      = sizeof(struct virtio_input_devids),
469         .u.ids     = {
470             .bustype = const_le16(BUS_VIRTUAL),
471             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
472             .product = const_le16(0x0003),
473             .version = const_le16(0x0002),
474         },
475     },{
476         .select    = VIRTIO_INPUT_CFG_EV_BITS,
477         .subsel    = EV_ABS,
478         .size      = 1,
479         .u.bitmap  = {
480             (1 << ABS_X) | (1 << ABS_Y),
481         },
482     },{
483         .select    = VIRTIO_INPUT_CFG_EV_BITS,
484         .subsel    = EV_REL,
485         .size      = 2,
486         .u.bitmap  = {
487             0,
488             (1 << (REL_WHEEL - 8))
489         },
490     },{
491         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
492         .subsel    = ABS_X,
493         .size      = sizeof(virtio_input_absinfo),
494         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
495         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
496     },{
497         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
498         .subsel    = ABS_Y,
499         .size      = sizeof(virtio_input_absinfo),
500         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
501         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
502     },
503     { /* end of list */ },
504 };
505 
506 static const Property virtio_tablet_properties[] = {
507     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
508 };
509 
510 static void virtio_tablet_class_init(ObjectClass *klass, void *data)
511 {
512     DeviceClass *dc = DEVICE_CLASS(klass);
513 
514     device_class_set_props(dc, virtio_tablet_properties);
515 }
516 
517 static void virtio_tablet_init(Object *obj)
518 {
519     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
520     VirtIOInput *vinput = VIRTIO_INPUT(obj);
521 
522     vhid->handler = &virtio_tablet_handler;
523     virtio_input_init_config(vinput, vhid->wheel_axis
524                              ? virtio_tablet_config_v2
525                              : virtio_tablet_config_v1);
526     virtio_input_extend_config(vinput, keymap_button,
527                                ARRAY_SIZE(keymap_button),
528                                VIRTIO_INPUT_CFG_EV_BITS, EV_KEY);
529 }
530 
531 static const TypeInfo virtio_tablet_info = {
532     .name          = TYPE_VIRTIO_TABLET,
533     .parent        = TYPE_VIRTIO_INPUT_HID,
534     .instance_size = sizeof(VirtIOInputHID),
535     .instance_init = virtio_tablet_init,
536     .class_init    = virtio_tablet_class_init,
537 };
538 
539 /* ----------------------------------------------------------------- */
540 
541 static const QemuInputHandler virtio_multitouch_handler = {
542     .name  = VIRTIO_ID_NAME_MULTITOUCH,
543     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_MTT,
544     .event = virtio_input_handle_event,
545     .sync  = virtio_input_handle_sync,
546 };
547 
548 static struct virtio_input_config virtio_multitouch_config[] = {
549     {
550         .select    = VIRTIO_INPUT_CFG_ID_NAME,
551         .size      = sizeof(VIRTIO_ID_NAME_MULTITOUCH),
552         .u.string  = VIRTIO_ID_NAME_MULTITOUCH,
553     },{
554         .select    = VIRTIO_INPUT_CFG_ID_DEVIDS,
555         .size      = sizeof(struct virtio_input_devids),
556         .u.ids     = {
557             .bustype = const_le16(BUS_VIRTUAL),
558             .vendor  = const_le16(0x0627), /* same we use for usb hid devices */
559             .product = const_le16(0x0003),
560             .version = const_le16(0x0001),
561         },
562     },{
563         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
564         .subsel    = ABS_MT_SLOT,
565         .size      = sizeof(virtio_input_absinfo),
566         .u.abs.min = const_le32(INPUT_EVENT_SLOTS_MIN),
567         .u.abs.max = const_le32(INPUT_EVENT_SLOTS_MAX),
568     },{
569         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
570         .subsel    = ABS_MT_TRACKING_ID,
571         .size      = sizeof(virtio_input_absinfo),
572         .u.abs.min = const_le32(INPUT_EVENT_SLOTS_MIN),
573         .u.abs.max = const_le32(INPUT_EVENT_SLOTS_MAX),
574     },{
575         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
576         .subsel    = ABS_MT_POSITION_X,
577         .size      = sizeof(virtio_input_absinfo),
578         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
579         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
580     },{
581         .select    = VIRTIO_INPUT_CFG_ABS_INFO,
582         .subsel    = ABS_MT_POSITION_Y,
583         .size      = sizeof(virtio_input_absinfo),
584         .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
585         .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
586     },
587     { /* end of list */ },
588 };
589 
590 static void virtio_multitouch_init(Object *obj)
591 {
592     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj);
593     VirtIOInput *vinput = VIRTIO_INPUT(obj);
594     unsigned short abs_props[] = {
595         INPUT_PROP_DIRECT,
596     };
597     unsigned short abs_bits[] = {
598         ABS_MT_SLOT,
599         ABS_MT_TRACKING_ID,
600         ABS_MT_POSITION_X,
601         ABS_MT_POSITION_Y,
602     };
603 
604     vhid->handler = &virtio_multitouch_handler;
605     virtio_input_init_config(vinput, virtio_multitouch_config);
606     virtio_input_extend_config(vinput, keymap_button,
607                                ARRAY_SIZE(keymap_button),
608                                VIRTIO_INPUT_CFG_EV_BITS, EV_KEY);
609     virtio_input_extend_config(vinput, abs_props,
610                                ARRAY_SIZE(abs_props),
611                                VIRTIO_INPUT_CFG_PROP_BITS, 0);
612     virtio_input_extend_config(vinput, abs_bits,
613                                ARRAY_SIZE(abs_bits),
614                                VIRTIO_INPUT_CFG_EV_BITS, EV_ABS);
615 }
616 
617 static const TypeInfo virtio_multitouch_info = {
618     .name          = TYPE_VIRTIO_MULTITOUCH,
619     .parent        = TYPE_VIRTIO_INPUT_HID,
620     .instance_size = sizeof(VirtIOInputHID),
621     .instance_init = virtio_multitouch_init,
622 };
623 
624 /* ----------------------------------------------------------------- */
625 
626 static void virtio_register_types(void)
627 {
628     type_register_static(&virtio_input_hid_info);
629     type_register_static(&virtio_keyboard_info);
630     type_register_static(&virtio_mouse_info);
631     type_register_static(&virtio_tablet_info);
632     type_register_static(&virtio_multitouch_info);
633 }
634 
635 type_init(virtio_register_types)
636