2 * Virtio Keyboard Device
4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * Kitae Kim <kt920.kim@samsung.com>
8 * GiWoong Kim <giwoong.kim@samsung.com>
9 * SeokYeon Hwang <syeon.hwang@samsung.com>
10 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "maru_device_ids.h"
32 #include "maru_virtio_keyboard.h"
33 #include "tizen/src/debug_ch.h"
36 MULTI_DEBUG_CHANNEL(qemu, virtio-kbd);
38 VirtQueueElement elem;
40 static void virtio_keyboard_handle(VirtIODevice *vdev, VirtQueue *vq)
42 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
45 if (virtio_queue_empty(vkbd->vq)) {
46 INFO("virtqueue is empty.\n");
50 /* Get a queue buffer which is written by guest side. */
52 index = virtqueue_pop(vq, &elem);
53 TRACE("virtqueue pop.\n");
54 } while (index < VIRTIO_KBD_QUEUE_SIZE);
57 void virtio_keyboard_notify(void *opaque)
59 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
64 ERR("VirtIOKeyboard is NULL.\n");
68 TRACE("[Enter] virtqueue notifier.\n");
70 if (!virtio_queue_ready(vkbd->vq)) {
71 INFO("virtqueue is not ready.\n");
75 if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
76 vkbd->kbdqueue.rptr = 0;
79 qemu_mutex_lock(&vkbd->event_mutex);
80 written_cnt = vkbd->kbdqueue.wptr;
82 while ((written_cnt--)) {
83 kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
85 if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
86 TRACE("FIXME: virtio queue is full.\n");
89 /* Copy keyboard data into guest side. */
90 TRACE("copy: keycode %d, type %d, elem_index %d\n",
91 kbdevt->code, kbdevt->type, vkbd->kbdqueue.rptr);
92 memcpy(elem.in_sg[vkbd->kbdqueue.rptr].iov_base, kbdevt, sizeof(EmulKbdEvent));
93 memset(kbdevt, 0x00, sizeof(EmulKbdEvent));
95 if (vkbd->kbdqueue.wptr > 0) {
96 vkbd->kbdqueue.wptr--;
97 TRACE("written_cnt: %d, wptr: %d, qemu_index: %d\n", written_cnt, vkbd->kbdqueue.wptr, vkbd->kbdqueue.rptr);
100 vkbd->kbdqueue.rptr++;
101 if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
102 vkbd->kbdqueue.rptr = 0;
105 qemu_mutex_unlock(&vkbd->event_mutex);
107 virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
108 virtio_notify(&vkbd->vdev, vkbd->vq);
110 TRACE("[Leave] virtqueue notifier.\n");
113 static void virtio_keyboard_event(void *opaque, int keycode)
117 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
120 ERR("VirtIOKeyboard is NULL.\n");
124 index = &(vkbd->kbdqueue.index);
125 TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
128 ERR("keyboard queue is overflow.\n");
132 if (*index == VIRTIO_KBD_QUEUE_SIZE) {
136 if (keycode < 0xe0) {
137 if (vkbd->extension_key) {
138 switch (keycode & 0x7f) {
139 case 28: /* KP_Enter */
142 case 29: /* Right Ctrl */
145 case 56: /* Right Alt */
154 case 73: /* Page Up */
169 case 81: /* Page Down */
172 case 82: /* Insert */
175 case 83: /* Delete */
179 WARN("There is no keymap for this keycode %d.\n", keycode);
181 vkbd->extension_key = 0;
183 kbdevt.code = keycode & 0x7f;
186 if (!(keycode & 0x80)) {
187 kbdevt.type = 1; /* KEY_PRESSED */
189 kbdevt.type = 0; /* KEY_RELEASED */
192 TRACE("Extension key.\n");
193 kbdevt.code = keycode;
194 vkbd->extension_key = 1;
197 qemu_mutex_lock(&vkbd->event_mutex);
198 memcpy(&vkbd->kbdqueue.kbdevent[(*index)++], &kbdevt, sizeof(kbdevt));
199 TRACE("event: keycode %d, type %d, index %d.\n",
200 kbdevt.code, kbdevt.type, ((*index) - 1));
202 vkbd->kbdqueue.wptr++;
203 qemu_mutex_unlock(&vkbd->event_mutex);
205 TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
207 qemu_bh_schedule(vkbd->bh);
210 static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
211 uint32_t request_feature)
213 TRACE("virtio_keyboard_get_features.\n");
217 static void virtio_keyboard_bh(void *opaque)
219 virtio_keyboard_notify(opaque);
222 static int virtio_keyboard_device_init(VirtIODevice *vdev)
224 VirtIOKeyboard *vkbd;
225 DeviceState *qdev = DEVICE(vdev);
226 vkbd = VIRTIO_KEYBOARD(vdev);
228 INFO("initialize virtio-keyboard device\n");
229 virtio_init(vdev, TYPE_VIRTIO_KEYBOARD, VIRTIO_ID_KEYBOARD, 0);
232 ERR("failed to initialize device\n");
236 memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
237 vkbd->extension_key = 0;
238 qemu_mutex_init(&vkbd->event_mutex);
240 vkbd->vq = virtio_add_queue(vdev, 128, virtio_keyboard_handle);
244 vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
246 /* register keyboard handler */
247 vkbd->eh_entry = qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
252 static int virtio_keyboard_device_exit(DeviceState *qdev)
254 VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
255 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
257 INFO("destroy device\n");
259 qemu_remove_kbd_event_handler(vkbd->eh_entry);
262 qemu_bh_delete(vkbd->bh);
265 qemu_mutex_destroy(&vkbd->event_mutex);
267 virtio_cleanup(vdev);
272 static void virtio_keyboard_class_init(ObjectClass *klass, void *data)
274 DeviceClass *dc = DEVICE_CLASS(klass);
275 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
276 dc->exit = virtio_keyboard_device_exit;
277 vdc->init = virtio_keyboard_device_init;
278 vdc->get_features = virtio_keyboard_get_features;
281 static const TypeInfo virtio_keyboard_info = {
282 .name = TYPE_VIRTIO_KEYBOARD,
283 .parent = TYPE_VIRTIO_DEVICE,
284 .instance_size = sizeof(VirtIOKeyboard),
285 .class_init = virtio_keyboard_class_init,
288 static void virtio_register_types(void)
290 type_register_static(&virtio_keyboard_info);
293 type_init(virtio_register_types)