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;
65 ERR("VirtIOKeyboard is NULL.\n");
69 TRACE("[Enter] virtqueue notifier.\n");
71 if (!virtio_queue_ready(vkbd->vq)) {
72 INFO("virtqueue is not ready.\n");
76 if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
77 vkbd->kbdqueue.rptr = 0;
80 qemu_mutex_lock(&vkbd->event_mutex);
81 written_cnt = vkbd->kbdqueue.wptr;
83 while ((written_cnt--)) {
84 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 VirtIODevice *virtio_keyboard_init(DeviceState *dev)
224 VirtIOKeyboard *vkbd;
225 INFO("initialize virtio-keyboard device\n");
227 vkbd = (VirtIOKeyboard *)virtio_common_init(VIRTIO_KBD_DEVICE_NAME,
228 VIRTIO_ID_KEYBOARD, 0, sizeof(VirtIOKeyboard));
230 ERR("failed to initialize device\n");
234 memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
235 vkbd->extension_key = 0;
236 qemu_mutex_init(&vkbd->event_mutex);
239 vkbd->vdev.get_features = virtio_keyboard_get_features;
240 vkbd->vq = virtio_add_queue(&vkbd->vdev, 128, virtio_keyboard_handle);
244 vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
246 /* register keyboard handler */
247 qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
252 void virtio_keyboard_exit(VirtIODevice *vdev)
254 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
255 INFO("destroy device\n");
257 qemu_remove_kbd_event_handler();
260 qemu_bh_delete(vkbd->bh);
263 qemu_mutex_destroy(&vkbd->event_mutex);
265 virtio_cleanup(vdev);