xref: /openbmc/qemu/hw/input/virtio-input-hid.c (revision 6016b7b4)
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 
23 /* ----------------------------------------------------------------- */
24 
25 static 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 
35 static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
36     [INPUT_AXIS_X]                   = REL_X,
37     [INPUT_AXIS_Y]                   = REL_Y,
38 };
39 
40 static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
41     [INPUT_AXIS_X]                   = ABS_X,
42     [INPUT_AXIS_Y]                   = ABS_Y,
43 };
44 
45 /* ----------------------------------------------------------------- */
46 
47 static 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 
73 static 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         /* keep gcc happy */
141         break;
142     }
143 }
144 
145 static 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 
157 static 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 
167 static void virtio_input_hid_unrealize(DeviceState *dev)
168 {
169     VirtIOInputHID *vhid = VIRTIO_INPUT_HID(dev);
170     qemu_input_handler_unregister(vhid->hs);
171 }
172 
173 static 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 
184 static 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 
213 static 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 
219 static 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 
231 static 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 
241 static 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 
248 static 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), /* same we use for usb hid devices */
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     { /* end of list */ },
275 };
276 
277 static 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 
288 static 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 
297 static 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 
304 static 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), /* same we use for usb hid devices */
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     { /* end of list */ },
327 };
328 
329 static 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), /* same we use for usb hid devices */
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     { /* end of list */ },
353 };
354 
355 static Property virtio_mouse_properties[] = {
356     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
357     DEFINE_PROP_END_OF_LIST(),
358 };
359 
360 static 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 
367 static 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 
380 static 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 
390 static 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 
397 static 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), /* same we use for usb hid devices */
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     { /* end of list */ },
432 };
433 
434 static 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), /* same we use for usb hid devices */
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     { /* end of list */ },
477 };
478 
479 static Property virtio_tablet_properties[] = {
480     DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true),
481     DEFINE_PROP_END_OF_LIST(),
482 };
483 
484 static 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 
491 static 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 
504 static 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 
514 static 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 
522 type_init(virtio_register_types)
523